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