openGauss-server/contrib/pgcrypto/mbuf.cpp

493 lines
10 KiB
C++

/*
* mbuf.c
* Memory buffer operations.
*
* Copyright (c) 2005 Marko Kreen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* contrib/pgcrypto/mbuf.c
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "px.h"
#include "mbuf.h"
#define STEP (16 * 1024)
struct MBuf {
uint8* data;
uint8* data_end;
uint8* read_pos;
uint8* buf_end;
bool no_write;
bool own_data;
};
int mbuf_avail(MBuf* mbuf)
{
return mbuf->data_end - mbuf->read_pos;
}
int mbuf_size(MBuf* mbuf)
{
return mbuf->data_end - mbuf->data;
}
int mbuf_tell(MBuf* mbuf)
{
return mbuf->read_pos - mbuf->data;
}
int mbuf_free(MBuf* mbuf)
{
if (mbuf->own_data) {
memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
px_free(mbuf->data);
}
px_free(mbuf);
return 0;
}
static void prepare_room(MBuf* mbuf, int block_len)
{
uint8* newbuf = NULL;
unsigned newlen;
if (mbuf->data_end + block_len <= mbuf->buf_end)
return;
newlen = (mbuf->buf_end - mbuf->data) + ((block_len + STEP + STEP - 1) & -STEP);
newbuf = (uint8*)px_realloc(mbuf->data, newlen);
mbuf->buf_end = newbuf + newlen;
mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
mbuf->data = newbuf;
return;
}
int mbuf_append(MBuf* dst, const uint8* buf, int len)
{
if (dst->no_write) {
px_debug("mbuf_append: no_write");
return PXE_BUG;
}
prepare_room(dst, len);
memcpy(dst->data_end, buf, len);
dst->data_end += len;
return 0;
}
MBuf* mbuf_create(int len)
{
MBuf* mbuf = NULL;
if (!len)
len = 8192;
mbuf = (MBuf*)px_alloc(sizeof *mbuf);
mbuf->data = (uint8*)px_alloc(len);
mbuf->buf_end = mbuf->data + len;
mbuf->data_end = mbuf->data;
mbuf->read_pos = mbuf->data;
mbuf->no_write = false;
mbuf->own_data = true;
return mbuf;
}
MBuf* mbuf_create_from_data(uint8* data, int len)
{
MBuf* mbuf = NULL;
mbuf = (MBuf*)px_alloc(sizeof *mbuf);
mbuf->data = (uint8*)data;
mbuf->buf_end = mbuf->data + len;
mbuf->data_end = mbuf->data + len;
mbuf->read_pos = mbuf->data;
mbuf->no_write = true;
mbuf->own_data = false;
return mbuf;
}
int mbuf_grab(MBuf* mbuf, int len, uint8** data_p)
{
if (len > mbuf_avail(mbuf))
len = mbuf_avail(mbuf);
mbuf->no_write = true;
*data_p = mbuf->read_pos;
mbuf->read_pos += len;
return len;
}
int mbuf_rewind(MBuf* mbuf)
{
mbuf->read_pos = mbuf->data;
return 0;
}
int mbuf_steal_data(MBuf* mbuf, uint8** data_p)
{
int len = mbuf_size(mbuf);
mbuf->no_write = true;
mbuf->own_data = false;
*data_p = mbuf->data;
mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL;
return len;
}
/*
* PullFilter
*/
struct PullFilter {
PullFilter* src;
const PullFilterOps* op;
int buflen;
uint8* buf;
int pos;
void* priv;
};
int pullf_create(PullFilter** pf_p, const PullFilterOps* op, void* init_arg, PullFilter* src)
{
PullFilter* pf = NULL;
void* priv = NULL;
int res;
if (op->init != NULL) {
res = op->init(&priv, init_arg, src);
if (res < 0)
return res;
} else {
priv = init_arg;
res = 0;
}
pf = (PullFilter*)px_alloc(sizeof(*pf));
memset(pf, 0, sizeof(*pf));
pf->buflen = res;
pf->op = op;
pf->priv = priv;
pf->src = src;
if (pf->buflen > 0) {
pf->buf = (uint8*)px_alloc(pf->buflen);
pf->pos = 0;
} else {
pf->buf = NULL;
pf->pos = 0;
}
*pf_p = pf;
return 0;
}
void pullf_free(PullFilter* pf)
{
if (pf->op->free)
pf->op->free(pf->priv);
if (pf->buf) {
memset(pf->buf, 0, pf->buflen);
px_free(pf->buf);
}
memset(pf, 0, sizeof(*pf));
px_free(pf);
}
/* may return less data than asked, 0 means eof */
int pullf_read(PullFilter* pf, int len, uint8** data_p)
{
int res;
if (pf->op->pull) {
if (pf->buflen && len > pf->buflen)
len = pf->buflen;
res = pf->op->pull(pf->priv, pf->src, len, data_p, pf->buf, pf->buflen);
} else
res = pullf_read(pf->src, len, data_p);
return res;
}
int pullf_read_max(PullFilter* pf, int len, uint8** data_p, uint8* tmpbuf)
{
int res, total;
uint8* tmp = NULL;
res = pullf_read(pf, len, data_p);
if (res <= 0 || res == len)
return res;
/* read was shorter, use tmpbuf */
memcpy(tmpbuf, *data_p, res);
*data_p = tmpbuf;
len -= res;
total = res;
while (len > 0) {
res = pullf_read(pf, len, &tmp);
if (res < 0) {
/* so the caller must clear only on success */
memset(tmpbuf, 0, total);
return res;
}
if (res == 0)
break;
memcpy(tmpbuf + total, tmp, res);
total += res;
}
return total;
}
/*
* caller wants exatly len bytes and dont bother with references
*/
int pullf_read_fixed(PullFilter* src, int len, uint8* dst)
{
int res;
uint8* p = NULL;
res = pullf_read_max(src, len, &p, dst);
if (res < 0)
return res;
if (res != len) {
px_debug("pullf_read_fixed: need=%d got=%d", len, res);
return PXE_MBUF_SHORT_READ;
}
if (p != dst)
memcpy(dst, p, len);
return 0;
}
/*
* read from MBuf
*/
static int pull_from_mbuf(void* arg, PullFilter* src, int len, uint8** data_p, uint8* buf, int buflen)
{
MBuf* mbuf = (MBuf*)arg;
return mbuf_grab(mbuf, len, data_p);
}
static const struct PullFilterOps mbuf_reader = {NULL, pull_from_mbuf, NULL};
int pullf_create_mbuf_reader(PullFilter** mp_p, MBuf* src)
{
return pullf_create(mp_p, &mbuf_reader, src, NULL);
}
/*
* PushFilter
*/
struct PushFilter {
PushFilter* next;
const PushFilterOps* op;
int block_size;
uint8* buf;
int pos;
void* priv;
};
int pushf_create(PushFilter** mp_p, const PushFilterOps* op, void* init_arg, PushFilter* next)
{
PushFilter* mp = NULL;
void* priv = NULL;
int res;
if (op->init != NULL) {
res = op->init(next, init_arg, &priv);
if (res < 0)
return res;
} else {
priv = init_arg;
res = 0;
}
mp = (PushFilter*)px_alloc(sizeof(*mp));
memset(mp, 0, sizeof(*mp));
mp->block_size = res;
mp->op = op;
mp->priv = priv;
mp->next = next;
if (mp->block_size > 0) {
mp->buf = (uint8*)px_alloc(mp->block_size);
mp->pos = 0;
} else {
mp->buf = NULL;
mp->pos = 0;
}
*mp_p = mp;
return 0;
}
void pushf_free(PushFilter* mp)
{
if (mp->op->free)
mp->op->free(mp->priv);
if (mp->buf) {
memset(mp->buf, 0, mp->block_size);
px_free(mp->buf);
}
memset(mp, 0, sizeof(*mp));
px_free(mp);
}
void pushf_free_all(PushFilter* mp)
{
PushFilter* tmp = NULL;
while (mp) {
tmp = mp->next;
pushf_free(mp);
mp = tmp;
}
}
static int wrap_process(PushFilter* mp, const uint8* data, int len)
{
int res;
if (mp->op->push != NULL)
res = mp->op->push(mp->next, mp->priv, data, len);
else
res = pushf_write(mp->next, data, len);
if (res > 0)
return PXE_BUG;
return res;
}
/* consumes all data, returns len on success */
int pushf_write(PushFilter* mp, const uint8* data, int len)
{
int need, res;
/*
* no buffering
*/
if (mp->block_size <= 0)
return wrap_process(mp, data, len);
/*
* try to empty buffer
*/
need = mp->block_size - mp->pos;
if (need > 0) {
if (len < need) {
memcpy(mp->buf + mp->pos, data, len);
mp->pos += len;
return 0;
}
memcpy(mp->buf + mp->pos, data, need);
len -= need;
data += need;
}
/*
* buffer full, process
*/
res = wrap_process(mp, mp->buf, mp->block_size);
if (res < 0)
return res;
mp->pos = 0;
/*
* now process directly from data
*/
while (len > 0) {
if (len > mp->block_size) {
res = wrap_process(mp, data, mp->block_size);
if (res < 0)
return res;
data += mp->block_size;
len -= mp->block_size;
} else {
memcpy(mp->buf, data, len);
mp->pos += len;
break;
}
}
return 0;
}
int pushf_flush(PushFilter* mp)
{
int res;
while (mp) {
if (mp->block_size > 0) {
res = wrap_process(mp, mp->buf, mp->pos);
if (res < 0)
return res;
}
if (mp->op->flush) {
res = mp->op->flush(mp->next, mp->priv);
if (res < 0)
return res;
}
mp = mp->next;
}
return 0;
}
/*
* write to MBuf
*/
static int push_into_mbuf(PushFilter* next, void* arg, const uint8* data, int len)
{
int res = 0;
MBuf* mbuf = (MBuf*)arg;
if (len > 0)
res = mbuf_append(mbuf, data, len);
return res < 0 ? res : 0;
}
static const struct PushFilterOps mbuf_filter = {NULL, push_into_mbuf, NULL, NULL};
int pushf_create_mbuf_writer(PushFilter** res, MBuf* dst)
{
return pushf_create(res, &mbuf_filter, dst, NULL);
}