xref: /freebsd/crypto/openssl/crypto/bio/bss_bio.c (revision aeb5019c481d34f2422c200e4751e24ec940fe3f)
18180e704SJung-uk Kim /* crypto/bio/bss_bio.c  */
250ef0093SJacques Vidrine /* ====================================================================
350ef0093SJacques Vidrine  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
450ef0093SJacques Vidrine  *
550ef0093SJacques Vidrine  * Redistribution and use in source and binary forms, with or without
650ef0093SJacques Vidrine  * modification, are permitted provided that the following conditions
750ef0093SJacques Vidrine  * are met:
850ef0093SJacques Vidrine  *
950ef0093SJacques Vidrine  * 1. Redistributions of source code must retain the above copyright
1050ef0093SJacques Vidrine  *    notice, this list of conditions and the following disclaimer.
1150ef0093SJacques Vidrine  *
1250ef0093SJacques Vidrine  * 2. Redistributions in binary form must reproduce the above copyright
1350ef0093SJacques Vidrine  *    notice, this list of conditions and the following disclaimer in
1450ef0093SJacques Vidrine  *    the documentation and/or other materials provided with the
1550ef0093SJacques Vidrine  *    distribution.
1650ef0093SJacques Vidrine  *
1750ef0093SJacques Vidrine  * 3. All advertising materials mentioning features or use of this
1850ef0093SJacques Vidrine  *    software must display the following acknowledgment:
1950ef0093SJacques Vidrine  *    "This product includes software developed by the OpenSSL Project
2050ef0093SJacques Vidrine  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
2150ef0093SJacques Vidrine  *
2250ef0093SJacques Vidrine  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2350ef0093SJacques Vidrine  *    endorse or promote products derived from this software without
2450ef0093SJacques Vidrine  *    prior written permission. For written permission, please contact
2550ef0093SJacques Vidrine  *    openssl-core@openssl.org.
2650ef0093SJacques Vidrine  *
2750ef0093SJacques Vidrine  * 5. Products derived from this software may not be called "OpenSSL"
2850ef0093SJacques Vidrine  *    nor may "OpenSSL" appear in their names without prior written
2950ef0093SJacques Vidrine  *    permission of the OpenSSL Project.
3050ef0093SJacques Vidrine  *
3150ef0093SJacques Vidrine  * 6. Redistributions of any form whatsoever must retain the following
3250ef0093SJacques Vidrine  *    acknowledgment:
3350ef0093SJacques Vidrine  *    "This product includes software developed by the OpenSSL Project
3450ef0093SJacques Vidrine  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
3550ef0093SJacques Vidrine  *
3650ef0093SJacques Vidrine  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
3750ef0093SJacques Vidrine  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3850ef0093SJacques Vidrine  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
3950ef0093SJacques Vidrine  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4050ef0093SJacques Vidrine  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4150ef0093SJacques Vidrine  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4250ef0093SJacques Vidrine  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4350ef0093SJacques Vidrine  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4450ef0093SJacques Vidrine  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4550ef0093SJacques Vidrine  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4650ef0093SJacques Vidrine  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
4750ef0093SJacques Vidrine  * OF THE POSSIBILITY OF SUCH DAMAGE.
4850ef0093SJacques Vidrine  * ====================================================================
4950ef0093SJacques Vidrine  *
5050ef0093SJacques Vidrine  * This product includes cryptographic software written by Eric Young
5150ef0093SJacques Vidrine  * (eay@cryptsoft.com).  This product includes software written by Tim
5250ef0093SJacques Vidrine  * Hudson (tjh@cryptsoft.com).
5350ef0093SJacques Vidrine  *
5450ef0093SJacques Vidrine  */
5574664626SKris Kennaway 
566f9291ceSJung-uk Kim /*
576f9291ceSJung-uk Kim  * Special method for a BIO where the other endpoint is also a BIO of this
586f9291ceSJung-uk Kim  * kind, handled by the same thread (i.e. the "peer" is actually ourselves,
596f9291ceSJung-uk Kim  * wearing a different hat). Such "BIO pairs" are mainly for using the SSL
606f9291ceSJung-uk Kim  * library with I/O interfaces for which no specific BIO method is available.
616f9291ceSJung-uk Kim  * See ssl/ssltest.c for some hints on how this can be used.
626f9291ceSJung-uk Kim  */
6374664626SKris Kennaway 
644f20a5a2SJacques Vidrine /* BIO_DEBUG implies BIO_PAIR_DEBUG */
654f20a5a2SJacques Vidrine #ifdef BIO_DEBUG
6674664626SKris Kennaway # ifndef BIO_PAIR_DEBUG
674f20a5a2SJacques Vidrine #  define BIO_PAIR_DEBUG
684f20a5a2SJacques Vidrine # endif
694f20a5a2SJacques Vidrine #endif
704f20a5a2SJacques Vidrine 
714f20a5a2SJacques Vidrine /* disable assert() unless BIO_PAIR_DEBUG has been defined */
724f20a5a2SJacques Vidrine #ifndef BIO_PAIR_DEBUG
734f20a5a2SJacques Vidrine # ifndef NDEBUG
7474664626SKris Kennaway #  define NDEBUG
7574664626SKris Kennaway # endif
764f20a5a2SJacques Vidrine #endif
7774664626SKris Kennaway 
7874664626SKris Kennaway #include <assert.h>
79f579bf8eSKris Kennaway #include <limits.h>
8074664626SKris Kennaway #include <stdlib.h>
8174664626SKris Kennaway #include <string.h>
8274664626SKris Kennaway 
8374664626SKris Kennaway #include <openssl/bio.h>
8474664626SKris Kennaway #include <openssl/err.h>
8574664626SKris Kennaway #include <openssl/crypto.h>
8674664626SKris Kennaway 
875c87c606SMark Murray #include "e_os.h"
88c1803d78SJacques Vidrine 
895c87c606SMark Murray /* VxWorks defines SSIZE_MAX with an empty value causing compile errors */
905c87c606SMark Murray #if defined(OPENSSL_SYS_VXWORKS)
91c1803d78SJacques Vidrine # undef SSIZE_MAX
925c87c606SMark Murray #endif
935c87c606SMark Murray #ifndef SSIZE_MAX
94f579bf8eSKris Kennaway # define SSIZE_MAX INT_MAX
95f579bf8eSKris Kennaway #endif
96f579bf8eSKris Kennaway 
9774664626SKris Kennaway static int bio_new(BIO *bio);
9874664626SKris Kennaway static int bio_free(BIO *bio);
9974664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size);
100ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num);
10174664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
102ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str);
10374664626SKris Kennaway 
10474664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2);
10574664626SKris Kennaway static void bio_destroy_pair(BIO *bio);
10674664626SKris Kennaway 
1076f9291ceSJung-uk Kim static BIO_METHOD methods_biop = {
10874664626SKris Kennaway     BIO_TYPE_BIO,
10974664626SKris Kennaway     "BIO pair",
11074664626SKris Kennaway     bio_write,
11174664626SKris Kennaway     bio_read,
11274664626SKris Kennaway     bio_puts,
11374664626SKris Kennaway     NULL /* no bio_gets */ ,
11474664626SKris Kennaway     bio_ctrl,
11574664626SKris Kennaway     bio_new,
116f579bf8eSKris Kennaway     bio_free,
117f579bf8eSKris Kennaway     NULL                        /* no bio_callback_ctrl */
11874664626SKris Kennaway };
11974664626SKris Kennaway 
12074664626SKris Kennaway BIO_METHOD *BIO_s_bio(void)
12174664626SKris Kennaway {
12274664626SKris Kennaway     return &methods_biop;
12374664626SKris Kennaway }
12474664626SKris Kennaway 
1256f9291ceSJung-uk Kim struct bio_bio_st {
1266f9291ceSJung-uk Kim     BIO *peer;                  /* NULL if buf == NULL. If peer != NULL, then
1276f9291ceSJung-uk Kim                                  * peer->ptr is also a bio_bio_st, and its
1286f9291ceSJung-uk Kim                                  * "peer" member points back to us. peer !=
1296f9291ceSJung-uk Kim                                  * NULL iff init != 0 in the BIO. */
13074664626SKris Kennaway     /* This is for what we write (i.e. reading uses peer's struct): */
13174664626SKris Kennaway     int closed;                 /* valid iff peer != NULL */
13274664626SKris Kennaway     size_t len;                 /* valid iff buf != NULL; 0 if peer == NULL */
13374664626SKris Kennaway     size_t offset;              /* valid iff buf != NULL; 0 if len == 0 */
13474664626SKris Kennaway     size_t size;
13574664626SKris Kennaway     char *buf;                  /* "size" elements (if != NULL) */
13674664626SKris Kennaway     size_t request;             /* valid iff peer != NULL; 0 if len != 0,
13774664626SKris Kennaway                                  * otherwise set by peer to number of bytes
1386f9291ceSJung-uk Kim                                  * it (unsuccessfully) tried to read, never
1396f9291ceSJung-uk Kim                                  * more than buffer space (size-len)
1406f9291ceSJung-uk Kim                                  * warrants. */
14174664626SKris Kennaway };
14274664626SKris Kennaway 
14374664626SKris Kennaway static int bio_new(BIO *bio)
14474664626SKris Kennaway {
14574664626SKris Kennaway     struct bio_bio_st *b;
14674664626SKris Kennaway 
147ddd58736SKris Kennaway     b = OPENSSL_malloc(sizeof *b);
14874664626SKris Kennaway     if (b == NULL)
14974664626SKris Kennaway         return 0;
15074664626SKris Kennaway 
15174664626SKris Kennaway     b->peer = NULL;
152*aeb5019cSJung-uk Kim     b->closed = 0;
153*aeb5019cSJung-uk Kim     b->len = 0;
154*aeb5019cSJung-uk Kim     b->offset = 0;
1556f9291ceSJung-uk Kim     /* enough for one TLS record (just a default) */
1566f9291ceSJung-uk Kim     b->size = 17 * 1024;
15774664626SKris Kennaway     b->buf = NULL;
158*aeb5019cSJung-uk Kim     b->request = 0;
15974664626SKris Kennaway 
16074664626SKris Kennaway     bio->ptr = b;
16174664626SKris Kennaway     return 1;
16274664626SKris Kennaway }
16374664626SKris Kennaway 
16474664626SKris Kennaway static int bio_free(BIO *bio)
16574664626SKris Kennaway {
16674664626SKris Kennaway     struct bio_bio_st *b;
16774664626SKris Kennaway 
16874664626SKris Kennaway     if (bio == NULL)
16974664626SKris Kennaway         return 0;
17074664626SKris Kennaway     b = bio->ptr;
17174664626SKris Kennaway 
17274664626SKris Kennaway     assert(b != NULL);
17374664626SKris Kennaway 
17474664626SKris Kennaway     if (b->peer)
17574664626SKris Kennaway         bio_destroy_pair(bio);
17674664626SKris Kennaway 
1776f9291ceSJung-uk Kim     if (b->buf != NULL) {
178ddd58736SKris Kennaway         OPENSSL_free(b->buf);
17974664626SKris Kennaway     }
18074664626SKris Kennaway 
181ddd58736SKris Kennaway     OPENSSL_free(b);
18274664626SKris Kennaway 
18374664626SKris Kennaway     return 1;
18474664626SKris Kennaway }
18574664626SKris Kennaway 
18674664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size_)
18774664626SKris Kennaway {
18874664626SKris Kennaway     size_t size = size_;
18974664626SKris Kennaway     size_t rest;
19074664626SKris Kennaway     struct bio_bio_st *b, *peer_b;
19174664626SKris Kennaway 
19274664626SKris Kennaway     BIO_clear_retry_flags(bio);
19374664626SKris Kennaway 
19474664626SKris Kennaway     if (!bio->init)
19574664626SKris Kennaway         return 0;
19674664626SKris Kennaway 
19774664626SKris Kennaway     b = bio->ptr;
19874664626SKris Kennaway     assert(b != NULL);
19974664626SKris Kennaway     assert(b->peer != NULL);
20074664626SKris Kennaway     peer_b = b->peer->ptr;
20174664626SKris Kennaway     assert(peer_b != NULL);
20274664626SKris Kennaway     assert(peer_b->buf != NULL);
20374664626SKris Kennaway 
20474664626SKris Kennaway     peer_b->request = 0;        /* will be set in "retry_read" situation */
20574664626SKris Kennaway 
20674664626SKris Kennaway     if (buf == NULL || size == 0)
20774664626SKris Kennaway         return 0;
20874664626SKris Kennaway 
2096f9291ceSJung-uk Kim     if (peer_b->len == 0) {
21074664626SKris Kennaway         if (peer_b->closed)
21174664626SKris Kennaway             return 0;           /* writer has closed, and no data is left */
2126f9291ceSJung-uk Kim         else {
21374664626SKris Kennaway             BIO_set_retry_read(bio); /* buffer is empty */
21474664626SKris Kennaway             if (size <= peer_b->size)
21574664626SKris Kennaway                 peer_b->request = size;
21674664626SKris Kennaway             else
2176f9291ceSJung-uk Kim                 /*
2186f9291ceSJung-uk Kim                  * don't ask for more than the peer can deliver in one write
2196f9291ceSJung-uk Kim                  */
22074664626SKris Kennaway                 peer_b->request = peer_b->size;
22174664626SKris Kennaway             return -1;
22274664626SKris Kennaway         }
22374664626SKris Kennaway     }
22474664626SKris Kennaway 
22574664626SKris Kennaway     /* we can read */
22674664626SKris Kennaway     if (peer_b->len < size)
22774664626SKris Kennaway         size = peer_b->len;
22874664626SKris Kennaway 
22974664626SKris Kennaway     /* now read "size" bytes */
23074664626SKris Kennaway 
23174664626SKris Kennaway     rest = size;
23274664626SKris Kennaway 
23374664626SKris Kennaway     assert(rest > 0);
2346f9291ceSJung-uk Kim     do {                        /* one or two iterations */
23574664626SKris Kennaway         size_t chunk;
23674664626SKris Kennaway 
23774664626SKris Kennaway         assert(rest <= peer_b->len);
23874664626SKris Kennaway         if (peer_b->offset + rest <= peer_b->size)
23974664626SKris Kennaway             chunk = rest;
24074664626SKris Kennaway         else
24174664626SKris Kennaway             /* wrap around ring buffer */
24274664626SKris Kennaway             chunk = peer_b->size - peer_b->offset;
24374664626SKris Kennaway         assert(peer_b->offset + chunk <= peer_b->size);
24474664626SKris Kennaway 
24574664626SKris Kennaway         memcpy(buf, peer_b->buf + peer_b->offset, chunk);
24674664626SKris Kennaway 
24774664626SKris Kennaway         peer_b->len -= chunk;
2486f9291ceSJung-uk Kim         if (peer_b->len) {
24974664626SKris Kennaway             peer_b->offset += chunk;
25074664626SKris Kennaway             assert(peer_b->offset <= peer_b->size);
25174664626SKris Kennaway             if (peer_b->offset == peer_b->size)
25274664626SKris Kennaway                 peer_b->offset = 0;
25374664626SKris Kennaway             buf += chunk;
2546f9291ceSJung-uk Kim         } else {
25574664626SKris Kennaway             /* buffer now empty, no need to advance "buf" */
25674664626SKris Kennaway             assert(chunk == rest);
25774664626SKris Kennaway             peer_b->offset = 0;
25874664626SKris Kennaway         }
25974664626SKris Kennaway         rest -= chunk;
26074664626SKris Kennaway     }
26174664626SKris Kennaway     while (rest);
26274664626SKris Kennaway 
26374664626SKris Kennaway     return size;
26474664626SKris Kennaway }
26574664626SKris Kennaway 
2666f9291ceSJung-uk Kim /*-
2676f9291ceSJung-uk Kim  * non-copying interface: provide pointer to available data in buffer
268f579bf8eSKris Kennaway  *    bio_nread0:  return number of available bytes
269f579bf8eSKris Kennaway  *    bio_nread:   also advance index
270f579bf8eSKris Kennaway  * (example usage:  bio_nread0(), read from buffer, bio_nread()
271f579bf8eSKris Kennaway  *  or just         bio_nread(), read from buffer)
272f579bf8eSKris Kennaway  */
2736f9291ceSJung-uk Kim /*
2746f9291ceSJung-uk Kim  * WARNING: The non-copying interface is largely untested as of yet and may
2756f9291ceSJung-uk Kim  * contain bugs.
2766f9291ceSJung-uk Kim  */
2771f13597dSJung-uk Kim static ossl_ssize_t bio_nread0(BIO *bio, char **buf)
278f579bf8eSKris Kennaway {
279f579bf8eSKris Kennaway     struct bio_bio_st *b, *peer_b;
2801f13597dSJung-uk Kim     ossl_ssize_t num;
281f579bf8eSKris Kennaway 
282f579bf8eSKris Kennaway     BIO_clear_retry_flags(bio);
283f579bf8eSKris Kennaway 
284f579bf8eSKris Kennaway     if (!bio->init)
285f579bf8eSKris Kennaway         return 0;
286f579bf8eSKris Kennaway 
287f579bf8eSKris Kennaway     b = bio->ptr;
288f579bf8eSKris Kennaway     assert(b != NULL);
289f579bf8eSKris Kennaway     assert(b->peer != NULL);
290f579bf8eSKris Kennaway     peer_b = b->peer->ptr;
291f579bf8eSKris Kennaway     assert(peer_b != NULL);
292f579bf8eSKris Kennaway     assert(peer_b->buf != NULL);
293f579bf8eSKris Kennaway 
294f579bf8eSKris Kennaway     peer_b->request = 0;
295f579bf8eSKris Kennaway 
2966f9291ceSJung-uk Kim     if (peer_b->len == 0) {
297f579bf8eSKris Kennaway         char dummy;
298f579bf8eSKris Kennaway 
299f579bf8eSKris Kennaway         /* avoid code duplication -- nothing available for reading */
300f579bf8eSKris Kennaway         return bio_read(bio, &dummy, 1); /* returns 0 or -1 */
301f579bf8eSKris Kennaway     }
302f579bf8eSKris Kennaway 
303f579bf8eSKris Kennaway     num = peer_b->len;
304f579bf8eSKris Kennaway     if (peer_b->size < peer_b->offset + num)
305f579bf8eSKris Kennaway         /* no ring buffer wrap-around for non-copying interface */
306f579bf8eSKris Kennaway         num = peer_b->size - peer_b->offset;
307f579bf8eSKris Kennaway     assert(num > 0);
308f579bf8eSKris Kennaway 
309f579bf8eSKris Kennaway     if (buf != NULL)
310f579bf8eSKris Kennaway         *buf = peer_b->buf + peer_b->offset;
311f579bf8eSKris Kennaway     return num;
312f579bf8eSKris Kennaway }
313f579bf8eSKris Kennaway 
3141f13597dSJung-uk Kim static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_)
315f579bf8eSKris Kennaway {
316f579bf8eSKris Kennaway     struct bio_bio_st *b, *peer_b;
3171f13597dSJung-uk Kim     ossl_ssize_t num, available;
318f579bf8eSKris Kennaway 
319f579bf8eSKris Kennaway     if (num_ > SSIZE_MAX)
320f579bf8eSKris Kennaway         num = SSIZE_MAX;
321f579bf8eSKris Kennaway     else
3221f13597dSJung-uk Kim         num = (ossl_ssize_t) num_;
323f579bf8eSKris Kennaway 
324f579bf8eSKris Kennaway     available = bio_nread0(bio, buf);
325f579bf8eSKris Kennaway     if (num > available)
326f579bf8eSKris Kennaway         num = available;
327f579bf8eSKris Kennaway     if (num <= 0)
328f579bf8eSKris Kennaway         return num;
329f579bf8eSKris Kennaway 
330f579bf8eSKris Kennaway     b = bio->ptr;
331f579bf8eSKris Kennaway     peer_b = b->peer->ptr;
332f579bf8eSKris Kennaway 
333f579bf8eSKris Kennaway     peer_b->len -= num;
3346f9291ceSJung-uk Kim     if (peer_b->len) {
335f579bf8eSKris Kennaway         peer_b->offset += num;
336f579bf8eSKris Kennaway         assert(peer_b->offset <= peer_b->size);
337f579bf8eSKris Kennaway         if (peer_b->offset == peer_b->size)
338f579bf8eSKris Kennaway             peer_b->offset = 0;
3396f9291ceSJung-uk Kim     } else
340f579bf8eSKris Kennaway         peer_b->offset = 0;
341f579bf8eSKris Kennaway 
342f579bf8eSKris Kennaway     return num;
343f579bf8eSKris Kennaway }
344f579bf8eSKris Kennaway 
345ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num_)
34674664626SKris Kennaway {
34774664626SKris Kennaway     size_t num = num_;
34874664626SKris Kennaway     size_t rest;
34974664626SKris Kennaway     struct bio_bio_st *b;
35074664626SKris Kennaway 
35174664626SKris Kennaway     BIO_clear_retry_flags(bio);
35274664626SKris Kennaway 
35374664626SKris Kennaway     if (!bio->init || buf == NULL || num == 0)
35474664626SKris Kennaway         return 0;
35574664626SKris Kennaway 
35674664626SKris Kennaway     b = bio->ptr;
35774664626SKris Kennaway     assert(b != NULL);
35874664626SKris Kennaway     assert(b->peer != NULL);
35974664626SKris Kennaway     assert(b->buf != NULL);
36074664626SKris Kennaway 
36174664626SKris Kennaway     b->request = 0;
3626f9291ceSJung-uk Kim     if (b->closed) {
36374664626SKris Kennaway         /* we already closed */
36474664626SKris Kennaway         BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
36574664626SKris Kennaway         return -1;
36674664626SKris Kennaway     }
36774664626SKris Kennaway 
36874664626SKris Kennaway     assert(b->len <= b->size);
36974664626SKris Kennaway 
3706f9291ceSJung-uk Kim     if (b->len == b->size) {
37174664626SKris Kennaway         BIO_set_retry_write(bio); /* buffer is full */
37274664626SKris Kennaway         return -1;
37374664626SKris Kennaway     }
37474664626SKris Kennaway 
37574664626SKris Kennaway     /* we can write */
37674664626SKris Kennaway     if (num > b->size - b->len)
37774664626SKris Kennaway         num = b->size - b->len;
37874664626SKris Kennaway 
37974664626SKris Kennaway     /* now write "num" bytes */
38074664626SKris Kennaway 
38174664626SKris Kennaway     rest = num;
38274664626SKris Kennaway 
38374664626SKris Kennaway     assert(rest > 0);
3846f9291ceSJung-uk Kim     do {                        /* one or two iterations */
38574664626SKris Kennaway         size_t write_offset;
38674664626SKris Kennaway         size_t chunk;
38774664626SKris Kennaway 
38874664626SKris Kennaway         assert(b->len + rest <= b->size);
38974664626SKris Kennaway 
39074664626SKris Kennaway         write_offset = b->offset + b->len;
39174664626SKris Kennaway         if (write_offset >= b->size)
39274664626SKris Kennaway             write_offset -= b->size;
39374664626SKris Kennaway         /* b->buf[write_offset] is the first byte we can write to. */
39474664626SKris Kennaway 
39574664626SKris Kennaway         if (write_offset + rest <= b->size)
39674664626SKris Kennaway             chunk = rest;
39774664626SKris Kennaway         else
39874664626SKris Kennaway             /* wrap around ring buffer */
39974664626SKris Kennaway             chunk = b->size - write_offset;
40074664626SKris Kennaway 
40174664626SKris Kennaway         memcpy(b->buf + write_offset, buf, chunk);
40274664626SKris Kennaway 
40374664626SKris Kennaway         b->len += chunk;
40474664626SKris Kennaway 
40574664626SKris Kennaway         assert(b->len <= b->size);
40674664626SKris Kennaway 
40774664626SKris Kennaway         rest -= chunk;
40874664626SKris Kennaway         buf += chunk;
40974664626SKris Kennaway     }
41074664626SKris Kennaway     while (rest);
41174664626SKris Kennaway 
41274664626SKris Kennaway     return num;
41374664626SKris Kennaway }
41474664626SKris Kennaway 
4156f9291ceSJung-uk Kim /*-
4166f9291ceSJung-uk Kim  * non-copying interface: provide pointer to region to write to
417f579bf8eSKris Kennaway  *   bio_nwrite0:  check how much space is available
418f579bf8eSKris Kennaway  *   bio_nwrite:   also increase length
419f579bf8eSKris Kennaway  * (example usage:  bio_nwrite0(), write to buffer, bio_nwrite()
420f579bf8eSKris Kennaway  *  or just         bio_nwrite(), write to buffer)
421f579bf8eSKris Kennaway  */
4221f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf)
423f579bf8eSKris Kennaway {
424f579bf8eSKris Kennaway     struct bio_bio_st *b;
425f579bf8eSKris Kennaway     size_t num;
426f579bf8eSKris Kennaway     size_t write_offset;
427f579bf8eSKris Kennaway 
428f579bf8eSKris Kennaway     BIO_clear_retry_flags(bio);
429f579bf8eSKris Kennaway 
430f579bf8eSKris Kennaway     if (!bio->init)
431f579bf8eSKris Kennaway         return 0;
432f579bf8eSKris Kennaway 
433f579bf8eSKris Kennaway     b = bio->ptr;
434f579bf8eSKris Kennaway     assert(b != NULL);
435f579bf8eSKris Kennaway     assert(b->peer != NULL);
436f579bf8eSKris Kennaway     assert(b->buf != NULL);
437f579bf8eSKris Kennaway 
438f579bf8eSKris Kennaway     b->request = 0;
4396f9291ceSJung-uk Kim     if (b->closed) {
440f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE);
441f579bf8eSKris Kennaway         return -1;
442f579bf8eSKris Kennaway     }
443f579bf8eSKris Kennaway 
444f579bf8eSKris Kennaway     assert(b->len <= b->size);
445f579bf8eSKris Kennaway 
4466f9291ceSJung-uk Kim     if (b->len == b->size) {
447f579bf8eSKris Kennaway         BIO_set_retry_write(bio);
448f579bf8eSKris Kennaway         return -1;
449f579bf8eSKris Kennaway     }
450f579bf8eSKris Kennaway 
451f579bf8eSKris Kennaway     num = b->size - b->len;
452f579bf8eSKris Kennaway     write_offset = b->offset + b->len;
453f579bf8eSKris Kennaway     if (write_offset >= b->size)
454f579bf8eSKris Kennaway         write_offset -= b->size;
455f579bf8eSKris Kennaway     if (write_offset + num > b->size)
4566f9291ceSJung-uk Kim         /*
4576f9291ceSJung-uk Kim          * no ring buffer wrap-around for non-copying interface (to fulfil
4586f9291ceSJung-uk Kim          * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have
4596f9291ceSJung-uk Kim          * to be called twice)
4606f9291ceSJung-uk Kim          */
461f579bf8eSKris Kennaway         num = b->size - write_offset;
462f579bf8eSKris Kennaway 
463f579bf8eSKris Kennaway     if (buf != NULL)
464f579bf8eSKris Kennaway         *buf = b->buf + write_offset;
465f579bf8eSKris Kennaway     assert(write_offset + num <= b->size);
466f579bf8eSKris Kennaway 
467f579bf8eSKris Kennaway     return num;
468f579bf8eSKris Kennaway }
469f579bf8eSKris Kennaway 
4701f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_)
471f579bf8eSKris Kennaway {
472f579bf8eSKris Kennaway     struct bio_bio_st *b;
4731f13597dSJung-uk Kim     ossl_ssize_t num, space;
474f579bf8eSKris Kennaway 
475f579bf8eSKris Kennaway     if (num_ > SSIZE_MAX)
476f579bf8eSKris Kennaway         num = SSIZE_MAX;
477f579bf8eSKris Kennaway     else
4781f13597dSJung-uk Kim         num = (ossl_ssize_t) num_;
479f579bf8eSKris Kennaway 
480f579bf8eSKris Kennaway     space = bio_nwrite0(bio, buf);
481f579bf8eSKris Kennaway     if (num > space)
482f579bf8eSKris Kennaway         num = space;
483f579bf8eSKris Kennaway     if (num <= 0)
484f579bf8eSKris Kennaway         return num;
485f579bf8eSKris Kennaway     b = bio->ptr;
486f579bf8eSKris Kennaway     assert(b != NULL);
487f579bf8eSKris Kennaway     b->len += num;
488f579bf8eSKris Kennaway     assert(b->len <= b->size);
489f579bf8eSKris Kennaway 
490f579bf8eSKris Kennaway     return num;
491f579bf8eSKris Kennaway }
492f579bf8eSKris Kennaway 
49374664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
49474664626SKris Kennaway {
49574664626SKris Kennaway     long ret;
49674664626SKris Kennaway     struct bio_bio_st *b = bio->ptr;
49774664626SKris Kennaway 
49874664626SKris Kennaway     assert(b != NULL);
49974664626SKris Kennaway 
5006f9291ceSJung-uk Kim     switch (cmd) {
50174664626SKris Kennaway         /* specific CTRL codes */
50274664626SKris Kennaway 
50374664626SKris Kennaway     case BIO_C_SET_WRITE_BUF_SIZE:
5046f9291ceSJung-uk Kim         if (b->peer) {
50574664626SKris Kennaway             BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE);
50674664626SKris Kennaway             ret = 0;
5076f9291ceSJung-uk Kim         } else if (num == 0) {
50874664626SKris Kennaway             BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT);
50974664626SKris Kennaway             ret = 0;
5106f9291ceSJung-uk Kim         } else {
51174664626SKris Kennaway             size_t new_size = num;
51274664626SKris Kennaway 
5136f9291ceSJung-uk Kim             if (b->size != new_size) {
5146f9291ceSJung-uk Kim                 if (b->buf) {
515ddd58736SKris Kennaway                     OPENSSL_free(b->buf);
51674664626SKris Kennaway                     b->buf = NULL;
51774664626SKris Kennaway                 }
51874664626SKris Kennaway                 b->size = new_size;
51974664626SKris Kennaway             }
52074664626SKris Kennaway             ret = 1;
52174664626SKris Kennaway         }
52274664626SKris Kennaway         break;
52374664626SKris Kennaway 
52474664626SKris Kennaway     case BIO_C_GET_WRITE_BUF_SIZE:
525a21b1b38SKris Kennaway         ret = (long)b->size;
526a21b1b38SKris Kennaway         break;
52774664626SKris Kennaway 
52874664626SKris Kennaway     case BIO_C_MAKE_BIO_PAIR:
52974664626SKris Kennaway         {
53074664626SKris Kennaway             BIO *other_bio = ptr;
53174664626SKris Kennaway 
53274664626SKris Kennaway             if (bio_make_pair(bio, other_bio))
53374664626SKris Kennaway                 ret = 1;
53474664626SKris Kennaway             else
53574664626SKris Kennaway                 ret = 0;
53674664626SKris Kennaway         }
53774664626SKris Kennaway         break;
53874664626SKris Kennaway 
53974664626SKris Kennaway     case BIO_C_DESTROY_BIO_PAIR:
5406f9291ceSJung-uk Kim         /*
5416f9291ceSJung-uk Kim          * Affects both BIOs in the pair -- call just once! Or let
5426f9291ceSJung-uk Kim          * BIO_free(bio1); BIO_free(bio2); do the job.
5436f9291ceSJung-uk Kim          */
54474664626SKris Kennaway         bio_destroy_pair(bio);
54574664626SKris Kennaway         ret = 1;
54674664626SKris Kennaway         break;
54774664626SKris Kennaway 
54874664626SKris Kennaway     case BIO_C_GET_WRITE_GUARANTEE:
5496f9291ceSJung-uk Kim         /*
5506f9291ceSJung-uk Kim          * How many bytes can the caller feed to the next write without
5516f9291ceSJung-uk Kim          * having to keep any?
5526f9291ceSJung-uk Kim          */
55374664626SKris Kennaway         if (b->peer == NULL || b->closed)
55474664626SKris Kennaway             ret = 0;
55574664626SKris Kennaway         else
55674664626SKris Kennaway             ret = (long)b->size - b->len;
55774664626SKris Kennaway         break;
55874664626SKris Kennaway 
55974664626SKris Kennaway     case BIO_C_GET_READ_REQUEST:
5606f9291ceSJung-uk Kim         /*
5616f9291ceSJung-uk Kim          * If the peer unsuccessfully tried to read, how many bytes were
5626f9291ceSJung-uk Kim          * requested? (As with BIO_CTRL_PENDING, that number can usually be
5636f9291ceSJung-uk Kim          * treated as boolean.)
5646f9291ceSJung-uk Kim          */
56574664626SKris Kennaway         ret = (long)b->request;
56674664626SKris Kennaway         break;
56774664626SKris Kennaway 
568f579bf8eSKris Kennaway     case BIO_C_RESET_READ_REQUEST:
5696f9291ceSJung-uk Kim         /*
5706f9291ceSJung-uk Kim          * Reset request.  (Can be useful after read attempts at the other
5716f9291ceSJung-uk Kim          * side that are meant to be non-blocking, e.g. when probing SSL_read
5726f9291ceSJung-uk Kim          * to see if any data is available.)
5736f9291ceSJung-uk Kim          */
574f579bf8eSKris Kennaway         b->request = 0;
575f579bf8eSKris Kennaway         ret = 1;
576f579bf8eSKris Kennaway         break;
577f579bf8eSKris Kennaway 
57874664626SKris Kennaway     case BIO_C_SHUTDOWN_WR:
57974664626SKris Kennaway         /* similar to shutdown(..., SHUT_WR) */
58074664626SKris Kennaway         b->closed = 1;
58174664626SKris Kennaway         ret = 1;
58274664626SKris Kennaway         break;
58374664626SKris Kennaway 
584f579bf8eSKris Kennaway     case BIO_C_NREAD0:
585f579bf8eSKris Kennaway         /* prepare for non-copying read */
586f579bf8eSKris Kennaway         ret = (long)bio_nread0(bio, ptr);
587f579bf8eSKris Kennaway         break;
588f579bf8eSKris Kennaway 
589f579bf8eSKris Kennaway     case BIO_C_NREAD:
590f579bf8eSKris Kennaway         /* non-copying read */
591f579bf8eSKris Kennaway         ret = (long)bio_nread(bio, ptr, (size_t)num);
592f579bf8eSKris Kennaway         break;
593f579bf8eSKris Kennaway 
594f579bf8eSKris Kennaway     case BIO_C_NWRITE0:
595f579bf8eSKris Kennaway         /* prepare for non-copying write */
596f579bf8eSKris Kennaway         ret = (long)bio_nwrite0(bio, ptr);
597f579bf8eSKris Kennaway         break;
598f579bf8eSKris Kennaway 
599f579bf8eSKris Kennaway     case BIO_C_NWRITE:
600f579bf8eSKris Kennaway         /* non-copying write */
601f579bf8eSKris Kennaway         ret = (long)bio_nwrite(bio, ptr, (size_t)num);
602f579bf8eSKris Kennaway         break;
603f579bf8eSKris Kennaway 
60474664626SKris Kennaway         /* standard CTRL codes follow */
60574664626SKris Kennaway 
60674664626SKris Kennaway     case BIO_CTRL_RESET:
6076f9291ceSJung-uk Kim         if (b->buf != NULL) {
60874664626SKris Kennaway             b->len = 0;
60974664626SKris Kennaway             b->offset = 0;
61074664626SKris Kennaway         }
61174664626SKris Kennaway         ret = 0;
61274664626SKris Kennaway         break;
61374664626SKris Kennaway 
61474664626SKris Kennaway     case BIO_CTRL_GET_CLOSE:
61574664626SKris Kennaway         ret = bio->shutdown;
61674664626SKris Kennaway         break;
61774664626SKris Kennaway 
61874664626SKris Kennaway     case BIO_CTRL_SET_CLOSE:
61974664626SKris Kennaway         bio->shutdown = (int)num;
62074664626SKris Kennaway         ret = 1;
62174664626SKris Kennaway         break;
62274664626SKris Kennaway 
62374664626SKris Kennaway     case BIO_CTRL_PENDING:
6246f9291ceSJung-uk Kim         if (b->peer != NULL) {
62574664626SKris Kennaway             struct bio_bio_st *peer_b = b->peer->ptr;
62674664626SKris Kennaway 
62774664626SKris Kennaway             ret = (long)peer_b->len;
6286f9291ceSJung-uk Kim         } else
62974664626SKris Kennaway             ret = 0;
63074664626SKris Kennaway         break;
63174664626SKris Kennaway 
63274664626SKris Kennaway     case BIO_CTRL_WPENDING:
63374664626SKris Kennaway         if (b->buf != NULL)
63474664626SKris Kennaway             ret = (long)b->len;
63574664626SKris Kennaway         else
63674664626SKris Kennaway             ret = 0;
63774664626SKris Kennaway         break;
63874664626SKris Kennaway 
63974664626SKris Kennaway     case BIO_CTRL_DUP:
64074664626SKris Kennaway         /* See BIO_dup_chain for circumstances we have to expect. */
64174664626SKris Kennaway         {
64274664626SKris Kennaway             BIO *other_bio = ptr;
64374664626SKris Kennaway             struct bio_bio_st *other_b;
64474664626SKris Kennaway 
64574664626SKris Kennaway             assert(other_bio != NULL);
64674664626SKris Kennaway             other_b = other_bio->ptr;
64774664626SKris Kennaway             assert(other_b != NULL);
64874664626SKris Kennaway 
64974664626SKris Kennaway             assert(other_b->buf == NULL); /* other_bio is always fresh */
65074664626SKris Kennaway 
65174664626SKris Kennaway             other_b->size = b->size;
65274664626SKris Kennaway         }
65374664626SKris Kennaway 
65474664626SKris Kennaway         ret = 1;
65574664626SKris Kennaway         break;
65674664626SKris Kennaway 
65774664626SKris Kennaway     case BIO_CTRL_FLUSH:
65874664626SKris Kennaway         ret = 1;
65974664626SKris Kennaway         break;
66074664626SKris Kennaway 
66174664626SKris Kennaway     case BIO_CTRL_EOF:
662*aeb5019cSJung-uk Kim         if (b->peer != NULL) {
663*aeb5019cSJung-uk Kim             struct bio_bio_st *peer_b = b->peer->ptr;
66474664626SKris Kennaway 
665*aeb5019cSJung-uk Kim             if (peer_b->len == 0 && peer_b->closed)
666*aeb5019cSJung-uk Kim                 ret = 1;
667*aeb5019cSJung-uk Kim             else
668*aeb5019cSJung-uk Kim                 ret = 0;
669*aeb5019cSJung-uk Kim         } else {
67074664626SKris Kennaway             ret = 1;
67174664626SKris Kennaway         }
67274664626SKris Kennaway         break;
67374664626SKris Kennaway 
67474664626SKris Kennaway     default:
67574664626SKris Kennaway         ret = 0;
67674664626SKris Kennaway     }
67774664626SKris Kennaway     return ret;
67874664626SKris Kennaway }
67974664626SKris Kennaway 
680ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str)
68174664626SKris Kennaway {
68274664626SKris Kennaway     return bio_write(bio, str, strlen(str));
68374664626SKris Kennaway }
68474664626SKris Kennaway 
68574664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2)
68674664626SKris Kennaway {
68774664626SKris Kennaway     struct bio_bio_st *b1, *b2;
68874664626SKris Kennaway 
68974664626SKris Kennaway     assert(bio1 != NULL);
69074664626SKris Kennaway     assert(bio2 != NULL);
69174664626SKris Kennaway 
69274664626SKris Kennaway     b1 = bio1->ptr;
69374664626SKris Kennaway     b2 = bio2->ptr;
69474664626SKris Kennaway 
6956f9291ceSJung-uk Kim     if (b1->peer != NULL || b2->peer != NULL) {
69674664626SKris Kennaway         BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE);
69774664626SKris Kennaway         return 0;
69874664626SKris Kennaway     }
69974664626SKris Kennaway 
7006f9291ceSJung-uk Kim     if (b1->buf == NULL) {
701ddd58736SKris Kennaway         b1->buf = OPENSSL_malloc(b1->size);
7026f9291ceSJung-uk Kim         if (b1->buf == NULL) {
70374664626SKris Kennaway             BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
70474664626SKris Kennaway             return 0;
70574664626SKris Kennaway         }
70674664626SKris Kennaway         b1->len = 0;
70774664626SKris Kennaway         b1->offset = 0;
70874664626SKris Kennaway     }
70974664626SKris Kennaway 
7106f9291ceSJung-uk Kim     if (b2->buf == NULL) {
711ddd58736SKris Kennaway         b2->buf = OPENSSL_malloc(b2->size);
7126f9291ceSJung-uk Kim         if (b2->buf == NULL) {
71374664626SKris Kennaway             BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
71474664626SKris Kennaway             return 0;
71574664626SKris Kennaway         }
71674664626SKris Kennaway         b2->len = 0;
71774664626SKris Kennaway         b2->offset = 0;
71874664626SKris Kennaway     }
71974664626SKris Kennaway 
72074664626SKris Kennaway     b1->peer = bio2;
72174664626SKris Kennaway     b1->closed = 0;
72274664626SKris Kennaway     b1->request = 0;
72374664626SKris Kennaway     b2->peer = bio1;
72474664626SKris Kennaway     b2->closed = 0;
72574664626SKris Kennaway     b2->request = 0;
72674664626SKris Kennaway 
72774664626SKris Kennaway     bio1->init = 1;
72874664626SKris Kennaway     bio2->init = 1;
72974664626SKris Kennaway 
73074664626SKris Kennaway     return 1;
73174664626SKris Kennaway }
73274664626SKris Kennaway 
73374664626SKris Kennaway static void bio_destroy_pair(BIO *bio)
73474664626SKris Kennaway {
73574664626SKris Kennaway     struct bio_bio_st *b = bio->ptr;
73674664626SKris Kennaway 
7376f9291ceSJung-uk Kim     if (b != NULL) {
73874664626SKris Kennaway         BIO *peer_bio = b->peer;
73974664626SKris Kennaway 
7406f9291ceSJung-uk Kim         if (peer_bio != NULL) {
74174664626SKris Kennaway             struct bio_bio_st *peer_b = peer_bio->ptr;
74274664626SKris Kennaway 
74374664626SKris Kennaway             assert(peer_b != NULL);
74474664626SKris Kennaway             assert(peer_b->peer == bio);
74574664626SKris Kennaway 
74674664626SKris Kennaway             peer_b->peer = NULL;
74774664626SKris Kennaway             peer_bio->init = 0;
74874664626SKris Kennaway             assert(peer_b->buf != NULL);
74974664626SKris Kennaway             peer_b->len = 0;
75074664626SKris Kennaway             peer_b->offset = 0;
75174664626SKris Kennaway 
75274664626SKris Kennaway             b->peer = NULL;
75374664626SKris Kennaway             bio->init = 0;
75474664626SKris Kennaway             assert(b->buf != NULL);
75574664626SKris Kennaway             b->len = 0;
75674664626SKris Kennaway             b->offset = 0;
75774664626SKris Kennaway         }
75874664626SKris Kennaway     }
75974664626SKris Kennaway }
76074664626SKris Kennaway 
76174664626SKris Kennaway /* Exported convenience functions */
76274664626SKris Kennaway int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
76374664626SKris Kennaway                      BIO **bio2_p, size_t writebuf2)
76474664626SKris Kennaway {
76574664626SKris Kennaway     BIO *bio1 = NULL, *bio2 = NULL;
76674664626SKris Kennaway     long r;
76774664626SKris Kennaway     int ret = 0;
76874664626SKris Kennaway 
76974664626SKris Kennaway     bio1 = BIO_new(BIO_s_bio());
77074664626SKris Kennaway     if (bio1 == NULL)
77174664626SKris Kennaway         goto err;
77274664626SKris Kennaway     bio2 = BIO_new(BIO_s_bio());
77374664626SKris Kennaway     if (bio2 == NULL)
77474664626SKris Kennaway         goto err;
77574664626SKris Kennaway 
7766f9291ceSJung-uk Kim     if (writebuf1) {
77774664626SKris Kennaway         r = BIO_set_write_buf_size(bio1, writebuf1);
77874664626SKris Kennaway         if (!r)
77974664626SKris Kennaway             goto err;
78074664626SKris Kennaway     }
7816f9291ceSJung-uk Kim     if (writebuf2) {
78274664626SKris Kennaway         r = BIO_set_write_buf_size(bio2, writebuf2);
78374664626SKris Kennaway         if (!r)
78474664626SKris Kennaway             goto err;
78574664626SKris Kennaway     }
78674664626SKris Kennaway 
78774664626SKris Kennaway     r = BIO_make_bio_pair(bio1, bio2);
78874664626SKris Kennaway     if (!r)
78974664626SKris Kennaway         goto err;
79074664626SKris Kennaway     ret = 1;
79174664626SKris Kennaway 
79274664626SKris Kennaway  err:
7936f9291ceSJung-uk Kim     if (ret == 0) {
7946f9291ceSJung-uk Kim         if (bio1) {
79574664626SKris Kennaway             BIO_free(bio1);
79674664626SKris Kennaway             bio1 = NULL;
79774664626SKris Kennaway         }
7986f9291ceSJung-uk Kim         if (bio2) {
79974664626SKris Kennaway             BIO_free(bio2);
80074664626SKris Kennaway             bio2 = NULL;
80174664626SKris Kennaway         }
80274664626SKris Kennaway     }
80374664626SKris Kennaway 
80474664626SKris Kennaway     *bio1_p = bio1;
80574664626SKris Kennaway     *bio2_p = bio2;
80674664626SKris Kennaway     return ret;
80774664626SKris Kennaway }
80874664626SKris Kennaway 
80974664626SKris Kennaway size_t BIO_ctrl_get_write_guarantee(BIO *bio)
81074664626SKris Kennaway {
81174664626SKris Kennaway     return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
81274664626SKris Kennaway }
81374664626SKris Kennaway 
81474664626SKris Kennaway size_t BIO_ctrl_get_read_request(BIO *bio)
81574664626SKris Kennaway {
81674664626SKris Kennaway     return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
81774664626SKris Kennaway }
818f579bf8eSKris Kennaway 
819f579bf8eSKris Kennaway int BIO_ctrl_reset_read_request(BIO *bio)
820f579bf8eSKris Kennaway {
821f579bf8eSKris Kennaway     return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0);
822f579bf8eSKris Kennaway }
823f579bf8eSKris Kennaway 
8246f9291ceSJung-uk Kim /*
8256f9291ceSJung-uk Kim  * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now
8266f9291ceSJung-uk Kim  * (conceivably some other BIOs could allow non-copying reads and writes
8276f9291ceSJung-uk Kim  * too.)
828f579bf8eSKris Kennaway  */
829f579bf8eSKris Kennaway int BIO_nread0(BIO *bio, char **buf)
830f579bf8eSKris Kennaway {
831f579bf8eSKris Kennaway     long ret;
832f579bf8eSKris Kennaway 
8336f9291ceSJung-uk Kim     if (!bio->init) {
834f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED);
835f579bf8eSKris Kennaway         return -2;
836f579bf8eSKris Kennaway     }
837f579bf8eSKris Kennaway 
838f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf);
839f579bf8eSKris Kennaway     if (ret > INT_MAX)
840f579bf8eSKris Kennaway         return INT_MAX;
841f579bf8eSKris Kennaway     else
842f579bf8eSKris Kennaway         return (int)ret;
843f579bf8eSKris Kennaway }
844f579bf8eSKris Kennaway 
845f579bf8eSKris Kennaway int BIO_nread(BIO *bio, char **buf, int num)
846f579bf8eSKris Kennaway {
847f579bf8eSKris Kennaway     int ret;
848f579bf8eSKris Kennaway 
8496f9291ceSJung-uk Kim     if (!bio->init) {
850f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED);
851f579bf8eSKris Kennaway         return -2;
852f579bf8eSKris Kennaway     }
853f579bf8eSKris Kennaway 
854f579bf8eSKris Kennaway     ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf);
855f579bf8eSKris Kennaway     if (ret > 0)
856f579bf8eSKris Kennaway         bio->num_read += ret;
857f579bf8eSKris Kennaway     return ret;
858f579bf8eSKris Kennaway }
859f579bf8eSKris Kennaway 
860f579bf8eSKris Kennaway int BIO_nwrite0(BIO *bio, char **buf)
861f579bf8eSKris Kennaway {
862f579bf8eSKris Kennaway     long ret;
863f579bf8eSKris Kennaway 
8646f9291ceSJung-uk Kim     if (!bio->init) {
865f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED);
866f579bf8eSKris Kennaway         return -2;
867f579bf8eSKris Kennaway     }
868f579bf8eSKris Kennaway 
869f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf);
870f579bf8eSKris Kennaway     if (ret > INT_MAX)
871f579bf8eSKris Kennaway         return INT_MAX;
872f579bf8eSKris Kennaway     else
873f579bf8eSKris Kennaway         return (int)ret;
874f579bf8eSKris Kennaway }
875f579bf8eSKris Kennaway 
876f579bf8eSKris Kennaway int BIO_nwrite(BIO *bio, char **buf, int num)
877f579bf8eSKris Kennaway {
878f579bf8eSKris Kennaway     int ret;
879f579bf8eSKris Kennaway 
8806f9291ceSJung-uk Kim     if (!bio->init) {
881f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED);
882f579bf8eSKris Kennaway         return -2;
883f579bf8eSKris Kennaway     }
884f579bf8eSKris Kennaway 
885f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf);
886f579bf8eSKris Kennaway     if (ret > 0)
887db522d3aSSimon L. B. Nielsen         bio->num_write += ret;
888f579bf8eSKris Kennaway     return ret;
889f579bf8eSKris Kennaway }
890