Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 1 | /* ==================================================================== |
| 2 | * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
| 7 | * |
| 8 | * 1. Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer in |
| 13 | * the documentation and/or other materials provided with the |
| 14 | * distribution. |
| 15 | * |
| 16 | * 3. All advertising materials mentioning features or use of this |
| 17 | * software must display the following acknowledgment: |
| 18 | * "This product includes software developed by the OpenSSL Project |
| 19 | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
| 20 | * |
| 21 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
| 22 | * endorse or promote products derived from this software without |
| 23 | * prior written permission. For written permission, please contact |
| 24 | * openssl-core@openssl.org. |
| 25 | * |
| 26 | * 5. Products derived from this software may not be called "OpenSSL" |
| 27 | * nor may "OpenSSL" appear in their names without prior written |
| 28 | * permission of the OpenSSL Project. |
| 29 | * |
| 30 | * 6. Redistributions of any form whatsoever must retain the following |
| 31 | * acknowledgment: |
| 32 | * "This product includes software developed by the OpenSSL Project |
| 33 | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
| 34 | * |
| 35 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
| 36 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 38 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
| 39 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 41 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 42 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 44 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 45 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| 46 | * OF THE POSSIBILITY OF SUCH DAMAGE. |
| 47 | * ==================================================================== |
| 48 | * |
| 49 | * This product includes cryptographic software written by Eric Young |
| 50 | * (eay@cryptsoft.com). This product includes software written by Tim |
| 51 | * Hudson (tjh@cryptsoft.com). */ |
| 52 | |
| 53 | #include <openssl/bio.h> |
| 54 | |
| 55 | #include <assert.h> |
Adam Langley | 2b2d66d | 2015-01-30 17:08:37 -0800 | [diff] [blame] | 56 | #include <string.h> |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 57 | |
| 58 | #include <openssl/buf.h> |
| 59 | #include <openssl/err.h> |
| 60 | #include <openssl/mem.h> |
| 61 | |
David Benjamin | 17cf2cb | 2016-12-13 01:07:13 -0500 | [diff] [blame] | 62 | #include "../internal.h" |
| 63 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 64 | |
| 65 | struct bio_bio_st { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 66 | BIO *peer; // NULL if buf == NULL. |
| 67 | // If peer != NULL, then peer->ptr is also a bio_bio_st, |
| 68 | // and its "peer" member points back to us. |
| 69 | // peer != NULL iff init != 0 in the BIO. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 70 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 71 | // This is for what we write (i.e. reading uses peer's struct): |
| 72 | int closed; // valid iff peer != NULL |
| 73 | size_t len; // valid iff buf != NULL; 0 if peer == NULL |
| 74 | size_t offset; // valid iff buf != NULL; 0 if len == 0 |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 75 | size_t size; |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 76 | uint8_t *buf; // "size" elements (if != NULL) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 77 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 78 | size_t request; // valid iff peer != NULL; 0 if len != 0, |
| 79 | // otherwise set by peer to number of bytes |
| 80 | // it (unsuccessfully) tried to read, |
| 81 | // never more than buffer space (size-len) warrants. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 82 | }; |
| 83 | |
| 84 | static int bio_new(BIO *bio) { |
| 85 | struct bio_bio_st *b; |
| 86 | |
| 87 | b = OPENSSL_malloc(sizeof *b); |
| 88 | if (b == NULL) { |
| 89 | return 0; |
| 90 | } |
David Benjamin | 17cf2cb | 2016-12-13 01:07:13 -0500 | [diff] [blame] | 91 | OPENSSL_memset(b, 0, sizeof(struct bio_bio_st)); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 92 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 93 | b->size = 17 * 1024; // enough for one TLS record (just a default) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 94 | bio->ptr = b; |
| 95 | return 1; |
| 96 | } |
| 97 | |
| 98 | static void bio_destroy_pair(BIO *bio) { |
| 99 | struct bio_bio_st *b = bio->ptr; |
| 100 | BIO *peer_bio; |
| 101 | struct bio_bio_st *peer_b; |
| 102 | |
| 103 | if (b == NULL) { |
| 104 | return; |
| 105 | } |
| 106 | |
| 107 | peer_bio = b->peer; |
| 108 | if (peer_bio == NULL) { |
| 109 | return; |
| 110 | } |
| 111 | |
| 112 | peer_b = peer_bio->ptr; |
| 113 | |
| 114 | assert(peer_b != NULL); |
| 115 | assert(peer_b->peer == bio); |
| 116 | |
| 117 | peer_b->peer = NULL; |
| 118 | peer_bio->init = 0; |
| 119 | assert(peer_b->buf != NULL); |
| 120 | peer_b->len = 0; |
| 121 | peer_b->offset = 0; |
| 122 | |
| 123 | b->peer = NULL; |
| 124 | bio->init = 0; |
| 125 | assert(b->buf != NULL); |
| 126 | b->len = 0; |
| 127 | b->offset = 0; |
| 128 | } |
| 129 | |
| 130 | static int bio_free(BIO *bio) { |
| 131 | struct bio_bio_st *b; |
| 132 | |
| 133 | if (bio == NULL) { |
| 134 | return 0; |
| 135 | } |
| 136 | b = bio->ptr; |
| 137 | |
| 138 | assert(b != NULL); |
| 139 | |
| 140 | if (b->peer) { |
| 141 | bio_destroy_pair(bio); |
| 142 | } |
| 143 | |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 144 | OPENSSL_free(b->buf); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 145 | OPENSSL_free(b); |
| 146 | |
| 147 | return 1; |
| 148 | } |
| 149 | |
| 150 | static int bio_read(BIO *bio, char *buf, int size_) { |
| 151 | size_t size = size_; |
| 152 | size_t rest; |
| 153 | struct bio_bio_st *b, *peer_b; |
| 154 | |
| 155 | BIO_clear_retry_flags(bio); |
| 156 | |
| 157 | if (!bio->init) { |
| 158 | return 0; |
| 159 | } |
| 160 | |
| 161 | b = bio->ptr; |
| 162 | assert(b != NULL); |
| 163 | assert(b->peer != NULL); |
| 164 | peer_b = b->peer->ptr; |
| 165 | assert(peer_b != NULL); |
| 166 | assert(peer_b->buf != NULL); |
| 167 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 168 | peer_b->request = 0; // will be set in "retry_read" situation |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 169 | |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 170 | if (buf == NULL || size == 0) { |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 171 | return 0; |
| 172 | } |
| 173 | |
| 174 | if (peer_b->len == 0) { |
| 175 | if (peer_b->closed) { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 176 | return 0; // writer has closed, and no data is left |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 177 | } else { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 178 | BIO_set_retry_read(bio); // buffer is empty |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 179 | if (size <= peer_b->size) { |
| 180 | peer_b->request = size; |
| 181 | } else { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 182 | // don't ask for more than the peer can |
| 183 | // deliver in one write |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 184 | peer_b->request = peer_b->size; |
| 185 | } |
| 186 | return -1; |
| 187 | } |
| 188 | } |
| 189 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 190 | // we can read |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 191 | if (peer_b->len < size) { |
| 192 | size = peer_b->len; |
| 193 | } |
| 194 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 195 | // now read "size" bytes |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 196 | rest = size; |
| 197 | |
| 198 | assert(rest > 0); |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 199 | // one or two iterations |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 200 | do { |
| 201 | size_t chunk; |
| 202 | |
| 203 | assert(rest <= peer_b->len); |
| 204 | if (peer_b->offset + rest <= peer_b->size) { |
| 205 | chunk = rest; |
| 206 | } else { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 207 | // wrap around ring buffer |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 208 | chunk = peer_b->size - peer_b->offset; |
| 209 | } |
| 210 | assert(peer_b->offset + chunk <= peer_b->size); |
| 211 | |
David Benjamin | 17cf2cb | 2016-12-13 01:07:13 -0500 | [diff] [blame] | 212 | OPENSSL_memcpy(buf, peer_b->buf + peer_b->offset, chunk); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 213 | |
| 214 | peer_b->len -= chunk; |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 215 | if (peer_b->len) { |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 216 | peer_b->offset += chunk; |
| 217 | assert(peer_b->offset <= peer_b->size); |
| 218 | if (peer_b->offset == peer_b->size) { |
| 219 | peer_b->offset = 0; |
| 220 | } |
| 221 | buf += chunk; |
| 222 | } else { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 223 | // buffer now empty, no need to advance "buf" |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 224 | assert(chunk == rest); |
| 225 | peer_b->offset = 0; |
| 226 | } |
| 227 | rest -= chunk; |
| 228 | } while (rest); |
| 229 | |
| 230 | return size; |
| 231 | } |
| 232 | |
| 233 | static int bio_write(BIO *bio, const char *buf, int num_) { |
| 234 | size_t num = num_; |
| 235 | size_t rest; |
| 236 | struct bio_bio_st *b; |
| 237 | |
| 238 | BIO_clear_retry_flags(bio); |
| 239 | |
| 240 | if (!bio->init || buf == NULL || num == 0) { |
| 241 | return 0; |
| 242 | } |
| 243 | |
| 244 | b = bio->ptr; |
| 245 | assert(b != NULL); |
| 246 | assert(b->peer != NULL); |
| 247 | assert(b->buf != NULL); |
| 248 | |
| 249 | b->request = 0; |
| 250 | if (b->closed) { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 251 | // we already closed |
David Benjamin | 3570d73 | 2015-06-29 00:28:17 -0400 | [diff] [blame] | 252 | OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 253 | return -1; |
| 254 | } |
| 255 | |
| 256 | assert(b->len <= b->size); |
| 257 | |
| 258 | if (b->len == b->size) { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 259 | BIO_set_retry_write(bio); // buffer is full |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 260 | return -1; |
| 261 | } |
| 262 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 263 | // we can write |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 264 | if (num > b->size - b->len) { |
| 265 | num = b->size - b->len; |
| 266 | } |
| 267 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 268 | // now write "num" bytes |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 269 | rest = num; |
| 270 | |
| 271 | assert(rest > 0); |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 272 | // one or two iterations |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 273 | do { |
| 274 | size_t write_offset; |
| 275 | size_t chunk; |
| 276 | |
| 277 | assert(b->len + rest <= b->size); |
| 278 | |
| 279 | write_offset = b->offset + b->len; |
| 280 | if (write_offset >= b->size) { |
| 281 | write_offset -= b->size; |
| 282 | } |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 283 | // b->buf[write_offset] is the first byte we can write to. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 284 | |
| 285 | if (write_offset + rest <= b->size) { |
| 286 | chunk = rest; |
| 287 | } else { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 288 | // wrap around ring buffer |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 289 | chunk = b->size - write_offset; |
| 290 | } |
| 291 | |
David Benjamin | 17cf2cb | 2016-12-13 01:07:13 -0500 | [diff] [blame] | 292 | OPENSSL_memcpy(b->buf + write_offset, buf, chunk); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 293 | |
| 294 | b->len += chunk; |
| 295 | |
| 296 | assert(b->len <= b->size); |
| 297 | |
| 298 | rest -= chunk; |
| 299 | buf += chunk; |
| 300 | } while (rest); |
| 301 | |
| 302 | return num; |
| 303 | } |
| 304 | |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 305 | static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len, |
| 306 | size_t writebuf2_len) { |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 307 | struct bio_bio_st *b1, *b2; |
| 308 | |
| 309 | assert(bio1 != NULL); |
| 310 | assert(bio2 != NULL); |
| 311 | |
| 312 | b1 = bio1->ptr; |
| 313 | b2 = bio2->ptr; |
| 314 | |
| 315 | if (b1->peer != NULL || b2->peer != NULL) { |
David Benjamin | 3570d73 | 2015-06-29 00:28:17 -0400 | [diff] [blame] | 316 | OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 317 | return 0; |
| 318 | } |
| 319 | |
| 320 | if (b1->buf == NULL) { |
Håvard Molland | 4e0a7e5 | 2014-11-21 16:21:01 +0100 | [diff] [blame] | 321 | if (writebuf1_len) { |
| 322 | b1->size = writebuf1_len; |
| 323 | } |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 324 | b1->buf = OPENSSL_malloc(b1->size); |
| 325 | if (b1->buf == NULL) { |
| 326 | OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); |
| 327 | return 0; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 328 | } |
| 329 | b1->len = 0; |
| 330 | b1->offset = 0; |
| 331 | } |
| 332 | |
| 333 | if (b2->buf == NULL) { |
Håvard Molland | 4e0a7e5 | 2014-11-21 16:21:01 +0100 | [diff] [blame] | 334 | if (writebuf2_len) { |
| 335 | b2->size = writebuf2_len; |
| 336 | } |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 337 | b2->buf = OPENSSL_malloc(b2->size); |
| 338 | if (b2->buf == NULL) { |
| 339 | OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); |
| 340 | return 0; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 341 | } |
| 342 | b2->len = 0; |
| 343 | b2->offset = 0; |
| 344 | } |
| 345 | |
| 346 | b1->peer = bio2; |
| 347 | b1->closed = 0; |
| 348 | b1->request = 0; |
| 349 | b2->peer = bio1; |
| 350 | b2->closed = 0; |
| 351 | b2->request = 0; |
| 352 | |
| 353 | bio1->init = 1; |
| 354 | bio2->init = 1; |
| 355 | |
| 356 | return 1; |
| 357 | } |
| 358 | |
| 359 | static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { |
| 360 | long ret; |
| 361 | struct bio_bio_st *b = bio->ptr; |
| 362 | |
| 363 | assert(b != NULL); |
| 364 | |
| 365 | switch (cmd) { |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 366 | // specific CTRL codes |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 367 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 368 | case BIO_C_GET_WRITE_BUF_SIZE: |
| 369 | ret = (long)b->size; |
| 370 | break; |
| 371 | |
| 372 | case BIO_C_GET_WRITE_GUARANTEE: |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 373 | // How many bytes can the caller feed to the next write |
| 374 | // without having to keep any? |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 375 | if (b->peer == NULL || b->closed) { |
| 376 | ret = 0; |
| 377 | } else { |
| 378 | ret = (long)b->size - b->len; |
| 379 | } |
| 380 | break; |
| 381 | |
| 382 | case BIO_C_GET_READ_REQUEST: |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 383 | // If the peer unsuccessfully tried to read, how many bytes |
| 384 | // were requested? (As with BIO_CTRL_PENDING, that number |
| 385 | // can usually be treated as boolean.) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 386 | ret = (long)b->request; |
| 387 | break; |
| 388 | |
| 389 | case BIO_C_RESET_READ_REQUEST: |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 390 | // Reset request. (Can be useful after read attempts |
| 391 | // at the other side that are meant to be non-blocking, |
| 392 | // e.g. when probing SSL_read to see if any data is |
| 393 | // available.) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 394 | b->request = 0; |
| 395 | ret = 1; |
| 396 | break; |
| 397 | |
| 398 | case BIO_C_SHUTDOWN_WR: |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 399 | // similar to shutdown(..., SHUT_WR) |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 400 | b->closed = 1; |
| 401 | ret = 1; |
| 402 | break; |
| 403 | |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 404 | // standard CTRL codes follow |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 405 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 406 | case BIO_CTRL_GET_CLOSE: |
| 407 | ret = bio->shutdown; |
| 408 | break; |
| 409 | |
| 410 | case BIO_CTRL_SET_CLOSE: |
| 411 | bio->shutdown = (int)num; |
| 412 | ret = 1; |
| 413 | break; |
| 414 | |
| 415 | case BIO_CTRL_PENDING: |
| 416 | if (b->peer != NULL) { |
| 417 | struct bio_bio_st *peer_b = b->peer->ptr; |
| 418 | ret = (long)peer_b->len; |
| 419 | } else { |
| 420 | ret = 0; |
| 421 | } |
| 422 | break; |
| 423 | |
| 424 | case BIO_CTRL_WPENDING: |
| 425 | ret = 0; |
| 426 | if (b->buf != NULL) { |
| 427 | ret = (long)b->len; |
| 428 | } |
| 429 | break; |
| 430 | |
| 431 | case BIO_CTRL_FLUSH: |
| 432 | ret = 1; |
| 433 | break; |
| 434 | |
| 435 | case BIO_CTRL_EOF: { |
| 436 | BIO *other_bio = ptr; |
| 437 | |
| 438 | if (other_bio) { |
| 439 | struct bio_bio_st *other_b = other_bio->ptr; |
| 440 | assert(other_b != NULL); |
| 441 | ret = other_b->len == 0 && other_b->closed; |
| 442 | } else { |
| 443 | ret = 1; |
| 444 | } |
| 445 | } break; |
| 446 | |
| 447 | default: |
| 448 | ret = 0; |
| 449 | } |
| 450 | return ret; |
| 451 | } |
| 452 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 453 | |
Håvard Molland | 4e0a7e5 | 2014-11-21 16:21:01 +0100 | [diff] [blame] | 454 | static const BIO_METHOD methods_biop = { |
David Benjamin | 6342111 | 2017-01-26 21:50:04 -0500 | [diff] [blame] | 455 | BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, NULL /* puts */, |
David Benjamin | 808f832 | 2017-08-18 14:06:02 -0400 | [diff] [blame] | 456 | NULL /* gets */, bio_ctrl, bio_new, bio_free, NULL /* callback_ctrl */, |
Håvard Molland | 4e0a7e5 | 2014-11-21 16:21:01 +0100 | [diff] [blame] | 457 | }; |
| 458 | |
Piotr Sikora | 9bb8ba6 | 2016-03-18 18:19:04 -0700 | [diff] [blame] | 459 | static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } |
Håvard Molland | 4e0a7e5 | 2014-11-21 16:21:01 +0100 | [diff] [blame] | 460 | |
David Benjamin | ed1d288 | 2016-12-06 22:24:52 -0500 | [diff] [blame] | 461 | int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len, |
| 462 | BIO** bio2_p, size_t writebuf2_len) { |
David Benjamin | 93c332b | 2016-12-06 22:29:48 -0500 | [diff] [blame] | 463 | BIO *bio1 = BIO_new(bio_s_bio()); |
| 464 | BIO *bio2 = BIO_new(bio_s_bio()); |
| 465 | if (bio1 == NULL || bio2 == NULL || |
| 466 | !bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) { |
David Benjamin | 22ccc2d | 2015-04-22 13:50:28 -0400 | [diff] [blame] | 467 | BIO_free(bio1); |
David Benjamin | 22ccc2d | 2015-04-22 13:50:28 -0400 | [diff] [blame] | 468 | BIO_free(bio2); |
David Benjamin | 93c332b | 2016-12-06 22:29:48 -0500 | [diff] [blame] | 469 | *bio1_p = NULL; |
| 470 | *bio2_p = NULL; |
| 471 | return 0; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 472 | } |
| 473 | |
| 474 | *bio1_p = bio1; |
| 475 | *bio2_p = bio2; |
David Benjamin | 93c332b | 2016-12-06 22:29:48 -0500 | [diff] [blame] | 476 | return 1; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 477 | } |
| 478 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 479 | size_t BIO_ctrl_get_read_request(BIO *bio) { |
| 480 | return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); |
| 481 | } |
| 482 | |
| 483 | size_t BIO_ctrl_get_write_guarantee(BIO *bio) { |
| 484 | return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); |
| 485 | } |
| 486 | |
| 487 | int BIO_shutdown_wr(BIO *bio) { |
| 488 | return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL); |
| 489 | } |