1 #ifndef HEADER_CURL_BUFQ_H 2 #define HEADER_CURL_BUFQ_H 3 /*************************************************************************** 4 * _ _ ____ _ 5 * Project ___| | | | _ \| | 6 * / __| | | | |_) | | 7 * | (__| |_| | _ <| |___ 8 * \___|\___/|_| \_\_____| 9 * 10 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 11 * 12 * This software is licensed as described in the file COPYING, which 13 * you should have received as part of this distribution. The terms 14 * are also available at https://curl.se/docs/copyright.html. 15 * 16 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 * copies of the Software, and permit persons to whom the Software is 18 * furnished to do so, under the terms of the COPYING file. 19 * 20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 * KIND, either express or implied. 22 * 23 * SPDX-License-Identifier: curl 24 * 25 ***************************************************************************/ 26 #include "curl_setup.h" 27 28 #include <curl/curl.h> 29 30 /** 31 * A chunk of bytes for reading and writing. 32 * The size is fixed a creation with read and write offset 33 * for where unread content is. 34 */ 35 struct buf_chunk { 36 struct buf_chunk *next; /* to keep it in a list */ 37 size_t dlen; /* the amount of allocated x.data[] */ 38 size_t r_offset; /* first unread bytes */ 39 size_t w_offset; /* one after last written byte */ 40 union { 41 unsigned char data[1]; /* the buffer for `dlen` bytes */ 42 void *dummy; /* alignment */ 43 } x; 44 }; 45 46 /** 47 * A pool for providing/keeping a number of chunks of the same size 48 * 49 * The same pool can be shared by many `bufq` instances. However, a pool 50 * is not thread safe. All bufqs using it are supposed to operate in the 51 * same thread. 52 */ 53 struct bufc_pool { 54 struct buf_chunk *spare; /* list of available spare chunks */ 55 size_t chunk_size; /* the size of chunks in this pool */ 56 size_t spare_count; /* current number of spare chunks in list */ 57 size_t spare_max; /* max number of spares to keep */ 58 }; 59 60 void Curl_bufcp_init(struct bufc_pool *pool, 61 size_t chunk_size, size_t spare_max); 62 63 void Curl_bufcp_free(struct bufc_pool *pool); 64 65 /** 66 * A queue of byte chunks for reading and writing. 67 * Reading is done from `head`, writing is done to `tail`. 68 * 69 * `bufq`s can be empty or full or neither. Its `len` is the number 70 * of bytes that can be read. For an empty bufq, `len` will be 0. 71 * 72 * By default, a bufq can hold up to `max_chunks * chunk_size` number 73 * of bytes. When `max_chunks` are used (in the `head` list) and the 74 * `tail` chunk is full, the bufq will report that it is full. 75 * 76 * On a full bufq, `len` may be less than the maximum number of bytes, 77 * e.g. when the head chunk is partially read. `len` may also become 78 * larger than the max when option `BUFQ_OPT_SOFT_LIMIT` is used. 79 * 80 * By default, writing to a full bufq will return (-1, CURLE_AGAIN). Same 81 * as reading from an empty bufq. 82 * With `BUFQ_OPT_SOFT_LIMIT` set, a bufq will allow writing becond this 83 * limit and use more than `max_chunks`. However it will report that it 84 * is full nevertheless. This is provided for situation where writes 85 * preferably never fail (except for memory exhaustion). 86 * 87 * By default and without a pool, a bufq will keep chunks that read 88 * read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will 89 * disable that and free chunks once they become empty. 90 * 91 * When providing a pool to a bufq, all chunk creation and spare handling 92 * will be delegated to that pool. 93 */ 94 struct bufq { 95 struct buf_chunk *head; /* chunk with bytes to read from */ 96 struct buf_chunk *tail; /* chunk to write to */ 97 struct buf_chunk *spare; /* list of free chunks, unless `pool` */ 98 struct bufc_pool *pool; /* optional pool for free chunks */ 99 size_t chunk_count; /* current number of chunks in `head+spare` */ 100 size_t max_chunks; /* max `head` chunks to use */ 101 size_t chunk_size; /* size of chunks to manage */ 102 int opts; /* options for handling queue, see below */ 103 }; 104 105 /** 106 * Default behaviour: chunk limit is "hard", meaning attempts to write 107 * more bytes than can be hold in `max_chunks` is refused and will return 108 * -1, CURLE_AGAIN. */ 109 #define BUFQ_OPT_NONE (0) 110 /** 111 * Make `max_chunks` a "soft" limit. A bufq will report that it is "full" 112 * when `max_chunks` are used, but allows writing beyond this limit. 113 */ 114 #define BUFQ_OPT_SOFT_LIMIT (1 << 0) 115 /** 116 * Do not keep spare chunks. 117 */ 118 #define BUFQ_OPT_NO_SPARES (1 << 1) 119 120 /** 121 * Initialize a buffer queue that can hold up to `max_chunks` buffers 122 * each of size `chunk_size`. The bufq will not allow writing of 123 * more bytes than can be held in `max_chunks`. 124 */ 125 void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks); 126 127 /** 128 * Initialize a buffer queue that can hold up to `max_chunks` buffers 129 * each of size `chunk_size` with the given options. See `BUFQ_OPT_*`. 130 */ 131 void Curl_bufq_init2(struct bufq *q, size_t chunk_size, 132 size_t max_chunks, int opts); 133 134 void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool, 135 size_t max_chunks, int opts); 136 137 /** 138 * Reset the buffer queue to be empty. Will keep any allocated buffer 139 * chunks around. 140 */ 141 void Curl_bufq_reset(struct bufq *q); 142 143 /** 144 * Free all resources held by the buffer queue. 145 */ 146 void Curl_bufq_free(struct bufq *q); 147 148 /** 149 * Return the total amount of data in the queue. 150 */ 151 size_t Curl_bufq_len(const struct bufq *q); 152 153 /** 154 * Return the total amount of free space in the queue. 155 * The returned length is the number of bytes that can 156 * be expected to be written successfully to the bufq, 157 * providing no memory allocations fail. 158 */ 159 size_t Curl_bufq_space(const struct bufq *q); 160 161 /** 162 * Returns TRUE iff there is no data in the buffer queue. 163 */ 164 bool Curl_bufq_is_empty(const struct bufq *q); 165 166 /** 167 * Returns TRUE iff there is no space left in the buffer queue. 168 */ 169 bool Curl_bufq_is_full(const struct bufq *q); 170 171 /** 172 * Write buf to the end of the buffer queue. The buf is copied 173 * and the amount of copied bytes is returned. 174 * A return code of -1 indicates an error, setting `err` to the 175 * cause. An err of CURLE_AGAIN is returned if the buffer queue is full. 176 */ 177 ssize_t Curl_bufq_write(struct bufq *q, 178 const unsigned char *buf, size_t len, 179 CURLcode *err); 180 181 /** 182 * Read buf from the start of the buffer queue. The buf is copied 183 * and the amount of copied bytes is returned. 184 * A return code of -1 indicates an error, setting `err` to the 185 * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty. 186 */ 187 ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, 188 CURLcode *err); 189 190 /** 191 * Peek at the head chunk in the buffer queue. Returns a pointer to 192 * the chunk buf (at the current offset) and its length. Does not 193 * modify the buffer queue. 194 * Returns TRUE iff bytes are available. Sets `pbuf` to NULL and `plen` 195 * to 0 when no bytes are available. 196 * Repeated calls return the same information until the buffer queue 197 * is modified, see `Curl_bufq_skip()`` 198 */ 199 bool Curl_bufq_peek(struct bufq *q, 200 const unsigned char **pbuf, size_t *plen); 201 202 bool Curl_bufq_peek_at(struct bufq *q, size_t offset, 203 const unsigned char **pbuf, size_t *plen); 204 205 /** 206 * Tell the buffer queue to discard `amount` buf bytes at the head 207 * of the queue. Skipping more buf than is currently buffered will 208 * just empty the queue. 209 */ 210 void Curl_bufq_skip(struct bufq *q, size_t amount); 211 212 typedef ssize_t Curl_bufq_writer(void *writer_ctx, 213 const unsigned char *buf, size_t len, 214 CURLcode *err); 215 /** 216 * Passes the chunks in the buffer queue to the writer and returns 217 * the amount of buf written. A writer may return -1 and CURLE_AGAIN 218 * to indicate blocking at which point the queue will stop and return 219 * the amount of buf passed so far. 220 * -1 is returned on any other errors reported by the writer. 221 * Note that in case of a -1 chunks may have been written and 222 * the buffer queue will have different length than before. 223 */ 224 ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, 225 void *writer_ctx, CURLcode *err); 226 227 typedef ssize_t Curl_bufq_reader(void *reader_ctx, 228 unsigned char *buf, size_t len, 229 CURLcode *err); 230 231 /** 232 * Read date and append it to the end of the buffer queue until the 233 * reader returns blocking or the queue is full. A reader returns 234 * -1 and CURLE_AGAIN to indicate blocking. 235 * Returns the total amount of buf read (may be 0) or -1 on other 236 * reader errors. 237 * Note that in case of a -1 chunks may have been read and 238 * the buffer queue will have different length than before. 239 */ 240 ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, 241 void *reader_ctx, CURLcode *err); 242 243 /** 244 * Read *once* up to `max_len` bytes and append it to the buffer. 245 * if `max_len` is 0, no limit is imposed besides the chunk space. 246 * Returns the total amount of buf read (may be 0) or -1 on other 247 * reader errors. 248 */ 249 ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, 250 Curl_bufq_reader *reader, void *reader_ctx, 251 CURLcode *err); 252 253 /** 254 * Write buf to the end of the buffer queue. 255 * Will write bufq content or passed `buf` directly using the `writer` 256 * callback when it sees fit. 'buf' might get passed directly 257 * on or is placed into the buffer, depending on `len` and current 258 * amount buffered, chunk size, etc. 259 */ 260 ssize_t Curl_bufq_write_pass(struct bufq *q, 261 const unsigned char *buf, size_t len, 262 Curl_bufq_writer *writer, void *writer_ctx, 263 CURLcode *err); 264 265 #endif /* HEADER_CURL_BUFQ_H */ 266