xref: /aosp_15_r20/external/curl/lib/bufq.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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