mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
Optimized BIO mem read - without reallocation
Currently on every BIO mem read operation the remaining data is reallocated. This commit solves the issue. BIO mem structure includes additional pointer to the read position. On every read the pointer moves instead of reallocating the memory for the remaining data. Reallocation accures before write and some ioctl operations, if the read pointer doesn't point on the beginning of the buffer. Also the flag is added to rewind the read pointer without losing the data. Reviewed-by: Richard Levitte <levitte@openssl.org> Reviewed-by: Rich Salz <rsalz@openssl.org>
This commit is contained in:
parent
6b88864310
commit
9fe9d0461e
@ -76,6 +76,12 @@ union bio_addr_st {
|
|||||||
|
|
||||||
/* END BIO_ADDRINFO/BIO_ADDR stuff. */
|
/* END BIO_ADDRINFO/BIO_ADDR stuff. */
|
||||||
|
|
||||||
|
/* BIO_BUF_MEM */
|
||||||
|
struct bio_buf_mem_st {
|
||||||
|
struct buf_mem_st *buf; /* allocated buffer */
|
||||||
|
struct buf_mem_st *readp; /* read pointer */
|
||||||
|
};
|
||||||
|
|
||||||
#include "internal/cryptlib.h"
|
#include "internal/cryptlib.h"
|
||||||
#include <internal/bio.h>
|
#include <internal/bio.h>
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
|||||||
static int mem_new(BIO *h);
|
static int mem_new(BIO *h);
|
||||||
static int secmem_new(BIO *h);
|
static int secmem_new(BIO *h);
|
||||||
static int mem_free(BIO *data);
|
static int mem_free(BIO *data);
|
||||||
|
static int mem_buf_free(BIO *data, int free_all);
|
||||||
|
static int mem_buf_sync(BIO *h);
|
||||||
static const BIO_METHOD mem_method = {
|
static const BIO_METHOD mem_method = {
|
||||||
BIO_TYPE_MEM,
|
BIO_TYPE_MEM,
|
||||||
"memory buffer",
|
"memory buffer",
|
||||||
@ -112,6 +114,7 @@ BIO *BIO_new_mem_buf(const void *buf, int len)
|
|||||||
{
|
{
|
||||||
BIO *ret;
|
BIO *ret;
|
||||||
BUF_MEM *b;
|
BUF_MEM *b;
|
||||||
|
BIO_BUF_MEM *bb;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
@ -121,11 +124,13 @@ BIO *BIO_new_mem_buf(const void *buf, int len)
|
|||||||
sz = (len < 0) ? strlen(buf) : (size_t)len;
|
sz = (len < 0) ? strlen(buf) : (size_t)len;
|
||||||
if ((ret = BIO_new(BIO_s_mem())) == NULL)
|
if ((ret = BIO_new(BIO_s_mem())) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
b = (BUF_MEM *)ret->ptr;
|
bb = (BIO_BUF_MEM *)ret->ptr;
|
||||||
|
b = bb->buf;
|
||||||
/* Cast away const and trust in the MEM_RDONLY flag. */
|
/* Cast away const and trust in the MEM_RDONLY flag. */
|
||||||
b->data = (void *)buf;
|
b->data = (void *)buf;
|
||||||
b->length = sz;
|
b->length = sz;
|
||||||
b->max = sz;
|
b->max = sz;
|
||||||
|
*bb->readp = *bb->buf;
|
||||||
ret->flags |= BIO_FLAGS_MEM_RDONLY;
|
ret->flags |= BIO_FLAGS_MEM_RDONLY;
|
||||||
/* Since this is static data retrying wont help */
|
/* Since this is static data retrying wont help */
|
||||||
ret->num = 0;
|
ret->num = 0;
|
||||||
@ -134,14 +139,19 @@ BIO *BIO_new_mem_buf(const void *buf, int len)
|
|||||||
|
|
||||||
static int mem_init(BIO *bi, unsigned long flags)
|
static int mem_init(BIO *bi, unsigned long flags)
|
||||||
{
|
{
|
||||||
BUF_MEM *b;
|
BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(BIO_BUF_MEM));
|
||||||
|
|
||||||
if ((b = BUF_MEM_new_ex(flags)) == NULL)
|
if (bb == NULL)
|
||||||
return(0);
|
return(0);
|
||||||
|
if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL)
|
||||||
|
return(0);
|
||||||
|
if ((bb->readp = OPENSSL_zalloc(sizeof(BUF_MEM))) == NULL)
|
||||||
|
return(0);
|
||||||
|
*bb->readp = *bb->buf;
|
||||||
bi->shutdown = 1;
|
bi->shutdown = 1;
|
||||||
bi->init = 1;
|
bi->init = 1;
|
||||||
bi->num = -1;
|
bi->num = -1;
|
||||||
bi->ptr = (char *)b;
|
bi->ptr = (char *)bb;
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,38 +166,64 @@ static int secmem_new(BIO *bi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int mem_free(BIO *a)
|
static int mem_free(BIO *a)
|
||||||
|
{
|
||||||
|
return (mem_buf_free(a, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mem_buf_free(BIO *a, int free_all)
|
||||||
{
|
{
|
||||||
if (a == NULL)
|
if (a == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (a->shutdown) {
|
if (a->shutdown) {
|
||||||
if ((a->init) && (a->ptr != NULL)) {
|
if ((a->init) && (a->ptr != NULL)) {
|
||||||
BUF_MEM *b;
|
BUF_MEM *b;
|
||||||
b = (BUF_MEM *)a->ptr;
|
BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr;
|
||||||
if (a->flags & BIO_FLAGS_MEM_RDONLY)
|
|
||||||
b->data = NULL;
|
if(bb != NULL) {
|
||||||
BUF_MEM_free(b);
|
b = bb->buf;
|
||||||
|
if (a->flags & BIO_FLAGS_MEM_RDONLY)
|
||||||
|
b->data = NULL;
|
||||||
|
BUF_MEM_free(b);
|
||||||
|
if(free_all) {
|
||||||
|
OPENSSL_free(bb->readp);
|
||||||
|
OPENSSL_free(bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
a->ptr = NULL;
|
a->ptr = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reallocate memory buffer if read pointer differs
|
||||||
|
*/
|
||||||
|
static int mem_buf_sync(BIO *b)
|
||||||
|
{
|
||||||
|
if((b != NULL) && (b->init) && (b->ptr != NULL)) {
|
||||||
|
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
|
||||||
|
|
||||||
|
if(bbm->readp->data != bbm->buf->data) {
|
||||||
|
memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length);
|
||||||
|
bbm->buf->length = bbm->readp->length;
|
||||||
|
bbm->readp->data = bbm->buf->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static int mem_read(BIO *b, char *out, int outl)
|
static int mem_read(BIO *b, char *out, int outl)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
BUF_MEM *bm;
|
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
|
||||||
|
BUF_MEM *bm = bbm->readp;
|
||||||
|
|
||||||
bm = (BUF_MEM *)b->ptr;
|
|
||||||
BIO_clear_retry_flags(b);
|
BIO_clear_retry_flags(b);
|
||||||
ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl;
|
ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl;
|
||||||
if ((out != NULL) && (ret > 0)) {
|
if ((out != NULL) && (ret > 0)) {
|
||||||
memcpy(out, bm->data, ret);
|
memcpy(out, bm->data, ret);
|
||||||
bm->length -= ret;
|
bm->length -= ret;
|
||||||
if (b->flags & BIO_FLAGS_MEM_RDONLY)
|
bm->data += ret;
|
||||||
bm->data += ret;
|
|
||||||
else {
|
|
||||||
memmove(&(bm->data[0]), &(bm->data[ret]), bm->length);
|
|
||||||
}
|
|
||||||
} else if (bm->length == 0) {
|
} else if (bm->length == 0) {
|
||||||
ret = b->num;
|
ret = b->num;
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@ -200,24 +236,23 @@ static int mem_write(BIO *b, const char *in, int inl)
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int blen;
|
int blen;
|
||||||
BUF_MEM *bm;
|
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
|
||||||
|
|
||||||
bm = (BUF_MEM *)b->ptr;
|
|
||||||
if (in == NULL) {
|
if (in == NULL) {
|
||||||
BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER);
|
BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b->flags & BIO_FLAGS_MEM_RDONLY) {
|
if (b->flags & BIO_FLAGS_MEM_RDONLY) {
|
||||||
BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO);
|
BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
BIO_clear_retry_flags(b);
|
BIO_clear_retry_flags(b);
|
||||||
blen = bm->length;
|
blen = bbm->readp->length;
|
||||||
if (BUF_MEM_grow_clean(bm, blen + inl) == 0)
|
mem_buf_sync(b);
|
||||||
|
if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0)
|
||||||
goto end;
|
goto end;
|
||||||
memcpy(&(bm->data[blen]), in, inl);
|
memcpy(bbm->buf->data + blen, in, inl);
|
||||||
|
*bbm->readp = *bbm->buf;
|
||||||
ret = inl;
|
ret = inl;
|
||||||
end:
|
end:
|
||||||
return (ret);
|
return (ret);
|
||||||
@ -227,29 +262,32 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
|
|||||||
{
|
{
|
||||||
long ret = 1;
|
long ret = 1;
|
||||||
char **pptr;
|
char **pptr;
|
||||||
|
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr;
|
||||||
BUF_MEM *bm = (BUF_MEM *)b->ptr;
|
BUF_MEM *bm;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BIO_CTRL_RESET:
|
case BIO_CTRL_RESET:
|
||||||
|
bm = bbm->buf;
|
||||||
if (bm->data != NULL) {
|
if (bm->data != NULL) {
|
||||||
/* For read only case reset to the start again */
|
/* For read only case reset to the start again */
|
||||||
if (b->flags & BIO_FLAGS_MEM_RDONLY) {
|
if ((b->flags & BIO_FLAGS_MEM_RDONLY) || (b->flags & BIO_FLAGS_NONCLEAR_RST)) {
|
||||||
bm->data -= bm->max - bm->length;
|
|
||||||
bm->length = bm->max;
|
bm->length = bm->max;
|
||||||
} else {
|
} else {
|
||||||
memset(bm->data, 0, bm->max);
|
memset(bm->data, 0, bm->max);
|
||||||
bm->length = 0;
|
bm->length = 0;
|
||||||
}
|
}
|
||||||
|
*bbm->readp = *bbm->buf;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BIO_CTRL_EOF:
|
case BIO_CTRL_EOF:
|
||||||
|
bm = bbm->readp;
|
||||||
ret = (long)(bm->length == 0);
|
ret = (long)(bm->length == 0);
|
||||||
break;
|
break;
|
||||||
case BIO_C_SET_BUF_MEM_EOF_RETURN:
|
case BIO_C_SET_BUF_MEM_EOF_RETURN:
|
||||||
b->num = (int)num;
|
b->num = (int)num;
|
||||||
break;
|
break;
|
||||||
case BIO_CTRL_INFO:
|
case BIO_CTRL_INFO:
|
||||||
|
bm = bbm->readp;
|
||||||
ret = (long)bm->length;
|
ret = (long)bm->length;
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
pptr = (char **)ptr;
|
pptr = (char **)ptr;
|
||||||
@ -257,12 +295,16 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BIO_C_SET_BUF_MEM:
|
case BIO_C_SET_BUF_MEM:
|
||||||
mem_free(b);
|
mem_buf_free(b, 0);
|
||||||
b->shutdown = (int)num;
|
b->shutdown = (int)num;
|
||||||
b->ptr = ptr;
|
bbm->buf = ptr;
|
||||||
|
*bbm->readp = *bbm->buf;
|
||||||
|
b->ptr = bbm;
|
||||||
break;
|
break;
|
||||||
case BIO_C_GET_BUF_MEM_PTR:
|
case BIO_C_GET_BUF_MEM_PTR:
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
|
mem_buf_sync(b);
|
||||||
|
bm = bbm->readp;
|
||||||
pptr = (char **)ptr;
|
pptr = (char **)ptr;
|
||||||
*pptr = (char *)bm;
|
*pptr = (char *)bm;
|
||||||
}
|
}
|
||||||
@ -273,11 +315,11 @@ static long mem_ctrl(BIO *b, int cmd, long num, void *ptr)
|
|||||||
case BIO_CTRL_SET_CLOSE:
|
case BIO_CTRL_SET_CLOSE:
|
||||||
b->shutdown = (int)num;
|
b->shutdown = (int)num;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BIO_CTRL_WPENDING:
|
case BIO_CTRL_WPENDING:
|
||||||
ret = 0L;
|
ret = 0L;
|
||||||
break;
|
break;
|
||||||
case BIO_CTRL_PENDING:
|
case BIO_CTRL_PENDING:
|
||||||
|
bm = bbm->readp;
|
||||||
ret = (long)bm->length;
|
ret = (long)bm->length;
|
||||||
break;
|
break;
|
||||||
case BIO_CTRL_DUP:
|
case BIO_CTRL_DUP:
|
||||||
@ -298,7 +340,8 @@ static int mem_gets(BIO *bp, char *buf, int size)
|
|||||||
int i, j;
|
int i, j;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
char *p;
|
char *p;
|
||||||
BUF_MEM *bm = (BUF_MEM *)bp->ptr;
|
BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr;
|
||||||
|
BUF_MEM *bm = bbm->readp;
|
||||||
|
|
||||||
BIO_clear_retry_flags(bp);
|
BIO_clear_retry_flags(bp);
|
||||||
j = bm->length;
|
j = bm->length;
|
||||||
|
@ -39,9 +39,10 @@ Memory BIOs support BIO_gets() and BIO_puts().
|
|||||||
If the BIO_CLOSE flag is set when a memory BIO is freed then the underlying
|
If the BIO_CLOSE flag is set when a memory BIO is freed then the underlying
|
||||||
BUF_MEM structure is also freed.
|
BUF_MEM structure is also freed.
|
||||||
|
|
||||||
Calling BIO_reset() on a read write memory BIO clears any data in it. On a
|
Calling BIO_reset() on a read write memory BIO clears any data in it if the
|
||||||
read only BIO it restores the BIO to its original state and the read only
|
flag BIO_FLAGS_NONCLEAR_RST is not set. On a read only BIO or if the flag
|
||||||
data can be read again.
|
BIO_FLAGS_NONCLEAR_RST is set it restores the BIO to its original state and
|
||||||
|
the data can be read again.
|
||||||
|
|
||||||
BIO_eof() is true if no data is in the BIO.
|
BIO_eof() is true if no data is in the BIO.
|
||||||
|
|
||||||
@ -90,12 +91,6 @@ give undefined results, including perhaps a program crash.
|
|||||||
|
|
||||||
There should be an option to set the maximum size of a memory BIO.
|
There should be an option to set the maximum size of a memory BIO.
|
||||||
|
|
||||||
There should be a way to "rewind" a read write BIO without destroying
|
|
||||||
its contents.
|
|
||||||
|
|
||||||
The copying operation should not occur after every small read of a large BIO
|
|
||||||
to improve efficiency.
|
|
||||||
|
|
||||||
=head1 EXAMPLE
|
=head1 EXAMPLE
|
||||||
|
|
||||||
Create a memory BIO and write some data to it:
|
Create a memory BIO and write some data to it:
|
||||||
|
@ -216,10 +216,12 @@ extern "C" {
|
|||||||
# define BIO_FLAGS_BASE64_NO_NL 0x100
|
# define BIO_FLAGS_BASE64_NO_NL 0x100
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used with memory BIOs: it means we shouldn't free up or change the
|
* This is used with memory BIOs:
|
||||||
* data in any way.
|
* BIO_FLAGS_MEM_RDONLY means we shouldn't free up or change the data in any way;
|
||||||
|
* BIO_FLAGS_NONCLEAR_RST means we should't clear data on reset.
|
||||||
*/
|
*/
|
||||||
# define BIO_FLAGS_MEM_RDONLY 0x200
|
# define BIO_FLAGS_MEM_RDONLY 0x200
|
||||||
|
# define BIO_FLAGS_NONCLEAR_RST 0x400
|
||||||
|
|
||||||
typedef union bio_addr_st BIO_ADDR;
|
typedef union bio_addr_st BIO_ADDR;
|
||||||
typedef struct bio_addrinfo_st BIO_ADDRINFO;
|
typedef struct bio_addrinfo_st BIO_ADDRINFO;
|
||||||
|
@ -128,6 +128,7 @@ typedef struct bn_recp_ctx_st BN_RECP_CTX;
|
|||||||
typedef struct bn_gencb_st BN_GENCB;
|
typedef struct bn_gencb_st BN_GENCB;
|
||||||
|
|
||||||
typedef struct buf_mem_st BUF_MEM;
|
typedef struct buf_mem_st BUF_MEM;
|
||||||
|
typedef struct bio_buf_mem_st BIO_BUF_MEM;
|
||||||
|
|
||||||
typedef struct evp_cipher_st EVP_CIPHER;
|
typedef struct evp_cipher_st EVP_CIPHER;
|
||||||
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
|
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
|
||||||
|
Loading…
Reference in New Issue
Block a user