Home | History | Annotate | Download | only in bio
      1 /* ====================================================================
      2  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in
     13  *    the documentation and/or other materials provided with the
     14  *    distribution.
     15  *
     16  * 3. All advertising materials mentioning features or use of this
     17  *    software must display the following acknowledgment:
     18  *    "This product includes software developed by the OpenSSL Project
     19  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
     20  *
     21  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     22  *    endorse or promote products derived from this software without
     23  *    prior written permission. For written permission, please contact
     24  *    openssl-core (at) openssl.org.
     25  *
     26  * 5. Products derived from this software may not be called "OpenSSL"
     27  *    nor may "OpenSSL" appear in their names without prior written
     28  *    permission of the OpenSSL Project.
     29  *
     30  * 6. Redistributions of any form whatsoever must retain the following
     31  *    acknowledgment:
     32  *    "This product includes software developed by the OpenSSL Project
     33  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
     34  *
     35  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     46  * OF THE POSSIBILITY OF SUCH DAMAGE.
     47  * ====================================================================
     48  *
     49  * This product includes cryptographic software written by Eric Young
     50  * (eay (at) cryptsoft.com).  This product includes software written by Tim
     51  * Hudson (tjh (at) cryptsoft.com). */
     52 
     53 #include <openssl/bio.h>
     54 
     55 #include <assert.h>
     56 #include <string.h>
     57 
     58 #include <openssl/buf.h>
     59 #include <openssl/err.h>
     60 #include <openssl/mem.h>
     61 
     62 
     63 struct bio_bio_st {
     64   BIO *peer; /* NULL if buf == NULL.
     65               * If peer != NULL, then peer->ptr is also a bio_bio_st,
     66               * and its "peer" member points back to us.
     67               * peer != NULL iff init != 0 in the BIO. */
     68 
     69   /* This is for what we write (i.e. reading uses peer's struct): */
     70   int closed;    /* valid iff peer != NULL */
     71   size_t len;    /* valid iff buf != NULL; 0 if peer == NULL */
     72   size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
     73   size_t size;
     74   uint8_t *buf; /* "size" elements (if != NULL) */
     75   char buf_externally_allocated; /* true iff buf was externally allocated. */
     76 
     77   char zero_copy_read_lock;  /* true iff a zero copy read operation
     78                               * is in progress. */
     79   char zero_copy_write_lock; /* true iff a zero copy write operation
     80                               * is in progress. */
     81 
     82   size_t request; /* valid iff peer != NULL; 0 if len != 0,
     83                    * otherwise set by peer to number of bytes
     84                    * it (unsuccessfully) tried to read,
     85                    * never more than buffer space (size-len) warrants. */
     86 };
     87 
     88 static int bio_new(BIO *bio) {
     89   struct bio_bio_st *b;
     90 
     91   b = OPENSSL_malloc(sizeof *b);
     92   if (b == NULL) {
     93     return 0;
     94   }
     95   memset(b, 0, sizeof(struct bio_bio_st));
     96 
     97   b->size = 17 * 1024; /* enough for one TLS record (just a default) */
     98   bio->ptr = b;
     99   return 1;
    100 }
    101 
    102 static void bio_destroy_pair(BIO *bio) {
    103   struct bio_bio_st *b = bio->ptr;
    104   BIO *peer_bio;
    105   struct bio_bio_st *peer_b;
    106 
    107   if (b == NULL) {
    108     return;
    109   }
    110 
    111   peer_bio = b->peer;
    112   if (peer_bio == NULL) {
    113     return;
    114   }
    115 
    116   peer_b = peer_bio->ptr;
    117 
    118   assert(peer_b != NULL);
    119   assert(peer_b->peer == bio);
    120 
    121   peer_b->peer = NULL;
    122   peer_bio->init = 0;
    123   assert(peer_b->buf != NULL);
    124   peer_b->len = 0;
    125   peer_b->offset = 0;
    126 
    127   b->peer = NULL;
    128   bio->init = 0;
    129   assert(b->buf != NULL);
    130   b->len = 0;
    131   b->offset = 0;
    132 }
    133 
    134 static int bio_free(BIO *bio) {
    135   struct bio_bio_st *b;
    136 
    137   if (bio == NULL) {
    138     return 0;
    139   }
    140   b = bio->ptr;
    141 
    142   assert(b != NULL);
    143 
    144   if (b->peer) {
    145     bio_destroy_pair(bio);
    146   }
    147 
    148   if (!b->buf_externally_allocated) {
    149     OPENSSL_free(b->buf);
    150   }
    151 
    152   OPENSSL_free(b);
    153 
    154   return 1;
    155 }
    156 
    157 static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b,
    158                                          uint8_t** out_read_buf,
    159                                          size_t* out_buf_offset) {
    160   size_t max_available;
    161   if (peer_b->len > peer_b->size - peer_b->offset) {
    162     /* Only the first half of the ring buffer can be read. */
    163     max_available = peer_b->size - peer_b->offset;
    164   } else {
    165     max_available = peer_b->len;
    166   }
    167 
    168   *out_read_buf = peer_b->buf;
    169   *out_buf_offset = peer_b->offset;
    170   return max_available;
    171 }
    172 
    173 int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf,
    174                                size_t* out_buf_offset,
    175                                size_t* out_available_bytes) {
    176   struct bio_bio_st* b;
    177   struct bio_bio_st* peer_b;
    178   size_t max_available;
    179   *out_available_bytes = 0;
    180 
    181   BIO_clear_retry_flags(bio);
    182 
    183   if (!bio->init) {
    184     OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
    185     return 0;
    186   }
    187 
    188   b = bio->ptr;
    189 
    190   if (!b || !b->peer) {
    191     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    192     return 0;
    193   }
    194 
    195   peer_b = b->peer->ptr;
    196   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
    197     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    198     return 0;
    199   }
    200 
    201   if (peer_b->zero_copy_read_lock) {
    202     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    203     return 0;
    204   }
    205 
    206   peer_b->request = 0;  /* Is not used by zero-copy API. */
    207 
    208   max_available =
    209       bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset);
    210 
    211   assert(peer_b->buf != NULL);
    212   if (max_available > 0) {
    213     peer_b->zero_copy_read_lock = 1;
    214   }
    215 
    216   *out_available_bytes = max_available;
    217   return 1;
    218 }
    219 
    220 int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) {
    221   struct bio_bio_st* b;
    222   struct bio_bio_st* peer_b;
    223   size_t max_available;
    224   size_t dummy_read_offset;
    225   uint8_t* dummy_read_buf;
    226 
    227   assert(BIO_get_retry_flags(bio) == 0);
    228 
    229   if (!bio->init) {
    230     OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
    231     return 0;
    232   }
    233 
    234   b = bio->ptr;
    235 
    236   if (!b || !b->peer) {
    237     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    238     return 0;
    239   }
    240 
    241   peer_b = b->peer->ptr;
    242   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
    243     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    244     return 0;
    245   }
    246 
    247   if (!peer_b->zero_copy_read_lock) {
    248     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    249     return 0;
    250   }
    251 
    252   max_available =
    253       bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset);
    254   if (bytes_read > max_available) {
    255     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    256     return 0;
    257   }
    258 
    259   assert(peer_b->len >= bytes_read);
    260   peer_b->len -= bytes_read;
    261   assert(peer_b->offset + bytes_read <= peer_b->size);
    262 
    263   /* Move read offset. If zero_copy_write_lock == 1 we must advance the
    264    * offset even if buffer becomes empty, to make sure
    265    * write_offset = (offset + len) mod size does not change. */
    266   if (peer_b->offset + bytes_read == peer_b->size ||
    267       (!peer_b->zero_copy_write_lock && peer_b->len == 0)) {
    268     peer_b->offset = 0;
    269   } else {
    270     peer_b->offset += bytes_read;
    271   }
    272 
    273   bio->num_read += bytes_read;
    274   peer_b->zero_copy_read_lock = 0;
    275   return 1;
    276 }
    277 
    278 static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b,
    279                                           uint8_t** out_write_buf,
    280                                           size_t* out_buf_offset) {
    281   size_t write_offset;
    282   size_t max_available;
    283 
    284   assert(b->len <= b->size);
    285 
    286   write_offset = b->offset + b->len;
    287 
    288   if (write_offset >= b->size) {
    289     /* Only the first half of the ring buffer can be written to. */
    290     write_offset -= b->size;
    291     /* write up to the start of the ring buffer. */
    292     max_available = b->offset - write_offset;
    293   } else {
    294     /* write up to the end the buffer. */
    295     max_available = b->size - write_offset;
    296   }
    297 
    298   *out_write_buf = b->buf;
    299   *out_buf_offset = write_offset;
    300   return max_available;
    301 }
    302 
    303 int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf,
    304                                 size_t* out_buf_offset,
    305                                 size_t* out_available_bytes) {
    306   struct bio_bio_st* b;
    307   struct bio_bio_st* peer_b;
    308   size_t max_available;
    309 
    310   *out_available_bytes = 0;
    311   BIO_clear_retry_flags(bio);
    312 
    313   if (!bio->init) {
    314     OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
    315     return 0;
    316   }
    317 
    318   b = bio->ptr;
    319 
    320   if (!b || !b->buf || !b->peer) {
    321     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    322     return 0;
    323   }
    324   peer_b = b->peer->ptr;
    325   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
    326     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    327     return 0;
    328   }
    329 
    330   assert(b->buf != NULL);
    331 
    332   if (b->zero_copy_write_lock) {
    333     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    334     return 0;
    335   }
    336 
    337   b->request = 0;
    338   if (b->closed) {
    339     /* Bio is already closed. */
    340     OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
    341     return 0;
    342   }
    343 
    344   max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset);
    345 
    346   if (max_available > 0) {
    347     b->zero_copy_write_lock = 1;
    348   }
    349 
    350   *out_available_bytes = max_available;
    351   return 1;
    352 }
    353 
    354 int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) {
    355   struct bio_bio_st* b;
    356   struct bio_bio_st* peer_b;
    357 
    358   size_t rest;
    359   size_t dummy_write_offset;
    360   uint8_t* dummy_write_buf;
    361 
    362   if (!bio->init) {
    363     OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
    364     return 0;
    365   }
    366 
    367   b = bio->ptr;
    368 
    369   if (!b || !b->buf || !b->peer) {
    370     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    371     return 0;
    372   }
    373   peer_b = b->peer->ptr;
    374   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
    375     OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
    376     return 0;
    377   }
    378 
    379   b->request = 0;
    380   if (b->closed) {
    381     /* BIO is already closed. */
    382     OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
    383     return 0;
    384   }
    385 
    386   if (!b->zero_copy_write_lock) {
    387     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    388     return 0;
    389   }
    390 
    391   rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset);
    392 
    393   if (bytes_written > rest) {
    394     OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
    395     return 0;
    396   }
    397 
    398   bio->num_write += bytes_written;
    399   /* Move write offset. */
    400   b->len += bytes_written;
    401   b->zero_copy_write_lock = 0;
    402   return 1;
    403 }
    404 
    405 static int bio_read(BIO *bio, char *buf, int size_) {
    406   size_t size = size_;
    407   size_t rest;
    408   struct bio_bio_st *b, *peer_b;
    409 
    410   BIO_clear_retry_flags(bio);
    411 
    412   if (!bio->init) {
    413     return 0;
    414   }
    415 
    416   b = bio->ptr;
    417   assert(b != NULL);
    418   assert(b->peer != NULL);
    419   peer_b = b->peer->ptr;
    420   assert(peer_b != NULL);
    421   assert(peer_b->buf != NULL);
    422 
    423   peer_b->request = 0; /* will be set in "retry_read" situation */
    424 
    425   if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) {
    426     return 0;
    427   }
    428 
    429   if (peer_b->len == 0) {
    430     if (peer_b->closed) {
    431       return 0; /* writer has closed, and no data is left */
    432     } else {
    433       BIO_set_retry_read(bio); /* buffer is empty */
    434       if (size <= peer_b->size) {
    435         peer_b->request = size;
    436       } else {
    437         /* don't ask for more than the peer can
    438          * deliver in one write */
    439         peer_b->request = peer_b->size;
    440       }
    441       return -1;
    442     }
    443   }
    444 
    445   /* we can read */
    446   if (peer_b->len < size) {
    447     size = peer_b->len;
    448   }
    449 
    450   /* now read "size" bytes */
    451   rest = size;
    452 
    453   assert(rest > 0);
    454   /* one or two iterations */
    455   do {
    456     size_t chunk;
    457 
    458     assert(rest <= peer_b->len);
    459     if (peer_b->offset + rest <= peer_b->size) {
    460       chunk = rest;
    461     } else {
    462       /* wrap around ring buffer */
    463       chunk = peer_b->size - peer_b->offset;
    464     }
    465     assert(peer_b->offset + chunk <= peer_b->size);
    466 
    467     memcpy(buf, peer_b->buf + peer_b->offset, chunk);
    468 
    469     peer_b->len -= chunk;
    470     /* If zero_copy_write_lock == 1 we must advance the offset even if buffer
    471      * becomes empty, to make sure write_offset = (offset + len) % size
    472      * does not change. */
    473     if (peer_b->len || peer_b->zero_copy_write_lock) {
    474       peer_b->offset += chunk;
    475       assert(peer_b->offset <= peer_b->size);
    476       if (peer_b->offset == peer_b->size) {
    477         peer_b->offset = 0;
    478       }
    479       buf += chunk;
    480     } else {
    481       /* buffer now empty, no need to advance "buf" */
    482       assert(chunk == rest);
    483       peer_b->offset = 0;
    484     }
    485     rest -= chunk;
    486   } while (rest);
    487 
    488   return size;
    489 }
    490 
    491 static int bio_write(BIO *bio, const char *buf, int num_) {
    492   size_t num = num_;
    493   size_t rest;
    494   struct bio_bio_st *b;
    495 
    496   BIO_clear_retry_flags(bio);
    497 
    498   if (!bio->init || buf == NULL || num == 0) {
    499     return 0;
    500   }
    501 
    502   b = bio->ptr;
    503   assert(b != NULL);
    504   assert(b->peer != NULL);
    505   assert(b->buf != NULL);
    506 
    507   if (b->zero_copy_write_lock) {
    508     return 0;
    509   }
    510 
    511   b->request = 0;
    512   if (b->closed) {
    513     /* we already closed */
    514     OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
    515     return -1;
    516   }
    517 
    518   assert(b->len <= b->size);
    519 
    520   if (b->len == b->size) {
    521     BIO_set_retry_write(bio); /* buffer is full */
    522     return -1;
    523   }
    524 
    525   /* we can write */
    526   if (num > b->size - b->len) {
    527     num = b->size - b->len;
    528   }
    529 
    530   /* now write "num" bytes */
    531   rest = num;
    532 
    533   assert(rest > 0);
    534   /* one or two iterations */
    535   do {
    536     size_t write_offset;
    537     size_t chunk;
    538 
    539     assert(b->len + rest <= b->size);
    540 
    541     write_offset = b->offset + b->len;
    542     if (write_offset >= b->size) {
    543       write_offset -= b->size;
    544     }
    545     /* b->buf[write_offset] is the first byte we can write to. */
    546 
    547     if (write_offset + rest <= b->size) {
    548       chunk = rest;
    549     } else {
    550       /* wrap around ring buffer */
    551       chunk = b->size - write_offset;
    552     }
    553 
    554     memcpy(b->buf + write_offset, buf, chunk);
    555 
    556     b->len += chunk;
    557 
    558     assert(b->len <= b->size);
    559 
    560     rest -= chunk;
    561     buf += chunk;
    562   } while (rest);
    563 
    564   return num;
    565 }
    566 
    567 static int bio_make_pair(BIO* bio1, BIO* bio2,
    568                          size_t writebuf1_len, uint8_t* ext_writebuf1,
    569                          size_t writebuf2_len, uint8_t* ext_writebuf2) {
    570   struct bio_bio_st *b1, *b2;
    571 
    572   assert(bio1 != NULL);
    573   assert(bio2 != NULL);
    574 
    575   b1 = bio1->ptr;
    576   b2 = bio2->ptr;
    577 
    578   if (b1->peer != NULL || b2->peer != NULL) {
    579     OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE);
    580     return 0;
    581   }
    582 
    583   assert(b1->buf_externally_allocated == 0);
    584   assert(b2->buf_externally_allocated == 0);
    585 
    586   if (b1->buf == NULL) {
    587     if (writebuf1_len) {
    588       b1->size = writebuf1_len;
    589     }
    590     if (!ext_writebuf1) {
    591       b1->buf_externally_allocated = 0;
    592       b1->buf = OPENSSL_malloc(b1->size);
    593       if (b1->buf == NULL) {
    594         OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
    595         return 0;
    596       }
    597     } else {
    598       b1->buf = ext_writebuf1;
    599       b1->buf_externally_allocated = 1;
    600     }
    601     b1->len = 0;
    602     b1->offset = 0;
    603   }
    604 
    605   if (b2->buf == NULL) {
    606     if (writebuf2_len) {
    607       b2->size = writebuf2_len;
    608     }
    609     if (!ext_writebuf2) {
    610       b2->buf_externally_allocated = 0;
    611       b2->buf = OPENSSL_malloc(b2->size);
    612       if (b2->buf == NULL) {
    613         OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
    614         return 0;
    615       }
    616     } else {
    617       b2->buf = ext_writebuf2;
    618       b2->buf_externally_allocated = 1;
    619     }
    620     b2->len = 0;
    621     b2->offset = 0;
    622   }
    623 
    624   b1->peer = bio2;
    625   b1->closed = 0;
    626   b1->request = 0;
    627   b1->zero_copy_read_lock = 0;
    628   b1->zero_copy_write_lock = 0;
    629   b2->peer = bio1;
    630   b2->closed = 0;
    631   b2->request = 0;
    632   b2->zero_copy_read_lock = 0;
    633   b2->zero_copy_write_lock = 0;
    634 
    635   bio1->init = 1;
    636   bio2->init = 1;
    637 
    638   return 1;
    639 }
    640 
    641 static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
    642   long ret;
    643   struct bio_bio_st *b = bio->ptr;
    644 
    645   assert(b != NULL);
    646 
    647   switch (cmd) {
    648     /* specific CTRL codes */
    649 
    650     case BIO_C_GET_WRITE_BUF_SIZE:
    651       ret = (long)b->size;
    652       break;
    653 
    654     case BIO_C_GET_WRITE_GUARANTEE:
    655       /* How many bytes can the caller feed to the next write
    656        * without having to keep any? */
    657       if (b->peer == NULL || b->closed) {
    658         ret = 0;
    659       } else {
    660         ret = (long)b->size - b->len;
    661       }
    662       break;
    663 
    664     case BIO_C_GET_READ_REQUEST:
    665       /* If the peer unsuccessfully tried to read, how many bytes
    666        * were requested?  (As with BIO_CTRL_PENDING, that number
    667        * can usually be treated as boolean.) */
    668       ret = (long)b->request;
    669       break;
    670 
    671     case BIO_C_RESET_READ_REQUEST:
    672       /* Reset request.  (Can be useful after read attempts
    673        * at the other side that are meant to be non-blocking,
    674        * e.g. when probing SSL_read to see if any data is
    675        * available.) */
    676       b->request = 0;
    677       ret = 1;
    678       break;
    679 
    680     case BIO_C_SHUTDOWN_WR:
    681       /* similar to shutdown(..., SHUT_WR) */
    682       b->closed = 1;
    683       ret = 1;
    684       break;
    685 
    686     /* standard CTRL codes follow */
    687 
    688     case BIO_CTRL_GET_CLOSE:
    689       ret = bio->shutdown;
    690       break;
    691 
    692     case BIO_CTRL_SET_CLOSE:
    693       bio->shutdown = (int)num;
    694       ret = 1;
    695       break;
    696 
    697     case BIO_CTRL_PENDING:
    698       if (b->peer != NULL) {
    699         struct bio_bio_st *peer_b = b->peer->ptr;
    700         ret = (long)peer_b->len;
    701       } else {
    702         ret = 0;
    703       }
    704       break;
    705 
    706     case BIO_CTRL_WPENDING:
    707       ret = 0;
    708       if (b->buf != NULL) {
    709         ret = (long)b->len;
    710       }
    711       break;
    712 
    713     case BIO_CTRL_FLUSH:
    714       ret = 1;
    715       break;
    716 
    717     case BIO_CTRL_EOF: {
    718       BIO *other_bio = ptr;
    719 
    720       if (other_bio) {
    721         struct bio_bio_st *other_b = other_bio->ptr;
    722         assert(other_b != NULL);
    723         ret = other_b->len == 0 && other_b->closed;
    724       } else {
    725         ret = 1;
    726       }
    727     } break;
    728 
    729     default:
    730       ret = 0;
    731   }
    732   return ret;
    733 }
    734 
    735 static int bio_puts(BIO *bio, const char *str) {
    736   return bio_write(bio, str, strlen(str));
    737 }
    738 
    739 static const BIO_METHOD methods_biop = {
    740     BIO_TYPE_BIO, "BIO pair",             bio_write, bio_read,
    741     bio_puts,     NULL /* no bio_gets */, bio_ctrl,  bio_new,
    742     bio_free,     NULL /* no bio_callback_ctrl */
    743 };
    744 
    745 const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
    746 
    747 int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1,
    748                      BIO** bio2_p, size_t writebuf2) {
    749   return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p,
    750                                        writebuf2, NULL);
    751 }
    752 
    753 int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len,
    754                                   uint8_t* ext_writebuf1,
    755                                   BIO** bio2_p, size_t writebuf2_len,
    756                                   uint8_t* ext_writebuf2) {
    757   BIO *bio1 = NULL, *bio2 = NULL;
    758   int ret = 0;
    759 
    760   /* External buffers must have sizes greater than 0. */
    761   if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) {
    762     goto err;
    763   }
    764 
    765   bio1 = BIO_new(bio_s_bio());
    766   if (bio1 == NULL) {
    767     goto err;
    768   }
    769   bio2 = BIO_new(bio_s_bio());
    770   if (bio2 == NULL) {
    771     goto err;
    772   }
    773 
    774   if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len,
    775                      ext_writebuf2)) {
    776     goto err;
    777   }
    778   ret = 1;
    779 
    780 err:
    781   if (ret == 0) {
    782     BIO_free(bio1);
    783     bio1 = NULL;
    784     BIO_free(bio2);
    785     bio2 = NULL;
    786   }
    787 
    788   *bio1_p = bio1;
    789   *bio2_p = bio2;
    790   return ret;
    791 }
    792 
    793 size_t BIO_ctrl_get_read_request(BIO *bio) {
    794   return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
    795 }
    796 
    797 size_t BIO_ctrl_get_write_guarantee(BIO *bio) {
    798   return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
    799 }
    800 
    801 int BIO_shutdown_wr(BIO *bio) {
    802   return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL);
    803 }
    804