1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker #include "bufq.h"
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
29*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
30*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
31*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
32*6236dae4SAndroid Build Coastguard Worker
chunk_is_empty(const struct buf_chunk * chunk)33*6236dae4SAndroid Build Coastguard Worker static bool chunk_is_empty(const struct buf_chunk *chunk)
34*6236dae4SAndroid Build Coastguard Worker {
35*6236dae4SAndroid Build Coastguard Worker return chunk->r_offset >= chunk->w_offset;
36*6236dae4SAndroid Build Coastguard Worker }
37*6236dae4SAndroid Build Coastguard Worker
chunk_is_full(const struct buf_chunk * chunk)38*6236dae4SAndroid Build Coastguard Worker static bool chunk_is_full(const struct buf_chunk *chunk)
39*6236dae4SAndroid Build Coastguard Worker {
40*6236dae4SAndroid Build Coastguard Worker return chunk->w_offset >= chunk->dlen;
41*6236dae4SAndroid Build Coastguard Worker }
42*6236dae4SAndroid Build Coastguard Worker
chunk_len(const struct buf_chunk * chunk)43*6236dae4SAndroid Build Coastguard Worker static size_t chunk_len(const struct buf_chunk *chunk)
44*6236dae4SAndroid Build Coastguard Worker {
45*6236dae4SAndroid Build Coastguard Worker return chunk->w_offset - chunk->r_offset;
46*6236dae4SAndroid Build Coastguard Worker }
47*6236dae4SAndroid Build Coastguard Worker
chunk_space(const struct buf_chunk * chunk)48*6236dae4SAndroid Build Coastguard Worker static size_t chunk_space(const struct buf_chunk *chunk)
49*6236dae4SAndroid Build Coastguard Worker {
50*6236dae4SAndroid Build Coastguard Worker return chunk->dlen - chunk->w_offset;
51*6236dae4SAndroid Build Coastguard Worker }
52*6236dae4SAndroid Build Coastguard Worker
chunk_reset(struct buf_chunk * chunk)53*6236dae4SAndroid Build Coastguard Worker static void chunk_reset(struct buf_chunk *chunk)
54*6236dae4SAndroid Build Coastguard Worker {
55*6236dae4SAndroid Build Coastguard Worker chunk->next = NULL;
56*6236dae4SAndroid Build Coastguard Worker chunk->r_offset = chunk->w_offset = 0;
57*6236dae4SAndroid Build Coastguard Worker }
58*6236dae4SAndroid Build Coastguard Worker
chunk_append(struct buf_chunk * chunk,const unsigned char * buf,size_t len)59*6236dae4SAndroid Build Coastguard Worker static size_t chunk_append(struct buf_chunk *chunk,
60*6236dae4SAndroid Build Coastguard Worker const unsigned char *buf, size_t len)
61*6236dae4SAndroid Build Coastguard Worker {
62*6236dae4SAndroid Build Coastguard Worker unsigned char *p = &chunk->x.data[chunk->w_offset];
63*6236dae4SAndroid Build Coastguard Worker size_t n = chunk->dlen - chunk->w_offset;
64*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->dlen >= chunk->w_offset);
65*6236dae4SAndroid Build Coastguard Worker if(n) {
66*6236dae4SAndroid Build Coastguard Worker n = CURLMIN(n, len);
67*6236dae4SAndroid Build Coastguard Worker memcpy(p, buf, n);
68*6236dae4SAndroid Build Coastguard Worker chunk->w_offset += n;
69*6236dae4SAndroid Build Coastguard Worker }
70*6236dae4SAndroid Build Coastguard Worker return n;
71*6236dae4SAndroid Build Coastguard Worker }
72*6236dae4SAndroid Build Coastguard Worker
chunk_read(struct buf_chunk * chunk,unsigned char * buf,size_t len)73*6236dae4SAndroid Build Coastguard Worker static size_t chunk_read(struct buf_chunk *chunk,
74*6236dae4SAndroid Build Coastguard Worker unsigned char *buf, size_t len)
75*6236dae4SAndroid Build Coastguard Worker {
76*6236dae4SAndroid Build Coastguard Worker unsigned char *p = &chunk->x.data[chunk->r_offset];
77*6236dae4SAndroid Build Coastguard Worker size_t n = chunk->w_offset - chunk->r_offset;
78*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
79*6236dae4SAndroid Build Coastguard Worker if(!n) {
80*6236dae4SAndroid Build Coastguard Worker return 0;
81*6236dae4SAndroid Build Coastguard Worker }
82*6236dae4SAndroid Build Coastguard Worker else if(n <= len) {
83*6236dae4SAndroid Build Coastguard Worker memcpy(buf, p, n);
84*6236dae4SAndroid Build Coastguard Worker chunk->r_offset = chunk->w_offset = 0;
85*6236dae4SAndroid Build Coastguard Worker return n;
86*6236dae4SAndroid Build Coastguard Worker }
87*6236dae4SAndroid Build Coastguard Worker else {
88*6236dae4SAndroid Build Coastguard Worker memcpy(buf, p, len);
89*6236dae4SAndroid Build Coastguard Worker chunk->r_offset += len;
90*6236dae4SAndroid Build Coastguard Worker return len;
91*6236dae4SAndroid Build Coastguard Worker }
92*6236dae4SAndroid Build Coastguard Worker }
93*6236dae4SAndroid Build Coastguard Worker
chunk_unwrite(struct buf_chunk * chunk,size_t len)94*6236dae4SAndroid Build Coastguard Worker static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len)
95*6236dae4SAndroid Build Coastguard Worker {
96*6236dae4SAndroid Build Coastguard Worker size_t n = chunk->w_offset - chunk->r_offset;
97*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
98*6236dae4SAndroid Build Coastguard Worker if(!n) {
99*6236dae4SAndroid Build Coastguard Worker return 0;
100*6236dae4SAndroid Build Coastguard Worker }
101*6236dae4SAndroid Build Coastguard Worker else if(n <= len) {
102*6236dae4SAndroid Build Coastguard Worker chunk->r_offset = chunk->w_offset = 0;
103*6236dae4SAndroid Build Coastguard Worker return n;
104*6236dae4SAndroid Build Coastguard Worker }
105*6236dae4SAndroid Build Coastguard Worker else {
106*6236dae4SAndroid Build Coastguard Worker chunk->w_offset -= len;
107*6236dae4SAndroid Build Coastguard Worker return len;
108*6236dae4SAndroid Build Coastguard Worker }
109*6236dae4SAndroid Build Coastguard Worker }
110*6236dae4SAndroid Build Coastguard Worker
chunk_slurpn(struct buf_chunk * chunk,size_t max_len,Curl_bufq_reader * reader,void * reader_ctx,CURLcode * err)111*6236dae4SAndroid Build Coastguard Worker static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
112*6236dae4SAndroid Build Coastguard Worker Curl_bufq_reader *reader,
113*6236dae4SAndroid Build Coastguard Worker void *reader_ctx, CURLcode *err)
114*6236dae4SAndroid Build Coastguard Worker {
115*6236dae4SAndroid Build Coastguard Worker unsigned char *p = &chunk->x.data[chunk->w_offset];
116*6236dae4SAndroid Build Coastguard Worker size_t n = chunk->dlen - chunk->w_offset; /* free amount */
117*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
118*6236dae4SAndroid Build Coastguard Worker
119*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->dlen >= chunk->w_offset);
120*6236dae4SAndroid Build Coastguard Worker if(!n) {
121*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
122*6236dae4SAndroid Build Coastguard Worker return -1;
123*6236dae4SAndroid Build Coastguard Worker }
124*6236dae4SAndroid Build Coastguard Worker if(max_len && n > max_len)
125*6236dae4SAndroid Build Coastguard Worker n = max_len;
126*6236dae4SAndroid Build Coastguard Worker nread = reader(reader_ctx, p, n, err);
127*6236dae4SAndroid Build Coastguard Worker if(nread > 0) {
128*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT((size_t)nread <= n);
129*6236dae4SAndroid Build Coastguard Worker chunk->w_offset += nread;
130*6236dae4SAndroid Build Coastguard Worker }
131*6236dae4SAndroid Build Coastguard Worker return nread;
132*6236dae4SAndroid Build Coastguard Worker }
133*6236dae4SAndroid Build Coastguard Worker
chunk_peek(const struct buf_chunk * chunk,const unsigned char ** pbuf,size_t * plen)134*6236dae4SAndroid Build Coastguard Worker static void chunk_peek(const struct buf_chunk *chunk,
135*6236dae4SAndroid Build Coastguard Worker const unsigned char **pbuf, size_t *plen)
136*6236dae4SAndroid Build Coastguard Worker {
137*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
138*6236dae4SAndroid Build Coastguard Worker *pbuf = &chunk->x.data[chunk->r_offset];
139*6236dae4SAndroid Build Coastguard Worker *plen = chunk->w_offset - chunk->r_offset;
140*6236dae4SAndroid Build Coastguard Worker }
141*6236dae4SAndroid Build Coastguard Worker
chunk_peek_at(const struct buf_chunk * chunk,size_t offset,const unsigned char ** pbuf,size_t * plen)142*6236dae4SAndroid Build Coastguard Worker static void chunk_peek_at(const struct buf_chunk *chunk, size_t offset,
143*6236dae4SAndroid Build Coastguard Worker const unsigned char **pbuf, size_t *plen)
144*6236dae4SAndroid Build Coastguard Worker {
145*6236dae4SAndroid Build Coastguard Worker offset += chunk->r_offset;
146*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->w_offset >= offset);
147*6236dae4SAndroid Build Coastguard Worker *pbuf = &chunk->x.data[offset];
148*6236dae4SAndroid Build Coastguard Worker *plen = chunk->w_offset - offset;
149*6236dae4SAndroid Build Coastguard Worker }
150*6236dae4SAndroid Build Coastguard Worker
chunk_skip(struct buf_chunk * chunk,size_t amount)151*6236dae4SAndroid Build Coastguard Worker static size_t chunk_skip(struct buf_chunk *chunk, size_t amount)
152*6236dae4SAndroid Build Coastguard Worker {
153*6236dae4SAndroid Build Coastguard Worker size_t n = chunk->w_offset - chunk->r_offset;
154*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
155*6236dae4SAndroid Build Coastguard Worker if(n) {
156*6236dae4SAndroid Build Coastguard Worker n = CURLMIN(n, amount);
157*6236dae4SAndroid Build Coastguard Worker chunk->r_offset += n;
158*6236dae4SAndroid Build Coastguard Worker if(chunk->r_offset == chunk->w_offset)
159*6236dae4SAndroid Build Coastguard Worker chunk->r_offset = chunk->w_offset = 0;
160*6236dae4SAndroid Build Coastguard Worker }
161*6236dae4SAndroid Build Coastguard Worker return n;
162*6236dae4SAndroid Build Coastguard Worker }
163*6236dae4SAndroid Build Coastguard Worker
chunk_list_free(struct buf_chunk ** anchor)164*6236dae4SAndroid Build Coastguard Worker static void chunk_list_free(struct buf_chunk **anchor)
165*6236dae4SAndroid Build Coastguard Worker {
166*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk;
167*6236dae4SAndroid Build Coastguard Worker while(*anchor) {
168*6236dae4SAndroid Build Coastguard Worker chunk = *anchor;
169*6236dae4SAndroid Build Coastguard Worker *anchor = chunk->next;
170*6236dae4SAndroid Build Coastguard Worker free(chunk);
171*6236dae4SAndroid Build Coastguard Worker }
172*6236dae4SAndroid Build Coastguard Worker }
173*6236dae4SAndroid Build Coastguard Worker
174*6236dae4SAndroid Build Coastguard Worker
175*6236dae4SAndroid Build Coastguard Worker
Curl_bufcp_init(struct bufc_pool * pool,size_t chunk_size,size_t spare_max)176*6236dae4SAndroid Build Coastguard Worker void Curl_bufcp_init(struct bufc_pool *pool,
177*6236dae4SAndroid Build Coastguard Worker size_t chunk_size, size_t spare_max)
178*6236dae4SAndroid Build Coastguard Worker {
179*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk_size > 0);
180*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(spare_max > 0);
181*6236dae4SAndroid Build Coastguard Worker memset(pool, 0, sizeof(*pool));
182*6236dae4SAndroid Build Coastguard Worker pool->chunk_size = chunk_size;
183*6236dae4SAndroid Build Coastguard Worker pool->spare_max = spare_max;
184*6236dae4SAndroid Build Coastguard Worker }
185*6236dae4SAndroid Build Coastguard Worker
bufcp_take(struct bufc_pool * pool,struct buf_chunk ** pchunk)186*6236dae4SAndroid Build Coastguard Worker static CURLcode bufcp_take(struct bufc_pool *pool,
187*6236dae4SAndroid Build Coastguard Worker struct buf_chunk **pchunk)
188*6236dae4SAndroid Build Coastguard Worker {
189*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk = NULL;
190*6236dae4SAndroid Build Coastguard Worker
191*6236dae4SAndroid Build Coastguard Worker if(pool->spare) {
192*6236dae4SAndroid Build Coastguard Worker chunk = pool->spare;
193*6236dae4SAndroid Build Coastguard Worker pool->spare = chunk->next;
194*6236dae4SAndroid Build Coastguard Worker --pool->spare_count;
195*6236dae4SAndroid Build Coastguard Worker chunk_reset(chunk);
196*6236dae4SAndroid Build Coastguard Worker *pchunk = chunk;
197*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
198*6236dae4SAndroid Build Coastguard Worker }
199*6236dae4SAndroid Build Coastguard Worker
200*6236dae4SAndroid Build Coastguard Worker chunk = calloc(1, sizeof(*chunk) + pool->chunk_size);
201*6236dae4SAndroid Build Coastguard Worker if(!chunk) {
202*6236dae4SAndroid Build Coastguard Worker *pchunk = NULL;
203*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
204*6236dae4SAndroid Build Coastguard Worker }
205*6236dae4SAndroid Build Coastguard Worker chunk->dlen = pool->chunk_size;
206*6236dae4SAndroid Build Coastguard Worker *pchunk = chunk;
207*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
208*6236dae4SAndroid Build Coastguard Worker }
209*6236dae4SAndroid Build Coastguard Worker
bufcp_put(struct bufc_pool * pool,struct buf_chunk * chunk)210*6236dae4SAndroid Build Coastguard Worker static void bufcp_put(struct bufc_pool *pool,
211*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk)
212*6236dae4SAndroid Build Coastguard Worker {
213*6236dae4SAndroid Build Coastguard Worker if(pool->spare_count >= pool->spare_max) {
214*6236dae4SAndroid Build Coastguard Worker free(chunk);
215*6236dae4SAndroid Build Coastguard Worker }
216*6236dae4SAndroid Build Coastguard Worker else {
217*6236dae4SAndroid Build Coastguard Worker chunk_reset(chunk);
218*6236dae4SAndroid Build Coastguard Worker chunk->next = pool->spare;
219*6236dae4SAndroid Build Coastguard Worker pool->spare = chunk;
220*6236dae4SAndroid Build Coastguard Worker ++pool->spare_count;
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker }
223*6236dae4SAndroid Build Coastguard Worker
Curl_bufcp_free(struct bufc_pool * pool)224*6236dae4SAndroid Build Coastguard Worker void Curl_bufcp_free(struct bufc_pool *pool)
225*6236dae4SAndroid Build Coastguard Worker {
226*6236dae4SAndroid Build Coastguard Worker chunk_list_free(&pool->spare);
227*6236dae4SAndroid Build Coastguard Worker pool->spare_count = 0;
228*6236dae4SAndroid Build Coastguard Worker }
229*6236dae4SAndroid Build Coastguard Worker
bufq_init(struct bufq * q,struct bufc_pool * pool,size_t chunk_size,size_t max_chunks,int opts)230*6236dae4SAndroid Build Coastguard Worker static void bufq_init(struct bufq *q, struct bufc_pool *pool,
231*6236dae4SAndroid Build Coastguard Worker size_t chunk_size, size_t max_chunks, int opts)
232*6236dae4SAndroid Build Coastguard Worker {
233*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(chunk_size > 0);
234*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(max_chunks > 0);
235*6236dae4SAndroid Build Coastguard Worker memset(q, 0, sizeof(*q));
236*6236dae4SAndroid Build Coastguard Worker q->chunk_size = chunk_size;
237*6236dae4SAndroid Build Coastguard Worker q->max_chunks = max_chunks;
238*6236dae4SAndroid Build Coastguard Worker q->pool = pool;
239*6236dae4SAndroid Build Coastguard Worker q->opts = opts;
240*6236dae4SAndroid Build Coastguard Worker }
241*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_init2(struct bufq * q,size_t chunk_size,size_t max_chunks,int opts)242*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_init2(struct bufq *q, size_t chunk_size, size_t max_chunks,
243*6236dae4SAndroid Build Coastguard Worker int opts)
244*6236dae4SAndroid Build Coastguard Worker {
245*6236dae4SAndroid Build Coastguard Worker bufq_init(q, NULL, chunk_size, max_chunks, opts);
246*6236dae4SAndroid Build Coastguard Worker }
247*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_init(struct bufq * q,size_t chunk_size,size_t max_chunks)248*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks)
249*6236dae4SAndroid Build Coastguard Worker {
250*6236dae4SAndroid Build Coastguard Worker bufq_init(q, NULL, chunk_size, max_chunks, BUFQ_OPT_NONE);
251*6236dae4SAndroid Build Coastguard Worker }
252*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_initp(struct bufq * q,struct bufc_pool * pool,size_t max_chunks,int opts)253*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool,
254*6236dae4SAndroid Build Coastguard Worker size_t max_chunks, int opts)
255*6236dae4SAndroid Build Coastguard Worker {
256*6236dae4SAndroid Build Coastguard Worker bufq_init(q, pool, pool->chunk_size, max_chunks, opts);
257*6236dae4SAndroid Build Coastguard Worker }
258*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_free(struct bufq * q)259*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_free(struct bufq *q)
260*6236dae4SAndroid Build Coastguard Worker {
261*6236dae4SAndroid Build Coastguard Worker chunk_list_free(&q->head);
262*6236dae4SAndroid Build Coastguard Worker chunk_list_free(&q->spare);
263*6236dae4SAndroid Build Coastguard Worker q->tail = NULL;
264*6236dae4SAndroid Build Coastguard Worker q->chunk_count = 0;
265*6236dae4SAndroid Build Coastguard Worker }
266*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_reset(struct bufq * q)267*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_reset(struct bufq *q)
268*6236dae4SAndroid Build Coastguard Worker {
269*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk;
270*6236dae4SAndroid Build Coastguard Worker while(q->head) {
271*6236dae4SAndroid Build Coastguard Worker chunk = q->head;
272*6236dae4SAndroid Build Coastguard Worker q->head = chunk->next;
273*6236dae4SAndroid Build Coastguard Worker chunk->next = q->spare;
274*6236dae4SAndroid Build Coastguard Worker q->spare = chunk;
275*6236dae4SAndroid Build Coastguard Worker }
276*6236dae4SAndroid Build Coastguard Worker q->tail = NULL;
277*6236dae4SAndroid Build Coastguard Worker }
278*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_len(const struct bufq * q)279*6236dae4SAndroid Build Coastguard Worker size_t Curl_bufq_len(const struct bufq *q)
280*6236dae4SAndroid Build Coastguard Worker {
281*6236dae4SAndroid Build Coastguard Worker const struct buf_chunk *chunk = q->head;
282*6236dae4SAndroid Build Coastguard Worker size_t len = 0;
283*6236dae4SAndroid Build Coastguard Worker while(chunk) {
284*6236dae4SAndroid Build Coastguard Worker len += chunk_len(chunk);
285*6236dae4SAndroid Build Coastguard Worker chunk = chunk->next;
286*6236dae4SAndroid Build Coastguard Worker }
287*6236dae4SAndroid Build Coastguard Worker return len;
288*6236dae4SAndroid Build Coastguard Worker }
289*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_space(const struct bufq * q)290*6236dae4SAndroid Build Coastguard Worker size_t Curl_bufq_space(const struct bufq *q)
291*6236dae4SAndroid Build Coastguard Worker {
292*6236dae4SAndroid Build Coastguard Worker size_t space = 0;
293*6236dae4SAndroid Build Coastguard Worker if(q->tail)
294*6236dae4SAndroid Build Coastguard Worker space += chunk_space(q->tail);
295*6236dae4SAndroid Build Coastguard Worker if(q->spare) {
296*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk = q->spare;
297*6236dae4SAndroid Build Coastguard Worker while(chunk) {
298*6236dae4SAndroid Build Coastguard Worker space += chunk->dlen;
299*6236dae4SAndroid Build Coastguard Worker chunk = chunk->next;
300*6236dae4SAndroid Build Coastguard Worker }
301*6236dae4SAndroid Build Coastguard Worker }
302*6236dae4SAndroid Build Coastguard Worker if(q->chunk_count < q->max_chunks) {
303*6236dae4SAndroid Build Coastguard Worker space += (q->max_chunks - q->chunk_count) * q->chunk_size;
304*6236dae4SAndroid Build Coastguard Worker }
305*6236dae4SAndroid Build Coastguard Worker return space;
306*6236dae4SAndroid Build Coastguard Worker }
307*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_is_empty(const struct bufq * q)308*6236dae4SAndroid Build Coastguard Worker bool Curl_bufq_is_empty(const struct bufq *q)
309*6236dae4SAndroid Build Coastguard Worker {
310*6236dae4SAndroid Build Coastguard Worker return !q->head || chunk_is_empty(q->head);
311*6236dae4SAndroid Build Coastguard Worker }
312*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_is_full(const struct bufq * q)313*6236dae4SAndroid Build Coastguard Worker bool Curl_bufq_is_full(const struct bufq *q)
314*6236dae4SAndroid Build Coastguard Worker {
315*6236dae4SAndroid Build Coastguard Worker if(!q->tail || q->spare)
316*6236dae4SAndroid Build Coastguard Worker return FALSE;
317*6236dae4SAndroid Build Coastguard Worker if(q->chunk_count < q->max_chunks)
318*6236dae4SAndroid Build Coastguard Worker return FALSE;
319*6236dae4SAndroid Build Coastguard Worker if(q->chunk_count > q->max_chunks)
320*6236dae4SAndroid Build Coastguard Worker return TRUE;
321*6236dae4SAndroid Build Coastguard Worker /* we have no spares and cannot make more, is the tail full? */
322*6236dae4SAndroid Build Coastguard Worker return chunk_is_full(q->tail);
323*6236dae4SAndroid Build Coastguard Worker }
324*6236dae4SAndroid Build Coastguard Worker
get_spare(struct bufq * q)325*6236dae4SAndroid Build Coastguard Worker static struct buf_chunk *get_spare(struct bufq *q)
326*6236dae4SAndroid Build Coastguard Worker {
327*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk = NULL;
328*6236dae4SAndroid Build Coastguard Worker
329*6236dae4SAndroid Build Coastguard Worker if(q->spare) {
330*6236dae4SAndroid Build Coastguard Worker chunk = q->spare;
331*6236dae4SAndroid Build Coastguard Worker q->spare = chunk->next;
332*6236dae4SAndroid Build Coastguard Worker chunk_reset(chunk);
333*6236dae4SAndroid Build Coastguard Worker return chunk;
334*6236dae4SAndroid Build Coastguard Worker }
335*6236dae4SAndroid Build Coastguard Worker
336*6236dae4SAndroid Build Coastguard Worker if(q->chunk_count >= q->max_chunks && (!(q->opts & BUFQ_OPT_SOFT_LIMIT)))
337*6236dae4SAndroid Build Coastguard Worker return NULL;
338*6236dae4SAndroid Build Coastguard Worker
339*6236dae4SAndroid Build Coastguard Worker if(q->pool) {
340*6236dae4SAndroid Build Coastguard Worker if(bufcp_take(q->pool, &chunk))
341*6236dae4SAndroid Build Coastguard Worker return NULL;
342*6236dae4SAndroid Build Coastguard Worker ++q->chunk_count;
343*6236dae4SAndroid Build Coastguard Worker return chunk;
344*6236dae4SAndroid Build Coastguard Worker }
345*6236dae4SAndroid Build Coastguard Worker else {
346*6236dae4SAndroid Build Coastguard Worker chunk = calloc(1, sizeof(*chunk) + q->chunk_size);
347*6236dae4SAndroid Build Coastguard Worker if(!chunk)
348*6236dae4SAndroid Build Coastguard Worker return NULL;
349*6236dae4SAndroid Build Coastguard Worker chunk->dlen = q->chunk_size;
350*6236dae4SAndroid Build Coastguard Worker ++q->chunk_count;
351*6236dae4SAndroid Build Coastguard Worker return chunk;
352*6236dae4SAndroid Build Coastguard Worker }
353*6236dae4SAndroid Build Coastguard Worker }
354*6236dae4SAndroid Build Coastguard Worker
prune_head(struct bufq * q)355*6236dae4SAndroid Build Coastguard Worker static void prune_head(struct bufq *q)
356*6236dae4SAndroid Build Coastguard Worker {
357*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk;
358*6236dae4SAndroid Build Coastguard Worker
359*6236dae4SAndroid Build Coastguard Worker while(q->head && chunk_is_empty(q->head)) {
360*6236dae4SAndroid Build Coastguard Worker chunk = q->head;
361*6236dae4SAndroid Build Coastguard Worker q->head = chunk->next;
362*6236dae4SAndroid Build Coastguard Worker if(q->tail == chunk)
363*6236dae4SAndroid Build Coastguard Worker q->tail = q->head;
364*6236dae4SAndroid Build Coastguard Worker if(q->pool) {
365*6236dae4SAndroid Build Coastguard Worker bufcp_put(q->pool, chunk);
366*6236dae4SAndroid Build Coastguard Worker --q->chunk_count;
367*6236dae4SAndroid Build Coastguard Worker }
368*6236dae4SAndroid Build Coastguard Worker else if((q->chunk_count > q->max_chunks) ||
369*6236dae4SAndroid Build Coastguard Worker (q->opts & BUFQ_OPT_NO_SPARES)) {
370*6236dae4SAndroid Build Coastguard Worker /* SOFT_LIMIT allowed us more than max. free spares until
371*6236dae4SAndroid Build Coastguard Worker * we are at max again. Or free them if we are configured
372*6236dae4SAndroid Build Coastguard Worker * to not use spares. */
373*6236dae4SAndroid Build Coastguard Worker free(chunk);
374*6236dae4SAndroid Build Coastguard Worker --q->chunk_count;
375*6236dae4SAndroid Build Coastguard Worker }
376*6236dae4SAndroid Build Coastguard Worker else {
377*6236dae4SAndroid Build Coastguard Worker chunk->next = q->spare;
378*6236dae4SAndroid Build Coastguard Worker q->spare = chunk;
379*6236dae4SAndroid Build Coastguard Worker }
380*6236dae4SAndroid Build Coastguard Worker }
381*6236dae4SAndroid Build Coastguard Worker }
382*6236dae4SAndroid Build Coastguard Worker
chunk_prev(struct buf_chunk * head,struct buf_chunk * chunk)383*6236dae4SAndroid Build Coastguard Worker static struct buf_chunk *chunk_prev(struct buf_chunk *head,
384*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk)
385*6236dae4SAndroid Build Coastguard Worker {
386*6236dae4SAndroid Build Coastguard Worker while(head) {
387*6236dae4SAndroid Build Coastguard Worker if(head == chunk)
388*6236dae4SAndroid Build Coastguard Worker return NULL;
389*6236dae4SAndroid Build Coastguard Worker if(head->next == chunk)
390*6236dae4SAndroid Build Coastguard Worker return head;
391*6236dae4SAndroid Build Coastguard Worker head = head->next;
392*6236dae4SAndroid Build Coastguard Worker }
393*6236dae4SAndroid Build Coastguard Worker return NULL;
394*6236dae4SAndroid Build Coastguard Worker }
395*6236dae4SAndroid Build Coastguard Worker
prune_tail(struct bufq * q)396*6236dae4SAndroid Build Coastguard Worker static void prune_tail(struct bufq *q)
397*6236dae4SAndroid Build Coastguard Worker {
398*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk;
399*6236dae4SAndroid Build Coastguard Worker
400*6236dae4SAndroid Build Coastguard Worker while(q->tail && chunk_is_empty(q->tail)) {
401*6236dae4SAndroid Build Coastguard Worker chunk = q->tail;
402*6236dae4SAndroid Build Coastguard Worker q->tail = chunk_prev(q->head, chunk);
403*6236dae4SAndroid Build Coastguard Worker if(q->tail)
404*6236dae4SAndroid Build Coastguard Worker q->tail->next = NULL;
405*6236dae4SAndroid Build Coastguard Worker if(q->head == chunk)
406*6236dae4SAndroid Build Coastguard Worker q->head = q->tail;
407*6236dae4SAndroid Build Coastguard Worker if(q->pool) {
408*6236dae4SAndroid Build Coastguard Worker bufcp_put(q->pool, chunk);
409*6236dae4SAndroid Build Coastguard Worker --q->chunk_count;
410*6236dae4SAndroid Build Coastguard Worker }
411*6236dae4SAndroid Build Coastguard Worker else if((q->chunk_count > q->max_chunks) ||
412*6236dae4SAndroid Build Coastguard Worker (q->opts & BUFQ_OPT_NO_SPARES)) {
413*6236dae4SAndroid Build Coastguard Worker /* SOFT_LIMIT allowed us more than max. free spares until
414*6236dae4SAndroid Build Coastguard Worker * we are at max again. Or free them if we are configured
415*6236dae4SAndroid Build Coastguard Worker * to not use spares. */
416*6236dae4SAndroid Build Coastguard Worker free(chunk);
417*6236dae4SAndroid Build Coastguard Worker --q->chunk_count;
418*6236dae4SAndroid Build Coastguard Worker }
419*6236dae4SAndroid Build Coastguard Worker else {
420*6236dae4SAndroid Build Coastguard Worker chunk->next = q->spare;
421*6236dae4SAndroid Build Coastguard Worker q->spare = chunk;
422*6236dae4SAndroid Build Coastguard Worker }
423*6236dae4SAndroid Build Coastguard Worker }
424*6236dae4SAndroid Build Coastguard Worker }
425*6236dae4SAndroid Build Coastguard Worker
get_non_full_tail(struct bufq * q)426*6236dae4SAndroid Build Coastguard Worker static struct buf_chunk *get_non_full_tail(struct bufq *q)
427*6236dae4SAndroid Build Coastguard Worker {
428*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *chunk;
429*6236dae4SAndroid Build Coastguard Worker
430*6236dae4SAndroid Build Coastguard Worker if(q->tail && !chunk_is_full(q->tail))
431*6236dae4SAndroid Build Coastguard Worker return q->tail;
432*6236dae4SAndroid Build Coastguard Worker chunk = get_spare(q);
433*6236dae4SAndroid Build Coastguard Worker if(chunk) {
434*6236dae4SAndroid Build Coastguard Worker /* new tail, and possibly new head */
435*6236dae4SAndroid Build Coastguard Worker if(q->tail) {
436*6236dae4SAndroid Build Coastguard Worker q->tail->next = chunk;
437*6236dae4SAndroid Build Coastguard Worker q->tail = chunk;
438*6236dae4SAndroid Build Coastguard Worker }
439*6236dae4SAndroid Build Coastguard Worker else {
440*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!q->head);
441*6236dae4SAndroid Build Coastguard Worker q->head = q->tail = chunk;
442*6236dae4SAndroid Build Coastguard Worker }
443*6236dae4SAndroid Build Coastguard Worker }
444*6236dae4SAndroid Build Coastguard Worker return chunk;
445*6236dae4SAndroid Build Coastguard Worker }
446*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_write(struct bufq * q,const unsigned char * buf,size_t len,CURLcode * err)447*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_write(struct bufq *q,
448*6236dae4SAndroid Build Coastguard Worker const unsigned char *buf, size_t len,
449*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
450*6236dae4SAndroid Build Coastguard Worker {
451*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *tail;
452*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = 0;
453*6236dae4SAndroid Build Coastguard Worker size_t n;
454*6236dae4SAndroid Build Coastguard Worker
455*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(q->max_chunks > 0);
456*6236dae4SAndroid Build Coastguard Worker while(len) {
457*6236dae4SAndroid Build Coastguard Worker tail = get_non_full_tail(q);
458*6236dae4SAndroid Build Coastguard Worker if(!tail) {
459*6236dae4SAndroid Build Coastguard Worker if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
460*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OUT_OF_MEMORY;
461*6236dae4SAndroid Build Coastguard Worker return -1;
462*6236dae4SAndroid Build Coastguard Worker }
463*6236dae4SAndroid Build Coastguard Worker break;
464*6236dae4SAndroid Build Coastguard Worker }
465*6236dae4SAndroid Build Coastguard Worker n = chunk_append(tail, buf, len);
466*6236dae4SAndroid Build Coastguard Worker if(!n)
467*6236dae4SAndroid Build Coastguard Worker break;
468*6236dae4SAndroid Build Coastguard Worker nwritten += n;
469*6236dae4SAndroid Build Coastguard Worker buf += n;
470*6236dae4SAndroid Build Coastguard Worker len -= n;
471*6236dae4SAndroid Build Coastguard Worker }
472*6236dae4SAndroid Build Coastguard Worker if(nwritten == 0 && len) {
473*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
474*6236dae4SAndroid Build Coastguard Worker return -1;
475*6236dae4SAndroid Build Coastguard Worker }
476*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
477*6236dae4SAndroid Build Coastguard Worker return nwritten;
478*6236dae4SAndroid Build Coastguard Worker }
479*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_cwrite(struct bufq * q,const char * buf,size_t len,size_t * pnwritten)480*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_bufq_cwrite(struct bufq *q,
481*6236dae4SAndroid Build Coastguard Worker const char *buf, size_t len,
482*6236dae4SAndroid Build Coastguard Worker size_t *pnwritten)
483*6236dae4SAndroid Build Coastguard Worker {
484*6236dae4SAndroid Build Coastguard Worker ssize_t n;
485*6236dae4SAndroid Build Coastguard Worker CURLcode result;
486*6236dae4SAndroid Build Coastguard Worker n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
487*6236dae4SAndroid Build Coastguard Worker *pnwritten = (n < 0) ? 0 : (size_t)n;
488*6236dae4SAndroid Build Coastguard Worker return result;
489*6236dae4SAndroid Build Coastguard Worker }
490*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_unwrite(struct bufq * q,size_t len)491*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
492*6236dae4SAndroid Build Coastguard Worker {
493*6236dae4SAndroid Build Coastguard Worker while(len && q->tail) {
494*6236dae4SAndroid Build Coastguard Worker len -= chunk_unwrite(q->tail, len);
495*6236dae4SAndroid Build Coastguard Worker prune_tail(q);
496*6236dae4SAndroid Build Coastguard Worker }
497*6236dae4SAndroid Build Coastguard Worker return len ? CURLE_AGAIN : CURLE_OK;
498*6236dae4SAndroid Build Coastguard Worker }
499*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_read(struct bufq * q,unsigned char * buf,size_t len,CURLcode * err)500*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
501*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
502*6236dae4SAndroid Build Coastguard Worker {
503*6236dae4SAndroid Build Coastguard Worker ssize_t nread = 0;
504*6236dae4SAndroid Build Coastguard Worker size_t n;
505*6236dae4SAndroid Build Coastguard Worker
506*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
507*6236dae4SAndroid Build Coastguard Worker while(len && q->head) {
508*6236dae4SAndroid Build Coastguard Worker n = chunk_read(q->head, buf, len);
509*6236dae4SAndroid Build Coastguard Worker if(n) {
510*6236dae4SAndroid Build Coastguard Worker nread += n;
511*6236dae4SAndroid Build Coastguard Worker buf += n;
512*6236dae4SAndroid Build Coastguard Worker len -= n;
513*6236dae4SAndroid Build Coastguard Worker }
514*6236dae4SAndroid Build Coastguard Worker prune_head(q);
515*6236dae4SAndroid Build Coastguard Worker }
516*6236dae4SAndroid Build Coastguard Worker if(nread == 0) {
517*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
518*6236dae4SAndroid Build Coastguard Worker return -1;
519*6236dae4SAndroid Build Coastguard Worker }
520*6236dae4SAndroid Build Coastguard Worker return nread;
521*6236dae4SAndroid Build Coastguard Worker }
522*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_cread(struct bufq * q,char * buf,size_t len,size_t * pnread)523*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
524*6236dae4SAndroid Build Coastguard Worker size_t *pnread)
525*6236dae4SAndroid Build Coastguard Worker {
526*6236dae4SAndroid Build Coastguard Worker ssize_t n;
527*6236dae4SAndroid Build Coastguard Worker CURLcode result;
528*6236dae4SAndroid Build Coastguard Worker n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
529*6236dae4SAndroid Build Coastguard Worker *pnread = (n < 0) ? 0 : (size_t)n;
530*6236dae4SAndroid Build Coastguard Worker return result;
531*6236dae4SAndroid Build Coastguard Worker }
532*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_peek(struct bufq * q,const unsigned char ** pbuf,size_t * plen)533*6236dae4SAndroid Build Coastguard Worker bool Curl_bufq_peek(struct bufq *q,
534*6236dae4SAndroid Build Coastguard Worker const unsigned char **pbuf, size_t *plen)
535*6236dae4SAndroid Build Coastguard Worker {
536*6236dae4SAndroid Build Coastguard Worker if(q->head && chunk_is_empty(q->head)) {
537*6236dae4SAndroid Build Coastguard Worker prune_head(q);
538*6236dae4SAndroid Build Coastguard Worker }
539*6236dae4SAndroid Build Coastguard Worker if(q->head && !chunk_is_empty(q->head)) {
540*6236dae4SAndroid Build Coastguard Worker chunk_peek(q->head, pbuf, plen);
541*6236dae4SAndroid Build Coastguard Worker return TRUE;
542*6236dae4SAndroid Build Coastguard Worker }
543*6236dae4SAndroid Build Coastguard Worker *pbuf = NULL;
544*6236dae4SAndroid Build Coastguard Worker *plen = 0;
545*6236dae4SAndroid Build Coastguard Worker return FALSE;
546*6236dae4SAndroid Build Coastguard Worker }
547*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_peek_at(struct bufq * q,size_t offset,const unsigned char ** pbuf,size_t * plen)548*6236dae4SAndroid Build Coastguard Worker bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
549*6236dae4SAndroid Build Coastguard Worker const unsigned char **pbuf, size_t *plen)
550*6236dae4SAndroid Build Coastguard Worker {
551*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *c = q->head;
552*6236dae4SAndroid Build Coastguard Worker size_t clen;
553*6236dae4SAndroid Build Coastguard Worker
554*6236dae4SAndroid Build Coastguard Worker while(c) {
555*6236dae4SAndroid Build Coastguard Worker clen = chunk_len(c);
556*6236dae4SAndroid Build Coastguard Worker if(!clen)
557*6236dae4SAndroid Build Coastguard Worker break;
558*6236dae4SAndroid Build Coastguard Worker if(offset >= clen) {
559*6236dae4SAndroid Build Coastguard Worker offset -= clen;
560*6236dae4SAndroid Build Coastguard Worker c = c->next;
561*6236dae4SAndroid Build Coastguard Worker continue;
562*6236dae4SAndroid Build Coastguard Worker }
563*6236dae4SAndroid Build Coastguard Worker chunk_peek_at(c, offset, pbuf, plen);
564*6236dae4SAndroid Build Coastguard Worker return TRUE;
565*6236dae4SAndroid Build Coastguard Worker }
566*6236dae4SAndroid Build Coastguard Worker *pbuf = NULL;
567*6236dae4SAndroid Build Coastguard Worker *plen = 0;
568*6236dae4SAndroid Build Coastguard Worker return FALSE;
569*6236dae4SAndroid Build Coastguard Worker }
570*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_skip(struct bufq * q,size_t amount)571*6236dae4SAndroid Build Coastguard Worker void Curl_bufq_skip(struct bufq *q, size_t amount)
572*6236dae4SAndroid Build Coastguard Worker {
573*6236dae4SAndroid Build Coastguard Worker size_t n;
574*6236dae4SAndroid Build Coastguard Worker
575*6236dae4SAndroid Build Coastguard Worker while(amount && q->head) {
576*6236dae4SAndroid Build Coastguard Worker n = chunk_skip(q->head, amount);
577*6236dae4SAndroid Build Coastguard Worker amount -= n;
578*6236dae4SAndroid Build Coastguard Worker prune_head(q);
579*6236dae4SAndroid Build Coastguard Worker }
580*6236dae4SAndroid Build Coastguard Worker }
581*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_pass(struct bufq * q,Curl_bufq_writer * writer,void * writer_ctx,CURLcode * err)582*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
583*6236dae4SAndroid Build Coastguard Worker void *writer_ctx, CURLcode *err)
584*6236dae4SAndroid Build Coastguard Worker {
585*6236dae4SAndroid Build Coastguard Worker const unsigned char *buf;
586*6236dae4SAndroid Build Coastguard Worker size_t blen;
587*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = 0;
588*6236dae4SAndroid Build Coastguard Worker
589*6236dae4SAndroid Build Coastguard Worker while(Curl_bufq_peek(q, &buf, &blen)) {
590*6236dae4SAndroid Build Coastguard Worker ssize_t chunk_written;
591*6236dae4SAndroid Build Coastguard Worker
592*6236dae4SAndroid Build Coastguard Worker chunk_written = writer(writer_ctx, buf, blen, err);
593*6236dae4SAndroid Build Coastguard Worker if(chunk_written < 0) {
594*6236dae4SAndroid Build Coastguard Worker if(!nwritten || *err != CURLE_AGAIN) {
595*6236dae4SAndroid Build Coastguard Worker /* blocked on first write or real error, fail */
596*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
597*6236dae4SAndroid Build Coastguard Worker }
598*6236dae4SAndroid Build Coastguard Worker break;
599*6236dae4SAndroid Build Coastguard Worker }
600*6236dae4SAndroid Build Coastguard Worker if(!chunk_written) {
601*6236dae4SAndroid Build Coastguard Worker if(!nwritten) {
602*6236dae4SAndroid Build Coastguard Worker /* treat as blocked */
603*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
604*6236dae4SAndroid Build Coastguard Worker nwritten = -1;
605*6236dae4SAndroid Build Coastguard Worker }
606*6236dae4SAndroid Build Coastguard Worker break;
607*6236dae4SAndroid Build Coastguard Worker }
608*6236dae4SAndroid Build Coastguard Worker Curl_bufq_skip(q, (size_t)chunk_written);
609*6236dae4SAndroid Build Coastguard Worker nwritten += chunk_written;
610*6236dae4SAndroid Build Coastguard Worker }
611*6236dae4SAndroid Build Coastguard Worker return nwritten;
612*6236dae4SAndroid Build Coastguard Worker }
613*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_write_pass(struct bufq * q,const unsigned char * buf,size_t len,Curl_bufq_writer * writer,void * writer_ctx,CURLcode * err)614*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_write_pass(struct bufq *q,
615*6236dae4SAndroid Build Coastguard Worker const unsigned char *buf, size_t len,
616*6236dae4SAndroid Build Coastguard Worker Curl_bufq_writer *writer, void *writer_ctx,
617*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
618*6236dae4SAndroid Build Coastguard Worker {
619*6236dae4SAndroid Build Coastguard Worker ssize_t nwritten = 0, n;
620*6236dae4SAndroid Build Coastguard Worker
621*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
622*6236dae4SAndroid Build Coastguard Worker while(len) {
623*6236dae4SAndroid Build Coastguard Worker if(Curl_bufq_is_full(q)) {
624*6236dae4SAndroid Build Coastguard Worker /* try to make room in case we are full */
625*6236dae4SAndroid Build Coastguard Worker n = Curl_bufq_pass(q, writer, writer_ctx, err);
626*6236dae4SAndroid Build Coastguard Worker if(n < 0) {
627*6236dae4SAndroid Build Coastguard Worker if(*err != CURLE_AGAIN) {
628*6236dae4SAndroid Build Coastguard Worker /* real error, fail */
629*6236dae4SAndroid Build Coastguard Worker return -1;
630*6236dae4SAndroid Build Coastguard Worker }
631*6236dae4SAndroid Build Coastguard Worker /* would block, bufq is full, give up */
632*6236dae4SAndroid Build Coastguard Worker break;
633*6236dae4SAndroid Build Coastguard Worker }
634*6236dae4SAndroid Build Coastguard Worker }
635*6236dae4SAndroid Build Coastguard Worker
636*6236dae4SAndroid Build Coastguard Worker /* Add whatever is remaining now to bufq */
637*6236dae4SAndroid Build Coastguard Worker n = Curl_bufq_write(q, buf, len, err);
638*6236dae4SAndroid Build Coastguard Worker if(n < 0) {
639*6236dae4SAndroid Build Coastguard Worker if(*err != CURLE_AGAIN) {
640*6236dae4SAndroid Build Coastguard Worker /* real error, fail */
641*6236dae4SAndroid Build Coastguard Worker return -1;
642*6236dae4SAndroid Build Coastguard Worker }
643*6236dae4SAndroid Build Coastguard Worker /* no room in bufq */
644*6236dae4SAndroid Build Coastguard Worker break;
645*6236dae4SAndroid Build Coastguard Worker }
646*6236dae4SAndroid Build Coastguard Worker /* edge case of writer returning 0 (and len is >0)
647*6236dae4SAndroid Build Coastguard Worker * break or we might enter an infinite loop here */
648*6236dae4SAndroid Build Coastguard Worker if(n == 0)
649*6236dae4SAndroid Build Coastguard Worker break;
650*6236dae4SAndroid Build Coastguard Worker
651*6236dae4SAndroid Build Coastguard Worker /* Maybe only part of `data` has been added, continue to loop */
652*6236dae4SAndroid Build Coastguard Worker buf += (size_t)n;
653*6236dae4SAndroid Build Coastguard Worker len -= (size_t)n;
654*6236dae4SAndroid Build Coastguard Worker nwritten += (size_t)n;
655*6236dae4SAndroid Build Coastguard Worker }
656*6236dae4SAndroid Build Coastguard Worker
657*6236dae4SAndroid Build Coastguard Worker if(!nwritten && len) {
658*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
659*6236dae4SAndroid Build Coastguard Worker return -1;
660*6236dae4SAndroid Build Coastguard Worker }
661*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
662*6236dae4SAndroid Build Coastguard Worker return nwritten;
663*6236dae4SAndroid Build Coastguard Worker }
664*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_sipn(struct bufq * q,size_t max_len,Curl_bufq_reader * reader,void * reader_ctx,CURLcode * err)665*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
666*6236dae4SAndroid Build Coastguard Worker Curl_bufq_reader *reader, void *reader_ctx,
667*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
668*6236dae4SAndroid Build Coastguard Worker {
669*6236dae4SAndroid Build Coastguard Worker struct buf_chunk *tail = NULL;
670*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
671*6236dae4SAndroid Build Coastguard Worker
672*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
673*6236dae4SAndroid Build Coastguard Worker tail = get_non_full_tail(q);
674*6236dae4SAndroid Build Coastguard Worker if(!tail) {
675*6236dae4SAndroid Build Coastguard Worker if(q->chunk_count < q->max_chunks) {
676*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OUT_OF_MEMORY;
677*6236dae4SAndroid Build Coastguard Worker return -1;
678*6236dae4SAndroid Build Coastguard Worker }
679*6236dae4SAndroid Build Coastguard Worker /* full, blocked */
680*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
681*6236dae4SAndroid Build Coastguard Worker return -1;
682*6236dae4SAndroid Build Coastguard Worker }
683*6236dae4SAndroid Build Coastguard Worker
684*6236dae4SAndroid Build Coastguard Worker nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err);
685*6236dae4SAndroid Build Coastguard Worker if(nread < 0) {
686*6236dae4SAndroid Build Coastguard Worker return -1;
687*6236dae4SAndroid Build Coastguard Worker }
688*6236dae4SAndroid Build Coastguard Worker else if(nread == 0) {
689*6236dae4SAndroid Build Coastguard Worker /* eof */
690*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
691*6236dae4SAndroid Build Coastguard Worker }
692*6236dae4SAndroid Build Coastguard Worker return nread;
693*6236dae4SAndroid Build Coastguard Worker }
694*6236dae4SAndroid Build Coastguard Worker
695*6236dae4SAndroid Build Coastguard Worker /**
696*6236dae4SAndroid Build Coastguard Worker * Read up to `max_len` bytes and append it to the end of the buffer queue.
697*6236dae4SAndroid Build Coastguard Worker * if `max_len` is 0, no limit is imposed and the call behaves exactly
698*6236dae4SAndroid Build Coastguard Worker * the same as `Curl_bufq_slurp()`.
699*6236dae4SAndroid Build Coastguard Worker * Returns the total amount of buf read (may be 0) or -1 on other
700*6236dae4SAndroid Build Coastguard Worker * reader errors.
701*6236dae4SAndroid Build Coastguard Worker * Note that even in case of a -1 chunks may have been read and
702*6236dae4SAndroid Build Coastguard Worker * the buffer queue will have different length than before.
703*6236dae4SAndroid Build Coastguard Worker */
bufq_slurpn(struct bufq * q,size_t max_len,Curl_bufq_reader * reader,void * reader_ctx,CURLcode * err)704*6236dae4SAndroid Build Coastguard Worker static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
705*6236dae4SAndroid Build Coastguard Worker Curl_bufq_reader *reader, void *reader_ctx,
706*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
707*6236dae4SAndroid Build Coastguard Worker {
708*6236dae4SAndroid Build Coastguard Worker ssize_t nread = 0, n;
709*6236dae4SAndroid Build Coastguard Worker
710*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
711*6236dae4SAndroid Build Coastguard Worker while(1) {
712*6236dae4SAndroid Build Coastguard Worker
713*6236dae4SAndroid Build Coastguard Worker n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err);
714*6236dae4SAndroid Build Coastguard Worker if(n < 0) {
715*6236dae4SAndroid Build Coastguard Worker if(!nread || *err != CURLE_AGAIN) {
716*6236dae4SAndroid Build Coastguard Worker /* blocked on first read or real error, fail */
717*6236dae4SAndroid Build Coastguard Worker nread = -1;
718*6236dae4SAndroid Build Coastguard Worker }
719*6236dae4SAndroid Build Coastguard Worker else
720*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
721*6236dae4SAndroid Build Coastguard Worker break;
722*6236dae4SAndroid Build Coastguard Worker }
723*6236dae4SAndroid Build Coastguard Worker else if(n == 0) {
724*6236dae4SAndroid Build Coastguard Worker /* eof */
725*6236dae4SAndroid Build Coastguard Worker *err = CURLE_OK;
726*6236dae4SAndroid Build Coastguard Worker break;
727*6236dae4SAndroid Build Coastguard Worker }
728*6236dae4SAndroid Build Coastguard Worker nread += (size_t)n;
729*6236dae4SAndroid Build Coastguard Worker if(max_len) {
730*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT((size_t)n <= max_len);
731*6236dae4SAndroid Build Coastguard Worker max_len -= (size_t)n;
732*6236dae4SAndroid Build Coastguard Worker if(!max_len)
733*6236dae4SAndroid Build Coastguard Worker break;
734*6236dae4SAndroid Build Coastguard Worker }
735*6236dae4SAndroid Build Coastguard Worker /* give up slurping when we get less bytes than we asked for */
736*6236dae4SAndroid Build Coastguard Worker if(q->tail && !chunk_is_full(q->tail))
737*6236dae4SAndroid Build Coastguard Worker break;
738*6236dae4SAndroid Build Coastguard Worker }
739*6236dae4SAndroid Build Coastguard Worker return nread;
740*6236dae4SAndroid Build Coastguard Worker }
741*6236dae4SAndroid Build Coastguard Worker
Curl_bufq_slurp(struct bufq * q,Curl_bufq_reader * reader,void * reader_ctx,CURLcode * err)742*6236dae4SAndroid Build Coastguard Worker ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
743*6236dae4SAndroid Build Coastguard Worker void *reader_ctx, CURLcode *err)
744*6236dae4SAndroid Build Coastguard Worker {
745*6236dae4SAndroid Build Coastguard Worker return bufq_slurpn(q, 0, reader, reader_ctx, err);
746*6236dae4SAndroid Build Coastguard Worker }
747