diff options
Diffstat (limited to 'src/lib/libcrypto/bio/bss_bio.c')
-rw-r--r-- | src/lib/libcrypto/bio/bss_bio.c | 256 |
1 files changed, 252 insertions, 4 deletions
diff --git a/src/lib/libcrypto/bio/bss_bio.c b/src/lib/libcrypto/bio/bss_bio.c index 562e9d8de2..0d0f9356f7 100644 --- a/src/lib/libcrypto/bio/bss_bio.c +++ b/src/lib/libcrypto/bio/bss_bio.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #endif | 13 | #endif |
14 | 14 | ||
15 | #include <assert.h> | 15 | #include <assert.h> |
16 | #include <limits.h> | ||
16 | #include <stdlib.h> | 17 | #include <stdlib.h> |
17 | #include <string.h> | 18 | #include <string.h> |
18 | 19 | ||
@@ -40,7 +41,8 @@ static BIO_METHOD methods_biop = | |||
40 | NULL /* no bio_gets */, | 41 | NULL /* no bio_gets */, |
41 | bio_ctrl, | 42 | bio_ctrl, |
42 | bio_new, | 43 | bio_new, |
43 | bio_free | 44 | bio_free, |
45 | NULL /* no bio_callback_ctrl */ | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | BIO_METHOD *BIO_s_bio(void) | 48 | BIO_METHOD *BIO_s_bio(void) |
@@ -64,7 +66,7 @@ struct bio_bio_st | |||
64 | 66 | ||
65 | size_t request; /* valid iff peer != NULL; 0 if len != 0, | 67 | size_t request; /* valid iff peer != NULL; 0 if len != 0, |
66 | * otherwise set by peer to number of bytes | 68 | * otherwise set by peer to number of bytes |
67 | * it (unsuccesfully) tried to read, | 69 | * it (unsuccessfully) tried to read, |
68 | * never more than buffer space (size-len) warrants. */ | 70 | * never more than buffer space (size-len) warrants. */ |
69 | }; | 71 | }; |
70 | 72 | ||
@@ -195,6 +197,81 @@ static int bio_read(BIO *bio, char *buf, int size_) | |||
195 | return size; | 197 | return size; |
196 | } | 198 | } |
197 | 199 | ||
200 | /* non-copying interface: provide pointer to available data in buffer | ||
201 | * bio_nread0: return number of available bytes | ||
202 | * bio_nread: also advance index | ||
203 | * (example usage: bio_nread0(), read from buffer, bio_nread() | ||
204 | * or just bio_nread(), read from buffer) | ||
205 | */ | ||
206 | /* WARNING: The non-copying interface is largely untested as of yet | ||
207 | * and may contain bugs. */ | ||
208 | static size_t bio_nread0(BIO *bio, char **buf) | ||
209 | { | ||
210 | struct bio_bio_st *b, *peer_b; | ||
211 | size_t num; | ||
212 | |||
213 | BIO_clear_retry_flags(bio); | ||
214 | |||
215 | if (!bio->init) | ||
216 | return 0; | ||
217 | |||
218 | b = bio->ptr; | ||
219 | assert(b != NULL); | ||
220 | assert(b->peer != NULL); | ||
221 | peer_b = b->peer->ptr; | ||
222 | assert(peer_b != NULL); | ||
223 | assert(peer_b->buf != NULL); | ||
224 | |||
225 | peer_b->request = 0; | ||
226 | |||
227 | if (peer_b->len == 0) | ||
228 | { | ||
229 | char dummy; | ||
230 | |||
231 | /* avoid code duplication -- nothing available for reading */ | ||
232 | return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ | ||
233 | } | ||
234 | |||
235 | num = peer_b->len; | ||
236 | if (peer_b->size < peer_b->offset + num) | ||
237 | /* no ring buffer wrap-around for non-copying interface */ | ||
238 | num = peer_b->size - peer_b->offset; | ||
239 | assert(num > 0); | ||
240 | |||
241 | if (buf != NULL) | ||
242 | *buf = peer_b->buf + peer_b->offset; | ||
243 | return num; | ||
244 | } | ||
245 | |||
246 | static size_t bio_nread(BIO *bio, char **buf, size_t num) | ||
247 | { | ||
248 | struct bio_bio_st *b, *peer_b; | ||
249 | size_t available; | ||
250 | |||
251 | available = bio_nread0(bio, buf); | ||
252 | if (num > available) | ||
253 | num = available; | ||
254 | if (num == 0) | ||
255 | return num; | ||
256 | |||
257 | b = bio->ptr; | ||
258 | peer_b = b->peer->ptr; | ||
259 | |||
260 | peer_b->len -= num; | ||
261 | if (peer_b->len) | ||
262 | { | ||
263 | peer_b->offset += num; | ||
264 | assert(peer_b->offset <= peer_b->size); | ||
265 | if (peer_b->offset == peer_b->size) | ||
266 | peer_b->offset = 0; | ||
267 | } | ||
268 | else | ||
269 | peer_b->offset = 0; | ||
270 | |||
271 | return num; | ||
272 | } | ||
273 | |||
274 | |||
198 | static int bio_write(BIO *bio, char *buf, int num_) | 275 | static int bio_write(BIO *bio, char *buf, int num_) |
199 | { | 276 | { |
200 | size_t num = num_; | 277 | size_t num = num_; |
@@ -268,6 +345,78 @@ static int bio_write(BIO *bio, char *buf, int num_) | |||
268 | return num; | 345 | return num; |
269 | } | 346 | } |
270 | 347 | ||
348 | /* non-copying interface: provide pointer to region to write to | ||
349 | * bio_nwrite0: check how much space is available | ||
350 | * bio_nwrite: also increase length | ||
351 | * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() | ||
352 | * or just bio_nwrite(), write to buffer) | ||
353 | */ | ||
354 | static size_t bio_nwrite0(BIO *bio, char **buf) | ||
355 | { | ||
356 | struct bio_bio_st *b; | ||
357 | size_t num; | ||
358 | size_t write_offset; | ||
359 | |||
360 | BIO_clear_retry_flags(bio); | ||
361 | |||
362 | if (!bio->init) | ||
363 | return 0; | ||
364 | |||
365 | b = bio->ptr; | ||
366 | assert(b != NULL); | ||
367 | assert(b->peer != NULL); | ||
368 | assert(b->buf != NULL); | ||
369 | |||
370 | b->request = 0; | ||
371 | if (b->closed) | ||
372 | { | ||
373 | BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | assert(b->len <= b->size); | ||
378 | |||
379 | if (b->len == b->size) | ||
380 | { | ||
381 | BIO_set_retry_write(bio); | ||
382 | return -1; | ||
383 | } | ||
384 | |||
385 | num = b->size - b->len; | ||
386 | write_offset = b->offset + b->len; | ||
387 | if (write_offset >= b->size) | ||
388 | write_offset -= b->size; | ||
389 | if (write_offset + num > b->size) | ||
390 | /* no ring buffer wrap-around for non-copying interface | ||
391 | * (to fulfil the promise by BIO_ctrl_get_write_guarantee, | ||
392 | * BIO_nwrite may have to be called twice) */ | ||
393 | num = b->size - write_offset; | ||
394 | |||
395 | if (buf != NULL) | ||
396 | *buf = b->buf + write_offset; | ||
397 | assert(write_offset + num <= b->size); | ||
398 | |||
399 | return num; | ||
400 | } | ||
401 | |||
402 | static size_t bio_nwrite(BIO *bio, char **buf, size_t num) | ||
403 | { | ||
404 | struct bio_bio_st *b; | ||
405 | size_t space; | ||
406 | |||
407 | space = bio_nwrite0(bio, buf); | ||
408 | if (num > space) | ||
409 | num = space; | ||
410 | if (num == 0) | ||
411 | return num; | ||
412 | b = bio->ptr; | ||
413 | assert(b != NULL); | ||
414 | b->len += num; | ||
415 | assert(b->len <= b->size); | ||
416 | |||
417 | return num; | ||
418 | } | ||
419 | |||
271 | 420 | ||
272 | static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) | 421 | static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) |
273 | { | 422 | { |
@@ -331,7 +480,7 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) | |||
331 | 480 | ||
332 | case BIO_C_GET_WRITE_GUARANTEE: | 481 | case BIO_C_GET_WRITE_GUARANTEE: |
333 | /* How many bytes can the caller feed to the next write | 482 | /* How many bytes can the caller feed to the next write |
334 | * withouth having to keep any? */ | 483 | * without having to keep any? */ |
335 | if (b->peer == NULL || b->closed) | 484 | if (b->peer == NULL || b->closed) |
336 | ret = 0; | 485 | ret = 0; |
337 | else | 486 | else |
@@ -339,18 +488,42 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) | |||
339 | break; | 488 | break; |
340 | 489 | ||
341 | case BIO_C_GET_READ_REQUEST: | 490 | case BIO_C_GET_READ_REQUEST: |
342 | /* If the peer unsuccesfully tried to read, how many bytes | 491 | /* If the peer unsuccessfully tried to read, how many bytes |
343 | * were requested? (As with BIO_CTRL_PENDING, that number | 492 | * were requested? (As with BIO_CTRL_PENDING, that number |
344 | * can usually be treated as boolean.) */ | 493 | * can usually be treated as boolean.) */ |
345 | ret = (long) b->request; | 494 | ret = (long) b->request; |
346 | break; | 495 | break; |
347 | 496 | ||
497 | case BIO_C_RESET_READ_REQUEST: | ||
498 | /* Reset request. (Can be useful after read attempts | ||
499 | * at the other side that are meant to be non-blocking, | ||
500 | * e.g. when probing SSL_read to see if any data is | ||
501 | * available.) */ | ||
502 | b->request = 0; | ||
503 | ret = 1; | ||
504 | break; | ||
505 | |||
348 | case BIO_C_SHUTDOWN_WR: | 506 | case BIO_C_SHUTDOWN_WR: |
349 | /* similar to shutdown(..., SHUT_WR) */ | 507 | /* similar to shutdown(..., SHUT_WR) */ |
350 | b->closed = 1; | 508 | b->closed = 1; |
351 | ret = 1; | 509 | ret = 1; |
352 | break; | 510 | break; |
353 | 511 | ||
512 | case BIO_C_NREAD: | ||
513 | /* non-copying read */ | ||
514 | ret = (long) bio_nread(bio, ptr, (size_t) num); | ||
515 | break; | ||
516 | |||
517 | case BIO_C_NWRITE0: | ||
518 | /* prepare for non-copying write */ | ||
519 | ret = (long) bio_nwrite0(bio, ptr); | ||
520 | break; | ||
521 | |||
522 | case BIO_C_NWRITE: | ||
523 | /* non-copying write */ | ||
524 | ret = (long) bio_nwrite(bio, ptr, (size_t) num); | ||
525 | break; | ||
526 | |||
354 | 527 | ||
355 | /* standard CTRL codes follow */ | 528 | /* standard CTRL codes follow */ |
356 | 529 | ||
@@ -586,3 +759,78 @@ size_t BIO_ctrl_get_read_request(BIO *bio) | |||
586 | { | 759 | { |
587 | return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); | 760 | return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); |
588 | } | 761 | } |
762 | |||
763 | int BIO_ctrl_reset_read_request(BIO *bio) | ||
764 | { | ||
765 | return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); | ||
766 | } | ||
767 | |||
768 | |||
769 | /* BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now | ||
770 | * (conceivably some other BIOs could allow non-copying reads and writes too.) | ||
771 | */ | ||
772 | int BIO_nread0(BIO *bio, char **buf) | ||
773 | { | ||
774 | long ret; | ||
775 | |||
776 | if (!bio->init) | ||
777 | { | ||
778 | BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); | ||
779 | return -2; | ||
780 | } | ||
781 | |||
782 | ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); | ||
783 | if (ret > INT_MAX) | ||
784 | return INT_MAX; | ||
785 | else | ||
786 | return (int) ret; | ||
787 | } | ||
788 | |||
789 | int BIO_nread(BIO *bio, char **buf, int num) | ||
790 | { | ||
791 | int ret; | ||
792 | |||
793 | if (!bio->init) | ||
794 | { | ||
795 | BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); | ||
796 | return -2; | ||
797 | } | ||
798 | |||
799 | ret = (int) BIO_ctrl(bio, BIO_C_NREAD, num, buf); | ||
800 | if (ret > 0) | ||
801 | bio->num_read += ret; | ||
802 | return ret; | ||
803 | } | ||
804 | |||
805 | int BIO_nwrite0(BIO *bio, char **buf) | ||
806 | { | ||
807 | long ret; | ||
808 | |||
809 | if (!bio->init) | ||
810 | { | ||
811 | BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); | ||
812 | return -2; | ||
813 | } | ||
814 | |||
815 | ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); | ||
816 | if (ret > INT_MAX) | ||
817 | return INT_MAX; | ||
818 | else | ||
819 | return (int) ret; | ||
820 | } | ||
821 | |||
822 | int BIO_nwrite(BIO *bio, char **buf, int num) | ||
823 | { | ||
824 | int ret; | ||
825 | |||
826 | if (!bio->init) | ||
827 | { | ||
828 | BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); | ||
829 | return -2; | ||
830 | } | ||
831 | |||
832 | ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); | ||
833 | if (ret > 0) | ||
834 | bio->num_read += ret; | ||
835 | return ret; | ||
836 | } | ||