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 */
35struct 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 */
53struct 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
60void Curl_bufcp_init(struct bufc_pool *pool,
61 size_t chunk_size, size_t spare_max);
62
63void 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 */
94struct 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 */
125void 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 */
131void Curl_bufq_init2(struct bufq *q, size_t chunk_size,
132 size_t max_chunks, int opts);
133
134void 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 */
141void Curl_bufq_reset(struct bufq *q);
142
143/**
144 * Free all resources held by the buffer queue.
145 */
146void Curl_bufq_free(struct bufq *q);
147
148/**
149 * Return the total amount of data in the queue.
150 */
151size_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 */
159size_t Curl_bufq_space(const struct bufq *q);
160
161/**
162 * Returns TRUE iff there is no data in the buffer queue.
163 */
164bool Curl_bufq_is_empty(const struct bufq *q);
165
166/**
167 * Returns TRUE iff there is no space left in the buffer queue.
168 */
169bool 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 */
177ssize_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 */
187ssize_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 */
199bool Curl_bufq_peek(struct bufq *q,
200 const unsigned char **pbuf, size_t *plen);
201
202bool 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 */
210void Curl_bufq_skip(struct bufq *q, size_t amount);
211
212typedef 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 */
224ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
225 void *writer_ctx, CURLcode *err);
226
227typedef 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 */
240ssize_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 */
249ssize_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 */
260ssize_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