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