From c1082a90bb38d3921816d41e3e4d354f0d5ab4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bodo=20M=C3=B6ller?= Date: Tue, 7 Sep 1999 21:37:09 +0000 Subject: [PATCH] Non-copying interface to BIO pairs. It's still totally untested ... --- CHANGES | 4 + crypto/bio/bio.h | 2 - crypto/bio/bss_bio.c | 232 +++++++++++++++++++++++++++++++++++++++++++ ssl/ssltest.c | 3 + 4 files changed, 239 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 2f40440310..7f347f20e5 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,10 @@ Changes between 0.9.4 and 0.9.5 [xx XXX 1999] + *) Non-copying interface to BIO pairs. + (still totally untested) + [Bodo Moeller] + *) New function ANS1_tag2str() to convert an ASN1 tag to a descriptive ASCII string. This was handled independently in various places before. [Steve Henson] diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h index 5558ac544c..a05e0c2eac 100644 --- a/crypto/bio/bio.h +++ b/crypto/bio/bio.h @@ -517,12 +517,10 @@ BIO * BIO_get_retry_BIO(BIO *bio, int *reason); int BIO_get_retry_reason(BIO *bio); BIO * BIO_dup_chain(BIO *in); -#if 0 /* not yet */ int BIO_nread0(BIO *bio, char **buf); int BIO_nread(BIO *bio, char **buf, int num); int BIO_nwrite0(BIO *bio, char **buf); int BIO_nwrite(BIO *bio, char **buf, int num); -#endif #ifndef WIN16 long BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi, diff --git a/crypto/bio/bss_bio.c b/crypto/bio/bss_bio.c index 562e9d8de2..ad8079495f 100644 --- a/crypto/bio/bss_bio.c +++ b/crypto/bio/bss_bio.c @@ -13,6 +13,7 @@ #endif #include +#include #include #include @@ -195,6 +196,82 @@ static int bio_read(BIO *bio, char *buf, int size_) return size; } +/* non-copying interface: provide pointer to available data in buffer + * bio_nread0: return number of available bytes + * bio_nread: also advance index + * (example usage: bio_nread0(), read from buffer, bio_nread() + * or just bio_nread(), read from buffer) + */ +/* WARNING: The non-copying interface is totally untested as of yet -- + * I wrote it, but have not yet read it; and surely it still is full + * of bugs. */ +static size_t bio_nread0(BIO *bio, char **buf) + { + struct bio_bio_st *b, *peer_b; + size_t num; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; + + if (peer_b->len == 0) + { + char dummy; + + /* avoid code duplication -- nothing available for reading */ + return bio_read(bio, &dummy, num); /* returns 0 or -1 */ + } + + num = peer_b->len; + if (peer_b->size < peer_b->offset + num) + /* no ring buffer wrap-around for non-copying interface */ + num = peer_b->size - peer_b->offset; + assert(num > 0); + + if (buf != NULL) + *buf = peer_b->buf + peer_b->offset; + return num; + } + +static size_t bio_nread(BIO *bio, char **buf, size_t num) + { + struct bio_bio_st *b, *peer_b; + size_t available; + + available = bio_nread0(bio, buf); + if (num > available) + num = available; + if (num <= 0) + return num; + + b = bio->ptr; + peer_b = b->peer->ptr; + + peer_b->len -= num; + if (peer_b->len) + { + peer_b->offset += num; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + } + else + peer_b->offset = 0; + + return num; + } + + static int bio_write(BIO *bio, char *buf, int num_) { size_t num = num_; @@ -268,6 +345,76 @@ static int bio_write(BIO *bio, char *buf, int num_) return num; } +/* non-copying interface: provide pointer to region to write to + * bio_nwrite0: check how much space is available + * bio_nwrite: also increase length + * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() + * or just bio_nwrite(), write to buffer) + */ +static size_t bio_nwrite0(BIO *bio, char **buf) + { + struct bio_bio_st *b; + size_t num; + size_t write_offset; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) + { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) + { + BIO_set_retry_write(bio); + return -1; + } + + num = b->size - b->len; + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + if (write_offset + num > b->size) + /* no ring buffer wrap-around for non-copying interface + * (to fulfil the promise by BIO_ctrl_get_write_guarantee, + * BIO_nwrite may have to be called twice) */ + num = b->size - write_offset; + + if (buf != NULL) + *buf = b->buf + write_offset; + assert(write_offset + num <= b->size); + + return num; + } + +static size_t bio_nwrite(BIO *bio, char **buf, size_t num) + { + struct bio_bio_st *b; + size_t space; + + space = bio_nwrite0(bio, buf); + if (num > space) + num = space; + if (num <= 0) + return num; + b->len += num; + assert(b->len <= b->size); + + return num; + } + static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { @@ -351,6 +498,21 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) ret = 1; break; + case BIO_C_NREAD: + /* non-copying read */ + ret = (long) bio_nread(bio, ptr, (size_t) num); + break; + + case BIO_C_NWRITE0: + /* prepare for non-copying write */ + ret = (long) bio_nwrite0(bio, ptr); + break; + + case BIO_C_NWRITE: + /* non-copying write */ + ret = (long) bio_nwrite(bio, ptr, (size_t) num); + break; + /* standard CTRL codes follow */ @@ -586,3 +748,73 @@ size_t BIO_ctrl_get_read_request(BIO *bio) { return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); } + + +/* BIO_nread0/nread/nwrite0/nwrite are availabe only for BIO pairs for now + * (conceivably some other BIOs could allow non-copying reads and writes too.) + */ +int BIO_nread0(BIO *bio, char **buf) + { + long ret; + + if (!bio->init) + { + BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int) ret; + } + +int BIO_nread(BIO *bio, char **buf, int num) + { + int ret; + + if (!bio->init) + { + BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); + return -2; + } + + ret = (int) BIO_ctrl(bio, BIO_C_NREAD, num, buf); + if (ret > 0) + bio->num_read += ret; + return ret; + } + +int BIO_nwrite0(BIO *bio, char **buf) + { + long ret; + + if (!bio->init) + { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int) ret; + } + +int BIO_nwrite(BIO *bio, char **buf, int num) + { + int ret; + + if (!bio->init) + { + BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); + if (ret > 0) + bio->num_read += ret; + return ret; + } diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 53a6570df6..b62f5ad4f7 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -653,6 +653,9 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count) { /* "I/O" BETWEEN CLIENT AND SERVER. */ + /* TODO: use non-blocking BIO interface for (say) the client + * to illustrate its use and to test it. */ + #define RELAYBUFSIZ 200 static char buf[RELAYBUFSIZ]; -- GitLab