xref: /freebsd/crypto/openssl/crypto/bio/bss_bio.c (revision 6f9291cea8b06d251243fd47a7234018541832a3)
174664626SKris Kennaway /* crypto/bio/bss_bio.c  -*- Mode: C; c-file-style: "eay" -*- */
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 
56*6f9291ceSJung-uk Kim /*
57*6f9291ceSJung-uk Kim  * Special method for a BIO where the other endpoint is also a BIO of this
58*6f9291ceSJung-uk Kim  * kind, handled by the same thread (i.e. the "peer" is actually ourselves,
59*6f9291ceSJung-uk Kim  * wearing a different hat). Such "BIO pairs" are mainly for using the SSL
60*6f9291ceSJung-uk Kim  * library with I/O interfaces for which no specific BIO method is available.
61*6f9291ceSJung-uk Kim  * See ssl/ssltest.c for some hints on how this can be used.
62*6f9291ceSJung-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 
107*6f9291ceSJung-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 
125*6f9291ceSJung-uk Kim struct bio_bio_st {
126*6f9291ceSJung-uk Kim     BIO *peer;                  /* NULL if buf == NULL. If peer != NULL, then
127*6f9291ceSJung-uk Kim                                  * peer->ptr is also a bio_bio_st, and its
128*6f9291ceSJung-uk Kim                                  * "peer" member points back to us. peer !=
129*6f9291ceSJung-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
138*6f9291ceSJung-uk Kim                                  * it (unsuccessfully) tried to read, never
139*6f9291ceSJung-uk Kim                                  * more than buffer space (size-len)
140*6f9291ceSJung-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*6f9291ceSJung-uk Kim     /* enough for one TLS record (just a default) */
153*6f9291ceSJung-uk Kim     b->size = 17 * 1024;
15474664626SKris Kennaway     b->buf = NULL;
15574664626SKris Kennaway 
15674664626SKris Kennaway     bio->ptr = b;
15774664626SKris Kennaway     return 1;
15874664626SKris Kennaway }
15974664626SKris Kennaway 
16074664626SKris Kennaway static int bio_free(BIO *bio)
16174664626SKris Kennaway {
16274664626SKris Kennaway     struct bio_bio_st *b;
16374664626SKris Kennaway 
16474664626SKris Kennaway     if (bio == NULL)
16574664626SKris Kennaway         return 0;
16674664626SKris Kennaway     b = bio->ptr;
16774664626SKris Kennaway 
16874664626SKris Kennaway     assert(b != NULL);
16974664626SKris Kennaway 
17074664626SKris Kennaway     if (b->peer)
17174664626SKris Kennaway         bio_destroy_pair(bio);
17274664626SKris Kennaway 
173*6f9291ceSJung-uk Kim     if (b->buf != NULL) {
174ddd58736SKris Kennaway         OPENSSL_free(b->buf);
17574664626SKris Kennaway     }
17674664626SKris Kennaway 
177ddd58736SKris Kennaway     OPENSSL_free(b);
17874664626SKris Kennaway 
17974664626SKris Kennaway     return 1;
18074664626SKris Kennaway }
18174664626SKris Kennaway 
18274664626SKris Kennaway static int bio_read(BIO *bio, char *buf, int size_)
18374664626SKris Kennaway {
18474664626SKris Kennaway     size_t size = size_;
18574664626SKris Kennaway     size_t rest;
18674664626SKris Kennaway     struct bio_bio_st *b, *peer_b;
18774664626SKris Kennaway 
18874664626SKris Kennaway     BIO_clear_retry_flags(bio);
18974664626SKris Kennaway 
19074664626SKris Kennaway     if (!bio->init)
19174664626SKris Kennaway         return 0;
19274664626SKris Kennaway 
19374664626SKris Kennaway     b = bio->ptr;
19474664626SKris Kennaway     assert(b != NULL);
19574664626SKris Kennaway     assert(b->peer != NULL);
19674664626SKris Kennaway     peer_b = b->peer->ptr;
19774664626SKris Kennaway     assert(peer_b != NULL);
19874664626SKris Kennaway     assert(peer_b->buf != NULL);
19974664626SKris Kennaway 
20074664626SKris Kennaway     peer_b->request = 0;        /* will be set in "retry_read" situation */
20174664626SKris Kennaway 
20274664626SKris Kennaway     if (buf == NULL || size == 0)
20374664626SKris Kennaway         return 0;
20474664626SKris Kennaway 
205*6f9291ceSJung-uk Kim     if (peer_b->len == 0) {
20674664626SKris Kennaway         if (peer_b->closed)
20774664626SKris Kennaway             return 0;           /* writer has closed, and no data is left */
208*6f9291ceSJung-uk Kim         else {
20974664626SKris Kennaway             BIO_set_retry_read(bio); /* buffer is empty */
21074664626SKris Kennaway             if (size <= peer_b->size)
21174664626SKris Kennaway                 peer_b->request = size;
21274664626SKris Kennaway             else
213*6f9291ceSJung-uk Kim                 /*
214*6f9291ceSJung-uk Kim                  * don't ask for more than the peer can deliver in one write
215*6f9291ceSJung-uk Kim                  */
21674664626SKris Kennaway                 peer_b->request = peer_b->size;
21774664626SKris Kennaway             return -1;
21874664626SKris Kennaway         }
21974664626SKris Kennaway     }
22074664626SKris Kennaway 
22174664626SKris Kennaway     /* we can read */
22274664626SKris Kennaway     if (peer_b->len < size)
22374664626SKris Kennaway         size = peer_b->len;
22474664626SKris Kennaway 
22574664626SKris Kennaway     /* now read "size" bytes */
22674664626SKris Kennaway 
22774664626SKris Kennaway     rest = size;
22874664626SKris Kennaway 
22974664626SKris Kennaway     assert(rest > 0);
230*6f9291ceSJung-uk Kim     do {                        /* one or two iterations */
23174664626SKris Kennaway         size_t chunk;
23274664626SKris Kennaway 
23374664626SKris Kennaway         assert(rest <= peer_b->len);
23474664626SKris Kennaway         if (peer_b->offset + rest <= peer_b->size)
23574664626SKris Kennaway             chunk = rest;
23674664626SKris Kennaway         else
23774664626SKris Kennaway             /* wrap around ring buffer */
23874664626SKris Kennaway             chunk = peer_b->size - peer_b->offset;
23974664626SKris Kennaway         assert(peer_b->offset + chunk <= peer_b->size);
24074664626SKris Kennaway 
24174664626SKris Kennaway         memcpy(buf, peer_b->buf + peer_b->offset, chunk);
24274664626SKris Kennaway 
24374664626SKris Kennaway         peer_b->len -= chunk;
244*6f9291ceSJung-uk Kim         if (peer_b->len) {
24574664626SKris Kennaway             peer_b->offset += chunk;
24674664626SKris Kennaway             assert(peer_b->offset <= peer_b->size);
24774664626SKris Kennaway             if (peer_b->offset == peer_b->size)
24874664626SKris Kennaway                 peer_b->offset = 0;
24974664626SKris Kennaway             buf += chunk;
250*6f9291ceSJung-uk Kim         } else {
25174664626SKris Kennaway             /* buffer now empty, no need to advance "buf" */
25274664626SKris Kennaway             assert(chunk == rest);
25374664626SKris Kennaway             peer_b->offset = 0;
25474664626SKris Kennaway         }
25574664626SKris Kennaway         rest -= chunk;
25674664626SKris Kennaway     }
25774664626SKris Kennaway     while (rest);
25874664626SKris Kennaway 
25974664626SKris Kennaway     return size;
26074664626SKris Kennaway }
26174664626SKris Kennaway 
262*6f9291ceSJung-uk Kim /*-
263*6f9291ceSJung-uk Kim  * non-copying interface: provide pointer to available data in buffer
264f579bf8eSKris Kennaway  *    bio_nread0:  return number of available bytes
265f579bf8eSKris Kennaway  *    bio_nread:   also advance index
266f579bf8eSKris Kennaway  * (example usage:  bio_nread0(), read from buffer, bio_nread()
267f579bf8eSKris Kennaway  *  or just         bio_nread(), read from buffer)
268f579bf8eSKris Kennaway  */
269*6f9291ceSJung-uk Kim /*
270*6f9291ceSJung-uk Kim  * WARNING: The non-copying interface is largely untested as of yet and may
271*6f9291ceSJung-uk Kim  * contain bugs.
272*6f9291ceSJung-uk Kim  */
2731f13597dSJung-uk Kim static ossl_ssize_t bio_nread0(BIO *bio, char **buf)
274f579bf8eSKris Kennaway {
275f579bf8eSKris Kennaway     struct bio_bio_st *b, *peer_b;
2761f13597dSJung-uk Kim     ossl_ssize_t num;
277f579bf8eSKris Kennaway 
278f579bf8eSKris Kennaway     BIO_clear_retry_flags(bio);
279f579bf8eSKris Kennaway 
280f579bf8eSKris Kennaway     if (!bio->init)
281f579bf8eSKris Kennaway         return 0;
282f579bf8eSKris Kennaway 
283f579bf8eSKris Kennaway     b = bio->ptr;
284f579bf8eSKris Kennaway     assert(b != NULL);
285f579bf8eSKris Kennaway     assert(b->peer != NULL);
286f579bf8eSKris Kennaway     peer_b = b->peer->ptr;
287f579bf8eSKris Kennaway     assert(peer_b != NULL);
288f579bf8eSKris Kennaway     assert(peer_b->buf != NULL);
289f579bf8eSKris Kennaway 
290f579bf8eSKris Kennaway     peer_b->request = 0;
291f579bf8eSKris Kennaway 
292*6f9291ceSJung-uk Kim     if (peer_b->len == 0) {
293f579bf8eSKris Kennaway         char dummy;
294f579bf8eSKris Kennaway 
295f579bf8eSKris Kennaway         /* avoid code duplication -- nothing available for reading */
296f579bf8eSKris Kennaway         return bio_read(bio, &dummy, 1); /* returns 0 or -1 */
297f579bf8eSKris Kennaway     }
298f579bf8eSKris Kennaway 
299f579bf8eSKris Kennaway     num = peer_b->len;
300f579bf8eSKris Kennaway     if (peer_b->size < peer_b->offset + num)
301f579bf8eSKris Kennaway         /* no ring buffer wrap-around for non-copying interface */
302f579bf8eSKris Kennaway         num = peer_b->size - peer_b->offset;
303f579bf8eSKris Kennaway     assert(num > 0);
304f579bf8eSKris Kennaway 
305f579bf8eSKris Kennaway     if (buf != NULL)
306f579bf8eSKris Kennaway         *buf = peer_b->buf + peer_b->offset;
307f579bf8eSKris Kennaway     return num;
308f579bf8eSKris Kennaway }
309f579bf8eSKris Kennaway 
3101f13597dSJung-uk Kim static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_)
311f579bf8eSKris Kennaway {
312f579bf8eSKris Kennaway     struct bio_bio_st *b, *peer_b;
3131f13597dSJung-uk Kim     ossl_ssize_t num, available;
314f579bf8eSKris Kennaway 
315f579bf8eSKris Kennaway     if (num_ > SSIZE_MAX)
316f579bf8eSKris Kennaway         num = SSIZE_MAX;
317f579bf8eSKris Kennaway     else
3181f13597dSJung-uk Kim         num = (ossl_ssize_t) num_;
319f579bf8eSKris Kennaway 
320f579bf8eSKris Kennaway     available = bio_nread0(bio, buf);
321f579bf8eSKris Kennaway     if (num > available)
322f579bf8eSKris Kennaway         num = available;
323f579bf8eSKris Kennaway     if (num <= 0)
324f579bf8eSKris Kennaway         return num;
325f579bf8eSKris Kennaway 
326f579bf8eSKris Kennaway     b = bio->ptr;
327f579bf8eSKris Kennaway     peer_b = b->peer->ptr;
328f579bf8eSKris Kennaway 
329f579bf8eSKris Kennaway     peer_b->len -= num;
330*6f9291ceSJung-uk Kim     if (peer_b->len) {
331f579bf8eSKris Kennaway         peer_b->offset += num;
332f579bf8eSKris Kennaway         assert(peer_b->offset <= peer_b->size);
333f579bf8eSKris Kennaway         if (peer_b->offset == peer_b->size)
334f579bf8eSKris Kennaway             peer_b->offset = 0;
335*6f9291ceSJung-uk Kim     } else
336f579bf8eSKris Kennaway         peer_b->offset = 0;
337f579bf8eSKris Kennaway 
338f579bf8eSKris Kennaway     return num;
339f579bf8eSKris Kennaway }
340f579bf8eSKris Kennaway 
341ddd58736SKris Kennaway static int bio_write(BIO *bio, const char *buf, int num_)
34274664626SKris Kennaway {
34374664626SKris Kennaway     size_t num = num_;
34474664626SKris Kennaway     size_t rest;
34574664626SKris Kennaway     struct bio_bio_st *b;
34674664626SKris Kennaway 
34774664626SKris Kennaway     BIO_clear_retry_flags(bio);
34874664626SKris Kennaway 
34974664626SKris Kennaway     if (!bio->init || buf == NULL || num == 0)
35074664626SKris Kennaway         return 0;
35174664626SKris Kennaway 
35274664626SKris Kennaway     b = bio->ptr;
35374664626SKris Kennaway     assert(b != NULL);
35474664626SKris Kennaway     assert(b->peer != NULL);
35574664626SKris Kennaway     assert(b->buf != NULL);
35674664626SKris Kennaway 
35774664626SKris Kennaway     b->request = 0;
358*6f9291ceSJung-uk Kim     if (b->closed) {
35974664626SKris Kennaway         /* we already closed */
36074664626SKris Kennaway         BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
36174664626SKris Kennaway         return -1;
36274664626SKris Kennaway     }
36374664626SKris Kennaway 
36474664626SKris Kennaway     assert(b->len <= b->size);
36574664626SKris Kennaway 
366*6f9291ceSJung-uk Kim     if (b->len == b->size) {
36774664626SKris Kennaway         BIO_set_retry_write(bio); /* buffer is full */
36874664626SKris Kennaway         return -1;
36974664626SKris Kennaway     }
37074664626SKris Kennaway 
37174664626SKris Kennaway     /* we can write */
37274664626SKris Kennaway     if (num > b->size - b->len)
37374664626SKris Kennaway         num = b->size - b->len;
37474664626SKris Kennaway 
37574664626SKris Kennaway     /* now write "num" bytes */
37674664626SKris Kennaway 
37774664626SKris Kennaway     rest = num;
37874664626SKris Kennaway 
37974664626SKris Kennaway     assert(rest > 0);
380*6f9291ceSJung-uk Kim     do {                        /* one or two iterations */
38174664626SKris Kennaway         size_t write_offset;
38274664626SKris Kennaway         size_t chunk;
38374664626SKris Kennaway 
38474664626SKris Kennaway         assert(b->len + rest <= b->size);
38574664626SKris Kennaway 
38674664626SKris Kennaway         write_offset = b->offset + b->len;
38774664626SKris Kennaway         if (write_offset >= b->size)
38874664626SKris Kennaway             write_offset -= b->size;
38974664626SKris Kennaway         /* b->buf[write_offset] is the first byte we can write to. */
39074664626SKris Kennaway 
39174664626SKris Kennaway         if (write_offset + rest <= b->size)
39274664626SKris Kennaway             chunk = rest;
39374664626SKris Kennaway         else
39474664626SKris Kennaway             /* wrap around ring buffer */
39574664626SKris Kennaway             chunk = b->size - write_offset;
39674664626SKris Kennaway 
39774664626SKris Kennaway         memcpy(b->buf + write_offset, buf, chunk);
39874664626SKris Kennaway 
39974664626SKris Kennaway         b->len += chunk;
40074664626SKris Kennaway 
40174664626SKris Kennaway         assert(b->len <= b->size);
40274664626SKris Kennaway 
40374664626SKris Kennaway         rest -= chunk;
40474664626SKris Kennaway         buf += chunk;
40574664626SKris Kennaway     }
40674664626SKris Kennaway     while (rest);
40774664626SKris Kennaway 
40874664626SKris Kennaway     return num;
40974664626SKris Kennaway }
41074664626SKris Kennaway 
411*6f9291ceSJung-uk Kim /*-
412*6f9291ceSJung-uk Kim  * non-copying interface: provide pointer to region to write to
413f579bf8eSKris Kennaway  *   bio_nwrite0:  check how much space is available
414f579bf8eSKris Kennaway  *   bio_nwrite:   also increase length
415f579bf8eSKris Kennaway  * (example usage:  bio_nwrite0(), write to buffer, bio_nwrite()
416f579bf8eSKris Kennaway  *  or just         bio_nwrite(), write to buffer)
417f579bf8eSKris Kennaway  */
4181f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf)
419f579bf8eSKris Kennaway {
420f579bf8eSKris Kennaway     struct bio_bio_st *b;
421f579bf8eSKris Kennaway     size_t num;
422f579bf8eSKris Kennaway     size_t write_offset;
423f579bf8eSKris Kennaway 
424f579bf8eSKris Kennaway     BIO_clear_retry_flags(bio);
425f579bf8eSKris Kennaway 
426f579bf8eSKris Kennaway     if (!bio->init)
427f579bf8eSKris Kennaway         return 0;
428f579bf8eSKris Kennaway 
429f579bf8eSKris Kennaway     b = bio->ptr;
430f579bf8eSKris Kennaway     assert(b != NULL);
431f579bf8eSKris Kennaway     assert(b->peer != NULL);
432f579bf8eSKris Kennaway     assert(b->buf != NULL);
433f579bf8eSKris Kennaway 
434f579bf8eSKris Kennaway     b->request = 0;
435*6f9291ceSJung-uk Kim     if (b->closed) {
436f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE);
437f579bf8eSKris Kennaway         return -1;
438f579bf8eSKris Kennaway     }
439f579bf8eSKris Kennaway 
440f579bf8eSKris Kennaway     assert(b->len <= b->size);
441f579bf8eSKris Kennaway 
442*6f9291ceSJung-uk Kim     if (b->len == b->size) {
443f579bf8eSKris Kennaway         BIO_set_retry_write(bio);
444f579bf8eSKris Kennaway         return -1;
445f579bf8eSKris Kennaway     }
446f579bf8eSKris Kennaway 
447f579bf8eSKris Kennaway     num = b->size - b->len;
448f579bf8eSKris Kennaway     write_offset = b->offset + b->len;
449f579bf8eSKris Kennaway     if (write_offset >= b->size)
450f579bf8eSKris Kennaway         write_offset -= b->size;
451f579bf8eSKris Kennaway     if (write_offset + num > b->size)
452*6f9291ceSJung-uk Kim         /*
453*6f9291ceSJung-uk Kim          * no ring buffer wrap-around for non-copying interface (to fulfil
454*6f9291ceSJung-uk Kim          * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have
455*6f9291ceSJung-uk Kim          * to be called twice)
456*6f9291ceSJung-uk Kim          */
457f579bf8eSKris Kennaway         num = b->size - write_offset;
458f579bf8eSKris Kennaway 
459f579bf8eSKris Kennaway     if (buf != NULL)
460f579bf8eSKris Kennaway         *buf = b->buf + write_offset;
461f579bf8eSKris Kennaway     assert(write_offset + num <= b->size);
462f579bf8eSKris Kennaway 
463f579bf8eSKris Kennaway     return num;
464f579bf8eSKris Kennaway }
465f579bf8eSKris Kennaway 
4661f13597dSJung-uk Kim static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_)
467f579bf8eSKris Kennaway {
468f579bf8eSKris Kennaway     struct bio_bio_st *b;
4691f13597dSJung-uk Kim     ossl_ssize_t num, space;
470f579bf8eSKris Kennaway 
471f579bf8eSKris Kennaway     if (num_ > SSIZE_MAX)
472f579bf8eSKris Kennaway         num = SSIZE_MAX;
473f579bf8eSKris Kennaway     else
4741f13597dSJung-uk Kim         num = (ossl_ssize_t) num_;
475f579bf8eSKris Kennaway 
476f579bf8eSKris Kennaway     space = bio_nwrite0(bio, buf);
477f579bf8eSKris Kennaway     if (num > space)
478f579bf8eSKris Kennaway         num = space;
479f579bf8eSKris Kennaway     if (num <= 0)
480f579bf8eSKris Kennaway         return num;
481f579bf8eSKris Kennaway     b = bio->ptr;
482f579bf8eSKris Kennaway     assert(b != NULL);
483f579bf8eSKris Kennaway     b->len += num;
484f579bf8eSKris Kennaway     assert(b->len <= b->size);
485f579bf8eSKris Kennaway 
486f579bf8eSKris Kennaway     return num;
487f579bf8eSKris Kennaway }
488f579bf8eSKris Kennaway 
48974664626SKris Kennaway static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
49074664626SKris Kennaway {
49174664626SKris Kennaway     long ret;
49274664626SKris Kennaway     struct bio_bio_st *b = bio->ptr;
49374664626SKris Kennaway 
49474664626SKris Kennaway     assert(b != NULL);
49574664626SKris Kennaway 
496*6f9291ceSJung-uk Kim     switch (cmd) {
49774664626SKris Kennaway         /* specific CTRL codes */
49874664626SKris Kennaway 
49974664626SKris Kennaway     case BIO_C_SET_WRITE_BUF_SIZE:
500*6f9291ceSJung-uk Kim         if (b->peer) {
50174664626SKris Kennaway             BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE);
50274664626SKris Kennaway             ret = 0;
503*6f9291ceSJung-uk Kim         } else if (num == 0) {
50474664626SKris Kennaway             BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT);
50574664626SKris Kennaway             ret = 0;
506*6f9291ceSJung-uk Kim         } else {
50774664626SKris Kennaway             size_t new_size = num;
50874664626SKris Kennaway 
509*6f9291ceSJung-uk Kim             if (b->size != new_size) {
510*6f9291ceSJung-uk Kim                 if (b->buf) {
511ddd58736SKris Kennaway                     OPENSSL_free(b->buf);
51274664626SKris Kennaway                     b->buf = NULL;
51374664626SKris Kennaway                 }
51474664626SKris Kennaway                 b->size = new_size;
51574664626SKris Kennaway             }
51674664626SKris Kennaway             ret = 1;
51774664626SKris Kennaway         }
51874664626SKris Kennaway         break;
51974664626SKris Kennaway 
52074664626SKris Kennaway     case BIO_C_GET_WRITE_BUF_SIZE:
521a21b1b38SKris Kennaway         ret = (long)b->size;
522a21b1b38SKris Kennaway         break;
52374664626SKris Kennaway 
52474664626SKris Kennaway     case BIO_C_MAKE_BIO_PAIR:
52574664626SKris Kennaway         {
52674664626SKris Kennaway             BIO *other_bio = ptr;
52774664626SKris Kennaway 
52874664626SKris Kennaway             if (bio_make_pair(bio, other_bio))
52974664626SKris Kennaway                 ret = 1;
53074664626SKris Kennaway             else
53174664626SKris Kennaway                 ret = 0;
53274664626SKris Kennaway         }
53374664626SKris Kennaway         break;
53474664626SKris Kennaway 
53574664626SKris Kennaway     case BIO_C_DESTROY_BIO_PAIR:
536*6f9291ceSJung-uk Kim         /*
537*6f9291ceSJung-uk Kim          * Affects both BIOs in the pair -- call just once! Or let
538*6f9291ceSJung-uk Kim          * BIO_free(bio1); BIO_free(bio2); do the job.
539*6f9291ceSJung-uk Kim          */
54074664626SKris Kennaway         bio_destroy_pair(bio);
54174664626SKris Kennaway         ret = 1;
54274664626SKris Kennaway         break;
54374664626SKris Kennaway 
54474664626SKris Kennaway     case BIO_C_GET_WRITE_GUARANTEE:
545*6f9291ceSJung-uk Kim         /*
546*6f9291ceSJung-uk Kim          * How many bytes can the caller feed to the next write without
547*6f9291ceSJung-uk Kim          * having to keep any?
548*6f9291ceSJung-uk Kim          */
54974664626SKris Kennaway         if (b->peer == NULL || b->closed)
55074664626SKris Kennaway             ret = 0;
55174664626SKris Kennaway         else
55274664626SKris Kennaway             ret = (long)b->size - b->len;
55374664626SKris Kennaway         break;
55474664626SKris Kennaway 
55574664626SKris Kennaway     case BIO_C_GET_READ_REQUEST:
556*6f9291ceSJung-uk Kim         /*
557*6f9291ceSJung-uk Kim          * If the peer unsuccessfully tried to read, how many bytes were
558*6f9291ceSJung-uk Kim          * requested? (As with BIO_CTRL_PENDING, that number can usually be
559*6f9291ceSJung-uk Kim          * treated as boolean.)
560*6f9291ceSJung-uk Kim          */
56174664626SKris Kennaway         ret = (long)b->request;
56274664626SKris Kennaway         break;
56374664626SKris Kennaway 
564f579bf8eSKris Kennaway     case BIO_C_RESET_READ_REQUEST:
565*6f9291ceSJung-uk Kim         /*
566*6f9291ceSJung-uk Kim          * Reset request.  (Can be useful after read attempts at the other
567*6f9291ceSJung-uk Kim          * side that are meant to be non-blocking, e.g. when probing SSL_read
568*6f9291ceSJung-uk Kim          * to see if any data is available.)
569*6f9291ceSJung-uk Kim          */
570f579bf8eSKris Kennaway         b->request = 0;
571f579bf8eSKris Kennaway         ret = 1;
572f579bf8eSKris Kennaway         break;
573f579bf8eSKris Kennaway 
57474664626SKris Kennaway     case BIO_C_SHUTDOWN_WR:
57574664626SKris Kennaway         /* similar to shutdown(..., SHUT_WR) */
57674664626SKris Kennaway         b->closed = 1;
57774664626SKris Kennaway         ret = 1;
57874664626SKris Kennaway         break;
57974664626SKris Kennaway 
580f579bf8eSKris Kennaway     case BIO_C_NREAD0:
581f579bf8eSKris Kennaway         /* prepare for non-copying read */
582f579bf8eSKris Kennaway         ret = (long)bio_nread0(bio, ptr);
583f579bf8eSKris Kennaway         break;
584f579bf8eSKris Kennaway 
585f579bf8eSKris Kennaway     case BIO_C_NREAD:
586f579bf8eSKris Kennaway         /* non-copying read */
587f579bf8eSKris Kennaway         ret = (long)bio_nread(bio, ptr, (size_t)num);
588f579bf8eSKris Kennaway         break;
589f579bf8eSKris Kennaway 
590f579bf8eSKris Kennaway     case BIO_C_NWRITE0:
591f579bf8eSKris Kennaway         /* prepare for non-copying write */
592f579bf8eSKris Kennaway         ret = (long)bio_nwrite0(bio, ptr);
593f579bf8eSKris Kennaway         break;
594f579bf8eSKris Kennaway 
595f579bf8eSKris Kennaway     case BIO_C_NWRITE:
596f579bf8eSKris Kennaway         /* non-copying write */
597f579bf8eSKris Kennaway         ret = (long)bio_nwrite(bio, ptr, (size_t)num);
598f579bf8eSKris Kennaway         break;
599f579bf8eSKris Kennaway 
60074664626SKris Kennaway         /* standard CTRL codes follow */
60174664626SKris Kennaway 
60274664626SKris Kennaway     case BIO_CTRL_RESET:
603*6f9291ceSJung-uk Kim         if (b->buf != NULL) {
60474664626SKris Kennaway             b->len = 0;
60574664626SKris Kennaway             b->offset = 0;
60674664626SKris Kennaway         }
60774664626SKris Kennaway         ret = 0;
60874664626SKris Kennaway         break;
60974664626SKris Kennaway 
61074664626SKris Kennaway     case BIO_CTRL_GET_CLOSE:
61174664626SKris Kennaway         ret = bio->shutdown;
61274664626SKris Kennaway         break;
61374664626SKris Kennaway 
61474664626SKris Kennaway     case BIO_CTRL_SET_CLOSE:
61574664626SKris Kennaway         bio->shutdown = (int)num;
61674664626SKris Kennaway         ret = 1;
61774664626SKris Kennaway         break;
61874664626SKris Kennaway 
61974664626SKris Kennaway     case BIO_CTRL_PENDING:
620*6f9291ceSJung-uk Kim         if (b->peer != NULL) {
62174664626SKris Kennaway             struct bio_bio_st *peer_b = b->peer->ptr;
62274664626SKris Kennaway 
62374664626SKris Kennaway             ret = (long)peer_b->len;
624*6f9291ceSJung-uk Kim         } else
62574664626SKris Kennaway             ret = 0;
62674664626SKris Kennaway         break;
62774664626SKris Kennaway 
62874664626SKris Kennaway     case BIO_CTRL_WPENDING:
62974664626SKris Kennaway         if (b->buf != NULL)
63074664626SKris Kennaway             ret = (long)b->len;
63174664626SKris Kennaway         else
63274664626SKris Kennaway             ret = 0;
63374664626SKris Kennaway         break;
63474664626SKris Kennaway 
63574664626SKris Kennaway     case BIO_CTRL_DUP:
63674664626SKris Kennaway         /* See BIO_dup_chain for circumstances we have to expect. */
63774664626SKris Kennaway         {
63874664626SKris Kennaway             BIO *other_bio = ptr;
63974664626SKris Kennaway             struct bio_bio_st *other_b;
64074664626SKris Kennaway 
64174664626SKris Kennaway             assert(other_bio != NULL);
64274664626SKris Kennaway             other_b = other_bio->ptr;
64374664626SKris Kennaway             assert(other_b != NULL);
64474664626SKris Kennaway 
64574664626SKris Kennaway             assert(other_b->buf == NULL); /* other_bio is always fresh */
64674664626SKris Kennaway 
64774664626SKris Kennaway             other_b->size = b->size;
64874664626SKris Kennaway         }
64974664626SKris Kennaway 
65074664626SKris Kennaway         ret = 1;
65174664626SKris Kennaway         break;
65274664626SKris Kennaway 
65374664626SKris Kennaway     case BIO_CTRL_FLUSH:
65474664626SKris Kennaway         ret = 1;
65574664626SKris Kennaway         break;
65674664626SKris Kennaway 
65774664626SKris Kennaway     case BIO_CTRL_EOF:
65874664626SKris Kennaway         {
65974664626SKris Kennaway             BIO *other_bio = ptr;
66074664626SKris Kennaway 
661*6f9291ceSJung-uk Kim             if (other_bio) {
66274664626SKris Kennaway                 struct bio_bio_st *other_b = other_bio->ptr;
66374664626SKris Kennaway 
66474664626SKris Kennaway                 assert(other_b != NULL);
66574664626SKris Kennaway                 ret = other_b->len == 0 && other_b->closed;
666*6f9291ceSJung-uk Kim             } else
66774664626SKris Kennaway                 ret = 1;
66874664626SKris Kennaway         }
66974664626SKris Kennaway         break;
67074664626SKris Kennaway 
67174664626SKris Kennaway     default:
67274664626SKris Kennaway         ret = 0;
67374664626SKris Kennaway     }
67474664626SKris Kennaway     return ret;
67574664626SKris Kennaway }
67674664626SKris Kennaway 
677ddd58736SKris Kennaway static int bio_puts(BIO *bio, const char *str)
67874664626SKris Kennaway {
67974664626SKris Kennaway     return bio_write(bio, str, strlen(str));
68074664626SKris Kennaway }
68174664626SKris Kennaway 
68274664626SKris Kennaway static int bio_make_pair(BIO *bio1, BIO *bio2)
68374664626SKris Kennaway {
68474664626SKris Kennaway     struct bio_bio_st *b1, *b2;
68574664626SKris Kennaway 
68674664626SKris Kennaway     assert(bio1 != NULL);
68774664626SKris Kennaway     assert(bio2 != NULL);
68874664626SKris Kennaway 
68974664626SKris Kennaway     b1 = bio1->ptr;
69074664626SKris Kennaway     b2 = bio2->ptr;
69174664626SKris Kennaway 
692*6f9291ceSJung-uk Kim     if (b1->peer != NULL || b2->peer != NULL) {
69374664626SKris Kennaway         BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE);
69474664626SKris Kennaway         return 0;
69574664626SKris Kennaway     }
69674664626SKris Kennaway 
697*6f9291ceSJung-uk Kim     if (b1->buf == NULL) {
698ddd58736SKris Kennaway         b1->buf = OPENSSL_malloc(b1->size);
699*6f9291ceSJung-uk Kim         if (b1->buf == NULL) {
70074664626SKris Kennaway             BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
70174664626SKris Kennaway             return 0;
70274664626SKris Kennaway         }
70374664626SKris Kennaway         b1->len = 0;
70474664626SKris Kennaway         b1->offset = 0;
70574664626SKris Kennaway     }
70674664626SKris Kennaway 
707*6f9291ceSJung-uk Kim     if (b2->buf == NULL) {
708ddd58736SKris Kennaway         b2->buf = OPENSSL_malloc(b2->size);
709*6f9291ceSJung-uk Kim         if (b2->buf == NULL) {
71074664626SKris Kennaway             BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
71174664626SKris Kennaway             return 0;
71274664626SKris Kennaway         }
71374664626SKris Kennaway         b2->len = 0;
71474664626SKris Kennaway         b2->offset = 0;
71574664626SKris Kennaway     }
71674664626SKris Kennaway 
71774664626SKris Kennaway     b1->peer = bio2;
71874664626SKris Kennaway     b1->closed = 0;
71974664626SKris Kennaway     b1->request = 0;
72074664626SKris Kennaway     b2->peer = bio1;
72174664626SKris Kennaway     b2->closed = 0;
72274664626SKris Kennaway     b2->request = 0;
72374664626SKris Kennaway 
72474664626SKris Kennaway     bio1->init = 1;
72574664626SKris Kennaway     bio2->init = 1;
72674664626SKris Kennaway 
72774664626SKris Kennaway     return 1;
72874664626SKris Kennaway }
72974664626SKris Kennaway 
73074664626SKris Kennaway static void bio_destroy_pair(BIO *bio)
73174664626SKris Kennaway {
73274664626SKris Kennaway     struct bio_bio_st *b = bio->ptr;
73374664626SKris Kennaway 
734*6f9291ceSJung-uk Kim     if (b != NULL) {
73574664626SKris Kennaway         BIO *peer_bio = b->peer;
73674664626SKris Kennaway 
737*6f9291ceSJung-uk Kim         if (peer_bio != NULL) {
73874664626SKris Kennaway             struct bio_bio_st *peer_b = peer_bio->ptr;
73974664626SKris Kennaway 
74074664626SKris Kennaway             assert(peer_b != NULL);
74174664626SKris Kennaway             assert(peer_b->peer == bio);
74274664626SKris Kennaway 
74374664626SKris Kennaway             peer_b->peer = NULL;
74474664626SKris Kennaway             peer_bio->init = 0;
74574664626SKris Kennaway             assert(peer_b->buf != NULL);
74674664626SKris Kennaway             peer_b->len = 0;
74774664626SKris Kennaway             peer_b->offset = 0;
74874664626SKris Kennaway 
74974664626SKris Kennaway             b->peer = NULL;
75074664626SKris Kennaway             bio->init = 0;
75174664626SKris Kennaway             assert(b->buf != NULL);
75274664626SKris Kennaway             b->len = 0;
75374664626SKris Kennaway             b->offset = 0;
75474664626SKris Kennaway         }
75574664626SKris Kennaway     }
75674664626SKris Kennaway }
75774664626SKris Kennaway 
75874664626SKris Kennaway /* Exported convenience functions */
75974664626SKris Kennaway int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
76074664626SKris Kennaway                      BIO **bio2_p, size_t writebuf2)
76174664626SKris Kennaway {
76274664626SKris Kennaway     BIO *bio1 = NULL, *bio2 = NULL;
76374664626SKris Kennaway     long r;
76474664626SKris Kennaway     int ret = 0;
76574664626SKris Kennaway 
76674664626SKris Kennaway     bio1 = BIO_new(BIO_s_bio());
76774664626SKris Kennaway     if (bio1 == NULL)
76874664626SKris Kennaway         goto err;
76974664626SKris Kennaway     bio2 = BIO_new(BIO_s_bio());
77074664626SKris Kennaway     if (bio2 == NULL)
77174664626SKris Kennaway         goto err;
77274664626SKris Kennaway 
773*6f9291ceSJung-uk Kim     if (writebuf1) {
77474664626SKris Kennaway         r = BIO_set_write_buf_size(bio1, writebuf1);
77574664626SKris Kennaway         if (!r)
77674664626SKris Kennaway             goto err;
77774664626SKris Kennaway     }
778*6f9291ceSJung-uk Kim     if (writebuf2) {
77974664626SKris Kennaway         r = BIO_set_write_buf_size(bio2, writebuf2);
78074664626SKris Kennaway         if (!r)
78174664626SKris Kennaway             goto err;
78274664626SKris Kennaway     }
78374664626SKris Kennaway 
78474664626SKris Kennaway     r = BIO_make_bio_pair(bio1, bio2);
78574664626SKris Kennaway     if (!r)
78674664626SKris Kennaway         goto err;
78774664626SKris Kennaway     ret = 1;
78874664626SKris Kennaway 
78974664626SKris Kennaway  err:
790*6f9291ceSJung-uk Kim     if (ret == 0) {
791*6f9291ceSJung-uk Kim         if (bio1) {
79274664626SKris Kennaway             BIO_free(bio1);
79374664626SKris Kennaway             bio1 = NULL;
79474664626SKris Kennaway         }
795*6f9291ceSJung-uk Kim         if (bio2) {
79674664626SKris Kennaway             BIO_free(bio2);
79774664626SKris Kennaway             bio2 = NULL;
79874664626SKris Kennaway         }
79974664626SKris Kennaway     }
80074664626SKris Kennaway 
80174664626SKris Kennaway     *bio1_p = bio1;
80274664626SKris Kennaway     *bio2_p = bio2;
80374664626SKris Kennaway     return ret;
80474664626SKris Kennaway }
80574664626SKris Kennaway 
80674664626SKris Kennaway size_t BIO_ctrl_get_write_guarantee(BIO *bio)
80774664626SKris Kennaway {
80874664626SKris Kennaway     return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
80974664626SKris Kennaway }
81074664626SKris Kennaway 
81174664626SKris Kennaway size_t BIO_ctrl_get_read_request(BIO *bio)
81274664626SKris Kennaway {
81374664626SKris Kennaway     return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
81474664626SKris Kennaway }
815f579bf8eSKris Kennaway 
816f579bf8eSKris Kennaway int BIO_ctrl_reset_read_request(BIO *bio)
817f579bf8eSKris Kennaway {
818f579bf8eSKris Kennaway     return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0);
819f579bf8eSKris Kennaway }
820f579bf8eSKris Kennaway 
821*6f9291ceSJung-uk Kim /*
822*6f9291ceSJung-uk Kim  * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now
823*6f9291ceSJung-uk Kim  * (conceivably some other BIOs could allow non-copying reads and writes
824*6f9291ceSJung-uk Kim  * too.)
825f579bf8eSKris Kennaway  */
826f579bf8eSKris Kennaway int BIO_nread0(BIO *bio, char **buf)
827f579bf8eSKris Kennaway {
828f579bf8eSKris Kennaway     long ret;
829f579bf8eSKris Kennaway 
830*6f9291ceSJung-uk Kim     if (!bio->init) {
831f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED);
832f579bf8eSKris Kennaway         return -2;
833f579bf8eSKris Kennaway     }
834f579bf8eSKris Kennaway 
835f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf);
836f579bf8eSKris Kennaway     if (ret > INT_MAX)
837f579bf8eSKris Kennaway         return INT_MAX;
838f579bf8eSKris Kennaway     else
839f579bf8eSKris Kennaway         return (int)ret;
840f579bf8eSKris Kennaway }
841f579bf8eSKris Kennaway 
842f579bf8eSKris Kennaway int BIO_nread(BIO *bio, char **buf, int num)
843f579bf8eSKris Kennaway {
844f579bf8eSKris Kennaway     int ret;
845f579bf8eSKris Kennaway 
846*6f9291ceSJung-uk Kim     if (!bio->init) {
847f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED);
848f579bf8eSKris Kennaway         return -2;
849f579bf8eSKris Kennaway     }
850f579bf8eSKris Kennaway 
851f579bf8eSKris Kennaway     ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf);
852f579bf8eSKris Kennaway     if (ret > 0)
853f579bf8eSKris Kennaway         bio->num_read += ret;
854f579bf8eSKris Kennaway     return ret;
855f579bf8eSKris Kennaway }
856f579bf8eSKris Kennaway 
857f579bf8eSKris Kennaway int BIO_nwrite0(BIO *bio, char **buf)
858f579bf8eSKris Kennaway {
859f579bf8eSKris Kennaway     long ret;
860f579bf8eSKris Kennaway 
861*6f9291ceSJung-uk Kim     if (!bio->init) {
862f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED);
863f579bf8eSKris Kennaway         return -2;
864f579bf8eSKris Kennaway     }
865f579bf8eSKris Kennaway 
866f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf);
867f579bf8eSKris Kennaway     if (ret > INT_MAX)
868f579bf8eSKris Kennaway         return INT_MAX;
869f579bf8eSKris Kennaway     else
870f579bf8eSKris Kennaway         return (int)ret;
871f579bf8eSKris Kennaway }
872f579bf8eSKris Kennaway 
873f579bf8eSKris Kennaway int BIO_nwrite(BIO *bio, char **buf, int num)
874f579bf8eSKris Kennaway {
875f579bf8eSKris Kennaway     int ret;
876f579bf8eSKris Kennaway 
877*6f9291ceSJung-uk Kim     if (!bio->init) {
878f579bf8eSKris Kennaway         BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED);
879f579bf8eSKris Kennaway         return -2;
880f579bf8eSKris Kennaway     }
881f579bf8eSKris Kennaway 
882f579bf8eSKris Kennaway     ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf);
883f579bf8eSKris Kennaway     if (ret > 0)
884db522d3aSSimon L. B. Nielsen         bio->num_write += ret;
885f579bf8eSKris Kennaway     return ret;
886f579bf8eSKris Kennaway }
887