-/* $OpenBSD: bss_mem.c,v 1.20 2022/02/19 08:11:16 jsing Exp $ */
+/* $OpenBSD: bss_mem.c,v 1.21 2022/02/19 15:59:12 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
struct bio_mem {
BUF_MEM *buf;
+ size_t read_offset;
};
+static size_t
+bio_mem_pending(struct bio_mem *bm)
+{
+ if (bm->read_offset > bm->buf->length)
+ return 0;
+
+ return bm->buf->length - bm->read_offset;
+}
+
+static uint8_t *
+bio_mem_read_ptr(struct bio_mem *bm)
+{
+ return &bm->buf->data[bm->read_offset];
+}
+
static int mem_new(BIO *bio);
static int mem_free(BIO *bio);
static int mem_write(BIO *bio, const char *in, int in_len);
if (out == NULL || out_len <= 0)
return 0;
- if ((size_t)out_len > bm->buf->length)
- out_len = bm->buf->length;
+ if ((size_t)out_len > bio_mem_pending(bm))
+ out_len = bio_mem_pending(bm);
if (out_len == 0) {
if (bio->num != 0)
return bio->num;
}
- memcpy(out, bm->buf->data, out_len);
- bm->buf->length -= out_len;
- if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
- bm->buf->data += out_len;
- } else {
- memmove(&(bm->buf->data[0]), &(bm->buf->data[out_len]),
- bm->buf->length);
- }
+ memcpy(out, bio_mem_read_ptr(bm), out_len);
+ bm->read_offset += out_len;
+
return out_len;
}
return -1;
}
+ if (bm->read_offset > 4096) {
+ memmove(bm->buf->data, bio_mem_read_ptr(bm),
+ bio_mem_pending(bm));
+ bm->buf->length = bio_mem_pending(bm);
+ bm->read_offset = 0;
+ }
+
/*
* Check for overflow and ensure we do not exceed an int, otherwise we
* cannot tell if BUF_MEM_grow_clean() succeeded.
switch (cmd) {
case BIO_CTRL_RESET:
if (bm->buf->data != NULL) {
- /* For read only case reset to the start again */
- if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
- bm->buf->data -= bm->buf->max - bm->buf->length;
- bm->buf->length = bm->buf->max;
- } else {
+ if (!(bio->flags & BIO_FLAGS_MEM_RDONLY)) {
memset(bm->buf->data, 0, bm->buf->max);
bm->buf->length = 0;
}
+ bm->read_offset = 0;
}
break;
case BIO_CTRL_EOF:
- ret = (long)(bm->buf->length == 0);
+ ret = (long)(bio_mem_pending(bm) == 0);
break;
case BIO_C_SET_BUF_MEM_EOF_RETURN:
bio->num = (int)num;
case BIO_CTRL_INFO:
if (ptr != NULL) {
pptr = (void **)ptr;
- *pptr = bm->buf->data;
+ *pptr = bio_mem_read_ptr(bm);
}
- ret = (long)bm->buf->length;
+ ret = (long)bio_mem_pending(bm);
break;
case BIO_C_SET_BUF_MEM:
BUF_MEM_free(bm->buf);
bio->shutdown = (int)num;
bm->buf = ptr;
+ bm->read_offset = 0;
break;
case BIO_C_GET_BUF_MEM_PTR:
if (ptr != NULL) {
ret = 0L;
break;
case BIO_CTRL_PENDING:
- ret = (long)bm->buf->length;
+ ret = (long)bio_mem_pending(bm);
break;
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH:
BIO_clear_retry_flags(bio);
- out_max = bm->buf->length;
+ out_max = bio_mem_pending(bm);
if (out_len - 1 < out_max)
out_max = out_len - 1;
if (out_max <= 0) {
return 0;
}
- p = bm->buf->data;
+ p = bio_mem_read_ptr(bm);
for (i = 0; i < out_max; i++) {
if (p[i] == '\n') {
i++;