bufq.h (9943B)
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 * 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 * Returns TRUE iff there is no data in the buffer queue. 155 */ 156 bool Curl_bufq_is_empty(const struct bufq *q); 157 158 /** 159 * Returns TRUE iff there is no space left in the buffer queue. 160 */ 161 bool Curl_bufq_is_full(const struct bufq *q); 162 163 /** 164 * Write buf to the end of the buffer queue. The buf is copied 165 * and the amount of copied bytes is returned. 166 * CURLE_AGAIN is returned if the buffer queue is full. 167 */ 168 CURLcode Curl_bufq_write(struct bufq *q, 169 const unsigned char *buf, size_t len, 170 size_t *pnwritten); 171 172 CURLcode Curl_bufq_cwrite(struct bufq *q, 173 const char *buf, size_t len, 174 size_t *pnwritten); 175 176 /** 177 * Read buf from the start of the buffer queue. The buf is copied 178 * and the amount of copied bytes is returned. 179 */ 180 CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, 181 size_t *pnread); 182 183 CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len, 184 size_t *pnread); 185 186 /** 187 * Peek at the head chunk in the buffer queue. Returns a pointer to 188 * the chunk buf (at the current offset) and its length. Does not 189 * modify the buffer queue. 190 * Returns TRUE iff bytes are available. Sets `pbuf` to NULL and `plen` 191 * to 0 when no bytes are available. 192 * Repeated calls return the same information until the buffer queue 193 * is modified, see `Curl_bufq_skip()`` 194 */ 195 bool Curl_bufq_peek(struct bufq *q, 196 const unsigned char **pbuf, size_t *plen); 197 198 bool Curl_bufq_peek_at(struct bufq *q, size_t offset, 199 const unsigned char **pbuf, size_t *plen); 200 201 /** 202 * Tell the buffer queue to discard `amount` buf bytes at the head 203 * of the queue. Skipping more buf than is currently buffered will 204 * just empty the queue. 205 */ 206 void Curl_bufq_skip(struct bufq *q, size_t amount); 207 208 typedef CURLcode Curl_bufq_writer(void *writer_ctx, 209 const unsigned char *buf, size_t len, 210 size_t *pwritten); 211 /** 212 * Passes the chunks in the buffer queue to the writer and returns 213 * the amount of buf written. A writer may return -1 and CURLE_AGAIN 214 * to indicate blocking at which point the queue will stop and return 215 * the amount of buf passed so far. 216 * -1 is returned on any other errors reported by the writer. 217 * Note that in case of a -1 chunks may have been written and 218 * the buffer queue will have different length than before. 219 */ 220 CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, 221 void *writer_ctx, size_t *pwritten); 222 223 typedef CURLcode Curl_bufq_reader(void *reader_ctx, 224 unsigned char *buf, size_t len, 225 size_t *pnread); 226 227 /** 228 * Read date and append it to the end of the buffer queue until the 229 * reader returns blocking or the queue is full. A reader returns 230 * CURLE_AGAIN to indicate blocking. 231 * Returns the total amount of buf read (may be 0) in `pnread` on success. 232 * Note that in case of an error chunks may have been read and 233 * the buffer queue will have different length than before. 234 */ 235 CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, 236 void *reader_ctx, size_t *pnread); 237 238 /** 239 * Read *once* up to `max_len` bytes and append it to the buffer. 240 * if `max_len` is 0, no limit is imposed besides the chunk space. 241 * Returns the total amount of buf read (may be 0) or -1 on other 242 * reader errors. 243 */ 244 CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len, 245 Curl_bufq_reader *reader, void *reader_ctx, 246 size_t *pnread); 247 248 /** 249 * Write buf to the end of the buffer queue. 250 * Will write bufq content or passed `buf` directly using the `writer` 251 * callback when it sees fit. 'buf' might get passed directly 252 * on or is placed into the buffer, depending on `len` and current 253 * amount buffered, chunk size, etc. 254 */ 255 CURLcode Curl_bufq_write_pass(struct bufq *q, 256 const unsigned char *buf, size_t len, 257 Curl_bufq_writer *writer, void *writer_ctx, 258 size_t *pwritten); 259 260 #endif /* HEADER_CURL_BUFQ_H */