#include "util-print.h"
#include "util-validate.h"
#include "util-debug.h"
+#include "util-error.h"
static void ListRegions(StreamingBuffer *sb);
return candidate;
}
+/** \note uses sc_errno to give error details */
static inline StreamingBufferRegion *InitBufferRegion(
StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint32_t min_size)
{
if (sb->regions == USHRT_MAX || (cfg->max_regions != 0 && sb->regions >= cfg->max_regions)) {
SCLogDebug("max regions reached");
+ sc_errno = SC_ELIMIT;
return NULL;
}
StreamingBufferRegion *aux_r = CALLOC(cfg, 1, sizeof(*aux_r));
- if (aux_r == NULL)
+ if (aux_r == NULL) {
+ sc_errno = SC_ENOMEM;
return NULL;
+ }
aux_r->buf = CALLOC(cfg, 1, MAX(cfg->buf_size, min_size));
if (aux_r->buf == NULL) {
FREE(cfg, aux_r, sizeof(*aux_r));
+ sc_errno = SC_ENOMEM;
return NULL;
}
aux_r->buf_size = MAX(cfg->buf_size, min_size);
{
sb->region.buf = CALLOC(cfg, 1, cfg->buf_size);
if (sb->region.buf == NULL) {
- return -1;
+ return SC_ENOMEM;
}
sb->region.buf_size = cfg->buf_size;
- return 0;
+ return SC_OK;
}
StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg)
{
StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer));
- if (sb != NULL) {
- sb->region.buf_size = cfg->buf_size;
- sb->regions = sb->max_regions = 1;
+ if (sb == NULL) {
+ sc_errno = SC_ENOMEM;
+ return NULL;
+ }
- if (cfg->buf_size > 0) {
- if (InitBuffer(sb, cfg) == 0) {
- return sb;
- }
- FREE(cfg, sb, sizeof(StreamingBuffer));
- /* implied buf_size == 0 */
- } else {
- return sb;
- }
+ sb->region.buf_size = cfg->buf_size;
+ sb->regions = sb->max_regions = 1;
+
+ if (cfg->buf_size == 0) {
+ return sb;
}
- return NULL;
+
+ int r = InitBuffer(sb, cfg);
+ if (r != SC_OK) {
+ FREE(cfg, sb, sizeof(StreamingBuffer));
+ sc_errno = r;
+ return NULL;
+ }
+ return sb;
}
void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
/* need to set up 2: existing data block and new data block */
StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
if (sbb == NULL) {
- return -1;
+ return SC_ENOMEM;
}
sbb->offset = sb->region.stream_offset;
sbb->len = sb->region.buf_offset;
StreamingBufferBlock *sbb2 = CALLOC(cfg, 1, sizeof(*sbb2));
if (sbb2 == NULL) {
- return -1;
+ return SC_ENOMEM;
}
sbb2->offset = region->stream_offset + rel_offset;
sbb2->len = data_len;
sb->sbb_size += sbb2->len;
if (SBB_RB_INSERT(&sb->sbb_tree, sbb2) != NULL) {
FREE(cfg, sbb2, sizeof(*sbb2));
- return -1;
+ return SC_EINVAL;
}
#ifdef DEBUG
SBBPrintList(sb);
#endif
- return 0;
+ return SC_OK;
}
/* setup with leading gap
DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
- if (sbb == NULL)
- return -1;
+ if (sbb == NULL) {
+ return SC_ENOMEM;
+ }
sbb->offset = offset;
sbb->len = data_len;
#ifdef DEBUG
SBBPrintList(sb);
#endif
- return 0;
+ return SC_OK;
}
static inline void ConsolidateFwd(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
SCLogDebug("* inserting: %u/%u", rel_offset, len);
StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
- if (sbb == NULL)
- return -1;
+ if (sbb == NULL) {
+ return SC_ENOMEM;
+ }
sbb->offset = region->stream_offset + rel_offset;
sbb->len = len;
SCLogDebug("* insert failed: exact match in tree with %p %" PRIu64 "/%u", res, res->offset,
res->len);
FREE(cfg, sbb, sizeof(StreamingBufferBlock));
- return 0;
+ return SC_OK;
}
sb->sbb_size += len; // may adjust based on consolidation below
SCLogDebug("insert at region head");
region->buf_offset = sbb->len;
}
- return 0;
+ return SC_OK;
}
static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
size, BIT_U32(30));
g2s_warn_once = true;
}
- return -1;
+ return SC_ELIMIT;
}
/* try to grow in multiples of cfg->buf_size */
void *ptr = REALLOC(cfg, region->buf, region->buf_size, grow);
if (ptr == NULL) {
- return -1;
+ return SC_ENOMEM;
}
/* for safe printing and general caution, lets memset the
* new data to 0 */
sb->buf_size_max = region->buf_size;
}
#endif
- return 0;
+ return SC_OK;
}
static int WARN_UNUSED GrowToSize(
if (!DATA_FITS(sb, data_len)) {
if (sb->region.buf_size == 0) {
- if (GrowToSize(sb, cfg, data_len) != 0)
+ if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
} else {
- if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != 0)
+ if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK)
return -1;
}
}
if (!DATA_FITS(sb, data_len)) {
if (sb->region.buf_size == 0) {
- if (GrowToSize(sb, cfg, data_len) != 0)
+ if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
} else {
- if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != 0)
+ if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK)
return -1;
}
}
/** \internal
* \brief process insert by consolidating the affected regions into one
+ * \note sets sc_errno
*/
static StreamingBufferRegion *BufferInsertAtRegionConsolidate(StreamingBuffer *sb,
const StreamingBufferConfig *cfg, StreamingBufferRegion *dst,
const uint64_t data_offset, const uint32_t data_len, StreamingBufferRegion *prev,
uint32_t dst_buf_size)
{
+ int retval;
#ifdef DEBUG
const uint64_t data_re = data_offset + data_len;
SCLogDebug("sb %p dst %p src_start %p src_end %p data_offset %" PRIu64
SCLogDebug("old_size %u, old_offset %u, dst_copy_offset %u", old_size, old_offset,
dst_copy_offset);
#endif
- if (GrowRegionToSize(sb, cfg, dst, dst_size) != 0)
+ if ((retval = GrowRegionToSize(sb, cfg, dst, dst_size)) != SC_OK) {
+ sc_errno = retval;
return NULL;
+ }
SCLogDebug("resized to %u -> %u", dst_size, dst->buf_size);
/* validate that the size is exactly what we asked for */
DEBUG_VALIDATE_BUG_ON(dst_size != dst->buf_size);
return dst;
}
+/** \note sets sc_errno */
static StreamingBufferRegion *BufferInsertAtRegionDo(StreamingBuffer *sb,
const StreamingBufferConfig *cfg, const uint64_t offset, const uint32_t len)
{
SCLogDebug("start region %p/%" PRIu64 "/%u", start, start->stream_offset, start->buf_size);
StreamingBufferRegion *big = FindLargestRegionForOffset(sb, cfg, start, offset, len);
DEBUG_VALIDATE_BUG_ON(big == NULL);
- if (big == NULL)
+ if (big == NULL) {
+ sc_errno = SC_EINVAL;
return NULL;
-
+ }
SCLogDebug("big region %p/%" PRIu64 "/%u", big, big->stream_offset, big->buf_size);
StreamingBufferRegion *end = FindRightEdge(sb, cfg, big, offset, len);
DEBUG_VALIDATE_BUG_ON(end == NULL);
- if (end == NULL)
+ if (end == NULL) {
+ sc_errno = SC_EINVAL;
return NULL;
+ }
insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size));
uint32_t new_buf_size =
}
SCLogDebug("end region %p/%" PRIu64 "/%u", end, end->stream_offset, end->buf_size);
+ /* sets sc_errno */
StreamingBufferRegion *ret = BufferInsertAtRegionConsolidate(
sb, cfg, big, start, end, offset, len, start_prev, new_buf_size);
return ret;
SCLogDebug("no matching region found, append to %p (%s)", append,
append == &sb->region ? "main" : "aux");
+ /* sets sc_errno */
StreamingBufferRegion *add = InitBufferRegion(sb, cfg, len);
if (add == NULL)
return NULL;
* Will find an existing region, expand it if needed. If no existing region exists or is
* a good fit, it will try to set up a new region. If the region then overlaps or gets
* too close to the next, merge them.
+ *
+ * \note sets sc_errno
*/
static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb,
const StreamingBufferConfig *cfg, const uint8_t *data, const uint32_t data_len,
"data_offset %" PRIu64
", data_len %u intersects with main region, no next or way before next region",
data_offset, data_len);
- if (sb->region.buf == NULL)
- if (InitBuffer(sb, cfg) == -1) // TODO init with size
+ if (sb->region.buf == NULL) {
+ int r;
+ if ((r = InitBuffer(sb, cfg)) != SC_OK) { // TODO init with size
+ sc_errno = r;
return NULL;
+ }
+ }
return &sb->region;
}
} else if (sb->region.next == NULL) {
+ /* InitBufferRegion sets sc_errno */
StreamingBufferRegion *aux_r = sb->region.next = InitBufferRegion(sb, cfg, data_len);
if (aux_r == NULL)
return NULL;
aux_r->stream_offset, aux_r->buf_size);
return aux_r;
}
+ /* BufferInsertAtRegionDo sets sc_errno */
StreamingBufferRegion *blob = BufferInsertAtRegionDo(sb, cfg, data_offset, data_len);
SCLogDebug("blob %p (%s)", blob, blob == &sb->region ? "main" : "aux");
return blob;
/**
* \param offset offset relative to StreamingBuffer::stream_offset
*
- * \return 0 in case of success
- * \return -1 on memory allocation errors
- * \return negative value on other errors
+ * \return SC_OK in case of success
+ * \return SC_E* errors otherwise
*/
int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset)
{
+ int r;
+
BUG_ON(seg == NULL);
DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset);
- if (offset < sb->region.stream_offset)
- return -2;
+ if (offset < sb->region.stream_offset) {
+ return SC_EINVAL;
+ }
StreamingBufferRegion *region = BufferInsertAtRegion(sb, cfg, data, data_len, offset);
if (region == NULL) {
- return -1;
+ return sc_errno;
}
const bool region_is_main = region == &sb->region;
uint32_t rel_offset = offset - region->stream_offset;
if (!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)) {
- if (GrowToSize(sb, cfg, (rel_offset + data_len)) != 0)
- return -1;
+ if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK)
+ return r;
}
DEBUG_VALIDATE_BUG_ON(!DATA_FITS_AT_OFFSET(region, data_len, rel_offset));
} else if (sb->region.buf_offset) {
SCLogDebug("beyond expected offset: SBBInit");
/* existing data, but there is a gap between us */
- if (SBBInit(sb, cfg, region, rel_offset, data_len) < 0)
- return -1;
+ if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
+ return r;
} else {
/* gap before data in empty list */
SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
- if (SBBInitLeadingGap(sb, cfg, region, offset, data_len) < 0)
- return -1;
+ if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK)
+ return r;
}
}
} else {
if (sb->region.buf_offset) {
/* existing data, but there is a gap between us */
SCLogDebug("empty sbb list, no data in main: use SBBInit");
- if (SBBInit(sb, cfg, region, rel_offset, data_len) < 0)
- return -1;
+ if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
+ return r;
} else {
/* gap before data in empty list */
SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
- if (SBBInitLeadingGap(sb, cfg, region, offset, data_len) < 0)
- return -1;
+ if ((r = SBBInitLeadingGap(sb, cfg, region, offset, data_len)) != SC_OK)
+ return r;
}
if (rel_offset == region->buf_offset) {
SCLogDebug("pre region->buf_offset %u", region->buf_offset);
} else {
SCLogDebug("updating sbb tree");
/* already have blocks, so append new block based on new data */
- if (SBBUpdate(sb, cfg, region, rel_offset, data_len) < 0)
- return -1;
+ if ((r = SBBUpdate(sb, cfg, region, rel_offset, data_len)) != SC_OK)
+ return r;
}
BUG_ON(!region_is_main && sb->head == NULL);
BUG_ON(offset + data_len > sb->region.stream_offset + sb->region.buf_offset);
}
- return 0;
+ return SC_OK;
}
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb,