1*e71b7053SJung-uk Kim /* 2*e71b7053SJung-uk Kim * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved. 350ef0093SJacques Vidrine * 4*e71b7053SJung-uk Kim * Licensed under the OpenSSL license (the "License"). You may not use 5*e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 6*e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at 7*e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html 850ef0093SJacques Vidrine */ 974664626SKris Kennaway 106f9291ceSJung-uk Kim /* 116f9291ceSJung-uk Kim * Special method for a BIO where the other endpoint is also a BIO of this 126f9291ceSJung-uk Kim * kind, handled by the same thread (i.e. the "peer" is actually ourselves, 136f9291ceSJung-uk Kim * wearing a different hat). Such "BIO pairs" are mainly for using the SSL 146f9291ceSJung-uk Kim * library with I/O interfaces for which no specific BIO method is available. 156f9291ceSJung-uk Kim * See ssl/ssltest.c for some hints on how this can be used. 166f9291ceSJung-uk Kim */ 1774664626SKris Kennaway 18*e71b7053SJung-uk Kim #include "e_os.h" 1974664626SKris Kennaway #include <assert.h> 20f579bf8eSKris Kennaway #include <limits.h> 2174664626SKris Kennaway #include <stdlib.h> 2274664626SKris Kennaway #include <string.h> 2374664626SKris Kennaway 24*e71b7053SJung-uk Kim #include "bio_lcl.h" 2574664626SKris Kennaway #include <openssl/err.h> 2674664626SKris Kennaway #include <openssl/crypto.h> 2774664626SKris Kennaway 2874664626SKris Kennaway static int bio_new(BIO *bio); 2974664626SKris Kennaway static int bio_free(BIO *bio); 3074664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size); 31ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num); 3274664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); 33ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str); 3474664626SKris Kennaway 3574664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2); 3674664626SKris Kennaway static void bio_destroy_pair(BIO *bio); 3774664626SKris Kennaway 38*e71b7053SJung-uk Kim static const BIO_METHOD methods_biop = { 3974664626SKris Kennaway BIO_TYPE_BIO, 4074664626SKris Kennaway "BIO pair", 41*e71b7053SJung-uk Kim /* TODO: Convert to new style write function */ 42*e71b7053SJung-uk Kim bwrite_conv, 4374664626SKris Kennaway bio_write, 44*e71b7053SJung-uk Kim /* TODO: Convert to new style read function */ 45*e71b7053SJung-uk Kim bread_conv, 4674664626SKris Kennaway bio_read, 4774664626SKris Kennaway bio_puts, 4874664626SKris Kennaway NULL /* no bio_gets */ , 4974664626SKris Kennaway bio_ctrl, 5074664626SKris Kennaway bio_new, 51f579bf8eSKris Kennaway bio_free, 52f579bf8eSKris Kennaway NULL /* no bio_callback_ctrl */ 5374664626SKris Kennaway }; 5474664626SKris Kennaway 55*e71b7053SJung-uk Kim const BIO_METHOD *BIO_s_bio(void) 5674664626SKris Kennaway { 5774664626SKris Kennaway return &methods_biop; 5874664626SKris Kennaway } 5974664626SKris Kennaway 606f9291ceSJung-uk Kim struct bio_bio_st { 616f9291ceSJung-uk Kim BIO *peer; /* NULL if buf == NULL. If peer != NULL, then 626f9291ceSJung-uk Kim * peer->ptr is also a bio_bio_st, and its 636f9291ceSJung-uk Kim * "peer" member points back to us. peer != 646f9291ceSJung-uk Kim * NULL iff init != 0 in the BIO. */ 6574664626SKris Kennaway /* This is for what we write (i.e. reading uses peer's struct): */ 6674664626SKris Kennaway int closed; /* valid iff peer != NULL */ 6774664626SKris Kennaway size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ 6874664626SKris Kennaway size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ 6974664626SKris Kennaway size_t size; 7074664626SKris Kennaway char *buf; /* "size" elements (if != NULL) */ 7174664626SKris Kennaway size_t request; /* valid iff peer != NULL; 0 if len != 0, 7274664626SKris Kennaway * otherwise set by peer to number of bytes 736f9291ceSJung-uk Kim * it (unsuccessfully) tried to read, never 746f9291ceSJung-uk Kim * more than buffer space (size-len) 756f9291ceSJung-uk Kim * warrants. */ 7674664626SKris Kennaway }; 7774664626SKris Kennaway 7874664626SKris Kennaway static int bio_new(BIO *bio) 7974664626SKris Kennaway { 80*e71b7053SJung-uk Kim struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b)); 8174664626SKris Kennaway 8274664626SKris Kennaway if (b == NULL) 8374664626SKris Kennaway return 0; 8474664626SKris Kennaway 856f9291ceSJung-uk Kim /* enough for one TLS record (just a default) */ 866f9291ceSJung-uk Kim b->size = 17 * 1024; 8774664626SKris Kennaway 8874664626SKris Kennaway bio->ptr = b; 8974664626SKris Kennaway return 1; 9074664626SKris Kennaway } 9174664626SKris Kennaway 9274664626SKris Kennaway static int bio_free(BIO *bio) 9374664626SKris Kennaway { 9474664626SKris Kennaway struct bio_bio_st *b; 9574664626SKris Kennaway 9674664626SKris Kennaway if (bio == NULL) 9774664626SKris Kennaway return 0; 9874664626SKris Kennaway b = bio->ptr; 9974664626SKris Kennaway 10074664626SKris Kennaway assert(b != NULL); 10174664626SKris Kennaway 10274664626SKris Kennaway if (b->peer) 10374664626SKris Kennaway bio_destroy_pair(bio); 10474664626SKris Kennaway 105ddd58736SKris Kennaway OPENSSL_free(b->buf); 106ddd58736SKris Kennaway OPENSSL_free(b); 10774664626SKris Kennaway 10874664626SKris Kennaway return 1; 10974664626SKris Kennaway } 11074664626SKris Kennaway 11174664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size_) 11274664626SKris Kennaway { 11374664626SKris Kennaway size_t size = size_; 11474664626SKris Kennaway size_t rest; 11574664626SKris Kennaway struct bio_bio_st *b, *peer_b; 11674664626SKris Kennaway 11774664626SKris Kennaway BIO_clear_retry_flags(bio); 11874664626SKris Kennaway 11974664626SKris Kennaway if (!bio->init) 12074664626SKris Kennaway return 0; 12174664626SKris Kennaway 12274664626SKris Kennaway b = bio->ptr; 12374664626SKris Kennaway assert(b != NULL); 12474664626SKris Kennaway assert(b->peer != NULL); 12574664626SKris Kennaway peer_b = b->peer->ptr; 12674664626SKris Kennaway assert(peer_b != NULL); 12774664626SKris Kennaway assert(peer_b->buf != NULL); 12874664626SKris Kennaway 12974664626SKris Kennaway peer_b->request = 0; /* will be set in "retry_read" situation */ 13074664626SKris Kennaway 13174664626SKris Kennaway if (buf == NULL || size == 0) 13274664626SKris Kennaway return 0; 13374664626SKris Kennaway 1346f9291ceSJung-uk Kim if (peer_b->len == 0) { 13574664626SKris Kennaway if (peer_b->closed) 13674664626SKris Kennaway return 0; /* writer has closed, and no data is left */ 1376f9291ceSJung-uk Kim else { 13874664626SKris Kennaway BIO_set_retry_read(bio); /* buffer is empty */ 13974664626SKris Kennaway if (size <= peer_b->size) 14074664626SKris Kennaway peer_b->request = size; 14174664626SKris Kennaway else 1426f9291ceSJung-uk Kim /* 1436f9291ceSJung-uk Kim * don't ask for more than the peer can deliver in one write 1446f9291ceSJung-uk Kim */ 14574664626SKris Kennaway peer_b->request = peer_b->size; 14674664626SKris Kennaway return -1; 14774664626SKris Kennaway } 14874664626SKris Kennaway } 14974664626SKris Kennaway 15074664626SKris Kennaway /* we can read */ 15174664626SKris Kennaway if (peer_b->len < size) 15274664626SKris Kennaway size = peer_b->len; 15374664626SKris Kennaway 15474664626SKris Kennaway /* now read "size" bytes */ 15574664626SKris Kennaway 15674664626SKris Kennaway rest = size; 15774664626SKris Kennaway 15874664626SKris Kennaway assert(rest > 0); 1596f9291ceSJung-uk Kim do { /* one or two iterations */ 16074664626SKris Kennaway size_t chunk; 16174664626SKris Kennaway 16274664626SKris Kennaway assert(rest <= peer_b->len); 16374664626SKris Kennaway if (peer_b->offset + rest <= peer_b->size) 16474664626SKris Kennaway chunk = rest; 16574664626SKris Kennaway else 16674664626SKris Kennaway /* wrap around ring buffer */ 16774664626SKris Kennaway chunk = peer_b->size - peer_b->offset; 16874664626SKris Kennaway assert(peer_b->offset + chunk <= peer_b->size); 16974664626SKris Kennaway 17074664626SKris Kennaway memcpy(buf, peer_b->buf + peer_b->offset, chunk); 17174664626SKris Kennaway 17274664626SKris Kennaway peer_b->len -= chunk; 1736f9291ceSJung-uk Kim if (peer_b->len) { 17474664626SKris Kennaway peer_b->offset += chunk; 17574664626SKris Kennaway assert(peer_b->offset <= peer_b->size); 17674664626SKris Kennaway if (peer_b->offset == peer_b->size) 17774664626SKris Kennaway peer_b->offset = 0; 17874664626SKris Kennaway buf += chunk; 1796f9291ceSJung-uk Kim } else { 18074664626SKris Kennaway /* buffer now empty, no need to advance "buf" */ 18174664626SKris Kennaway assert(chunk == rest); 18274664626SKris Kennaway peer_b->offset = 0; 18374664626SKris Kennaway } 18474664626SKris Kennaway rest -= chunk; 18574664626SKris Kennaway } 18674664626SKris Kennaway while (rest); 18774664626SKris Kennaway 18874664626SKris Kennaway return size; 18974664626SKris Kennaway } 19074664626SKris Kennaway 1916f9291ceSJung-uk Kim /*- 1926f9291ceSJung-uk Kim * non-copying interface: provide pointer to available data in buffer 193f579bf8eSKris Kennaway * bio_nread0: return number of available bytes 194f579bf8eSKris Kennaway * bio_nread: also advance index 195f579bf8eSKris Kennaway * (example usage: bio_nread0(), read from buffer, bio_nread() 196f579bf8eSKris Kennaway * or just bio_nread(), read from buffer) 197f579bf8eSKris Kennaway */ 1986f9291ceSJung-uk Kim /* 1996f9291ceSJung-uk Kim * WARNING: The non-copying interface is largely untested as of yet and may 2006f9291ceSJung-uk Kim * contain bugs. 2016f9291ceSJung-uk Kim */ 2021f13597dSJung-uk Kim static ossl_ssize_t bio_nread0(BIO *bio, char **buf) 203f579bf8eSKris Kennaway { 204f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b; 2051f13597dSJung-uk Kim ossl_ssize_t num; 206f579bf8eSKris Kennaway 207f579bf8eSKris Kennaway BIO_clear_retry_flags(bio); 208f579bf8eSKris Kennaway 209f579bf8eSKris Kennaway if (!bio->init) 210f579bf8eSKris Kennaway return 0; 211f579bf8eSKris Kennaway 212f579bf8eSKris Kennaway b = bio->ptr; 213f579bf8eSKris Kennaway assert(b != NULL); 214f579bf8eSKris Kennaway assert(b->peer != NULL); 215f579bf8eSKris Kennaway peer_b = b->peer->ptr; 216f579bf8eSKris Kennaway assert(peer_b != NULL); 217f579bf8eSKris Kennaway assert(peer_b->buf != NULL); 218f579bf8eSKris Kennaway 219f579bf8eSKris Kennaway peer_b->request = 0; 220f579bf8eSKris Kennaway 2216f9291ceSJung-uk Kim if (peer_b->len == 0) { 222f579bf8eSKris Kennaway char dummy; 223f579bf8eSKris Kennaway 224f579bf8eSKris Kennaway /* avoid code duplication -- nothing available for reading */ 225f579bf8eSKris Kennaway return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ 226f579bf8eSKris Kennaway } 227f579bf8eSKris Kennaway 228f579bf8eSKris Kennaway num = peer_b->len; 229f579bf8eSKris Kennaway if (peer_b->size < peer_b->offset + num) 230f579bf8eSKris Kennaway /* no ring buffer wrap-around for non-copying interface */ 231f579bf8eSKris Kennaway num = peer_b->size - peer_b->offset; 232f579bf8eSKris Kennaway assert(num > 0); 233f579bf8eSKris Kennaway 234f579bf8eSKris Kennaway if (buf != NULL) 235f579bf8eSKris Kennaway *buf = peer_b->buf + peer_b->offset; 236f579bf8eSKris Kennaway return num; 237f579bf8eSKris Kennaway } 238f579bf8eSKris Kennaway 2391f13597dSJung-uk Kim static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_) 240f579bf8eSKris Kennaway { 241f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b; 2421f13597dSJung-uk Kim ossl_ssize_t num, available; 243f579bf8eSKris Kennaway 244*e71b7053SJung-uk Kim if (num_ > OSSL_SSIZE_MAX) 245*e71b7053SJung-uk Kim num = OSSL_SSIZE_MAX; 246f579bf8eSKris Kennaway else 2471f13597dSJung-uk Kim num = (ossl_ssize_t) num_; 248f579bf8eSKris Kennaway 249f579bf8eSKris Kennaway available = bio_nread0(bio, buf); 250f579bf8eSKris Kennaway if (num > available) 251f579bf8eSKris Kennaway num = available; 252f579bf8eSKris Kennaway if (num <= 0) 253f579bf8eSKris Kennaway return num; 254f579bf8eSKris Kennaway 255f579bf8eSKris Kennaway b = bio->ptr; 256f579bf8eSKris Kennaway peer_b = b->peer->ptr; 257f579bf8eSKris Kennaway 258f579bf8eSKris Kennaway peer_b->len -= num; 2596f9291ceSJung-uk Kim if (peer_b->len) { 260f579bf8eSKris Kennaway peer_b->offset += num; 261f579bf8eSKris Kennaway assert(peer_b->offset <= peer_b->size); 262f579bf8eSKris Kennaway if (peer_b->offset == peer_b->size) 263f579bf8eSKris Kennaway peer_b->offset = 0; 2646f9291ceSJung-uk Kim } else 265f579bf8eSKris Kennaway peer_b->offset = 0; 266f579bf8eSKris Kennaway 267f579bf8eSKris Kennaway return num; 268f579bf8eSKris Kennaway } 269f579bf8eSKris Kennaway 270ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num_) 27174664626SKris Kennaway { 27274664626SKris Kennaway size_t num = num_; 27374664626SKris Kennaway size_t rest; 27474664626SKris Kennaway struct bio_bio_st *b; 27574664626SKris Kennaway 27674664626SKris Kennaway BIO_clear_retry_flags(bio); 27774664626SKris Kennaway 27874664626SKris Kennaway if (!bio->init || buf == NULL || num == 0) 27974664626SKris Kennaway return 0; 28074664626SKris Kennaway 28174664626SKris Kennaway b = bio->ptr; 28274664626SKris Kennaway assert(b != NULL); 28374664626SKris Kennaway assert(b->peer != NULL); 28474664626SKris Kennaway assert(b->buf != NULL); 28574664626SKris Kennaway 28674664626SKris Kennaway b->request = 0; 2876f9291ceSJung-uk Kim if (b->closed) { 28874664626SKris Kennaway /* we already closed */ 28974664626SKris Kennaway BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); 29074664626SKris Kennaway return -1; 29174664626SKris Kennaway } 29274664626SKris Kennaway 29374664626SKris Kennaway assert(b->len <= b->size); 29474664626SKris Kennaway 2956f9291ceSJung-uk Kim if (b->len == b->size) { 29674664626SKris Kennaway BIO_set_retry_write(bio); /* buffer is full */ 29774664626SKris Kennaway return -1; 29874664626SKris Kennaway } 29974664626SKris Kennaway 30074664626SKris Kennaway /* we can write */ 30174664626SKris Kennaway if (num > b->size - b->len) 30274664626SKris Kennaway num = b->size - b->len; 30374664626SKris Kennaway 30474664626SKris Kennaway /* now write "num" bytes */ 30574664626SKris Kennaway 30674664626SKris Kennaway rest = num; 30774664626SKris Kennaway 30874664626SKris Kennaway assert(rest > 0); 3096f9291ceSJung-uk Kim do { /* one or two iterations */ 31074664626SKris Kennaway size_t write_offset; 31174664626SKris Kennaway size_t chunk; 31274664626SKris Kennaway 31374664626SKris Kennaway assert(b->len + rest <= b->size); 31474664626SKris Kennaway 31574664626SKris Kennaway write_offset = b->offset + b->len; 31674664626SKris Kennaway if (write_offset >= b->size) 31774664626SKris Kennaway write_offset -= b->size; 31874664626SKris Kennaway /* b->buf[write_offset] is the first byte we can write to. */ 31974664626SKris Kennaway 32074664626SKris Kennaway if (write_offset + rest <= b->size) 32174664626SKris Kennaway chunk = rest; 32274664626SKris Kennaway else 32374664626SKris Kennaway /* wrap around ring buffer */ 32474664626SKris Kennaway chunk = b->size - write_offset; 32574664626SKris Kennaway 32674664626SKris Kennaway memcpy(b->buf + write_offset, buf, chunk); 32774664626SKris Kennaway 32874664626SKris Kennaway b->len += chunk; 32974664626SKris Kennaway 33074664626SKris Kennaway assert(b->len <= b->size); 33174664626SKris Kennaway 33274664626SKris Kennaway rest -= chunk; 33374664626SKris Kennaway buf += chunk; 33474664626SKris Kennaway } 33574664626SKris Kennaway while (rest); 33674664626SKris Kennaway 33774664626SKris Kennaway return num; 33874664626SKris Kennaway } 33974664626SKris Kennaway 3406f9291ceSJung-uk Kim /*- 3416f9291ceSJung-uk Kim * non-copying interface: provide pointer to region to write to 342f579bf8eSKris Kennaway * bio_nwrite0: check how much space is available 343f579bf8eSKris Kennaway * bio_nwrite: also increase length 344f579bf8eSKris Kennaway * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() 345f579bf8eSKris Kennaway * or just bio_nwrite(), write to buffer) 346f579bf8eSKris Kennaway */ 3471f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf) 348f579bf8eSKris Kennaway { 349f579bf8eSKris Kennaway struct bio_bio_st *b; 350f579bf8eSKris Kennaway size_t num; 351f579bf8eSKris Kennaway size_t write_offset; 352f579bf8eSKris Kennaway 353f579bf8eSKris Kennaway BIO_clear_retry_flags(bio); 354f579bf8eSKris Kennaway 355f579bf8eSKris Kennaway if (!bio->init) 356f579bf8eSKris Kennaway return 0; 357f579bf8eSKris Kennaway 358f579bf8eSKris Kennaway b = bio->ptr; 359f579bf8eSKris Kennaway assert(b != NULL); 360f579bf8eSKris Kennaway assert(b->peer != NULL); 361f579bf8eSKris Kennaway assert(b->buf != NULL); 362f579bf8eSKris Kennaway 363f579bf8eSKris Kennaway b->request = 0; 3646f9291ceSJung-uk Kim if (b->closed) { 365f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); 366f579bf8eSKris Kennaway return -1; 367f579bf8eSKris Kennaway } 368f579bf8eSKris Kennaway 369f579bf8eSKris Kennaway assert(b->len <= b->size); 370f579bf8eSKris Kennaway 3716f9291ceSJung-uk Kim if (b->len == b->size) { 372f579bf8eSKris Kennaway BIO_set_retry_write(bio); 373f579bf8eSKris Kennaway return -1; 374f579bf8eSKris Kennaway } 375f579bf8eSKris Kennaway 376f579bf8eSKris Kennaway num = b->size - b->len; 377f579bf8eSKris Kennaway write_offset = b->offset + b->len; 378f579bf8eSKris Kennaway if (write_offset >= b->size) 379f579bf8eSKris Kennaway write_offset -= b->size; 380f579bf8eSKris Kennaway if (write_offset + num > b->size) 3816f9291ceSJung-uk Kim /* 3826f9291ceSJung-uk Kim * no ring buffer wrap-around for non-copying interface (to fulfil 3836f9291ceSJung-uk Kim * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have 3846f9291ceSJung-uk Kim * to be called twice) 3856f9291ceSJung-uk Kim */ 386f579bf8eSKris Kennaway num = b->size - write_offset; 387f579bf8eSKris Kennaway 388f579bf8eSKris Kennaway if (buf != NULL) 389f579bf8eSKris Kennaway *buf = b->buf + write_offset; 390f579bf8eSKris Kennaway assert(write_offset + num <= b->size); 391f579bf8eSKris Kennaway 392f579bf8eSKris Kennaway return num; 393f579bf8eSKris Kennaway } 394f579bf8eSKris Kennaway 3951f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_) 396f579bf8eSKris Kennaway { 397f579bf8eSKris Kennaway struct bio_bio_st *b; 3981f13597dSJung-uk Kim ossl_ssize_t num, space; 399f579bf8eSKris Kennaway 400*e71b7053SJung-uk Kim if (num_ > OSSL_SSIZE_MAX) 401*e71b7053SJung-uk Kim num = OSSL_SSIZE_MAX; 402f579bf8eSKris Kennaway else 4031f13597dSJung-uk Kim num = (ossl_ssize_t) num_; 404f579bf8eSKris Kennaway 405f579bf8eSKris Kennaway space = bio_nwrite0(bio, buf); 406f579bf8eSKris Kennaway if (num > space) 407f579bf8eSKris Kennaway num = space; 408f579bf8eSKris Kennaway if (num <= 0) 409f579bf8eSKris Kennaway return num; 410f579bf8eSKris Kennaway b = bio->ptr; 411f579bf8eSKris Kennaway assert(b != NULL); 412f579bf8eSKris Kennaway b->len += num; 413f579bf8eSKris Kennaway assert(b->len <= b->size); 414f579bf8eSKris Kennaway 415f579bf8eSKris Kennaway return num; 416f579bf8eSKris Kennaway } 417f579bf8eSKris Kennaway 41874664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) 41974664626SKris Kennaway { 42074664626SKris Kennaway long ret; 42174664626SKris Kennaway struct bio_bio_st *b = bio->ptr; 42274664626SKris Kennaway 42374664626SKris Kennaway assert(b != NULL); 42474664626SKris Kennaway 4256f9291ceSJung-uk Kim switch (cmd) { 42674664626SKris Kennaway /* specific CTRL codes */ 42774664626SKris Kennaway 42874664626SKris Kennaway case BIO_C_SET_WRITE_BUF_SIZE: 4296f9291ceSJung-uk Kim if (b->peer) { 43074664626SKris Kennaway BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); 43174664626SKris Kennaway ret = 0; 4326f9291ceSJung-uk Kim } else if (num == 0) { 43374664626SKris Kennaway BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT); 43474664626SKris Kennaway ret = 0; 4356f9291ceSJung-uk Kim } else { 43674664626SKris Kennaway size_t new_size = num; 43774664626SKris Kennaway 4386f9291ceSJung-uk Kim if (b->size != new_size) { 439ddd58736SKris Kennaway OPENSSL_free(b->buf); 44074664626SKris Kennaway b->buf = NULL; 44174664626SKris Kennaway b->size = new_size; 44274664626SKris Kennaway } 44374664626SKris Kennaway ret = 1; 44474664626SKris Kennaway } 44574664626SKris Kennaway break; 44674664626SKris Kennaway 44774664626SKris Kennaway case BIO_C_GET_WRITE_BUF_SIZE: 448a21b1b38SKris Kennaway ret = (long)b->size; 449a21b1b38SKris Kennaway break; 45074664626SKris Kennaway 45174664626SKris Kennaway case BIO_C_MAKE_BIO_PAIR: 45274664626SKris Kennaway { 45374664626SKris Kennaway BIO *other_bio = ptr; 45474664626SKris Kennaway 45574664626SKris Kennaway if (bio_make_pair(bio, other_bio)) 45674664626SKris Kennaway ret = 1; 45774664626SKris Kennaway else 45874664626SKris Kennaway ret = 0; 45974664626SKris Kennaway } 46074664626SKris Kennaway break; 46174664626SKris Kennaway 46274664626SKris Kennaway case BIO_C_DESTROY_BIO_PAIR: 4636f9291ceSJung-uk Kim /* 4646f9291ceSJung-uk Kim * Affects both BIOs in the pair -- call just once! Or let 4656f9291ceSJung-uk Kim * BIO_free(bio1); BIO_free(bio2); do the job. 4666f9291ceSJung-uk Kim */ 46774664626SKris Kennaway bio_destroy_pair(bio); 46874664626SKris Kennaway ret = 1; 46974664626SKris Kennaway break; 47074664626SKris Kennaway 47174664626SKris Kennaway case BIO_C_GET_WRITE_GUARANTEE: 4726f9291ceSJung-uk Kim /* 4736f9291ceSJung-uk Kim * How many bytes can the caller feed to the next write without 4746f9291ceSJung-uk Kim * having to keep any? 4756f9291ceSJung-uk Kim */ 47674664626SKris Kennaway if (b->peer == NULL || b->closed) 47774664626SKris Kennaway ret = 0; 47874664626SKris Kennaway else 47974664626SKris Kennaway ret = (long)b->size - b->len; 48074664626SKris Kennaway break; 48174664626SKris Kennaway 48274664626SKris Kennaway case BIO_C_GET_READ_REQUEST: 4836f9291ceSJung-uk Kim /* 4846f9291ceSJung-uk Kim * If the peer unsuccessfully tried to read, how many bytes were 4856f9291ceSJung-uk Kim * requested? (As with BIO_CTRL_PENDING, that number can usually be 4866f9291ceSJung-uk Kim * treated as boolean.) 4876f9291ceSJung-uk Kim */ 48874664626SKris Kennaway ret = (long)b->request; 48974664626SKris Kennaway break; 49074664626SKris Kennaway 491f579bf8eSKris Kennaway case BIO_C_RESET_READ_REQUEST: 4926f9291ceSJung-uk Kim /* 4936f9291ceSJung-uk Kim * Reset request. (Can be useful after read attempts at the other 4946f9291ceSJung-uk Kim * side that are meant to be non-blocking, e.g. when probing SSL_read 4956f9291ceSJung-uk Kim * to see if any data is available.) 4966f9291ceSJung-uk Kim */ 497f579bf8eSKris Kennaway b->request = 0; 498f579bf8eSKris Kennaway ret = 1; 499f579bf8eSKris Kennaway break; 500f579bf8eSKris Kennaway 50174664626SKris Kennaway case BIO_C_SHUTDOWN_WR: 50274664626SKris Kennaway /* similar to shutdown(..., SHUT_WR) */ 50374664626SKris Kennaway b->closed = 1; 50474664626SKris Kennaway ret = 1; 50574664626SKris Kennaway break; 50674664626SKris Kennaway 507f579bf8eSKris Kennaway case BIO_C_NREAD0: 508f579bf8eSKris Kennaway /* prepare for non-copying read */ 509f579bf8eSKris Kennaway ret = (long)bio_nread0(bio, ptr); 510f579bf8eSKris Kennaway break; 511f579bf8eSKris Kennaway 512f579bf8eSKris Kennaway case BIO_C_NREAD: 513f579bf8eSKris Kennaway /* non-copying read */ 514f579bf8eSKris Kennaway ret = (long)bio_nread(bio, ptr, (size_t)num); 515f579bf8eSKris Kennaway break; 516f579bf8eSKris Kennaway 517f579bf8eSKris Kennaway case BIO_C_NWRITE0: 518f579bf8eSKris Kennaway /* prepare for non-copying write */ 519f579bf8eSKris Kennaway ret = (long)bio_nwrite0(bio, ptr); 520f579bf8eSKris Kennaway break; 521f579bf8eSKris Kennaway 522f579bf8eSKris Kennaway case BIO_C_NWRITE: 523f579bf8eSKris Kennaway /* non-copying write */ 524f579bf8eSKris Kennaway ret = (long)bio_nwrite(bio, ptr, (size_t)num); 525f579bf8eSKris Kennaway break; 526f579bf8eSKris Kennaway 52774664626SKris Kennaway /* standard CTRL codes follow */ 52874664626SKris Kennaway 52974664626SKris Kennaway case BIO_CTRL_RESET: 5306f9291ceSJung-uk Kim if (b->buf != NULL) { 53174664626SKris Kennaway b->len = 0; 53274664626SKris Kennaway b->offset = 0; 53374664626SKris Kennaway } 53474664626SKris Kennaway ret = 0; 53574664626SKris Kennaway break; 53674664626SKris Kennaway 53774664626SKris Kennaway case BIO_CTRL_GET_CLOSE: 53874664626SKris Kennaway ret = bio->shutdown; 53974664626SKris Kennaway break; 54074664626SKris Kennaway 54174664626SKris Kennaway case BIO_CTRL_SET_CLOSE: 54274664626SKris Kennaway bio->shutdown = (int)num; 54374664626SKris Kennaway ret = 1; 54474664626SKris Kennaway break; 54574664626SKris Kennaway 54674664626SKris Kennaway case BIO_CTRL_PENDING: 5476f9291ceSJung-uk Kim if (b->peer != NULL) { 54874664626SKris Kennaway struct bio_bio_st *peer_b = b->peer->ptr; 54974664626SKris Kennaway 55074664626SKris Kennaway ret = (long)peer_b->len; 5516f9291ceSJung-uk Kim } else 55274664626SKris Kennaway ret = 0; 55374664626SKris Kennaway break; 55474664626SKris Kennaway 55574664626SKris Kennaway case BIO_CTRL_WPENDING: 55674664626SKris Kennaway if (b->buf != NULL) 55774664626SKris Kennaway ret = (long)b->len; 55874664626SKris Kennaway else 55974664626SKris Kennaway ret = 0; 56074664626SKris Kennaway break; 56174664626SKris Kennaway 56274664626SKris Kennaway case BIO_CTRL_DUP: 56374664626SKris Kennaway /* See BIO_dup_chain for circumstances we have to expect. */ 56474664626SKris Kennaway { 56574664626SKris Kennaway BIO *other_bio = ptr; 56674664626SKris Kennaway struct bio_bio_st *other_b; 56774664626SKris Kennaway 56874664626SKris Kennaway assert(other_bio != NULL); 56974664626SKris Kennaway other_b = other_bio->ptr; 57074664626SKris Kennaway assert(other_b != NULL); 57174664626SKris Kennaway 57274664626SKris Kennaway assert(other_b->buf == NULL); /* other_bio is always fresh */ 57374664626SKris Kennaway 57474664626SKris Kennaway other_b->size = b->size; 57574664626SKris Kennaway } 57674664626SKris Kennaway 57774664626SKris Kennaway ret = 1; 57874664626SKris Kennaway break; 57974664626SKris Kennaway 58074664626SKris Kennaway case BIO_CTRL_FLUSH: 58174664626SKris Kennaway ret = 1; 58274664626SKris Kennaway break; 58374664626SKris Kennaway 58474664626SKris Kennaway case BIO_CTRL_EOF: 585aeb5019cSJung-uk Kim if (b->peer != NULL) { 586aeb5019cSJung-uk Kim struct bio_bio_st *peer_b = b->peer->ptr; 58774664626SKris Kennaway 588aeb5019cSJung-uk Kim if (peer_b->len == 0 && peer_b->closed) 589aeb5019cSJung-uk Kim ret = 1; 590aeb5019cSJung-uk Kim else 591aeb5019cSJung-uk Kim ret = 0; 592aeb5019cSJung-uk Kim } else { 59374664626SKris Kennaway ret = 1; 59474664626SKris Kennaway } 59574664626SKris Kennaway break; 59674664626SKris Kennaway 59774664626SKris Kennaway default: 59874664626SKris Kennaway ret = 0; 59974664626SKris Kennaway } 60074664626SKris Kennaway return ret; 60174664626SKris Kennaway } 60274664626SKris Kennaway 603ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str) 60474664626SKris Kennaway { 60574664626SKris Kennaway return bio_write(bio, str, strlen(str)); 60674664626SKris Kennaway } 60774664626SKris Kennaway 60874664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2) 60974664626SKris Kennaway { 61074664626SKris Kennaway struct bio_bio_st *b1, *b2; 61174664626SKris Kennaway 61274664626SKris Kennaway assert(bio1 != NULL); 61374664626SKris Kennaway assert(bio2 != NULL); 61474664626SKris Kennaway 61574664626SKris Kennaway b1 = bio1->ptr; 61674664626SKris Kennaway b2 = bio2->ptr; 61774664626SKris Kennaway 6186f9291ceSJung-uk Kim if (b1->peer != NULL || b2->peer != NULL) { 61974664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE); 62074664626SKris Kennaway return 0; 62174664626SKris Kennaway } 62274664626SKris Kennaway 6236f9291ceSJung-uk Kim if (b1->buf == NULL) { 624ddd58736SKris Kennaway b1->buf = OPENSSL_malloc(b1->size); 6256f9291ceSJung-uk Kim if (b1->buf == NULL) { 62674664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); 62774664626SKris Kennaway return 0; 62874664626SKris Kennaway } 62974664626SKris Kennaway b1->len = 0; 63074664626SKris Kennaway b1->offset = 0; 63174664626SKris Kennaway } 63274664626SKris Kennaway 6336f9291ceSJung-uk Kim if (b2->buf == NULL) { 634ddd58736SKris Kennaway b2->buf = OPENSSL_malloc(b2->size); 6356f9291ceSJung-uk Kim if (b2->buf == NULL) { 63674664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); 63774664626SKris Kennaway return 0; 63874664626SKris Kennaway } 63974664626SKris Kennaway b2->len = 0; 64074664626SKris Kennaway b2->offset = 0; 64174664626SKris Kennaway } 64274664626SKris Kennaway 64374664626SKris Kennaway b1->peer = bio2; 64474664626SKris Kennaway b1->closed = 0; 64574664626SKris Kennaway b1->request = 0; 64674664626SKris Kennaway b2->peer = bio1; 64774664626SKris Kennaway b2->closed = 0; 64874664626SKris Kennaway b2->request = 0; 64974664626SKris Kennaway 65074664626SKris Kennaway bio1->init = 1; 65174664626SKris Kennaway bio2->init = 1; 65274664626SKris Kennaway 65374664626SKris Kennaway return 1; 65474664626SKris Kennaway } 65574664626SKris Kennaway 65674664626SKris Kennaway static void bio_destroy_pair(BIO *bio) 65774664626SKris Kennaway { 65874664626SKris Kennaway struct bio_bio_st *b = bio->ptr; 65974664626SKris Kennaway 6606f9291ceSJung-uk Kim if (b != NULL) { 66174664626SKris Kennaway BIO *peer_bio = b->peer; 66274664626SKris Kennaway 6636f9291ceSJung-uk Kim if (peer_bio != NULL) { 66474664626SKris Kennaway struct bio_bio_st *peer_b = peer_bio->ptr; 66574664626SKris Kennaway 66674664626SKris Kennaway assert(peer_b != NULL); 66774664626SKris Kennaway assert(peer_b->peer == bio); 66874664626SKris Kennaway 66974664626SKris Kennaway peer_b->peer = NULL; 67074664626SKris Kennaway peer_bio->init = 0; 67174664626SKris Kennaway assert(peer_b->buf != NULL); 67274664626SKris Kennaway peer_b->len = 0; 67374664626SKris Kennaway peer_b->offset = 0; 67474664626SKris Kennaway 67574664626SKris Kennaway b->peer = NULL; 67674664626SKris Kennaway bio->init = 0; 67774664626SKris Kennaway assert(b->buf != NULL); 67874664626SKris Kennaway b->len = 0; 67974664626SKris Kennaway b->offset = 0; 68074664626SKris Kennaway } 68174664626SKris Kennaway } 68274664626SKris Kennaway } 68374664626SKris Kennaway 68474664626SKris Kennaway /* Exported convenience functions */ 68574664626SKris Kennaway int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, 68674664626SKris Kennaway BIO **bio2_p, size_t writebuf2) 68774664626SKris Kennaway { 68874664626SKris Kennaway BIO *bio1 = NULL, *bio2 = NULL; 68974664626SKris Kennaway long r; 69074664626SKris Kennaway int ret = 0; 69174664626SKris Kennaway 69274664626SKris Kennaway bio1 = BIO_new(BIO_s_bio()); 69374664626SKris Kennaway if (bio1 == NULL) 69474664626SKris Kennaway goto err; 69574664626SKris Kennaway bio2 = BIO_new(BIO_s_bio()); 69674664626SKris Kennaway if (bio2 == NULL) 69774664626SKris Kennaway goto err; 69874664626SKris Kennaway 6996f9291ceSJung-uk Kim if (writebuf1) { 70074664626SKris Kennaway r = BIO_set_write_buf_size(bio1, writebuf1); 70174664626SKris Kennaway if (!r) 70274664626SKris Kennaway goto err; 70374664626SKris Kennaway } 7046f9291ceSJung-uk Kim if (writebuf2) { 70574664626SKris Kennaway r = BIO_set_write_buf_size(bio2, writebuf2); 70674664626SKris Kennaway if (!r) 70774664626SKris Kennaway goto err; 70874664626SKris Kennaway } 70974664626SKris Kennaway 71074664626SKris Kennaway r = BIO_make_bio_pair(bio1, bio2); 71174664626SKris Kennaway if (!r) 71274664626SKris Kennaway goto err; 71374664626SKris Kennaway ret = 1; 71474664626SKris Kennaway 71574664626SKris Kennaway err: 7166f9291ceSJung-uk Kim if (ret == 0) { 71774664626SKris Kennaway BIO_free(bio1); 71874664626SKris Kennaway bio1 = NULL; 71974664626SKris Kennaway BIO_free(bio2); 72074664626SKris Kennaway bio2 = NULL; 72174664626SKris Kennaway } 72274664626SKris Kennaway 72374664626SKris Kennaway *bio1_p = bio1; 72474664626SKris Kennaway *bio2_p = bio2; 72574664626SKris Kennaway return ret; 72674664626SKris Kennaway } 72774664626SKris Kennaway 72874664626SKris Kennaway size_t BIO_ctrl_get_write_guarantee(BIO *bio) 72974664626SKris Kennaway { 73074664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); 73174664626SKris Kennaway } 73274664626SKris Kennaway 73374664626SKris Kennaway size_t BIO_ctrl_get_read_request(BIO *bio) 73474664626SKris Kennaway { 73574664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); 73674664626SKris Kennaway } 737f579bf8eSKris Kennaway 738f579bf8eSKris Kennaway int BIO_ctrl_reset_read_request(BIO *bio) 739f579bf8eSKris Kennaway { 740f579bf8eSKris Kennaway return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); 741f579bf8eSKris Kennaway } 742f579bf8eSKris Kennaway 7436f9291ceSJung-uk Kim /* 7446f9291ceSJung-uk Kim * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now 7456f9291ceSJung-uk Kim * (conceivably some other BIOs could allow non-copying reads and writes 7466f9291ceSJung-uk Kim * too.) 747f579bf8eSKris Kennaway */ 748f579bf8eSKris Kennaway int BIO_nread0(BIO *bio, char **buf) 749f579bf8eSKris Kennaway { 750f579bf8eSKris Kennaway long ret; 751f579bf8eSKris Kennaway 7526f9291ceSJung-uk Kim if (!bio->init) { 753f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); 754f579bf8eSKris Kennaway return -2; 755f579bf8eSKris Kennaway } 756f579bf8eSKris Kennaway 757f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); 758f579bf8eSKris Kennaway if (ret > INT_MAX) 759f579bf8eSKris Kennaway return INT_MAX; 760f579bf8eSKris Kennaway else 761f579bf8eSKris Kennaway return (int)ret; 762f579bf8eSKris Kennaway } 763f579bf8eSKris Kennaway 764f579bf8eSKris Kennaway int BIO_nread(BIO *bio, char **buf, int num) 765f579bf8eSKris Kennaway { 766f579bf8eSKris Kennaway int ret; 767f579bf8eSKris Kennaway 7686f9291ceSJung-uk Kim if (!bio->init) { 769f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); 770f579bf8eSKris Kennaway return -2; 771f579bf8eSKris Kennaway } 772f579bf8eSKris Kennaway 773f579bf8eSKris Kennaway ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf); 774f579bf8eSKris Kennaway if (ret > 0) 775f579bf8eSKris Kennaway bio->num_read += ret; 776f579bf8eSKris Kennaway return ret; 777f579bf8eSKris Kennaway } 778f579bf8eSKris Kennaway 779f579bf8eSKris Kennaway int BIO_nwrite0(BIO *bio, char **buf) 780f579bf8eSKris Kennaway { 781f579bf8eSKris Kennaway long ret; 782f579bf8eSKris Kennaway 7836f9291ceSJung-uk Kim if (!bio->init) { 784f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); 785f579bf8eSKris Kennaway return -2; 786f579bf8eSKris Kennaway } 787f579bf8eSKris Kennaway 788f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); 789f579bf8eSKris Kennaway if (ret > INT_MAX) 790f579bf8eSKris Kennaway return INT_MAX; 791f579bf8eSKris Kennaway else 792f579bf8eSKris Kennaway return (int)ret; 793f579bf8eSKris Kennaway } 794f579bf8eSKris Kennaway 795f579bf8eSKris Kennaway int BIO_nwrite(BIO *bio, char **buf, int num) 796f579bf8eSKris Kennaway { 797f579bf8eSKris Kennaway int ret; 798f579bf8eSKris Kennaway 7996f9291ceSJung-uk Kim if (!bio->init) { 800f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); 801f579bf8eSKris Kennaway return -2; 802f579bf8eSKris Kennaway } 803f579bf8eSKris Kennaway 804f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); 805f579bf8eSKris Kennaway if (ret > 0) 806db522d3aSSimon L. B. Nielsen bio->num_write += ret; 807f579bf8eSKris Kennaway return ret; 808f579bf8eSKris Kennaway } 809