174664626SKris Kennaway /* crypto/bio/bss_bio.c -*- Mode: C; c-file-style: "eay" -*- */ 274664626SKris Kennaway 374664626SKris Kennaway /* Special method for a BIO where the other endpoint is also a BIO 474664626SKris Kennaway * of this kind, handled by the same thread (i.e. the "peer" is actually 574664626SKris Kennaway * ourselves, wearing a different hat). 674664626SKris Kennaway * Such "BIO pairs" are mainly for using the SSL library with I/O interfaces 774664626SKris Kennaway * for which no specific BIO method is available. 874664626SKris Kennaway * See ssl/ssltest.c for some hints on how this can be used. */ 974664626SKris Kennaway 1074664626SKris Kennaway #ifndef BIO_PAIR_DEBUG 1174664626SKris Kennaway # undef NDEBUG /* avoid conflicting definitions */ 1274664626SKris Kennaway # define NDEBUG 1374664626SKris Kennaway #endif 1474664626SKris Kennaway 1574664626SKris Kennaway #include <assert.h> 16f579bf8eSKris Kennaway #include <limits.h> 1774664626SKris Kennaway #include <stdlib.h> 1874664626SKris Kennaway #include <string.h> 1974664626SKris Kennaway 2074664626SKris Kennaway #include <openssl/bio.h> 2174664626SKris Kennaway #include <openssl/err.h> 22f579bf8eSKris Kennaway #include <openssl/err.h> 2374664626SKris Kennaway #include <openssl/crypto.h> 2474664626SKris Kennaway 25f579bf8eSKris Kennaway #include "openssl/e_os.h" 26f579bf8eSKris Kennaway #ifndef SSIZE_MAX 27f579bf8eSKris Kennaway # define SSIZE_MAX INT_MAX 28f579bf8eSKris Kennaway #endif 29f579bf8eSKris Kennaway 3074664626SKris Kennaway static int bio_new(BIO *bio); 3174664626SKris Kennaway static int bio_free(BIO *bio); 3274664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size); 33ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num); 3474664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); 35ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str); 3674664626SKris Kennaway 3774664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2); 3874664626SKris Kennaway static void bio_destroy_pair(BIO *bio); 3974664626SKris Kennaway 4074664626SKris Kennaway static BIO_METHOD methods_biop = 4174664626SKris Kennaway { 4274664626SKris Kennaway BIO_TYPE_BIO, 4374664626SKris Kennaway "BIO pair", 4474664626SKris Kennaway bio_write, 4574664626SKris Kennaway bio_read, 4674664626SKris Kennaway bio_puts, 4774664626SKris Kennaway NULL /* no bio_gets */, 4874664626SKris Kennaway bio_ctrl, 4974664626SKris Kennaway bio_new, 50f579bf8eSKris Kennaway bio_free, 51f579bf8eSKris Kennaway NULL /* no bio_callback_ctrl */ 5274664626SKris Kennaway }; 5374664626SKris Kennaway 5474664626SKris Kennaway BIO_METHOD *BIO_s_bio(void) 5574664626SKris Kennaway { 5674664626SKris Kennaway return &methods_biop; 5774664626SKris Kennaway } 5874664626SKris Kennaway 5974664626SKris Kennaway struct bio_bio_st 6074664626SKris Kennaway { 6174664626SKris Kennaway BIO *peer; /* NULL if buf == NULL. 6274664626SKris Kennaway * If peer != NULL, then peer->ptr is also a bio_bio_st, 6374664626SKris Kennaway * and its "peer" member points back to us. 6474664626SKris Kennaway * peer != NULL iff init != 0 in the BIO. */ 6574664626SKris Kennaway 6674664626SKris Kennaway /* This is for what we write (i.e. reading uses peer's struct): */ 6774664626SKris Kennaway int closed; /* valid iff peer != NULL */ 6874664626SKris Kennaway size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ 6974664626SKris Kennaway size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ 7074664626SKris Kennaway size_t size; 7174664626SKris Kennaway char *buf; /* "size" elements (if != NULL) */ 7274664626SKris Kennaway 7374664626SKris Kennaway size_t request; /* valid iff peer != NULL; 0 if len != 0, 7474664626SKris Kennaway * otherwise set by peer to number of bytes 75f579bf8eSKris Kennaway * it (unsuccessfully) tried to read, 7674664626SKris Kennaway * never more than buffer space (size-len) warrants. */ 7774664626SKris Kennaway }; 7874664626SKris Kennaway 7974664626SKris Kennaway static int bio_new(BIO *bio) 8074664626SKris Kennaway { 8174664626SKris Kennaway struct bio_bio_st *b; 8274664626SKris Kennaway 83ddd58736SKris Kennaway b = OPENSSL_malloc(sizeof *b); 8474664626SKris Kennaway if (b == NULL) 8574664626SKris Kennaway return 0; 8674664626SKris Kennaway 8774664626SKris Kennaway b->peer = NULL; 8874664626SKris Kennaway b->size = 17*1024; /* enough for one TLS record (just a default) */ 8974664626SKris Kennaway b->buf = NULL; 9074664626SKris Kennaway 9174664626SKris Kennaway bio->ptr = b; 9274664626SKris Kennaway return 1; 9374664626SKris Kennaway } 9474664626SKris Kennaway 9574664626SKris Kennaway 9674664626SKris Kennaway static int bio_free(BIO *bio) 9774664626SKris Kennaway { 9874664626SKris Kennaway struct bio_bio_st *b; 9974664626SKris Kennaway 10074664626SKris Kennaway if (bio == NULL) 10174664626SKris Kennaway return 0; 10274664626SKris Kennaway b = bio->ptr; 10374664626SKris Kennaway 10474664626SKris Kennaway assert(b != NULL); 10574664626SKris Kennaway 10674664626SKris Kennaway if (b->peer) 10774664626SKris Kennaway bio_destroy_pair(bio); 10874664626SKris Kennaway 10974664626SKris Kennaway if (b->buf != NULL) 11074664626SKris Kennaway { 111ddd58736SKris Kennaway OPENSSL_free(b->buf); 11274664626SKris Kennaway } 11374664626SKris Kennaway 114ddd58736SKris Kennaway OPENSSL_free(b); 11574664626SKris Kennaway 11674664626SKris Kennaway return 1; 11774664626SKris Kennaway } 11874664626SKris Kennaway 11974664626SKris Kennaway 12074664626SKris Kennaway 12174664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size_) 12274664626SKris Kennaway { 12374664626SKris Kennaway size_t size = size_; 12474664626SKris Kennaway size_t rest; 12574664626SKris Kennaway struct bio_bio_st *b, *peer_b; 12674664626SKris Kennaway 12774664626SKris Kennaway BIO_clear_retry_flags(bio); 12874664626SKris Kennaway 12974664626SKris Kennaway if (!bio->init) 13074664626SKris Kennaway return 0; 13174664626SKris Kennaway 13274664626SKris Kennaway b = bio->ptr; 13374664626SKris Kennaway assert(b != NULL); 13474664626SKris Kennaway assert(b->peer != NULL); 13574664626SKris Kennaway peer_b = b->peer->ptr; 13674664626SKris Kennaway assert(peer_b != NULL); 13774664626SKris Kennaway assert(peer_b->buf != NULL); 13874664626SKris Kennaway 13974664626SKris Kennaway peer_b->request = 0; /* will be set in "retry_read" situation */ 14074664626SKris Kennaway 14174664626SKris Kennaway if (buf == NULL || size == 0) 14274664626SKris Kennaway return 0; 14374664626SKris Kennaway 14474664626SKris Kennaway if (peer_b->len == 0) 14574664626SKris Kennaway { 14674664626SKris Kennaway if (peer_b->closed) 14774664626SKris Kennaway return 0; /* writer has closed, and no data is left */ 14874664626SKris Kennaway else 14974664626SKris Kennaway { 15074664626SKris Kennaway BIO_set_retry_read(bio); /* buffer is empty */ 15174664626SKris Kennaway if (size <= peer_b->size) 15274664626SKris Kennaway peer_b->request = size; 15374664626SKris Kennaway else 15474664626SKris Kennaway /* don't ask for more than the peer can 15574664626SKris Kennaway * deliver in one write */ 15674664626SKris Kennaway peer_b->request = peer_b->size; 15774664626SKris Kennaway return -1; 15874664626SKris Kennaway } 15974664626SKris Kennaway } 16074664626SKris Kennaway 16174664626SKris Kennaway /* we can read */ 16274664626SKris Kennaway if (peer_b->len < size) 16374664626SKris Kennaway size = peer_b->len; 16474664626SKris Kennaway 16574664626SKris Kennaway /* now read "size" bytes */ 16674664626SKris Kennaway 16774664626SKris Kennaway rest = size; 16874664626SKris Kennaway 16974664626SKris Kennaway assert(rest > 0); 17074664626SKris Kennaway do /* one or two iterations */ 17174664626SKris Kennaway { 17274664626SKris Kennaway size_t chunk; 17374664626SKris Kennaway 17474664626SKris Kennaway assert(rest <= peer_b->len); 17574664626SKris Kennaway if (peer_b->offset + rest <= peer_b->size) 17674664626SKris Kennaway chunk = rest; 17774664626SKris Kennaway else 17874664626SKris Kennaway /* wrap around ring buffer */ 17974664626SKris Kennaway chunk = peer_b->size - peer_b->offset; 18074664626SKris Kennaway assert(peer_b->offset + chunk <= peer_b->size); 18174664626SKris Kennaway 18274664626SKris Kennaway memcpy(buf, peer_b->buf + peer_b->offset, chunk); 18374664626SKris Kennaway 18474664626SKris Kennaway peer_b->len -= chunk; 18574664626SKris Kennaway if (peer_b->len) 18674664626SKris Kennaway { 18774664626SKris Kennaway peer_b->offset += chunk; 18874664626SKris Kennaway assert(peer_b->offset <= peer_b->size); 18974664626SKris Kennaway if (peer_b->offset == peer_b->size) 19074664626SKris Kennaway peer_b->offset = 0; 19174664626SKris Kennaway buf += chunk; 19274664626SKris Kennaway } 19374664626SKris Kennaway else 19474664626SKris Kennaway { 19574664626SKris Kennaway /* buffer now empty, no need to advance "buf" */ 19674664626SKris Kennaway assert(chunk == rest); 19774664626SKris Kennaway peer_b->offset = 0; 19874664626SKris Kennaway } 19974664626SKris Kennaway rest -= chunk; 20074664626SKris Kennaway } 20174664626SKris Kennaway while (rest); 20274664626SKris Kennaway 20374664626SKris Kennaway return size; 20474664626SKris Kennaway } 20574664626SKris Kennaway 206f579bf8eSKris Kennaway /* non-copying interface: provide pointer to available data in buffer 207f579bf8eSKris Kennaway * bio_nread0: return number of available bytes 208f579bf8eSKris Kennaway * bio_nread: also advance index 209f579bf8eSKris Kennaway * (example usage: bio_nread0(), read from buffer, bio_nread() 210f579bf8eSKris Kennaway * or just bio_nread(), read from buffer) 211f579bf8eSKris Kennaway */ 212f579bf8eSKris Kennaway /* WARNING: The non-copying interface is largely untested as of yet 213f579bf8eSKris Kennaway * and may contain bugs. */ 214f579bf8eSKris Kennaway static ssize_t bio_nread0(BIO *bio, char **buf) 215f579bf8eSKris Kennaway { 216f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b; 217f579bf8eSKris Kennaway ssize_t num; 218f579bf8eSKris Kennaway 219f579bf8eSKris Kennaway BIO_clear_retry_flags(bio); 220f579bf8eSKris Kennaway 221f579bf8eSKris Kennaway if (!bio->init) 222f579bf8eSKris Kennaway return 0; 223f579bf8eSKris Kennaway 224f579bf8eSKris Kennaway b = bio->ptr; 225f579bf8eSKris Kennaway assert(b != NULL); 226f579bf8eSKris Kennaway assert(b->peer != NULL); 227f579bf8eSKris Kennaway peer_b = b->peer->ptr; 228f579bf8eSKris Kennaway assert(peer_b != NULL); 229f579bf8eSKris Kennaway assert(peer_b->buf != NULL); 230f579bf8eSKris Kennaway 231f579bf8eSKris Kennaway peer_b->request = 0; 232f579bf8eSKris Kennaway 233f579bf8eSKris Kennaway if (peer_b->len == 0) 234f579bf8eSKris Kennaway { 235f579bf8eSKris Kennaway char dummy; 236f579bf8eSKris Kennaway 237f579bf8eSKris Kennaway /* avoid code duplication -- nothing available for reading */ 238f579bf8eSKris Kennaway return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ 239f579bf8eSKris Kennaway } 240f579bf8eSKris Kennaway 241f579bf8eSKris Kennaway num = peer_b->len; 242f579bf8eSKris Kennaway if (peer_b->size < peer_b->offset + num) 243f579bf8eSKris Kennaway /* no ring buffer wrap-around for non-copying interface */ 244f579bf8eSKris Kennaway num = peer_b->size - peer_b->offset; 245f579bf8eSKris Kennaway assert(num > 0); 246f579bf8eSKris Kennaway 247f579bf8eSKris Kennaway if (buf != NULL) 248f579bf8eSKris Kennaway *buf = peer_b->buf + peer_b->offset; 249f579bf8eSKris Kennaway return num; 250f579bf8eSKris Kennaway } 251f579bf8eSKris Kennaway 252f579bf8eSKris Kennaway static ssize_t bio_nread(BIO *bio, char **buf, size_t num_) 253f579bf8eSKris Kennaway { 254f579bf8eSKris Kennaway struct bio_bio_st *b, *peer_b; 255f579bf8eSKris Kennaway ssize_t num, available; 256f579bf8eSKris Kennaway 257f579bf8eSKris Kennaway if (num_ > SSIZE_MAX) 258f579bf8eSKris Kennaway num = SSIZE_MAX; 259f579bf8eSKris Kennaway else 260f579bf8eSKris Kennaway num = (ssize_t)num_; 261f579bf8eSKris Kennaway 262f579bf8eSKris Kennaway available = bio_nread0(bio, buf); 263f579bf8eSKris Kennaway if (num > available) 264f579bf8eSKris Kennaway num = available; 265f579bf8eSKris Kennaway if (num <= 0) 266f579bf8eSKris Kennaway return num; 267f579bf8eSKris Kennaway 268f579bf8eSKris Kennaway b = bio->ptr; 269f579bf8eSKris Kennaway peer_b = b->peer->ptr; 270f579bf8eSKris Kennaway 271f579bf8eSKris Kennaway peer_b->len -= num; 272f579bf8eSKris Kennaway if (peer_b->len) 273f579bf8eSKris Kennaway { 274f579bf8eSKris Kennaway peer_b->offset += num; 275f579bf8eSKris Kennaway assert(peer_b->offset <= peer_b->size); 276f579bf8eSKris Kennaway if (peer_b->offset == peer_b->size) 277f579bf8eSKris Kennaway peer_b->offset = 0; 278f579bf8eSKris Kennaway } 279f579bf8eSKris Kennaway else 280f579bf8eSKris Kennaway peer_b->offset = 0; 281f579bf8eSKris Kennaway 282f579bf8eSKris Kennaway return num; 283f579bf8eSKris Kennaway } 284f579bf8eSKris Kennaway 285f579bf8eSKris Kennaway 286ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num_) 28774664626SKris Kennaway { 28874664626SKris Kennaway size_t num = num_; 28974664626SKris Kennaway size_t rest; 29074664626SKris Kennaway struct bio_bio_st *b; 29174664626SKris Kennaway 29274664626SKris Kennaway BIO_clear_retry_flags(bio); 29374664626SKris Kennaway 29474664626SKris Kennaway if (!bio->init || buf == NULL || num == 0) 29574664626SKris Kennaway return 0; 29674664626SKris Kennaway 29774664626SKris Kennaway b = bio->ptr; 29874664626SKris Kennaway assert(b != NULL); 29974664626SKris Kennaway assert(b->peer != NULL); 30074664626SKris Kennaway assert(b->buf != NULL); 30174664626SKris Kennaway 30274664626SKris Kennaway b->request = 0; 30374664626SKris Kennaway if (b->closed) 30474664626SKris Kennaway { 30574664626SKris Kennaway /* we already closed */ 30674664626SKris Kennaway BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); 30774664626SKris Kennaway return -1; 30874664626SKris Kennaway } 30974664626SKris Kennaway 31074664626SKris Kennaway assert(b->len <= b->size); 31174664626SKris Kennaway 31274664626SKris Kennaway if (b->len == b->size) 31374664626SKris Kennaway { 31474664626SKris Kennaway BIO_set_retry_write(bio); /* buffer is full */ 31574664626SKris Kennaway return -1; 31674664626SKris Kennaway } 31774664626SKris Kennaway 31874664626SKris Kennaway /* we can write */ 31974664626SKris Kennaway if (num > b->size - b->len) 32074664626SKris Kennaway num = b->size - b->len; 32174664626SKris Kennaway 32274664626SKris Kennaway /* now write "num" bytes */ 32374664626SKris Kennaway 32474664626SKris Kennaway rest = num; 32574664626SKris Kennaway 32674664626SKris Kennaway assert(rest > 0); 32774664626SKris Kennaway do /* one or two iterations */ 32874664626SKris Kennaway { 32974664626SKris Kennaway size_t write_offset; 33074664626SKris Kennaway size_t chunk; 33174664626SKris Kennaway 33274664626SKris Kennaway assert(b->len + rest <= b->size); 33374664626SKris Kennaway 33474664626SKris Kennaway write_offset = b->offset + b->len; 33574664626SKris Kennaway if (write_offset >= b->size) 33674664626SKris Kennaway write_offset -= b->size; 33774664626SKris Kennaway /* b->buf[write_offset] is the first byte we can write to. */ 33874664626SKris Kennaway 33974664626SKris Kennaway if (write_offset + rest <= b->size) 34074664626SKris Kennaway chunk = rest; 34174664626SKris Kennaway else 34274664626SKris Kennaway /* wrap around ring buffer */ 34374664626SKris Kennaway chunk = b->size - write_offset; 34474664626SKris Kennaway 34574664626SKris Kennaway memcpy(b->buf + write_offset, buf, chunk); 34674664626SKris Kennaway 34774664626SKris Kennaway b->len += chunk; 34874664626SKris Kennaway 34974664626SKris Kennaway assert(b->len <= b->size); 35074664626SKris Kennaway 35174664626SKris Kennaway rest -= chunk; 35274664626SKris Kennaway buf += chunk; 35374664626SKris Kennaway } 35474664626SKris Kennaway while (rest); 35574664626SKris Kennaway 35674664626SKris Kennaway return num; 35774664626SKris Kennaway } 35874664626SKris Kennaway 359f579bf8eSKris Kennaway /* non-copying interface: provide pointer to region to write to 360f579bf8eSKris Kennaway * bio_nwrite0: check how much space is available 361f579bf8eSKris Kennaway * bio_nwrite: also increase length 362f579bf8eSKris Kennaway * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() 363f579bf8eSKris Kennaway * or just bio_nwrite(), write to buffer) 364f579bf8eSKris Kennaway */ 365f579bf8eSKris Kennaway static ssize_t bio_nwrite0(BIO *bio, char **buf) 366f579bf8eSKris Kennaway { 367f579bf8eSKris Kennaway struct bio_bio_st *b; 368f579bf8eSKris Kennaway size_t num; 369f579bf8eSKris Kennaway size_t write_offset; 370f579bf8eSKris Kennaway 371f579bf8eSKris Kennaway BIO_clear_retry_flags(bio); 372f579bf8eSKris Kennaway 373f579bf8eSKris Kennaway if (!bio->init) 374f579bf8eSKris Kennaway return 0; 375f579bf8eSKris Kennaway 376f579bf8eSKris Kennaway b = bio->ptr; 377f579bf8eSKris Kennaway assert(b != NULL); 378f579bf8eSKris Kennaway assert(b->peer != NULL); 379f579bf8eSKris Kennaway assert(b->buf != NULL); 380f579bf8eSKris Kennaway 381f579bf8eSKris Kennaway b->request = 0; 382f579bf8eSKris Kennaway if (b->closed) 383f579bf8eSKris Kennaway { 384f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); 385f579bf8eSKris Kennaway return -1; 386f579bf8eSKris Kennaway } 387f579bf8eSKris Kennaway 388f579bf8eSKris Kennaway assert(b->len <= b->size); 389f579bf8eSKris Kennaway 390f579bf8eSKris Kennaway if (b->len == b->size) 391f579bf8eSKris Kennaway { 392f579bf8eSKris Kennaway BIO_set_retry_write(bio); 393f579bf8eSKris Kennaway return -1; 394f579bf8eSKris Kennaway } 395f579bf8eSKris Kennaway 396f579bf8eSKris Kennaway num = b->size - b->len; 397f579bf8eSKris Kennaway write_offset = b->offset + b->len; 398f579bf8eSKris Kennaway if (write_offset >= b->size) 399f579bf8eSKris Kennaway write_offset -= b->size; 400f579bf8eSKris Kennaway if (write_offset + num > b->size) 401f579bf8eSKris Kennaway /* no ring buffer wrap-around for non-copying interface 402f579bf8eSKris Kennaway * (to fulfil the promise by BIO_ctrl_get_write_guarantee, 403f579bf8eSKris Kennaway * BIO_nwrite may have to be called twice) */ 404f579bf8eSKris Kennaway num = b->size - write_offset; 405f579bf8eSKris Kennaway 406f579bf8eSKris Kennaway if (buf != NULL) 407f579bf8eSKris Kennaway *buf = b->buf + write_offset; 408f579bf8eSKris Kennaway assert(write_offset + num <= b->size); 409f579bf8eSKris Kennaway 410f579bf8eSKris Kennaway return num; 411f579bf8eSKris Kennaway } 412f579bf8eSKris Kennaway 413f579bf8eSKris Kennaway static ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_) 414f579bf8eSKris Kennaway { 415f579bf8eSKris Kennaway struct bio_bio_st *b; 416f579bf8eSKris Kennaway ssize_t num, space; 417f579bf8eSKris Kennaway 418f579bf8eSKris Kennaway if (num_ > SSIZE_MAX) 419f579bf8eSKris Kennaway num = SSIZE_MAX; 420f579bf8eSKris Kennaway else 421f579bf8eSKris Kennaway num = (ssize_t)num_; 422f579bf8eSKris Kennaway 423f579bf8eSKris Kennaway space = bio_nwrite0(bio, buf); 424f579bf8eSKris Kennaway if (num > space) 425f579bf8eSKris Kennaway num = space; 426f579bf8eSKris Kennaway if (num <= 0) 427f579bf8eSKris Kennaway return num; 428f579bf8eSKris Kennaway b = bio->ptr; 429f579bf8eSKris Kennaway assert(b != NULL); 430f579bf8eSKris Kennaway b->len += num; 431f579bf8eSKris Kennaway assert(b->len <= b->size); 432f579bf8eSKris Kennaway 433f579bf8eSKris Kennaway return num; 434f579bf8eSKris Kennaway } 435f579bf8eSKris Kennaway 43674664626SKris Kennaway 43774664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) 43874664626SKris Kennaway { 43974664626SKris Kennaway long ret; 44074664626SKris Kennaway struct bio_bio_st *b = bio->ptr; 44174664626SKris Kennaway 44274664626SKris Kennaway assert(b != NULL); 44374664626SKris Kennaway 44474664626SKris Kennaway switch (cmd) 44574664626SKris Kennaway { 44674664626SKris Kennaway /* specific CTRL codes */ 44774664626SKris Kennaway 44874664626SKris Kennaway case BIO_C_SET_WRITE_BUF_SIZE: 44974664626SKris Kennaway if (b->peer) 45074664626SKris Kennaway { 45174664626SKris Kennaway BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); 45274664626SKris Kennaway ret = 0; 45374664626SKris Kennaway } 45474664626SKris Kennaway else if (num == 0) 45574664626SKris Kennaway { 45674664626SKris Kennaway BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT); 45774664626SKris Kennaway ret = 0; 45874664626SKris Kennaway } 45974664626SKris Kennaway else 46074664626SKris Kennaway { 46174664626SKris Kennaway size_t new_size = num; 46274664626SKris Kennaway 46374664626SKris Kennaway if (b->size != new_size) 46474664626SKris Kennaway { 46574664626SKris Kennaway if (b->buf) 46674664626SKris Kennaway { 467ddd58736SKris Kennaway OPENSSL_free(b->buf); 46874664626SKris Kennaway b->buf = NULL; 46974664626SKris Kennaway } 47074664626SKris Kennaway b->size = new_size; 47174664626SKris Kennaway } 47274664626SKris Kennaway ret = 1; 47374664626SKris Kennaway } 47474664626SKris Kennaway break; 47574664626SKris Kennaway 47674664626SKris Kennaway case BIO_C_GET_WRITE_BUF_SIZE: 477a21b1b38SKris Kennaway ret = (long) b->size; 478a21b1b38SKris Kennaway break; 47974664626SKris Kennaway 48074664626SKris Kennaway case BIO_C_MAKE_BIO_PAIR: 48174664626SKris Kennaway { 48274664626SKris Kennaway BIO *other_bio = ptr; 48374664626SKris Kennaway 48474664626SKris Kennaway if (bio_make_pair(bio, other_bio)) 48574664626SKris Kennaway ret = 1; 48674664626SKris Kennaway else 48774664626SKris Kennaway ret = 0; 48874664626SKris Kennaway } 48974664626SKris Kennaway break; 49074664626SKris Kennaway 49174664626SKris Kennaway case BIO_C_DESTROY_BIO_PAIR: 49274664626SKris Kennaway /* Effects both BIOs in the pair -- call just once! 49374664626SKris Kennaway * Or let BIO_free(bio1); BIO_free(bio2); do the job. */ 49474664626SKris Kennaway bio_destroy_pair(bio); 49574664626SKris Kennaway ret = 1; 49674664626SKris Kennaway break; 49774664626SKris Kennaway 49874664626SKris Kennaway case BIO_C_GET_WRITE_GUARANTEE: 49974664626SKris Kennaway /* How many bytes can the caller feed to the next write 500f579bf8eSKris Kennaway * without having to keep any? */ 50174664626SKris Kennaway if (b->peer == NULL || b->closed) 50274664626SKris Kennaway ret = 0; 50374664626SKris Kennaway else 50474664626SKris Kennaway ret = (long) b->size - b->len; 50574664626SKris Kennaway break; 50674664626SKris Kennaway 50774664626SKris Kennaway case BIO_C_GET_READ_REQUEST: 508f579bf8eSKris Kennaway /* If the peer unsuccessfully tried to read, how many bytes 50974664626SKris Kennaway * were requested? (As with BIO_CTRL_PENDING, that number 51074664626SKris Kennaway * can usually be treated as boolean.) */ 51174664626SKris Kennaway ret = (long) b->request; 51274664626SKris Kennaway break; 51374664626SKris Kennaway 514f579bf8eSKris Kennaway case BIO_C_RESET_READ_REQUEST: 515f579bf8eSKris Kennaway /* Reset request. (Can be useful after read attempts 516f579bf8eSKris Kennaway * at the other side that are meant to be non-blocking, 517f579bf8eSKris Kennaway * e.g. when probing SSL_read to see if any data is 518f579bf8eSKris Kennaway * available.) */ 519f579bf8eSKris Kennaway b->request = 0; 520f579bf8eSKris Kennaway ret = 1; 521f579bf8eSKris Kennaway break; 522f579bf8eSKris Kennaway 52374664626SKris Kennaway case BIO_C_SHUTDOWN_WR: 52474664626SKris Kennaway /* similar to shutdown(..., SHUT_WR) */ 52574664626SKris Kennaway b->closed = 1; 52674664626SKris Kennaway ret = 1; 52774664626SKris Kennaway break; 52874664626SKris Kennaway 529f579bf8eSKris Kennaway case BIO_C_NREAD0: 530f579bf8eSKris Kennaway /* prepare for non-copying read */ 531f579bf8eSKris Kennaway ret = (long) bio_nread0(bio, ptr); 532f579bf8eSKris Kennaway break; 533f579bf8eSKris Kennaway 534f579bf8eSKris Kennaway case BIO_C_NREAD: 535f579bf8eSKris Kennaway /* non-copying read */ 536f579bf8eSKris Kennaway ret = (long) bio_nread(bio, ptr, (size_t) num); 537f579bf8eSKris Kennaway break; 538f579bf8eSKris Kennaway 539f579bf8eSKris Kennaway case BIO_C_NWRITE0: 540f579bf8eSKris Kennaway /* prepare for non-copying write */ 541f579bf8eSKris Kennaway ret = (long) bio_nwrite0(bio, ptr); 542f579bf8eSKris Kennaway break; 543f579bf8eSKris Kennaway 544f579bf8eSKris Kennaway case BIO_C_NWRITE: 545f579bf8eSKris Kennaway /* non-copying write */ 546f579bf8eSKris Kennaway ret = (long) bio_nwrite(bio, ptr, (size_t) num); 547f579bf8eSKris Kennaway break; 548f579bf8eSKris Kennaway 54974664626SKris Kennaway 55074664626SKris Kennaway /* standard CTRL codes follow */ 55174664626SKris Kennaway 55274664626SKris Kennaway case BIO_CTRL_RESET: 55374664626SKris Kennaway if (b->buf != NULL) 55474664626SKris Kennaway { 55574664626SKris Kennaway b->len = 0; 55674664626SKris Kennaway b->offset = 0; 55774664626SKris Kennaway } 55874664626SKris Kennaway ret = 0; 55974664626SKris Kennaway break; 56074664626SKris Kennaway 56174664626SKris Kennaway case BIO_CTRL_GET_CLOSE: 56274664626SKris Kennaway ret = bio->shutdown; 56374664626SKris Kennaway break; 56474664626SKris Kennaway 56574664626SKris Kennaway case BIO_CTRL_SET_CLOSE: 56674664626SKris Kennaway bio->shutdown = (int) num; 56774664626SKris Kennaway ret = 1; 56874664626SKris Kennaway break; 56974664626SKris Kennaway 57074664626SKris Kennaway case BIO_CTRL_PENDING: 57174664626SKris Kennaway if (b->peer != NULL) 57274664626SKris Kennaway { 57374664626SKris Kennaway struct bio_bio_st *peer_b = b->peer->ptr; 57474664626SKris Kennaway 57574664626SKris Kennaway ret = (long) peer_b->len; 57674664626SKris Kennaway } 57774664626SKris Kennaway else 57874664626SKris Kennaway ret = 0; 57974664626SKris Kennaway break; 58074664626SKris Kennaway 58174664626SKris Kennaway case BIO_CTRL_WPENDING: 58274664626SKris Kennaway if (b->buf != NULL) 58374664626SKris Kennaway ret = (long) b->len; 58474664626SKris Kennaway else 58574664626SKris Kennaway ret = 0; 58674664626SKris Kennaway break; 58774664626SKris Kennaway 58874664626SKris Kennaway case BIO_CTRL_DUP: 58974664626SKris Kennaway /* See BIO_dup_chain for circumstances we have to expect. */ 59074664626SKris Kennaway { 59174664626SKris Kennaway BIO *other_bio = ptr; 59274664626SKris Kennaway struct bio_bio_st *other_b; 59374664626SKris Kennaway 59474664626SKris Kennaway assert(other_bio != NULL); 59574664626SKris Kennaway other_b = other_bio->ptr; 59674664626SKris Kennaway assert(other_b != NULL); 59774664626SKris Kennaway 59874664626SKris Kennaway assert(other_b->buf == NULL); /* other_bio is always fresh */ 59974664626SKris Kennaway 60074664626SKris Kennaway other_b->size = b->size; 60174664626SKris Kennaway } 60274664626SKris Kennaway 60374664626SKris Kennaway ret = 1; 60474664626SKris Kennaway break; 60574664626SKris Kennaway 60674664626SKris Kennaway case BIO_CTRL_FLUSH: 60774664626SKris Kennaway ret = 1; 60874664626SKris Kennaway break; 60974664626SKris Kennaway 61074664626SKris Kennaway case BIO_CTRL_EOF: 61174664626SKris Kennaway { 61274664626SKris Kennaway BIO *other_bio = ptr; 61374664626SKris Kennaway 61474664626SKris Kennaway if (other_bio) 61574664626SKris Kennaway { 61674664626SKris Kennaway struct bio_bio_st *other_b = other_bio->ptr; 61774664626SKris Kennaway 61874664626SKris Kennaway assert(other_b != NULL); 61974664626SKris Kennaway ret = other_b->len == 0 && other_b->closed; 62074664626SKris Kennaway } 62174664626SKris Kennaway else 62274664626SKris Kennaway ret = 1; 62374664626SKris Kennaway } 62474664626SKris Kennaway break; 62574664626SKris Kennaway 62674664626SKris Kennaway default: 62774664626SKris Kennaway ret = 0; 62874664626SKris Kennaway } 62974664626SKris Kennaway return ret; 63074664626SKris Kennaway } 63174664626SKris Kennaway 632ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str) 63374664626SKris Kennaway { 63474664626SKris Kennaway return bio_write(bio, str, strlen(str)); 63574664626SKris Kennaway } 63674664626SKris Kennaway 63774664626SKris Kennaway 63874664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2) 63974664626SKris Kennaway { 64074664626SKris Kennaway struct bio_bio_st *b1, *b2; 64174664626SKris Kennaway 64274664626SKris Kennaway assert(bio1 != NULL); 64374664626SKris Kennaway assert(bio2 != NULL); 64474664626SKris Kennaway 64574664626SKris Kennaway b1 = bio1->ptr; 64674664626SKris Kennaway b2 = bio2->ptr; 64774664626SKris Kennaway 64874664626SKris Kennaway if (b1->peer != NULL || b2->peer != NULL) 64974664626SKris Kennaway { 65074664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE); 65174664626SKris Kennaway return 0; 65274664626SKris Kennaway } 65374664626SKris Kennaway 65474664626SKris Kennaway if (b1->buf == NULL) 65574664626SKris Kennaway { 656ddd58736SKris Kennaway b1->buf = OPENSSL_malloc(b1->size); 65774664626SKris Kennaway if (b1->buf == NULL) 65874664626SKris Kennaway { 65974664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); 66074664626SKris Kennaway return 0; 66174664626SKris Kennaway } 66274664626SKris Kennaway b1->len = 0; 66374664626SKris Kennaway b1->offset = 0; 66474664626SKris Kennaway } 66574664626SKris Kennaway 66674664626SKris Kennaway if (b2->buf == NULL) 66774664626SKris Kennaway { 668ddd58736SKris Kennaway b2->buf = OPENSSL_malloc(b2->size); 66974664626SKris Kennaway if (b2->buf == NULL) 67074664626SKris Kennaway { 67174664626SKris Kennaway BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); 67274664626SKris Kennaway return 0; 67374664626SKris Kennaway } 67474664626SKris Kennaway b2->len = 0; 67574664626SKris Kennaway b2->offset = 0; 67674664626SKris Kennaway } 67774664626SKris Kennaway 67874664626SKris Kennaway b1->peer = bio2; 67974664626SKris Kennaway b1->closed = 0; 68074664626SKris Kennaway b1->request = 0; 68174664626SKris Kennaway b2->peer = bio1; 68274664626SKris Kennaway b2->closed = 0; 68374664626SKris Kennaway b2->request = 0; 68474664626SKris Kennaway 68574664626SKris Kennaway bio1->init = 1; 68674664626SKris Kennaway bio2->init = 1; 68774664626SKris Kennaway 68874664626SKris Kennaway return 1; 68974664626SKris Kennaway } 69074664626SKris Kennaway 69174664626SKris Kennaway static void bio_destroy_pair(BIO *bio) 69274664626SKris Kennaway { 69374664626SKris Kennaway struct bio_bio_st *b = bio->ptr; 69474664626SKris Kennaway 69574664626SKris Kennaway if (b != NULL) 69674664626SKris Kennaway { 69774664626SKris Kennaway BIO *peer_bio = b->peer; 69874664626SKris Kennaway 69974664626SKris Kennaway if (peer_bio != NULL) 70074664626SKris Kennaway { 70174664626SKris Kennaway struct bio_bio_st *peer_b = peer_bio->ptr; 70274664626SKris Kennaway 70374664626SKris Kennaway assert(peer_b != NULL); 70474664626SKris Kennaway assert(peer_b->peer == bio); 70574664626SKris Kennaway 70674664626SKris Kennaway peer_b->peer = NULL; 70774664626SKris Kennaway peer_bio->init = 0; 70874664626SKris Kennaway assert(peer_b->buf != NULL); 70974664626SKris Kennaway peer_b->len = 0; 71074664626SKris Kennaway peer_b->offset = 0; 71174664626SKris Kennaway 71274664626SKris Kennaway b->peer = NULL; 71374664626SKris Kennaway bio->init = 0; 71474664626SKris Kennaway assert(b->buf != NULL); 71574664626SKris Kennaway b->len = 0; 71674664626SKris Kennaway b->offset = 0; 71774664626SKris Kennaway } 71874664626SKris Kennaway } 71974664626SKris Kennaway } 72074664626SKris Kennaway 72174664626SKris Kennaway 72274664626SKris Kennaway /* Exported convenience functions */ 72374664626SKris Kennaway int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, 72474664626SKris Kennaway BIO **bio2_p, size_t writebuf2) 72574664626SKris Kennaway { 72674664626SKris Kennaway BIO *bio1 = NULL, *bio2 = NULL; 72774664626SKris Kennaway long r; 72874664626SKris Kennaway int ret = 0; 72974664626SKris Kennaway 73074664626SKris Kennaway bio1 = BIO_new(BIO_s_bio()); 73174664626SKris Kennaway if (bio1 == NULL) 73274664626SKris Kennaway goto err; 73374664626SKris Kennaway bio2 = BIO_new(BIO_s_bio()); 73474664626SKris Kennaway if (bio2 == NULL) 73574664626SKris Kennaway goto err; 73674664626SKris Kennaway 73774664626SKris Kennaway if (writebuf1) 73874664626SKris Kennaway { 73974664626SKris Kennaway r = BIO_set_write_buf_size(bio1, writebuf1); 74074664626SKris Kennaway if (!r) 74174664626SKris Kennaway goto err; 74274664626SKris Kennaway } 74374664626SKris Kennaway if (writebuf2) 74474664626SKris Kennaway { 74574664626SKris Kennaway r = BIO_set_write_buf_size(bio2, writebuf2); 74674664626SKris Kennaway if (!r) 74774664626SKris Kennaway goto err; 74874664626SKris Kennaway } 74974664626SKris Kennaway 75074664626SKris Kennaway r = BIO_make_bio_pair(bio1, bio2); 75174664626SKris Kennaway if (!r) 75274664626SKris Kennaway goto err; 75374664626SKris Kennaway ret = 1; 75474664626SKris Kennaway 75574664626SKris Kennaway err: 75674664626SKris Kennaway if (ret == 0) 75774664626SKris Kennaway { 75874664626SKris Kennaway if (bio1) 75974664626SKris Kennaway { 76074664626SKris Kennaway BIO_free(bio1); 76174664626SKris Kennaway bio1 = NULL; 76274664626SKris Kennaway } 76374664626SKris Kennaway if (bio2) 76474664626SKris Kennaway { 76574664626SKris Kennaway BIO_free(bio2); 76674664626SKris Kennaway bio2 = NULL; 76774664626SKris Kennaway } 76874664626SKris Kennaway } 76974664626SKris Kennaway 77074664626SKris Kennaway *bio1_p = bio1; 77174664626SKris Kennaway *bio2_p = bio2; 77274664626SKris Kennaway return ret; 77374664626SKris Kennaway } 77474664626SKris Kennaway 77574664626SKris Kennaway size_t BIO_ctrl_get_write_guarantee(BIO *bio) 77674664626SKris Kennaway { 77774664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); 77874664626SKris Kennaway } 77974664626SKris Kennaway 78074664626SKris Kennaway size_t BIO_ctrl_get_read_request(BIO *bio) 78174664626SKris Kennaway { 78274664626SKris Kennaway return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); 78374664626SKris Kennaway } 784f579bf8eSKris Kennaway 785f579bf8eSKris Kennaway int BIO_ctrl_reset_read_request(BIO *bio) 786f579bf8eSKris Kennaway { 787f579bf8eSKris Kennaway return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); 788f579bf8eSKris Kennaway } 789f579bf8eSKris Kennaway 790f579bf8eSKris Kennaway 791f579bf8eSKris Kennaway /* BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now 792f579bf8eSKris Kennaway * (conceivably some other BIOs could allow non-copying reads and writes too.) 793f579bf8eSKris Kennaway */ 794f579bf8eSKris Kennaway int BIO_nread0(BIO *bio, char **buf) 795f579bf8eSKris Kennaway { 796f579bf8eSKris Kennaway long ret; 797f579bf8eSKris Kennaway 798f579bf8eSKris Kennaway if (!bio->init) 799f579bf8eSKris Kennaway { 800f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); 801f579bf8eSKris Kennaway return -2; 802f579bf8eSKris Kennaway } 803f579bf8eSKris Kennaway 804f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); 805f579bf8eSKris Kennaway if (ret > INT_MAX) 806f579bf8eSKris Kennaway return INT_MAX; 807f579bf8eSKris Kennaway else 808f579bf8eSKris Kennaway return (int) ret; 809f579bf8eSKris Kennaway } 810f579bf8eSKris Kennaway 811f579bf8eSKris Kennaway int BIO_nread(BIO *bio, char **buf, int num) 812f579bf8eSKris Kennaway { 813f579bf8eSKris Kennaway int ret; 814f579bf8eSKris Kennaway 815f579bf8eSKris Kennaway if (!bio->init) 816f579bf8eSKris Kennaway { 817f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); 818f579bf8eSKris Kennaway return -2; 819f579bf8eSKris Kennaway } 820f579bf8eSKris Kennaway 821f579bf8eSKris Kennaway ret = (int) BIO_ctrl(bio, BIO_C_NREAD, num, buf); 822f579bf8eSKris Kennaway if (ret > 0) 823f579bf8eSKris Kennaway bio->num_read += ret; 824f579bf8eSKris Kennaway return ret; 825f579bf8eSKris Kennaway } 826f579bf8eSKris Kennaway 827f579bf8eSKris Kennaway int BIO_nwrite0(BIO *bio, char **buf) 828f579bf8eSKris Kennaway { 829f579bf8eSKris Kennaway long ret; 830f579bf8eSKris Kennaway 831f579bf8eSKris Kennaway if (!bio->init) 832f579bf8eSKris Kennaway { 833f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); 834f579bf8eSKris Kennaway return -2; 835f579bf8eSKris Kennaway } 836f579bf8eSKris Kennaway 837f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); 838f579bf8eSKris Kennaway if (ret > INT_MAX) 839f579bf8eSKris Kennaway return INT_MAX; 840f579bf8eSKris Kennaway else 841f579bf8eSKris Kennaway return (int) ret; 842f579bf8eSKris Kennaway } 843f579bf8eSKris Kennaway 844f579bf8eSKris Kennaway int BIO_nwrite(BIO *bio, char **buf, int num) 845f579bf8eSKris Kennaway { 846f579bf8eSKris Kennaway int ret; 847f579bf8eSKris Kennaway 848f579bf8eSKris Kennaway if (!bio->init) 849f579bf8eSKris Kennaway { 850f579bf8eSKris Kennaway BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); 851f579bf8eSKris Kennaway return -2; 852f579bf8eSKris Kennaway } 853f579bf8eSKris Kennaway 854f579bf8eSKris Kennaway ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); 855f579bf8eSKris Kennaway if (ret > 0) 856f579bf8eSKris Kennaway bio->num_read += ret; 857f579bf8eSKris Kennaway return ret; 858f579bf8eSKris Kennaway } 859