155714Skris/* crypto/bio/bf_buff.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280304Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280304Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280304Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280304Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280304Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <errno.h>
6155714Skris#include "cryptlib.h"
6255714Skris#include <openssl/bio.h>
6355714Skris
64280304Sjkimstatic int buffer_write(BIO *h, const char *buf, int num);
6568651Skrisstatic int buffer_read(BIO *h, char *buf, int size);
6668651Skrisstatic int buffer_puts(BIO *h, const char *str);
6768651Skrisstatic int buffer_gets(BIO *h, char *str, int size);
6868651Skrisstatic long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
6955714Skrisstatic int buffer_new(BIO *h);
7055714Skrisstatic int buffer_free(BIO *data);
7168651Skrisstatic long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
72280304Sjkim#define DEFAULT_BUFFER_SIZE     4096
7355714Skris
74280304Sjkimstatic BIO_METHOD methods_buffer = {
75280304Sjkim    BIO_TYPE_BUFFER,
76280304Sjkim    "buffer",
77280304Sjkim    buffer_write,
78280304Sjkim    buffer_read,
79280304Sjkim    buffer_puts,
80280304Sjkim    buffer_gets,
81280304Sjkim    buffer_ctrl,
82280304Sjkim    buffer_new,
83280304Sjkim    buffer_free,
84280304Sjkim    buffer_callback_ctrl,
85280304Sjkim};
8655714Skris
8755714SkrisBIO_METHOD *BIO_f_buffer(void)
88280304Sjkim{
89280304Sjkim    return (&methods_buffer);
90280304Sjkim}
9155714Skris
9255714Skrisstatic int buffer_new(BIO *bi)
93280304Sjkim{
94280304Sjkim    BIO_F_BUFFER_CTX *ctx;
9555714Skris
96280304Sjkim    ctx = (BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
97280304Sjkim    if (ctx == NULL)
98280304Sjkim        return (0);
99280304Sjkim    ctx->ibuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
100280304Sjkim    if (ctx->ibuf == NULL) {
101280304Sjkim        OPENSSL_free(ctx);
102280304Sjkim        return (0);
103280304Sjkim    }
104280304Sjkim    ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
105280304Sjkim    if (ctx->obuf == NULL) {
106280304Sjkim        OPENSSL_free(ctx->ibuf);
107280304Sjkim        OPENSSL_free(ctx);
108280304Sjkim        return (0);
109280304Sjkim    }
110280304Sjkim    ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
111280304Sjkim    ctx->obuf_size = DEFAULT_BUFFER_SIZE;
112280304Sjkim    ctx->ibuf_len = 0;
113280304Sjkim    ctx->ibuf_off = 0;
114280304Sjkim    ctx->obuf_len = 0;
115280304Sjkim    ctx->obuf_off = 0;
11655714Skris
117280304Sjkim    bi->init = 1;
118280304Sjkim    bi->ptr = (char *)ctx;
119280304Sjkim    bi->flags = 0;
120280304Sjkim    return (1);
121280304Sjkim}
12255714Skris
12355714Skrisstatic int buffer_free(BIO *a)
124280304Sjkim{
125280304Sjkim    BIO_F_BUFFER_CTX *b;
12655714Skris
127280304Sjkim    if (a == NULL)
128280304Sjkim        return (0);
129280304Sjkim    b = (BIO_F_BUFFER_CTX *)a->ptr;
130280304Sjkim    if (b->ibuf != NULL)
131280304Sjkim        OPENSSL_free(b->ibuf);
132280304Sjkim    if (b->obuf != NULL)
133280304Sjkim        OPENSSL_free(b->obuf);
134280304Sjkim    OPENSSL_free(a->ptr);
135280304Sjkim    a->ptr = NULL;
136280304Sjkim    a->init = 0;
137280304Sjkim    a->flags = 0;
138280304Sjkim    return (1);
139280304Sjkim}
140280304Sjkim
14155714Skrisstatic int buffer_read(BIO *b, char *out, int outl)
142280304Sjkim{
143280304Sjkim    int i, num = 0;
144280304Sjkim    BIO_F_BUFFER_CTX *ctx;
14555714Skris
146280304Sjkim    if (out == NULL)
147280304Sjkim        return (0);
148280304Sjkim    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
14955714Skris
150280304Sjkim    if ((ctx == NULL) || (b->next_bio == NULL))
151280304Sjkim        return (0);
152280304Sjkim    num = 0;
153280304Sjkim    BIO_clear_retry_flags(b);
15455714Skris
155280304Sjkim start:
156280304Sjkim    i = ctx->ibuf_len;
157280304Sjkim    /* If there is stuff left over, grab it */
158280304Sjkim    if (i != 0) {
159280304Sjkim        if (i > outl)
160280304Sjkim            i = outl;
161280304Sjkim        memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
162280304Sjkim        ctx->ibuf_off += i;
163280304Sjkim        ctx->ibuf_len -= i;
164280304Sjkim        num += i;
165280304Sjkim        if (outl == i)
166280304Sjkim            return (num);
167280304Sjkim        outl -= i;
168280304Sjkim        out += i;
169280304Sjkim    }
17055714Skris
171280304Sjkim    /*
172280304Sjkim     * We may have done a partial read. try to do more. We have nothing in
173280304Sjkim     * the buffer. If we get an error and have read some data, just return it
174280304Sjkim     * and let them retry to get the error again. copy direct to parent
175280304Sjkim     * address space
176280304Sjkim     */
177280304Sjkim    if (outl > ctx->ibuf_size) {
178280304Sjkim        for (;;) {
179280304Sjkim            i = BIO_read(b->next_bio, out, outl);
180280304Sjkim            if (i <= 0) {
181280304Sjkim                BIO_copy_next_retry(b);
182280304Sjkim                if (i < 0)
183280304Sjkim                    return ((num > 0) ? num : i);
184280304Sjkim                if (i == 0)
185280304Sjkim                    return (num);
186280304Sjkim            }
187280304Sjkim            num += i;
188280304Sjkim            if (outl == i)
189280304Sjkim                return (num);
190280304Sjkim            out += i;
191280304Sjkim            outl -= i;
192280304Sjkim        }
193280304Sjkim    }
194280304Sjkim    /* else */
19555714Skris
196280304Sjkim    /* we are going to be doing some buffering */
197280304Sjkim    i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
198280304Sjkim    if (i <= 0) {
199280304Sjkim        BIO_copy_next_retry(b);
200280304Sjkim        if (i < 0)
201280304Sjkim            return ((num > 0) ? num : i);
202280304Sjkim        if (i == 0)
203280304Sjkim            return (num);
204280304Sjkim    }
205280304Sjkim    ctx->ibuf_off = 0;
206280304Sjkim    ctx->ibuf_len = i;
20755714Skris
208280304Sjkim    /* Lets re-read using ourselves :-) */
209280304Sjkim    goto start;
210280304Sjkim}
21155714Skris
21268651Skrisstatic int buffer_write(BIO *b, const char *in, int inl)
213280304Sjkim{
214280304Sjkim    int i, num = 0;
215280304Sjkim    BIO_F_BUFFER_CTX *ctx;
21655714Skris
217280304Sjkim    if ((in == NULL) || (inl <= 0))
218280304Sjkim        return (0);
219280304Sjkim    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
220280304Sjkim    if ((ctx == NULL) || (b->next_bio == NULL))
221280304Sjkim        return (0);
22255714Skris
223280304Sjkim    BIO_clear_retry_flags(b);
224280304Sjkim start:
225280304Sjkim    i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
226280304Sjkim    /* add to buffer and return */
227280304Sjkim    if (i >= inl) {
228280304Sjkim        memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
229280304Sjkim        ctx->obuf_len += inl;
230280304Sjkim        return (num + inl);
231280304Sjkim    }
232280304Sjkim    /* else */
233280304Sjkim    /* stuff already in buffer, so add to it first, then flush */
234280304Sjkim    if (ctx->obuf_len != 0) {
235280304Sjkim        if (i > 0) {            /* lets fill it up if we can */
236280304Sjkim            memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
237280304Sjkim            in += i;
238280304Sjkim            inl -= i;
239280304Sjkim            num += i;
240280304Sjkim            ctx->obuf_len += i;
241280304Sjkim        }
242280304Sjkim        /* we now have a full buffer needing flushing */
243280304Sjkim        for (;;) {
244280304Sjkim            i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
245280304Sjkim                          ctx->obuf_len);
246280304Sjkim            if (i <= 0) {
247280304Sjkim                BIO_copy_next_retry(b);
24855714Skris
249280304Sjkim                if (i < 0)
250280304Sjkim                    return ((num > 0) ? num : i);
251280304Sjkim                if (i == 0)
252280304Sjkim                    return (num);
253280304Sjkim            }
254280304Sjkim            ctx->obuf_off += i;
255280304Sjkim            ctx->obuf_len -= i;
256280304Sjkim            if (ctx->obuf_len == 0)
257280304Sjkim                break;
258280304Sjkim        }
259280304Sjkim    }
260280304Sjkim    /*
261280304Sjkim     * we only get here if the buffer has been flushed and we still have
262280304Sjkim     * stuff to write
263280304Sjkim     */
264280304Sjkim    ctx->obuf_off = 0;
26555714Skris
266280304Sjkim    /* we now have inl bytes to write */
267280304Sjkim    while (inl >= ctx->obuf_size) {
268280304Sjkim        i = BIO_write(b->next_bio, in, inl);
269280304Sjkim        if (i <= 0) {
270280304Sjkim            BIO_copy_next_retry(b);
271280304Sjkim            if (i < 0)
272280304Sjkim                return ((num > 0) ? num : i);
273280304Sjkim            if (i == 0)
274280304Sjkim                return (num);
275280304Sjkim        }
276280304Sjkim        num += i;
277280304Sjkim        in += i;
278280304Sjkim        inl -= i;
279280304Sjkim        if (inl == 0)
280280304Sjkim            return (num);
281280304Sjkim    }
28255714Skris
283280304Sjkim    /*
284280304Sjkim     * copy the rest into the buffer since we have only a small amount left
285280304Sjkim     */
286280304Sjkim    goto start;
287280304Sjkim}
28855714Skris
28968651Skrisstatic long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
290280304Sjkim{
291280304Sjkim    BIO *dbio;
292280304Sjkim    BIO_F_BUFFER_CTX *ctx;
293280304Sjkim    long ret = 1;
294280304Sjkim    char *p1, *p2;
295280304Sjkim    int r, i, *ip;
296280304Sjkim    int ibs, obs;
29755714Skris
298280304Sjkim    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
29955714Skris
300280304Sjkim    switch (cmd) {
301280304Sjkim    case BIO_CTRL_RESET:
302280304Sjkim        ctx->ibuf_off = 0;
303280304Sjkim        ctx->ibuf_len = 0;
304280304Sjkim        ctx->obuf_off = 0;
305280304Sjkim        ctx->obuf_len = 0;
306280304Sjkim        if (b->next_bio == NULL)
307280304Sjkim            return (0);
308280304Sjkim        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
309280304Sjkim        break;
310280304Sjkim    case BIO_CTRL_INFO:
311280304Sjkim        ret = (long)ctx->obuf_len;
312280304Sjkim        break;
313280304Sjkim    case BIO_C_GET_BUFF_NUM_LINES:
314280304Sjkim        ret = 0;
315280304Sjkim        p1 = ctx->ibuf;
316280304Sjkim        for (i = 0; i < ctx->ibuf_len; i++) {
317280304Sjkim            if (p1[ctx->ibuf_off + i] == '\n')
318280304Sjkim                ret++;
319280304Sjkim        }
320280304Sjkim        break;
321280304Sjkim    case BIO_CTRL_WPENDING:
322280304Sjkim        ret = (long)ctx->obuf_len;
323280304Sjkim        if (ret == 0) {
324280304Sjkim            if (b->next_bio == NULL)
325280304Sjkim                return (0);
326280304Sjkim            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
327280304Sjkim        }
328280304Sjkim        break;
329280304Sjkim    case BIO_CTRL_PENDING:
330280304Sjkim        ret = (long)ctx->ibuf_len;
331280304Sjkim        if (ret == 0) {
332280304Sjkim            if (b->next_bio == NULL)
333280304Sjkim                return (0);
334280304Sjkim            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
335280304Sjkim        }
336280304Sjkim        break;
337280304Sjkim    case BIO_C_SET_BUFF_READ_DATA:
338280304Sjkim        if (num > ctx->ibuf_size) {
339280304Sjkim            p1 = OPENSSL_malloc((int)num);
340280304Sjkim            if (p1 == NULL)
341280304Sjkim                goto malloc_error;
342280304Sjkim            if (ctx->ibuf != NULL)
343280304Sjkim                OPENSSL_free(ctx->ibuf);
344280304Sjkim            ctx->ibuf = p1;
345280304Sjkim        }
346280304Sjkim        ctx->ibuf_off = 0;
347280304Sjkim        ctx->ibuf_len = (int)num;
348280304Sjkim        memcpy(ctx->ibuf, ptr, (int)num);
349280304Sjkim        ret = 1;
350280304Sjkim        break;
351280304Sjkim    case BIO_C_SET_BUFF_SIZE:
352280304Sjkim        if (ptr != NULL) {
353280304Sjkim            ip = (int *)ptr;
354280304Sjkim            if (*ip == 0) {
355280304Sjkim                ibs = (int)num;
356280304Sjkim                obs = ctx->obuf_size;
357280304Sjkim            } else {            /* if (*ip == 1) */
35855714Skris
359280304Sjkim                ibs = ctx->ibuf_size;
360280304Sjkim                obs = (int)num;
361280304Sjkim            }
362280304Sjkim        } else {
363280304Sjkim            ibs = (int)num;
364280304Sjkim            obs = (int)num;
365280304Sjkim        }
366280304Sjkim        p1 = ctx->ibuf;
367280304Sjkim        p2 = ctx->obuf;
368280304Sjkim        if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
369280304Sjkim            p1 = (char *)OPENSSL_malloc((int)num);
370280304Sjkim            if (p1 == NULL)
371280304Sjkim                goto malloc_error;
372280304Sjkim        }
373280304Sjkim        if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
374280304Sjkim            p2 = (char *)OPENSSL_malloc((int)num);
375280304Sjkim            if (p2 == NULL) {
376280304Sjkim                if (p1 != ctx->ibuf)
377280304Sjkim                    OPENSSL_free(p1);
378280304Sjkim                goto malloc_error;
379280304Sjkim            }
380280304Sjkim        }
381280304Sjkim        if (ctx->ibuf != p1) {
382280304Sjkim            OPENSSL_free(ctx->ibuf);
383280304Sjkim            ctx->ibuf = p1;
384280304Sjkim            ctx->ibuf_off = 0;
385280304Sjkim            ctx->ibuf_len = 0;
386280304Sjkim            ctx->ibuf_size = ibs;
387280304Sjkim        }
388280304Sjkim        if (ctx->obuf != p2) {
389280304Sjkim            OPENSSL_free(ctx->obuf);
390280304Sjkim            ctx->obuf = p2;
391280304Sjkim            ctx->obuf_off = 0;
392280304Sjkim            ctx->obuf_len = 0;
393280304Sjkim            ctx->obuf_size = obs;
394280304Sjkim        }
395280304Sjkim        break;
396280304Sjkim    case BIO_C_DO_STATE_MACHINE:
397280304Sjkim        if (b->next_bio == NULL)
398280304Sjkim            return (0);
399280304Sjkim        BIO_clear_retry_flags(b);
400280304Sjkim        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
401280304Sjkim        BIO_copy_next_retry(b);
402280304Sjkim        break;
40355714Skris
404280304Sjkim    case BIO_CTRL_FLUSH:
405280304Sjkim        if (b->next_bio == NULL)
406280304Sjkim            return (0);
407280304Sjkim        if (ctx->obuf_len <= 0) {
408280304Sjkim            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
409280304Sjkim            break;
410280304Sjkim        }
411280304Sjkim
412280304Sjkim        for (;;) {
413280304Sjkim            BIO_clear_retry_flags(b);
414280304Sjkim            if (ctx->obuf_len > 0) {
415280304Sjkim                r = BIO_write(b->next_bio,
416280304Sjkim                              &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
41755714Skris#if 0
418280304Sjkim                fprintf(stderr, "FLUSH [%3d] %3d -> %3d\n", ctx->obuf_off,
419280304Sjkim                        ctx->obuf_len, r);
42055714Skris#endif
421280304Sjkim                BIO_copy_next_retry(b);
422280304Sjkim                if (r <= 0)
423280304Sjkim                    return ((long)r);
424280304Sjkim                ctx->obuf_off += r;
425280304Sjkim                ctx->obuf_len -= r;
426280304Sjkim            } else {
427280304Sjkim                ctx->obuf_len = 0;
428280304Sjkim                ctx->obuf_off = 0;
429280304Sjkim                ret = 1;
430280304Sjkim                break;
431280304Sjkim            }
432280304Sjkim        }
433280304Sjkim        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
434280304Sjkim        break;
435280304Sjkim    case BIO_CTRL_DUP:
436280304Sjkim        dbio = (BIO *)ptr;
437280304Sjkim        if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
438280304Sjkim            !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
439280304Sjkim            ret = 0;
440280304Sjkim        break;
441280304Sjkim    default:
442280304Sjkim        if (b->next_bio == NULL)
443280304Sjkim            return (0);
444280304Sjkim        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
445280304Sjkim        break;
446280304Sjkim    }
447280304Sjkim    return (ret);
448280304Sjkim malloc_error:
449280304Sjkim    BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
450280304Sjkim    return (0);
451280304Sjkim}
45255714Skris
45368651Skrisstatic long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
454280304Sjkim{
455280304Sjkim    long ret = 1;
45659191Skris
457280304Sjkim    if (b->next_bio == NULL)
458280304Sjkim        return (0);
459280304Sjkim    switch (cmd) {
460280304Sjkim    default:
461280304Sjkim        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
462280304Sjkim        break;
463280304Sjkim    }
464280304Sjkim    return (ret);
465280304Sjkim}
46659191Skris
46755714Skrisstatic int buffer_gets(BIO *b, char *buf, int size)
468280304Sjkim{
469280304Sjkim    BIO_F_BUFFER_CTX *ctx;
470280304Sjkim    int num = 0, i, flag;
471280304Sjkim    char *p;
47255714Skris
473280304Sjkim    ctx = (BIO_F_BUFFER_CTX *)b->ptr;
474280304Sjkim    size--;                     /* reserve space for a '\0' */
475280304Sjkim    BIO_clear_retry_flags(b);
47655714Skris
477280304Sjkim    for (;;) {
478280304Sjkim        if (ctx->ibuf_len > 0) {
479280304Sjkim            p = &(ctx->ibuf[ctx->ibuf_off]);
480280304Sjkim            flag = 0;
481280304Sjkim            for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
482280304Sjkim                *(buf++) = p[i];
483280304Sjkim                if (p[i] == '\n') {
484280304Sjkim                    flag = 1;
485280304Sjkim                    i++;
486280304Sjkim                    break;
487280304Sjkim                }
488280304Sjkim            }
489280304Sjkim            num += i;
490280304Sjkim            size -= i;
491280304Sjkim            ctx->ibuf_len -= i;
492280304Sjkim            ctx->ibuf_off += i;
493280304Sjkim            if (flag || size == 0) {
494280304Sjkim                *buf = '\0';
495280304Sjkim                return (num);
496280304Sjkim            }
497280304Sjkim        } else {                /* read another chunk */
49855714Skris
499280304Sjkim            i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
500280304Sjkim            if (i <= 0) {
501280304Sjkim                BIO_copy_next_retry(b);
502280304Sjkim                *buf = '\0';
503280304Sjkim                if (i < 0)
504280304Sjkim                    return ((num > 0) ? num : i);
505280304Sjkim                if (i == 0)
506280304Sjkim                    return (num);
507280304Sjkim            }
508280304Sjkim            ctx->ibuf_len = i;
509280304Sjkim            ctx->ibuf_off = 0;
510280304Sjkim        }
511280304Sjkim    }
512280304Sjkim}
513280304Sjkim
51468651Skrisstatic int buffer_puts(BIO *b, const char *str)
515280304Sjkim{
516280304Sjkim    return (buffer_write(b, str, strlen(str)));
517280304Sjkim}
518