diff options
author | Matt Caswell <matt@openssl.org> | 2016-09-05 17:26:58 +0100 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-10-28 09:48:54 +0100 |
commit | d07aee2c7a33e77d97d8e13811af3637e3849cb2 (patch) | |
tree | 1c3452687dbd734f4e739713f29fbf770f5524dd /crypto/bio/bio_lib.c | |
parent | 229bd12487f8576fc088dc4f641950ac33c62033 (diff) |
Create BIO_read_ex() which handles size_t arguments
Also extend BIO_METHOD to be able to supply an implementation for the new
BIO_read function.
Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'crypto/bio/bio_lib.c')
-rw-r--r-- | crypto/bio/bio_lib.c | 118 |
1 files changed, 98 insertions, 20 deletions
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c index 62392c3a52..c3633f255f 100644 --- a/crypto/bio/bio_lib.c +++ b/crypto/bio/bio_lib.c @@ -142,18 +142,26 @@ void BIO_set_flags(BIO *b, int flags) b->flags |= flags; } -long (*BIO_get_callback(const BIO *b)) (struct bio_st *, int, const char *, - int, long, long) { +BIO_callback_fn BIO_get_callback(const BIO *b) +{ return b->callback; } -void BIO_set_callback(BIO *b, - long (*cb) (struct bio_st *, int, const char *, int, - long, long)) +void BIO_set_callback(BIO *b, BIO_callback_fn cb) { b->callback = cb; } +BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) +{ + return b->callback_ex; +} + +void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) +{ + b->callback_ex = cb; +} + void BIO_set_callback_arg(BIO *b, char *arg) { b->cb_arg = arg; @@ -174,34 +182,104 @@ int BIO_method_type(const BIO *b) return b->method->type; } +static int bio_call_callback(BIO *b, int oper, const char *argp, size_t len, + int argi, long argl, int inret, size_t *processed, + long *lret) +{ + long ret; + int bareoper; + + if (b->callback_ex != NULL) { + return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed, + lret); + } + + /* Strip off the BIO_CB_RETURN flag */ + bareoper = oper & ~BIO_CB_RETURN; + /* + * We have an old style callback, so we will have to do nasty casts and + * check for overflows. + */ + if (bareoper == BIO_CB_READ || bareoper == BIO_CB_WRITE + || bareoper == BIO_CB_GETS) { + /* In this case |len| is set, and should be used instead of |argi| */ + if (len > INT_MAX) + return 0; + + argi = (int)len; + + if (inret && (oper & BIO_CB_RETURN)) { + if (*processed > INT_MAX) + return 0; + inret = *processed; + } + } + + ret = b->callback(b, oper, argp, argi, argl, inret); + if (bareoper == BIO_CB_CTRL) + return 1; + + if (ret > INT_MAX || ret < INT_MIN) + return 0; + + if (lret != NULL) + *lret = ret; + + if (ret >= 0) { + *processed = (size_t)ret; + ret = 1; + } + + return (int)ret; +} + int BIO_read(BIO *b, void *out, int outl) { - int i; - long (*cb) (BIO *, int, const char *, int, long, long); + size_t read; + int ret; + + if (outl < 0) + return 0; + + ret = BIO_read_ex(b, out, (size_t)outl, &read); + + if (ret > 0) { + /* *read should always be <= outl */ + ret = (int)read; + } + + return ret; +} + +int BIO_read_ex(BIO *b, void *out, size_t outl, size_t *read) +{ + int ret; if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) { - BIOerr(BIO_F_BIO_READ, BIO_R_UNSUPPORTED_METHOD); + BIOerr(BIO_F_BIO_READ_EX, BIO_R_UNSUPPORTED_METHOD); return (-2); } - cb = b->callback; - if ((cb != NULL) && - ((i = (int)cb(b, BIO_CB_READ, out, outl, 0L, 1L)) <= 0)) - return (i); + if ((b->callback != NULL || b->callback_ex != NULL) && + ((ret = bio_call_callback(b, BIO_CB_READ, out, outl, 0, 0L, 1L, read, + NULL)) <= 0)) + return ret; if (!b->init) { - BIOerr(BIO_F_BIO_READ, BIO_R_UNINITIALIZED); - return (-2); + BIOerr(BIO_F_BIO_READ_EX, BIO_R_UNINITIALIZED); + return -2; } - i = b->method->bread(b, out, outl); + ret = b->method->bread(b, out, outl, read); - if (i > 0) - b->num_read += (uint64_t)i; + if (ret > 0) + b->num_read += (uint64_t)*read; - if (cb != NULL) - i = (int)cb(b, BIO_CB_READ | BIO_CB_RETURN, out, outl, 0L, (long)i); - return (i); + if (b->callback != NULL || b->callback_ex != NULL) + ret = bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, out, outl, 0, + 0L, ret, read, NULL); + + return ret; } int BIO_write(BIO *b, const void *in, int inl) |