1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * Special method for a BIO where the other endpoint is also a BIO of this
12e1051a39Sopenharmony_ci * kind, handled by the same thread (i.e. the "peer" is actually ourselves,
13e1051a39Sopenharmony_ci * wearing a different hat). Such "BIO pairs" are mainly for using the SSL
14e1051a39Sopenharmony_ci * library with I/O interfaces for which no specific BIO method is available.
15e1051a39Sopenharmony_ci * See ssl/ssltest.c for some hints on how this can be used.
16e1051a39Sopenharmony_ci */
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_ci#include "e_os.h"
19e1051a39Sopenharmony_ci#include <assert.h>
20e1051a39Sopenharmony_ci#include <limits.h>
21e1051a39Sopenharmony_ci#include <stdlib.h>
22e1051a39Sopenharmony_ci#include <string.h>
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci#include "bio_local.h"
25e1051a39Sopenharmony_ci#include <openssl/err.h>
26e1051a39Sopenharmony_ci#include <openssl/crypto.h>
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_cistatic int bio_new(BIO *bio);
29e1051a39Sopenharmony_cistatic int bio_free(BIO *bio);
30e1051a39Sopenharmony_cistatic int bio_read(BIO *bio, char *buf, int size);
31e1051a39Sopenharmony_cistatic int bio_write(BIO *bio, const char *buf, int num);
32e1051a39Sopenharmony_cistatic long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
33e1051a39Sopenharmony_cistatic int bio_puts(BIO *bio, const char *str);
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_cistatic int bio_make_pair(BIO *bio1, BIO *bio2);
36e1051a39Sopenharmony_cistatic void bio_destroy_pair(BIO *bio);
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_cistatic const BIO_METHOD methods_biop = {
39e1051a39Sopenharmony_ci    BIO_TYPE_BIO,
40e1051a39Sopenharmony_ci    "BIO pair",
41e1051a39Sopenharmony_ci    bwrite_conv,
42e1051a39Sopenharmony_ci    bio_write,
43e1051a39Sopenharmony_ci    bread_conv,
44e1051a39Sopenharmony_ci    bio_read,
45e1051a39Sopenharmony_ci    bio_puts,
46e1051a39Sopenharmony_ci    NULL /* no bio_gets */ ,
47e1051a39Sopenharmony_ci    bio_ctrl,
48e1051a39Sopenharmony_ci    bio_new,
49e1051a39Sopenharmony_ci    bio_free,
50e1051a39Sopenharmony_ci    NULL                        /* no bio_callback_ctrl */
51e1051a39Sopenharmony_ci};
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_bio(void)
54e1051a39Sopenharmony_ci{
55e1051a39Sopenharmony_ci    return &methods_biop;
56e1051a39Sopenharmony_ci}
57e1051a39Sopenharmony_ci
58e1051a39Sopenharmony_cistruct bio_bio_st {
59e1051a39Sopenharmony_ci    BIO *peer;                  /* NULL if buf == NULL. If peer != NULL, then
60e1051a39Sopenharmony_ci                                 * peer->ptr is also a bio_bio_st, and its
61e1051a39Sopenharmony_ci                                 * "peer" member points back to us. peer !=
62e1051a39Sopenharmony_ci                                 * NULL iff init != 0 in the BIO. */
63e1051a39Sopenharmony_ci    /* This is for what we write (i.e. reading uses peer's struct): */
64e1051a39Sopenharmony_ci    int closed;                 /* valid iff peer != NULL */
65e1051a39Sopenharmony_ci    size_t len;                 /* valid iff buf != NULL; 0 if peer == NULL */
66e1051a39Sopenharmony_ci    size_t offset;              /* valid iff buf != NULL; 0 if len == 0 */
67e1051a39Sopenharmony_ci    size_t size;
68e1051a39Sopenharmony_ci    char *buf;                  /* "size" elements (if != NULL) */
69e1051a39Sopenharmony_ci    size_t request;             /* valid iff peer != NULL; 0 if len != 0,
70e1051a39Sopenharmony_ci                                 * otherwise set by peer to number of bytes
71e1051a39Sopenharmony_ci                                 * it (unsuccessfully) tried to read, never
72e1051a39Sopenharmony_ci                                 * more than buffer space (size-len)
73e1051a39Sopenharmony_ci                                 * warrants. */
74e1051a39Sopenharmony_ci};
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_cistatic int bio_new(BIO *bio)
77e1051a39Sopenharmony_ci{
78e1051a39Sopenharmony_ci    struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b));
79e1051a39Sopenharmony_ci
80e1051a39Sopenharmony_ci    if (b == NULL)
81e1051a39Sopenharmony_ci        return 0;
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ci    /* enough for one TLS record (just a default) */
84e1051a39Sopenharmony_ci    b->size = 17 * 1024;
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ci    bio->ptr = b;
87e1051a39Sopenharmony_ci    return 1;
88e1051a39Sopenharmony_ci}
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_cistatic int bio_free(BIO *bio)
91e1051a39Sopenharmony_ci{
92e1051a39Sopenharmony_ci    struct bio_bio_st *b;
93e1051a39Sopenharmony_ci
94e1051a39Sopenharmony_ci    if (bio == NULL)
95e1051a39Sopenharmony_ci        return 0;
96e1051a39Sopenharmony_ci    b = bio->ptr;
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    assert(b != NULL);
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci    if (b->peer)
101e1051a39Sopenharmony_ci        bio_destroy_pair(bio);
102e1051a39Sopenharmony_ci
103e1051a39Sopenharmony_ci    OPENSSL_free(b->buf);
104e1051a39Sopenharmony_ci    OPENSSL_free(b);
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_ci    return 1;
107e1051a39Sopenharmony_ci}
108e1051a39Sopenharmony_ci
109e1051a39Sopenharmony_cistatic int bio_read(BIO *bio, char *buf, int size_)
110e1051a39Sopenharmony_ci{
111e1051a39Sopenharmony_ci    size_t size = size_;
112e1051a39Sopenharmony_ci    size_t rest;
113e1051a39Sopenharmony_ci    struct bio_bio_st *b, *peer_b;
114e1051a39Sopenharmony_ci
115e1051a39Sopenharmony_ci    BIO_clear_retry_flags(bio);
116e1051a39Sopenharmony_ci
117e1051a39Sopenharmony_ci    if (!bio->init)
118e1051a39Sopenharmony_ci        return 0;
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    b = bio->ptr;
121e1051a39Sopenharmony_ci    assert(b != NULL);
122e1051a39Sopenharmony_ci    assert(b->peer != NULL);
123e1051a39Sopenharmony_ci    peer_b = b->peer->ptr;
124e1051a39Sopenharmony_ci    assert(peer_b != NULL);
125e1051a39Sopenharmony_ci    assert(peer_b->buf != NULL);
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ci    peer_b->request = 0;        /* will be set in "retry_read" situation */
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ci    if (buf == NULL || size == 0)
130e1051a39Sopenharmony_ci        return 0;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    if (peer_b->len == 0) {
133e1051a39Sopenharmony_ci        if (peer_b->closed)
134e1051a39Sopenharmony_ci            return 0;           /* writer has closed, and no data is left */
135e1051a39Sopenharmony_ci        else {
136e1051a39Sopenharmony_ci            BIO_set_retry_read(bio); /* buffer is empty */
137e1051a39Sopenharmony_ci            if (size <= peer_b->size)
138e1051a39Sopenharmony_ci                peer_b->request = size;
139e1051a39Sopenharmony_ci            else
140e1051a39Sopenharmony_ci                /*
141e1051a39Sopenharmony_ci                 * don't ask for more than the peer can deliver in one write
142e1051a39Sopenharmony_ci                 */
143e1051a39Sopenharmony_ci                peer_b->request = peer_b->size;
144e1051a39Sopenharmony_ci            return -1;
145e1051a39Sopenharmony_ci        }
146e1051a39Sopenharmony_ci    }
147e1051a39Sopenharmony_ci
148e1051a39Sopenharmony_ci    /* we can read */
149e1051a39Sopenharmony_ci    if (peer_b->len < size)
150e1051a39Sopenharmony_ci        size = peer_b->len;
151e1051a39Sopenharmony_ci
152e1051a39Sopenharmony_ci    /* now read "size" bytes */
153e1051a39Sopenharmony_ci
154e1051a39Sopenharmony_ci    rest = size;
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci    assert(rest > 0);
157e1051a39Sopenharmony_ci    do {                        /* one or two iterations */
158e1051a39Sopenharmony_ci        size_t chunk;
159e1051a39Sopenharmony_ci
160e1051a39Sopenharmony_ci        assert(rest <= peer_b->len);
161e1051a39Sopenharmony_ci        if (peer_b->offset + rest <= peer_b->size)
162e1051a39Sopenharmony_ci            chunk = rest;
163e1051a39Sopenharmony_ci        else
164e1051a39Sopenharmony_ci            /* wrap around ring buffer */
165e1051a39Sopenharmony_ci            chunk = peer_b->size - peer_b->offset;
166e1051a39Sopenharmony_ci        assert(peer_b->offset + chunk <= peer_b->size);
167e1051a39Sopenharmony_ci
168e1051a39Sopenharmony_ci        memcpy(buf, peer_b->buf + peer_b->offset, chunk);
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_ci        peer_b->len -= chunk;
171e1051a39Sopenharmony_ci        if (peer_b->len) {
172e1051a39Sopenharmony_ci            peer_b->offset += chunk;
173e1051a39Sopenharmony_ci            assert(peer_b->offset <= peer_b->size);
174e1051a39Sopenharmony_ci            if (peer_b->offset == peer_b->size)
175e1051a39Sopenharmony_ci                peer_b->offset = 0;
176e1051a39Sopenharmony_ci            buf += chunk;
177e1051a39Sopenharmony_ci        } else {
178e1051a39Sopenharmony_ci            /* buffer now empty, no need to advance "buf" */
179e1051a39Sopenharmony_ci            assert(chunk == rest);
180e1051a39Sopenharmony_ci            peer_b->offset = 0;
181e1051a39Sopenharmony_ci        }
182e1051a39Sopenharmony_ci        rest -= chunk;
183e1051a39Sopenharmony_ci    }
184e1051a39Sopenharmony_ci    while (rest);
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    return size;
187e1051a39Sopenharmony_ci}
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_ci/*-
190e1051a39Sopenharmony_ci * non-copying interface: provide pointer to available data in buffer
191e1051a39Sopenharmony_ci *    bio_nread0:  return number of available bytes
192e1051a39Sopenharmony_ci *    bio_nread:   also advance index
193e1051a39Sopenharmony_ci * (example usage:  bio_nread0(), read from buffer, bio_nread()
194e1051a39Sopenharmony_ci *  or just         bio_nread(), read from buffer)
195e1051a39Sopenharmony_ci */
196e1051a39Sopenharmony_ci/*
197e1051a39Sopenharmony_ci * WARNING: The non-copying interface is largely untested as of yet and may
198e1051a39Sopenharmony_ci * contain bugs.
199e1051a39Sopenharmony_ci */
200e1051a39Sopenharmony_cistatic ossl_ssize_t bio_nread0(BIO *bio, char **buf)
201e1051a39Sopenharmony_ci{
202e1051a39Sopenharmony_ci    struct bio_bio_st *b, *peer_b;
203e1051a39Sopenharmony_ci    ossl_ssize_t num;
204e1051a39Sopenharmony_ci
205e1051a39Sopenharmony_ci    BIO_clear_retry_flags(bio);
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (!bio->init)
208e1051a39Sopenharmony_ci        return 0;
209e1051a39Sopenharmony_ci
210e1051a39Sopenharmony_ci    b = bio->ptr;
211e1051a39Sopenharmony_ci    assert(b != NULL);
212e1051a39Sopenharmony_ci    assert(b->peer != NULL);
213e1051a39Sopenharmony_ci    peer_b = b->peer->ptr;
214e1051a39Sopenharmony_ci    assert(peer_b != NULL);
215e1051a39Sopenharmony_ci    assert(peer_b->buf != NULL);
216e1051a39Sopenharmony_ci
217e1051a39Sopenharmony_ci    peer_b->request = 0;
218e1051a39Sopenharmony_ci
219e1051a39Sopenharmony_ci    if (peer_b->len == 0) {
220e1051a39Sopenharmony_ci        char dummy;
221e1051a39Sopenharmony_ci
222e1051a39Sopenharmony_ci        /* avoid code duplication -- nothing available for reading */
223e1051a39Sopenharmony_ci        return bio_read(bio, &dummy, 1); /* returns 0 or -1 */
224e1051a39Sopenharmony_ci    }
225e1051a39Sopenharmony_ci
226e1051a39Sopenharmony_ci    num = peer_b->len;
227e1051a39Sopenharmony_ci    if (peer_b->size < peer_b->offset + num)
228e1051a39Sopenharmony_ci        /* no ring buffer wrap-around for non-copying interface */
229e1051a39Sopenharmony_ci        num = peer_b->size - peer_b->offset;
230e1051a39Sopenharmony_ci    assert(num > 0);
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ci    if (buf != NULL)
233e1051a39Sopenharmony_ci        *buf = peer_b->buf + peer_b->offset;
234e1051a39Sopenharmony_ci    return num;
235e1051a39Sopenharmony_ci}
236e1051a39Sopenharmony_ci
237e1051a39Sopenharmony_cistatic ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_)
238e1051a39Sopenharmony_ci{
239e1051a39Sopenharmony_ci    struct bio_bio_st *b, *peer_b;
240e1051a39Sopenharmony_ci    ossl_ssize_t num, available;
241e1051a39Sopenharmony_ci
242e1051a39Sopenharmony_ci    if (num_ > OSSL_SSIZE_MAX)
243e1051a39Sopenharmony_ci        num = OSSL_SSIZE_MAX;
244e1051a39Sopenharmony_ci    else
245e1051a39Sopenharmony_ci        num = (ossl_ssize_t) num_;
246e1051a39Sopenharmony_ci
247e1051a39Sopenharmony_ci    available = bio_nread0(bio, buf);
248e1051a39Sopenharmony_ci    if (num > available)
249e1051a39Sopenharmony_ci        num = available;
250e1051a39Sopenharmony_ci    if (num <= 0)
251e1051a39Sopenharmony_ci        return num;
252e1051a39Sopenharmony_ci
253e1051a39Sopenharmony_ci    b = bio->ptr;
254e1051a39Sopenharmony_ci    peer_b = b->peer->ptr;
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_ci    peer_b->len -= num;
257e1051a39Sopenharmony_ci    if (peer_b->len) {
258e1051a39Sopenharmony_ci        peer_b->offset += num;
259e1051a39Sopenharmony_ci        assert(peer_b->offset <= peer_b->size);
260e1051a39Sopenharmony_ci        if (peer_b->offset == peer_b->size)
261e1051a39Sopenharmony_ci            peer_b->offset = 0;
262e1051a39Sopenharmony_ci    } else
263e1051a39Sopenharmony_ci        peer_b->offset = 0;
264e1051a39Sopenharmony_ci
265e1051a39Sopenharmony_ci    return num;
266e1051a39Sopenharmony_ci}
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_cistatic int bio_write(BIO *bio, const char *buf, int num_)
269e1051a39Sopenharmony_ci{
270e1051a39Sopenharmony_ci    size_t num = num_;
271e1051a39Sopenharmony_ci    size_t rest;
272e1051a39Sopenharmony_ci    struct bio_bio_st *b;
273e1051a39Sopenharmony_ci
274e1051a39Sopenharmony_ci    BIO_clear_retry_flags(bio);
275e1051a39Sopenharmony_ci
276e1051a39Sopenharmony_ci    if (!bio->init || buf == NULL || num == 0)
277e1051a39Sopenharmony_ci        return 0;
278e1051a39Sopenharmony_ci
279e1051a39Sopenharmony_ci    b = bio->ptr;
280e1051a39Sopenharmony_ci    assert(b != NULL);
281e1051a39Sopenharmony_ci    assert(b->peer != NULL);
282e1051a39Sopenharmony_ci    assert(b->buf != NULL);
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci    b->request = 0;
285e1051a39Sopenharmony_ci    if (b->closed) {
286e1051a39Sopenharmony_ci        /* we already closed */
287e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
288e1051a39Sopenharmony_ci        return -1;
289e1051a39Sopenharmony_ci    }
290e1051a39Sopenharmony_ci
291e1051a39Sopenharmony_ci    assert(b->len <= b->size);
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_ci    if (b->len == b->size) {
294e1051a39Sopenharmony_ci        BIO_set_retry_write(bio); /* buffer is full */
295e1051a39Sopenharmony_ci        return -1;
296e1051a39Sopenharmony_ci    }
297e1051a39Sopenharmony_ci
298e1051a39Sopenharmony_ci    /* we can write */
299e1051a39Sopenharmony_ci    if (num > b->size - b->len)
300e1051a39Sopenharmony_ci        num = b->size - b->len;
301e1051a39Sopenharmony_ci
302e1051a39Sopenharmony_ci    /* now write "num" bytes */
303e1051a39Sopenharmony_ci
304e1051a39Sopenharmony_ci    rest = num;
305e1051a39Sopenharmony_ci
306e1051a39Sopenharmony_ci    assert(rest > 0);
307e1051a39Sopenharmony_ci    do {                        /* one or two iterations */
308e1051a39Sopenharmony_ci        size_t write_offset;
309e1051a39Sopenharmony_ci        size_t chunk;
310e1051a39Sopenharmony_ci
311e1051a39Sopenharmony_ci        assert(b->len + rest <= b->size);
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_ci        write_offset = b->offset + b->len;
314e1051a39Sopenharmony_ci        if (write_offset >= b->size)
315e1051a39Sopenharmony_ci            write_offset -= b->size;
316e1051a39Sopenharmony_ci        /* b->buf[write_offset] is the first byte we can write to. */
317e1051a39Sopenharmony_ci
318e1051a39Sopenharmony_ci        if (write_offset + rest <= b->size)
319e1051a39Sopenharmony_ci            chunk = rest;
320e1051a39Sopenharmony_ci        else
321e1051a39Sopenharmony_ci            /* wrap around ring buffer */
322e1051a39Sopenharmony_ci            chunk = b->size - write_offset;
323e1051a39Sopenharmony_ci
324e1051a39Sopenharmony_ci        memcpy(b->buf + write_offset, buf, chunk);
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci        b->len += chunk;
327e1051a39Sopenharmony_ci
328e1051a39Sopenharmony_ci        assert(b->len <= b->size);
329e1051a39Sopenharmony_ci
330e1051a39Sopenharmony_ci        rest -= chunk;
331e1051a39Sopenharmony_ci        buf += chunk;
332e1051a39Sopenharmony_ci    }
333e1051a39Sopenharmony_ci    while (rest);
334e1051a39Sopenharmony_ci
335e1051a39Sopenharmony_ci    return num;
336e1051a39Sopenharmony_ci}
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci/*-
339e1051a39Sopenharmony_ci * non-copying interface: provide pointer to region to write to
340e1051a39Sopenharmony_ci *   bio_nwrite0:  check how much space is available
341e1051a39Sopenharmony_ci *   bio_nwrite:   also increase length
342e1051a39Sopenharmony_ci * (example usage:  bio_nwrite0(), write to buffer, bio_nwrite()
343e1051a39Sopenharmony_ci *  or just         bio_nwrite(), write to buffer)
344e1051a39Sopenharmony_ci */
345e1051a39Sopenharmony_cistatic ossl_ssize_t bio_nwrite0(BIO *bio, char **buf)
346e1051a39Sopenharmony_ci{
347e1051a39Sopenharmony_ci    struct bio_bio_st *b;
348e1051a39Sopenharmony_ci    size_t num;
349e1051a39Sopenharmony_ci    size_t write_offset;
350e1051a39Sopenharmony_ci
351e1051a39Sopenharmony_ci    BIO_clear_retry_flags(bio);
352e1051a39Sopenharmony_ci
353e1051a39Sopenharmony_ci    if (!bio->init)
354e1051a39Sopenharmony_ci        return 0;
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci    b = bio->ptr;
357e1051a39Sopenharmony_ci    assert(b != NULL);
358e1051a39Sopenharmony_ci    assert(b->peer != NULL);
359e1051a39Sopenharmony_ci    assert(b->buf != NULL);
360e1051a39Sopenharmony_ci
361e1051a39Sopenharmony_ci    b->request = 0;
362e1051a39Sopenharmony_ci    if (b->closed) {
363e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_BROKEN_PIPE);
364e1051a39Sopenharmony_ci        return -1;
365e1051a39Sopenharmony_ci    }
366e1051a39Sopenharmony_ci
367e1051a39Sopenharmony_ci    assert(b->len <= b->size);
368e1051a39Sopenharmony_ci
369e1051a39Sopenharmony_ci    if (b->len == b->size) {
370e1051a39Sopenharmony_ci        BIO_set_retry_write(bio);
371e1051a39Sopenharmony_ci        return -1;
372e1051a39Sopenharmony_ci    }
373e1051a39Sopenharmony_ci
374e1051a39Sopenharmony_ci    num = b->size - b->len;
375e1051a39Sopenharmony_ci    write_offset = b->offset + b->len;
376e1051a39Sopenharmony_ci    if (write_offset >= b->size)
377e1051a39Sopenharmony_ci        write_offset -= b->size;
378e1051a39Sopenharmony_ci    if (write_offset + num > b->size)
379e1051a39Sopenharmony_ci        /*
380e1051a39Sopenharmony_ci         * no ring buffer wrap-around for non-copying interface (to fulfil
381e1051a39Sopenharmony_ci         * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have
382e1051a39Sopenharmony_ci         * to be called twice)
383e1051a39Sopenharmony_ci         */
384e1051a39Sopenharmony_ci        num = b->size - write_offset;
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_ci    if (buf != NULL)
387e1051a39Sopenharmony_ci        *buf = b->buf + write_offset;
388e1051a39Sopenharmony_ci    assert(write_offset + num <= b->size);
389e1051a39Sopenharmony_ci
390e1051a39Sopenharmony_ci    return num;
391e1051a39Sopenharmony_ci}
392e1051a39Sopenharmony_ci
393e1051a39Sopenharmony_cistatic ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_)
394e1051a39Sopenharmony_ci{
395e1051a39Sopenharmony_ci    struct bio_bio_st *b;
396e1051a39Sopenharmony_ci    ossl_ssize_t num, space;
397e1051a39Sopenharmony_ci
398e1051a39Sopenharmony_ci    if (num_ > OSSL_SSIZE_MAX)
399e1051a39Sopenharmony_ci        num = OSSL_SSIZE_MAX;
400e1051a39Sopenharmony_ci    else
401e1051a39Sopenharmony_ci        num = (ossl_ssize_t) num_;
402e1051a39Sopenharmony_ci
403e1051a39Sopenharmony_ci    space = bio_nwrite0(bio, buf);
404e1051a39Sopenharmony_ci    if (num > space)
405e1051a39Sopenharmony_ci        num = space;
406e1051a39Sopenharmony_ci    if (num <= 0)
407e1051a39Sopenharmony_ci        return num;
408e1051a39Sopenharmony_ci    b = bio->ptr;
409e1051a39Sopenharmony_ci    assert(b != NULL);
410e1051a39Sopenharmony_ci    b->len += num;
411e1051a39Sopenharmony_ci    assert(b->len <= b->size);
412e1051a39Sopenharmony_ci
413e1051a39Sopenharmony_ci    return num;
414e1051a39Sopenharmony_ci}
415e1051a39Sopenharmony_ci
416e1051a39Sopenharmony_cistatic long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
417e1051a39Sopenharmony_ci{
418e1051a39Sopenharmony_ci    long ret;
419e1051a39Sopenharmony_ci    struct bio_bio_st *b = bio->ptr;
420e1051a39Sopenharmony_ci
421e1051a39Sopenharmony_ci    assert(b != NULL);
422e1051a39Sopenharmony_ci
423e1051a39Sopenharmony_ci    switch (cmd) {
424e1051a39Sopenharmony_ci        /* specific CTRL codes */
425e1051a39Sopenharmony_ci
426e1051a39Sopenharmony_ci    case BIO_C_SET_WRITE_BUF_SIZE:
427e1051a39Sopenharmony_ci        if (b->peer) {
428e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
429e1051a39Sopenharmony_ci            ret = 0;
430e1051a39Sopenharmony_ci        } else if (num == 0) {
431e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
432e1051a39Sopenharmony_ci            ret = 0;
433e1051a39Sopenharmony_ci        } else {
434e1051a39Sopenharmony_ci            size_t new_size = num;
435e1051a39Sopenharmony_ci
436e1051a39Sopenharmony_ci            if (b->size != new_size) {
437e1051a39Sopenharmony_ci                OPENSSL_free(b->buf);
438e1051a39Sopenharmony_ci                b->buf = NULL;
439e1051a39Sopenharmony_ci                b->size = new_size;
440e1051a39Sopenharmony_ci            }
441e1051a39Sopenharmony_ci            ret = 1;
442e1051a39Sopenharmony_ci        }
443e1051a39Sopenharmony_ci        break;
444e1051a39Sopenharmony_ci
445e1051a39Sopenharmony_ci    case BIO_C_GET_WRITE_BUF_SIZE:
446e1051a39Sopenharmony_ci        ret = (long)b->size;
447e1051a39Sopenharmony_ci        break;
448e1051a39Sopenharmony_ci
449e1051a39Sopenharmony_ci    case BIO_C_MAKE_BIO_PAIR:
450e1051a39Sopenharmony_ci        {
451e1051a39Sopenharmony_ci            BIO *other_bio = ptr;
452e1051a39Sopenharmony_ci
453e1051a39Sopenharmony_ci            if (bio_make_pair(bio, other_bio))
454e1051a39Sopenharmony_ci                ret = 1;
455e1051a39Sopenharmony_ci            else
456e1051a39Sopenharmony_ci                ret = 0;
457e1051a39Sopenharmony_ci        }
458e1051a39Sopenharmony_ci        break;
459e1051a39Sopenharmony_ci
460e1051a39Sopenharmony_ci    case BIO_C_DESTROY_BIO_PAIR:
461e1051a39Sopenharmony_ci        /*
462e1051a39Sopenharmony_ci         * Affects both BIOs in the pair -- call just once! Or let
463e1051a39Sopenharmony_ci         * BIO_free(bio1); BIO_free(bio2); do the job.
464e1051a39Sopenharmony_ci         */
465e1051a39Sopenharmony_ci        bio_destroy_pair(bio);
466e1051a39Sopenharmony_ci        ret = 1;
467e1051a39Sopenharmony_ci        break;
468e1051a39Sopenharmony_ci
469e1051a39Sopenharmony_ci    case BIO_C_GET_WRITE_GUARANTEE:
470e1051a39Sopenharmony_ci        /*
471e1051a39Sopenharmony_ci         * How many bytes can the caller feed to the next write without
472e1051a39Sopenharmony_ci         * having to keep any?
473e1051a39Sopenharmony_ci         */
474e1051a39Sopenharmony_ci        if (b->peer == NULL || b->closed)
475e1051a39Sopenharmony_ci            ret = 0;
476e1051a39Sopenharmony_ci        else
477e1051a39Sopenharmony_ci            ret = (long)b->size - b->len;
478e1051a39Sopenharmony_ci        break;
479e1051a39Sopenharmony_ci
480e1051a39Sopenharmony_ci    case BIO_C_GET_READ_REQUEST:
481e1051a39Sopenharmony_ci        /*
482e1051a39Sopenharmony_ci         * If the peer unsuccessfully tried to read, how many bytes were
483e1051a39Sopenharmony_ci         * requested? (As with BIO_CTRL_PENDING, that number can usually be
484e1051a39Sopenharmony_ci         * treated as boolean.)
485e1051a39Sopenharmony_ci         */
486e1051a39Sopenharmony_ci        ret = (long)b->request;
487e1051a39Sopenharmony_ci        break;
488e1051a39Sopenharmony_ci
489e1051a39Sopenharmony_ci    case BIO_C_RESET_READ_REQUEST:
490e1051a39Sopenharmony_ci        /*
491e1051a39Sopenharmony_ci         * Reset request.  (Can be useful after read attempts at the other
492e1051a39Sopenharmony_ci         * side that are meant to be non-blocking, e.g. when probing SSL_read
493e1051a39Sopenharmony_ci         * to see if any data is available.)
494e1051a39Sopenharmony_ci         */
495e1051a39Sopenharmony_ci        b->request = 0;
496e1051a39Sopenharmony_ci        ret = 1;
497e1051a39Sopenharmony_ci        break;
498e1051a39Sopenharmony_ci
499e1051a39Sopenharmony_ci    case BIO_C_SHUTDOWN_WR:
500e1051a39Sopenharmony_ci        /* similar to shutdown(..., SHUT_WR) */
501e1051a39Sopenharmony_ci        b->closed = 1;
502e1051a39Sopenharmony_ci        ret = 1;
503e1051a39Sopenharmony_ci        break;
504e1051a39Sopenharmony_ci
505e1051a39Sopenharmony_ci    case BIO_C_NREAD0:
506e1051a39Sopenharmony_ci        /* prepare for non-copying read */
507e1051a39Sopenharmony_ci        ret = (long)bio_nread0(bio, ptr);
508e1051a39Sopenharmony_ci        break;
509e1051a39Sopenharmony_ci
510e1051a39Sopenharmony_ci    case BIO_C_NREAD:
511e1051a39Sopenharmony_ci        /* non-copying read */
512e1051a39Sopenharmony_ci        ret = (long)bio_nread(bio, ptr, (size_t)num);
513e1051a39Sopenharmony_ci        break;
514e1051a39Sopenharmony_ci
515e1051a39Sopenharmony_ci    case BIO_C_NWRITE0:
516e1051a39Sopenharmony_ci        /* prepare for non-copying write */
517e1051a39Sopenharmony_ci        ret = (long)bio_nwrite0(bio, ptr);
518e1051a39Sopenharmony_ci        break;
519e1051a39Sopenharmony_ci
520e1051a39Sopenharmony_ci    case BIO_C_NWRITE:
521e1051a39Sopenharmony_ci        /* non-copying write */
522e1051a39Sopenharmony_ci        ret = (long)bio_nwrite(bio, ptr, (size_t)num);
523e1051a39Sopenharmony_ci        break;
524e1051a39Sopenharmony_ci
525e1051a39Sopenharmony_ci        /* standard CTRL codes follow */
526e1051a39Sopenharmony_ci
527e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
528e1051a39Sopenharmony_ci        if (b->buf != NULL) {
529e1051a39Sopenharmony_ci            b->len = 0;
530e1051a39Sopenharmony_ci            b->offset = 0;
531e1051a39Sopenharmony_ci        }
532e1051a39Sopenharmony_ci        ret = 0;
533e1051a39Sopenharmony_ci        break;
534e1051a39Sopenharmony_ci
535e1051a39Sopenharmony_ci    case BIO_CTRL_GET_CLOSE:
536e1051a39Sopenharmony_ci        ret = bio->shutdown;
537e1051a39Sopenharmony_ci        break;
538e1051a39Sopenharmony_ci
539e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CLOSE:
540e1051a39Sopenharmony_ci        bio->shutdown = (int)num;
541e1051a39Sopenharmony_ci        ret = 1;
542e1051a39Sopenharmony_ci        break;
543e1051a39Sopenharmony_ci
544e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:
545e1051a39Sopenharmony_ci        if (b->peer != NULL) {
546e1051a39Sopenharmony_ci            struct bio_bio_st *peer_b = b->peer->ptr;
547e1051a39Sopenharmony_ci
548e1051a39Sopenharmony_ci            ret = (long)peer_b->len;
549e1051a39Sopenharmony_ci        } else
550e1051a39Sopenharmony_ci            ret = 0;
551e1051a39Sopenharmony_ci        break;
552e1051a39Sopenharmony_ci
553e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:
554e1051a39Sopenharmony_ci        if (b->buf != NULL)
555e1051a39Sopenharmony_ci            ret = (long)b->len;
556e1051a39Sopenharmony_ci        else
557e1051a39Sopenharmony_ci            ret = 0;
558e1051a39Sopenharmony_ci        break;
559e1051a39Sopenharmony_ci
560e1051a39Sopenharmony_ci    case BIO_CTRL_DUP:
561e1051a39Sopenharmony_ci        /* See BIO_dup_chain for circumstances we have to expect. */
562e1051a39Sopenharmony_ci        {
563e1051a39Sopenharmony_ci            BIO *other_bio = ptr;
564e1051a39Sopenharmony_ci            struct bio_bio_st *other_b;
565e1051a39Sopenharmony_ci
566e1051a39Sopenharmony_ci            assert(other_bio != NULL);
567e1051a39Sopenharmony_ci            other_b = other_bio->ptr;
568e1051a39Sopenharmony_ci            assert(other_b != NULL);
569e1051a39Sopenharmony_ci
570e1051a39Sopenharmony_ci            assert(other_b->buf == NULL); /* other_bio is always fresh */
571e1051a39Sopenharmony_ci
572e1051a39Sopenharmony_ci            other_b->size = b->size;
573e1051a39Sopenharmony_ci        }
574e1051a39Sopenharmony_ci
575e1051a39Sopenharmony_ci        ret = 1;
576e1051a39Sopenharmony_ci        break;
577e1051a39Sopenharmony_ci
578e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
579e1051a39Sopenharmony_ci        ret = 1;
580e1051a39Sopenharmony_ci        break;
581e1051a39Sopenharmony_ci
582e1051a39Sopenharmony_ci    case BIO_CTRL_EOF:
583e1051a39Sopenharmony_ci        if (b->peer != NULL) {
584e1051a39Sopenharmony_ci            struct bio_bio_st *peer_b = b->peer->ptr;
585e1051a39Sopenharmony_ci
586e1051a39Sopenharmony_ci            if (peer_b->len == 0 && peer_b->closed)
587e1051a39Sopenharmony_ci                ret = 1;
588e1051a39Sopenharmony_ci            else
589e1051a39Sopenharmony_ci                ret = 0;
590e1051a39Sopenharmony_ci        } else {
591e1051a39Sopenharmony_ci            ret = 1;
592e1051a39Sopenharmony_ci        }
593e1051a39Sopenharmony_ci        break;
594e1051a39Sopenharmony_ci
595e1051a39Sopenharmony_ci    default:
596e1051a39Sopenharmony_ci        ret = 0;
597e1051a39Sopenharmony_ci    }
598e1051a39Sopenharmony_ci    return ret;
599e1051a39Sopenharmony_ci}
600e1051a39Sopenharmony_ci
601e1051a39Sopenharmony_cistatic int bio_puts(BIO *bio, const char *str)
602e1051a39Sopenharmony_ci{
603e1051a39Sopenharmony_ci    return bio_write(bio, str, strlen(str));
604e1051a39Sopenharmony_ci}
605e1051a39Sopenharmony_ci
606e1051a39Sopenharmony_cistatic int bio_make_pair(BIO *bio1, BIO *bio2)
607e1051a39Sopenharmony_ci{
608e1051a39Sopenharmony_ci    struct bio_bio_st *b1, *b2;
609e1051a39Sopenharmony_ci
610e1051a39Sopenharmony_ci    assert(bio1 != NULL);
611e1051a39Sopenharmony_ci    assert(bio2 != NULL);
612e1051a39Sopenharmony_ci
613e1051a39Sopenharmony_ci    b1 = bio1->ptr;
614e1051a39Sopenharmony_ci    b2 = bio2->ptr;
615e1051a39Sopenharmony_ci
616e1051a39Sopenharmony_ci    if (b1->peer != NULL || b2->peer != NULL) {
617e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_IN_USE);
618e1051a39Sopenharmony_ci        return 0;
619e1051a39Sopenharmony_ci    }
620e1051a39Sopenharmony_ci
621e1051a39Sopenharmony_ci    if (b1->buf == NULL) {
622e1051a39Sopenharmony_ci        b1->buf = OPENSSL_malloc(b1->size);
623e1051a39Sopenharmony_ci        if (b1->buf == NULL) {
624e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
625e1051a39Sopenharmony_ci            return 0;
626e1051a39Sopenharmony_ci        }
627e1051a39Sopenharmony_ci        b1->len = 0;
628e1051a39Sopenharmony_ci        b1->offset = 0;
629e1051a39Sopenharmony_ci    }
630e1051a39Sopenharmony_ci
631e1051a39Sopenharmony_ci    if (b2->buf == NULL) {
632e1051a39Sopenharmony_ci        b2->buf = OPENSSL_malloc(b2->size);
633e1051a39Sopenharmony_ci        if (b2->buf == NULL) {
634e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
635e1051a39Sopenharmony_ci            return 0;
636e1051a39Sopenharmony_ci        }
637e1051a39Sopenharmony_ci        b2->len = 0;
638e1051a39Sopenharmony_ci        b2->offset = 0;
639e1051a39Sopenharmony_ci    }
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci    b1->peer = bio2;
642e1051a39Sopenharmony_ci    b1->closed = 0;
643e1051a39Sopenharmony_ci    b1->request = 0;
644e1051a39Sopenharmony_ci    b2->peer = bio1;
645e1051a39Sopenharmony_ci    b2->closed = 0;
646e1051a39Sopenharmony_ci    b2->request = 0;
647e1051a39Sopenharmony_ci
648e1051a39Sopenharmony_ci    bio1->init = 1;
649e1051a39Sopenharmony_ci    bio2->init = 1;
650e1051a39Sopenharmony_ci
651e1051a39Sopenharmony_ci    return 1;
652e1051a39Sopenharmony_ci}
653e1051a39Sopenharmony_ci
654e1051a39Sopenharmony_cistatic void bio_destroy_pair(BIO *bio)
655e1051a39Sopenharmony_ci{
656e1051a39Sopenharmony_ci    struct bio_bio_st *b = bio->ptr;
657e1051a39Sopenharmony_ci
658e1051a39Sopenharmony_ci    if (b != NULL) {
659e1051a39Sopenharmony_ci        BIO *peer_bio = b->peer;
660e1051a39Sopenharmony_ci
661e1051a39Sopenharmony_ci        if (peer_bio != NULL) {
662e1051a39Sopenharmony_ci            struct bio_bio_st *peer_b = peer_bio->ptr;
663e1051a39Sopenharmony_ci
664e1051a39Sopenharmony_ci            assert(peer_b != NULL);
665e1051a39Sopenharmony_ci            assert(peer_b->peer == bio);
666e1051a39Sopenharmony_ci
667e1051a39Sopenharmony_ci            peer_b->peer = NULL;
668e1051a39Sopenharmony_ci            peer_bio->init = 0;
669e1051a39Sopenharmony_ci            assert(peer_b->buf != NULL);
670e1051a39Sopenharmony_ci            peer_b->len = 0;
671e1051a39Sopenharmony_ci            peer_b->offset = 0;
672e1051a39Sopenharmony_ci
673e1051a39Sopenharmony_ci            b->peer = NULL;
674e1051a39Sopenharmony_ci            bio->init = 0;
675e1051a39Sopenharmony_ci            assert(b->buf != NULL);
676e1051a39Sopenharmony_ci            b->len = 0;
677e1051a39Sopenharmony_ci            b->offset = 0;
678e1051a39Sopenharmony_ci        }
679e1051a39Sopenharmony_ci    }
680e1051a39Sopenharmony_ci}
681e1051a39Sopenharmony_ci
682e1051a39Sopenharmony_ci/* Exported convenience functions */
683e1051a39Sopenharmony_ciint BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
684e1051a39Sopenharmony_ci                     BIO **bio2_p, size_t writebuf2)
685e1051a39Sopenharmony_ci{
686e1051a39Sopenharmony_ci    BIO *bio1 = NULL, *bio2 = NULL;
687e1051a39Sopenharmony_ci    long r;
688e1051a39Sopenharmony_ci    int ret = 0;
689e1051a39Sopenharmony_ci
690e1051a39Sopenharmony_ci    bio1 = BIO_new(BIO_s_bio());
691e1051a39Sopenharmony_ci    if (bio1 == NULL)
692e1051a39Sopenharmony_ci        goto err;
693e1051a39Sopenharmony_ci    bio2 = BIO_new(BIO_s_bio());
694e1051a39Sopenharmony_ci    if (bio2 == NULL)
695e1051a39Sopenharmony_ci        goto err;
696e1051a39Sopenharmony_ci
697e1051a39Sopenharmony_ci    if (writebuf1) {
698e1051a39Sopenharmony_ci        r = BIO_set_write_buf_size(bio1, writebuf1);
699e1051a39Sopenharmony_ci        if (!r)
700e1051a39Sopenharmony_ci            goto err;
701e1051a39Sopenharmony_ci    }
702e1051a39Sopenharmony_ci    if (writebuf2) {
703e1051a39Sopenharmony_ci        r = BIO_set_write_buf_size(bio2, writebuf2);
704e1051a39Sopenharmony_ci        if (!r)
705e1051a39Sopenharmony_ci            goto err;
706e1051a39Sopenharmony_ci    }
707e1051a39Sopenharmony_ci
708e1051a39Sopenharmony_ci    r = BIO_make_bio_pair(bio1, bio2);
709e1051a39Sopenharmony_ci    if (!r)
710e1051a39Sopenharmony_ci        goto err;
711e1051a39Sopenharmony_ci    ret = 1;
712e1051a39Sopenharmony_ci
713e1051a39Sopenharmony_ci err:
714e1051a39Sopenharmony_ci    if (ret == 0) {
715e1051a39Sopenharmony_ci        BIO_free(bio1);
716e1051a39Sopenharmony_ci        bio1 = NULL;
717e1051a39Sopenharmony_ci        BIO_free(bio2);
718e1051a39Sopenharmony_ci        bio2 = NULL;
719e1051a39Sopenharmony_ci    }
720e1051a39Sopenharmony_ci
721e1051a39Sopenharmony_ci    *bio1_p = bio1;
722e1051a39Sopenharmony_ci    *bio2_p = bio2;
723e1051a39Sopenharmony_ci    return ret;
724e1051a39Sopenharmony_ci}
725e1051a39Sopenharmony_ci
726e1051a39Sopenharmony_cisize_t BIO_ctrl_get_write_guarantee(BIO *bio)
727e1051a39Sopenharmony_ci{
728e1051a39Sopenharmony_ci    return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
729e1051a39Sopenharmony_ci}
730e1051a39Sopenharmony_ci
731e1051a39Sopenharmony_cisize_t BIO_ctrl_get_read_request(BIO *bio)
732e1051a39Sopenharmony_ci{
733e1051a39Sopenharmony_ci    return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
734e1051a39Sopenharmony_ci}
735e1051a39Sopenharmony_ci
736e1051a39Sopenharmony_ciint BIO_ctrl_reset_read_request(BIO *bio)
737e1051a39Sopenharmony_ci{
738e1051a39Sopenharmony_ci    return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0);
739e1051a39Sopenharmony_ci}
740e1051a39Sopenharmony_ci
741e1051a39Sopenharmony_ci/*
742e1051a39Sopenharmony_ci * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now
743e1051a39Sopenharmony_ci * (conceivably some other BIOs could allow non-copying reads and writes
744e1051a39Sopenharmony_ci * too.)
745e1051a39Sopenharmony_ci */
746e1051a39Sopenharmony_ciint BIO_nread0(BIO *bio, char **buf)
747e1051a39Sopenharmony_ci{
748e1051a39Sopenharmony_ci    long ret;
749e1051a39Sopenharmony_ci
750e1051a39Sopenharmony_ci    if (!bio->init) {
751e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
752e1051a39Sopenharmony_ci        return -2;
753e1051a39Sopenharmony_ci    }
754e1051a39Sopenharmony_ci
755e1051a39Sopenharmony_ci    ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf);
756e1051a39Sopenharmony_ci    if (ret > INT_MAX)
757e1051a39Sopenharmony_ci        return INT_MAX;
758e1051a39Sopenharmony_ci    else
759e1051a39Sopenharmony_ci        return (int)ret;
760e1051a39Sopenharmony_ci}
761e1051a39Sopenharmony_ci
762e1051a39Sopenharmony_ciint BIO_nread(BIO *bio, char **buf, int num)
763e1051a39Sopenharmony_ci{
764e1051a39Sopenharmony_ci    int ret;
765e1051a39Sopenharmony_ci
766e1051a39Sopenharmony_ci    if (!bio->init) {
767e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
768e1051a39Sopenharmony_ci        return -2;
769e1051a39Sopenharmony_ci    }
770e1051a39Sopenharmony_ci
771e1051a39Sopenharmony_ci    ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf);
772e1051a39Sopenharmony_ci    if (ret > 0)
773e1051a39Sopenharmony_ci        bio->num_read += ret;
774e1051a39Sopenharmony_ci    return ret;
775e1051a39Sopenharmony_ci}
776e1051a39Sopenharmony_ci
777e1051a39Sopenharmony_ciint BIO_nwrite0(BIO *bio, char **buf)
778e1051a39Sopenharmony_ci{
779e1051a39Sopenharmony_ci    long ret;
780e1051a39Sopenharmony_ci
781e1051a39Sopenharmony_ci    if (!bio->init) {
782e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
783e1051a39Sopenharmony_ci        return -2;
784e1051a39Sopenharmony_ci    }
785e1051a39Sopenharmony_ci
786e1051a39Sopenharmony_ci    ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf);
787e1051a39Sopenharmony_ci    if (ret > INT_MAX)
788e1051a39Sopenharmony_ci        return INT_MAX;
789e1051a39Sopenharmony_ci    else
790e1051a39Sopenharmony_ci        return (int)ret;
791e1051a39Sopenharmony_ci}
792e1051a39Sopenharmony_ci
793e1051a39Sopenharmony_ciint BIO_nwrite(BIO *bio, char **buf, int num)
794e1051a39Sopenharmony_ci{
795e1051a39Sopenharmony_ci    int ret;
796e1051a39Sopenharmony_ci
797e1051a39Sopenharmony_ci    if (!bio->init) {
798e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
799e1051a39Sopenharmony_ci        return -2;
800e1051a39Sopenharmony_ci    }
801e1051a39Sopenharmony_ci
802e1051a39Sopenharmony_ci    ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf);
803e1051a39Sopenharmony_ci    if (ret > 0)
804e1051a39Sopenharmony_ci        bio->num_write += ret;
805e1051a39Sopenharmony_ci    return ret;
806e1051a39Sopenharmony_ci}
807