Home | History | Annotate | Download | only in bio
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) cryptsoft.com).
      6  * The implementation was written so as to conform with Netscapes SSL.
      7  *
      8  * This library is free for commercial and non-commercial use as long as
      9  * the following conditions are aheared to.  The following conditions
     10  * apply to all code found in this distribution, be it the RC4, RSA,
     11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     12  * included with this distribution is covered by the same copyright terms
     13  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     14  *
     15  * Copyright remains Eric Young's, and as such any Copyright notices in
     16  * the code are not to be removed.
     17  * If this package is used in a product, Eric Young should be given attribution
     18  * as the author of the parts of the library used.
     19  * This can be in the form of a textual message at program startup or
     20  * in documentation (online or textual) provided with the package.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  * 3. All advertising materials mentioning features or use of this software
     31  *    must display the following acknowledgement:
     32  *    "This product includes cryptographic software written by
     33  *     Eric Young (eay (at) cryptsoft.com)"
     34  *    The word 'cryptographic' can be left out if the rouines from the library
     35  *    being used are not cryptographic related :-).
     36  * 4. If you include any Windows specific code (or a derivative thereof) from
     37  *    the apps directory (application code) you must include an acknowledgement:
     38  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  *
     52  * The licence and distribution terms for any publically available version or
     53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     54  * copied and put under another distribution licence
     55  * [including the GNU Public Licence.] */
     56 
     57 #include <openssl/bio.h>
     58 
     59 #include <string.h>
     60 
     61 #include <openssl/buf.h>
     62 #include <openssl/err.h>
     63 #include <openssl/mem.h>
     64 
     65 
     66 #define DEFAULT_BUFFER_SIZE 4096
     67 
     68 typedef struct bio_f_buffer_ctx_struct {
     69   /* Buffers are setup like this:
     70    *
     71    * <---------------------- size ----------------------->
     72    * +---------------------------------------------------+
     73    * | consumed | remaining          | free space        |
     74    * +---------------------------------------------------+
     75    * <-- off --><------- len ------->
     76    */
     77 
     78   int ibuf_size;  /* how big is the input buffer */
     79   int obuf_size;  /* how big is the output buffer */
     80 
     81   char *ibuf;   /* the char array */
     82   int ibuf_len; /* how many bytes are in it */
     83   int ibuf_off; /* write/read offset */
     84 
     85   char *obuf;   /* the char array */
     86   int obuf_len; /* how many bytes are in it */
     87   int obuf_off; /* write/read offset */
     88 } BIO_F_BUFFER_CTX;
     89 
     90 static int buffer_new(BIO *bio) {
     91   BIO_F_BUFFER_CTX *ctx;
     92 
     93   ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
     94   if (ctx == NULL) {
     95     return 0;
     96   }
     97   memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
     98 
     99   ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
    100   if (ctx->ibuf == NULL) {
    101     goto err1;
    102   }
    103   ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
    104   if (ctx->obuf == NULL) {
    105     goto err2;
    106   }
    107   ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
    108   ctx->obuf_size = DEFAULT_BUFFER_SIZE;
    109 
    110   bio->init = 1;
    111   bio->ptr = (char *)ctx;
    112   return 1;
    113 
    114 err2:
    115   OPENSSL_free(ctx->ibuf);
    116 
    117 err1:
    118   OPENSSL_free(ctx);
    119   return 0;
    120 }
    121 
    122 static int buffer_free(BIO *bio) {
    123   BIO_F_BUFFER_CTX *ctx;
    124 
    125   if (bio == NULL || bio->ptr == NULL) {
    126     return 0;
    127   }
    128 
    129   ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
    130   OPENSSL_free(ctx->ibuf);
    131   OPENSSL_free(ctx->obuf);
    132   OPENSSL_free(bio->ptr);
    133 
    134   bio->ptr = NULL;
    135   bio->init = 0;
    136   bio->flags = 0;
    137 
    138   return 1;
    139 }
    140 
    141 static int buffer_read(BIO *bio, char *out, int outl) {
    142   int i, num = 0;
    143   BIO_F_BUFFER_CTX *ctx;
    144 
    145   ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
    146 
    147   if (ctx == NULL || bio->next_bio == NULL) {
    148     return 0;
    149   }
    150 
    151   num = 0;
    152   BIO_clear_retry_flags(bio);
    153 
    154   for (;;) {
    155     i = ctx->ibuf_len;
    156     /* If there is stuff left over, grab it */
    157     if (i != 0) {
    158       if (i > outl) {
    159         i = outl;
    160       }
    161       memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
    162       ctx->ibuf_off += i;
    163       ctx->ibuf_len -= i;
    164       num += i;
    165       if (outl == i) {
    166         return num;
    167       }
    168       outl -= i;
    169       out += i;
    170     }
    171 
    172     /* We may have done a partial read. Try to do more. We have nothing in the
    173      * buffer. If we get an error and have read some data, just return it and
    174      * let them retry to get the error again. Copy direct to parent address
    175      * space */
    176     if (outl > ctx->ibuf_size) {
    177       for (;;) {
    178         i = BIO_read(bio->next_bio, out, outl);
    179         if (i <= 0) {
    180           BIO_copy_next_retry(bio);
    181           if (i < 0) {
    182             return (num > 0) ? num : i;
    183           }
    184           return num;
    185         }
    186         num += i;
    187         if (outl == i) {
    188           return num;
    189         }
    190         out += i;
    191         outl -= i;
    192       }
    193     }
    194     /* else */
    195 
    196     /* we are going to be doing some buffering */
    197     i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
    198     if (i <= 0) {
    199       BIO_copy_next_retry(bio);
    200       if (i < 0) {
    201         return (num > 0) ? num : i;
    202       }
    203       return num;
    204     }
    205     ctx->ibuf_off = 0;
    206     ctx->ibuf_len = i;
    207   }
    208 }
    209 
    210 static int buffer_write(BIO *b, const char *in, int inl) {
    211   int i, num = 0;
    212   BIO_F_BUFFER_CTX *ctx;
    213 
    214   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
    215   if (ctx == NULL || b->next_bio == NULL) {
    216     return 0;
    217   }
    218 
    219   BIO_clear_retry_flags(b);
    220 
    221   for (;;) {
    222     i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
    223     /* add to buffer and return */
    224     if (i >= inl) {
    225       memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
    226       ctx->obuf_len += inl;
    227       return num + inl;
    228     }
    229     /* else */
    230     /* stuff already in buffer, so add to it first, then flush */
    231     if (ctx->obuf_len != 0) {
    232       if (i > 0) {
    233         memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
    234         in += i;
    235         inl -= i;
    236         num += i;
    237         ctx->obuf_len += i;
    238       }
    239 
    240       /* we now have a full buffer needing flushing */
    241       for (;;) {
    242         i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
    243         if (i <= 0) {
    244           BIO_copy_next_retry(b);
    245 
    246           if (i < 0) {
    247             return (num > 0) ? num : i;
    248           }
    249           return num;
    250         }
    251         ctx->obuf_off += i;
    252         ctx->obuf_len -= i;
    253         if (ctx->obuf_len == 0) {
    254           break;
    255         }
    256       }
    257     }
    258 
    259     /* we only get here if the buffer has been flushed and we
    260      * still have stuff to write */
    261     ctx->obuf_off = 0;
    262 
    263     /* we now have inl bytes to write */
    264     while (inl >= ctx->obuf_size) {
    265       i = BIO_write(b->next_bio, in, inl);
    266       if (i <= 0) {
    267         BIO_copy_next_retry(b);
    268         if (i < 0) {
    269           return (num > 0) ? num : i;
    270         }
    271         return num;
    272       }
    273       num += i;
    274       in += i;
    275       inl -= i;
    276       if (inl == 0) {
    277         return num;
    278       }
    279     }
    280 
    281     /* copy the rest into the buffer since we have only a small
    282      * amount left */
    283   }
    284 }
    285 
    286 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
    287   BIO_F_BUFFER_CTX *ctx;
    288   long ret = 1;
    289   char *p1, *p2;
    290   int r, *ip;
    291   int ibs, obs;
    292 
    293   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
    294 
    295   switch (cmd) {
    296     case BIO_CTRL_RESET:
    297       ctx->ibuf_off = 0;
    298       ctx->ibuf_len = 0;
    299       ctx->obuf_off = 0;
    300       ctx->obuf_len = 0;
    301       if (b->next_bio == NULL) {
    302         return 0;
    303       }
    304       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    305       break;
    306 
    307     case BIO_CTRL_INFO:
    308       ret = ctx->obuf_len;
    309       break;
    310 
    311     case BIO_CTRL_WPENDING:
    312       ret = (long)ctx->obuf_len;
    313       if (ret == 0) {
    314         if (b->next_bio == NULL) {
    315           return 0;
    316         }
    317         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    318       }
    319       break;
    320 
    321     case BIO_CTRL_PENDING:
    322       ret = (long)ctx->ibuf_len;
    323       if (ret == 0) {
    324         if (b->next_bio == NULL) {
    325           return 0;
    326         }
    327         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    328       }
    329       break;
    330 
    331     case BIO_C_SET_BUFF_SIZE:
    332       ip = (int *)ptr;
    333       if (*ip == 0) {
    334         ibs = (int)num;
    335         obs = ctx->obuf_size;
    336       } else /* if (*ip == 1) */ {
    337         ibs = ctx->ibuf_size;
    338         obs = (int)num;
    339       }
    340       p1 = ctx->ibuf;
    341       p2 = ctx->obuf;
    342       if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
    343         p1 = (char *)OPENSSL_malloc(ibs);
    344         if (p1 == NULL) {
    345           goto malloc_error;
    346         }
    347       }
    348       if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
    349         p2 = (char *)OPENSSL_malloc(obs);
    350         if (p2 == NULL) {
    351           if (p1 != ctx->ibuf) {
    352             OPENSSL_free(p1);
    353           }
    354           goto malloc_error;
    355         }
    356       }
    357 
    358       if (ctx->ibuf != p1) {
    359         OPENSSL_free(ctx->ibuf);
    360         ctx->ibuf = p1;
    361         ctx->ibuf_size = ibs;
    362       }
    363       ctx->ibuf_off = 0;
    364       ctx->ibuf_len = 0;
    365 
    366       if (ctx->obuf != p2) {
    367         OPENSSL_free(ctx->obuf);
    368         ctx->obuf = p2;
    369         ctx->obuf_size = obs;
    370       }
    371       ctx->obuf_off = 0;
    372       ctx->obuf_len = 0;
    373       break;
    374 
    375     case BIO_CTRL_FLUSH:
    376       if (b->next_bio == NULL) {
    377         return 0;
    378       }
    379 
    380       while (ctx->obuf_len > 0) {
    381         BIO_clear_retry_flags(b);
    382         r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
    383                       ctx->obuf_len);
    384         BIO_copy_next_retry(b);
    385         if (r <= 0) {
    386           return r;
    387         }
    388         ctx->obuf_off += r;
    389         ctx->obuf_len -= r;
    390       }
    391 
    392       ctx->obuf_len = 0;
    393       ctx->obuf_off = 0;
    394       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    395       break;
    396 
    397     default:
    398       if (b->next_bio == NULL) {
    399         return 0;
    400       }
    401       BIO_clear_retry_flags(b);
    402       ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
    403       BIO_copy_next_retry(b);
    404       break;
    405   }
    406   return ret;
    407 
    408 malloc_error:
    409   OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE);
    410   return 0;
    411 }
    412 
    413 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
    414   long ret = 1;
    415 
    416   if (b->next_bio == NULL) {
    417     return 0;
    418   }
    419 
    420   switch (cmd) {
    421     default:
    422       ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
    423       break;
    424   }
    425   return ret;
    426 }
    427 
    428 static int buffer_gets(BIO *b, char *buf, int size) {
    429   BIO_F_BUFFER_CTX *ctx;
    430   int num = 0, i, flag;
    431   char *p;
    432 
    433   ctx = (BIO_F_BUFFER_CTX *)b->ptr;
    434   if (buf == NULL || size <= 0) {
    435     return 0;
    436   }
    437 
    438   size--; /* reserve space for a '\0' */
    439   BIO_clear_retry_flags(b);
    440 
    441   for (;;) {
    442     if (ctx->ibuf_len > 0) {
    443       p = &ctx->ibuf[ctx->ibuf_off];
    444       flag = 0;
    445       for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
    446         *(buf++) = p[i];
    447         if (p[i] == '\n') {
    448           flag = 1;
    449           i++;
    450           break;
    451         }
    452       }
    453       num += i;
    454       size -= i;
    455       ctx->ibuf_len -= i;
    456       ctx->ibuf_off += i;
    457       if (flag || size == 0) {
    458         *buf = '\0';
    459         return num;
    460       }
    461     } else /* read another chunk */
    462     {
    463       i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
    464       if (i <= 0) {
    465         BIO_copy_next_retry(b);
    466         *buf = '\0';
    467         if (i < 0) {
    468           return (num > 0) ? num : i;
    469         }
    470         return num;
    471       }
    472       ctx->ibuf_len = i;
    473       ctx->ibuf_off = 0;
    474     }
    475   }
    476 }
    477 
    478 static int buffer_puts(BIO *b, const char *str) {
    479   return buffer_write(b, str, strlen(str));
    480 }
    481 
    482 static const BIO_METHOD methods_buffer = {
    483     BIO_TYPE_BUFFER, "buffer",             buffer_write, buffer_read,
    484     buffer_puts,     buffer_gets,          buffer_ctrl,  buffer_new,
    485     buffer_free,     buffer_callback_ctrl,
    486 };
    487 
    488 const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
    489 
    490 int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
    491   return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
    492 }
    493 
    494 int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
    495   return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
    496 }
    497