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