• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22550237931

01 Mar 2026 06:56PM UTC coverage: 64.812% (-8.9%) from 73.687%
22550237931

Pull #14920

github

web-flow
Merge e05854a6d into 90823fa90
Pull Request #14920: draft: rust based configuration file parser and loader - v4

561 of 789 new or added lines in 4 files covered. (71.1%)

23225 existing lines in 498 files now uncovered.

131605 of 203055 relevant lines covered (64.81%)

2328818.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.81
/src/util-streaming-buffer.c
1
/* Copyright (C) 2015-2023 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
#include "suricata-common.h"
19
#include "util-streaming-buffer.h"
20
#include "util-unittest.h"
21
#include "util-print.h"
22
#include "util-validate.h"
23
#include "util-debug.h"
24
#include "util-error.h"
25

26
#include "app-layer-htp-mem.h"
27
#include "conf-yaml-loader.h"
28
#include "app-layer-htp.h"
29

30
static void ListRegions(StreamingBuffer *sb);
31

32
#define DUMP_REGIONS 0 // set to 1 to dump a visual representation of the regions list and sbb tree.
33

34
/**
35
 * \file
36
 *
37
 * \author Victor Julien <victor@inliniac.net>
38
 *
39
 *  \brief Streaming Buffer API
40
 */
41

42
static void *ReallocFunc(void *ptr, const size_t size)
43
{
21,664✔
44
    void *ptrmem = SCRealloc(ptr, size);
21,664✔
45
    if (unlikely(ptrmem == NULL)) {
21,664✔
46
        sc_errno = SC_ENOMEM;
×
47
    }
×
48
    return ptrmem;
21,664✔
49
}
21,664✔
50

51
static void *CallocFunc(const size_t nm, const size_t sz)
52
{
19,894✔
53
    void *ptrmem = SCCalloc(nm, sz);
19,894✔
54
    if (unlikely(ptrmem == NULL)) {
19,894✔
55
        sc_errno = SC_ENOMEM;
×
56
    }
×
57
    return ptrmem;
19,894✔
58
}
19,894✔
59

60
/* memory handling wrappers. If config doesn't define it's own set of
61
 * functions, use the defaults */
62
// TODO the default allocators don't set `sc_errno` yet.
63
#define CALLOC(cfg, n, s) (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : CallocFunc((n), (s))
258,023✔
64
#define REALLOC(cfg, ptr, orig_s, s)                                                               \
65
    (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : ReallocFunc((ptr), (s))
116,490✔
66
#define FREE(cfg, ptr, s) \
67
    (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr))
257,970✔
68

69
static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg);
70

71
RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare);
1,881,231✔
72

1,881,231✔
73
int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b)
1,881,231✔
74
{
1,881,231✔
75
    SCLogDebug("a %" PRIu64 " len %u, b %" PRIu64 " len %u", a->offset, a->len, b->offset, b->len);
244,435✔
76

77
    if (a->offset > b->offset)
244,435✔
78
        SCReturnInt(1);
232,938✔
79
    else if (a->offset < b->offset)
11,497✔
80
        SCReturnInt(-1);
11,158✔
81
    else {
339✔
82
        if (a->len == 0 || b->len == 0 || a->len ==  b->len)
339✔
83
            SCReturnInt(0);
238✔
84
        else if (a->len > b->len)
101✔
85
            SCReturnInt(1);
9✔
86
        else
92✔
87
            SCReturnInt(-1);
92✔
88
    }
339✔
89
}
244,435✔
90

91
/* inclusive compare function that also considers the right edge,
92
 * not just the offset. */
93
static inline int InclusiveCompare(StreamingBufferBlock *lookup, StreamingBufferBlock *intree) {
684,042✔
94
    const uint64_t lre = lookup->offset + lookup->len;
684,042✔
95
    const uint64_t tre = intree->offset + intree->len;
684,042✔
96
    if (lre <= intree->offset)   // entirely before
684,042✔
97
        return -1;
81,810✔
98
    else if (lookup->offset < tre && lre <= tre) // (some) overlap
602,232✔
99
        return 0;
287,987✔
100
    else
314,245✔
101
        return 1;   // entirely after
314,245✔
102
}
684,042✔
103

104
StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm)
105
{
442,390✔
106
    SCLogDebug("looking up %" PRIu64, elm->offset);
442,390✔
107

108
    struct StreamingBufferBlock *tmp = RB_ROOT(head);
442,390✔
109
    struct StreamingBufferBlock *res = NULL;
442,390✔
110
    while (tmp) {
838,445✔
111
        SCLogDebug("compare with %" PRIu64 "/%u", tmp->offset, tmp->len);
684,042✔
112
        const int comp = InclusiveCompare(elm, tmp);
684,042✔
113
        SCLogDebug("compare result: %d", comp);
684,042✔
114
        if (comp < 0) {
684,042✔
115
            res = tmp;
81,810✔
116
            tmp = RB_LEFT(tmp, rb);
81,810✔
117
        } else if (comp > 0) {
602,232✔
118
            tmp = RB_RIGHT(tmp, rb);
314,245✔
119
        } else {
314,245✔
120
            return tmp;
287,987✔
121
        }
287,987✔
122
    }
684,042✔
123
    return res;
154,403✔
124
}
442,390✔
125

126
/** \interal
127
 *  \brief does data region intersect with list region 'r'
128
 *  Takes the max gap into account.
129
 */
130
static inline bool RegionsIntersect(const StreamingBufferConfig *cfg,
131
        const StreamingBufferRegion *r, const uint64_t offset, const uint64_t re)
132
{
644,297✔
133
    /* create the data range for the region, adding the max gap */
134
    const uint64_t reg_o =
644,297✔
135
            r->stream_offset > cfg->region_gap ? (r->stream_offset - cfg->region_gap) : 0;
644,297✔
136
    const uint64_t reg_re = r->stream_offset + r->buf_size + cfg->region_gap;
644,297✔
137
    SCLogDebug("r %p: %" PRIu64 "/%" PRIu64 " - adjusted %" PRIu64 "/%" PRIu64, r, r->stream_offset,
644,297✔
138
            r->stream_offset + r->buf_size, reg_o, reg_re);
644,297✔
139
    /* check if data range intersects with region range */
140
    /* [offset:re] and [reg_o:reg_re] do not intersect if and only if
141
     * re < reg_o or if reg_re < offset (one segment is strictly before the other)
142
     * trusting that offset<=re and reg_o<=reg_re
143
     */
144
    if (re < reg_o || reg_re < offset) {
644,297✔
145
        return false;
2,228✔
146
    }
2,228✔
147
    return true;
642,069✔
148
}
644,297✔
149

150
/** \internal
151
 *  \brief find the first region for merging.
152
 */
153
static StreamingBufferRegion *FindFirstRegionForOffset(const StreamingBufferConfig *cfg,
154
        StreamingBufferRegion *r, const uint64_t offset, const uint32_t len,
155
        StreamingBufferRegion **prev)
156
{
81✔
157
    const uint64_t data_re = offset + len;
81✔
158
    SCLogDebug("looking for first region matching %" PRIu64 "/%" PRIu64, offset, data_re);
81✔
159

160
    StreamingBufferRegion *p = NULL;
81✔
161
    for (; r != NULL; r = r->next) {
169✔
162
        if (RegionsIntersect(cfg, r, offset, data_re)) {
161✔
163
            *prev = p;
73✔
164
            return r;
73✔
165
        }
73✔
166
        p = r;
88✔
167
    }
88✔
168
    *prev = NULL;
8✔
169
    return NULL;
8✔
170
}
81✔
171

172
static StreamingBufferRegion *FindLargestRegionForOffset(const StreamingBufferConfig *cfg,
173
        StreamingBufferRegion *r, const uint64_t offset, const uint32_t len)
174
{
73✔
175
    const uint64_t data_re = offset + len;
73✔
176
    SCLogDebug("starting at %p/%" PRIu64 ", offset %" PRIu64 ", data_re %" PRIu64, r,
73✔
177
            r->stream_offset, offset, data_re);
73✔
178
    StreamingBufferRegion *candidate = r;
73✔
179
    for (; r != NULL; r = r->next) {
147✔
180
#ifdef DEBUG
181
        const uint64_t reg_re = r->stream_offset + r->buf_size;
182
        SCLogDebug("checking: %p/%" PRIu64 "/%" PRIu64 ", offset %" PRIu64 "/%" PRIu64, r,
183
                r->stream_offset, reg_re, offset, data_re);
184
#endif
185
        if (!RegionsIntersect(cfg, r, offset, data_re))
74✔
186
            return candidate;
×
187

188
        if (r->buf_size > candidate->buf_size) {
74✔
189
            SCLogDebug("candidate %p as size %u > %u", candidate, r->buf_size, candidate->buf_size);
1✔
190
            candidate = r;
1✔
191
        }
1✔
192
    }
74✔
193
    return candidate;
73✔
194
}
73✔
195

196
static StreamingBufferRegion *FindRightEdge(const StreamingBufferConfig *cfg,
197
        StreamingBufferRegion *r, const uint64_t offset, const uint32_t len)
198
{
73✔
199
    const uint64_t data_re = offset + len;
73✔
200
    StreamingBufferRegion *candidate = r;
73✔
201
    for (; r != NULL; r = r->next) {
146✔
202
        if (!RegionsIntersect(cfg, r, offset, data_re)) {
73✔
203
            SCLogDebug(
×
204
                    "r %p is out of scope: %" PRIu64 "/%u/%" PRIu64, r, offset, len, offset + len);
×
205
            return candidate;
×
206
        }
×
207
        candidate = r;
73✔
208
    }
73✔
209
    return candidate;
73✔
210
}
73✔
211

212
/** \note uses sc_errno to give error details */
213
static inline StreamingBufferRegion *InitBufferRegion(
214
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint32_t min_size)
215
{
218✔
216
    if ((cfg->max_regions != 0 && sb->regions >= cfg->max_regions) || (sb->regions == UINT16_MAX)) {
218✔
217
        SCLogDebug("max regions reached");
×
218
        sc_errno = SC_ELIMIT;
×
219
        return NULL;
×
220
    }
×
221

222
    StreamingBufferRegion *aux_r = CALLOC(cfg, 1, sizeof(*aux_r));
218✔
223
    if (aux_r == NULL) {
218✔
224
        return NULL;
×
225
    }
×
226

227
    aux_r->buf = CALLOC(cfg, 1, MAX(cfg->buf_size, min_size));
218✔
228
    if (aux_r->buf == NULL) {
218✔
229
        FREE(cfg, aux_r, sizeof(*aux_r));
×
230
        return NULL;
×
231
    }
×
232
    aux_r->buf_size = MAX(cfg->buf_size, min_size);
218✔
233
    sb->regions++;
218✔
234
    sb->max_regions = MAX(sb->regions, sb->max_regions);
218✔
235
    return aux_r;
218✔
236
}
218✔
237

238
static inline int InitBuffer(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
239
{
78,850✔
240
    sb->region.buf = CALLOC(cfg, 1, cfg->buf_size);
78,850✔
241
    if (sb->region.buf == NULL) {
78,850✔
242
        return sc_errno;
×
243
    }
×
244
    sb->region.buf_size = cfg->buf_size;
78,850✔
245
    return SC_OK;
78,850✔
246
}
78,850✔
247

248
StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg)
249
{
26,235✔
250
    StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer));
26,235✔
251
    if (sb == NULL) {
26,235✔
252
        return NULL;
×
253
    }
×
254

255
    sb->region.buf_size = cfg->buf_size;
26,235✔
256
    sb->regions = sb->max_regions = 1;
26,235✔
257

258
    if (cfg->buf_size == 0) {
26,235✔
259
        return sb;
×
260
    }
×
261

262
    int r = InitBuffer(sb, cfg);
26,235✔
263
    if (r != SC_OK) {
26,235✔
264
        FREE(cfg, sb, sizeof(StreamingBuffer));
×
265
        sc_errno = r;
×
266
        return NULL;
×
267
    }
×
268
    return sb;
26,235✔
269
}
26,235✔
270

271
void StreamingBufferClear(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
272
{
315,168✔
273
    if (sb != NULL) {
315,168✔
274
        SCLogDebug("sb->region.buf_size %u max %u", sb->region.buf_size, sb->buf_size_max);
315,168✔
275

276
        SBBFree(sb, cfg);
315,168✔
277
        ListRegions(sb);
315,168✔
278
        if (sb->region.buf != NULL) {
315,168✔
279
            FREE(cfg, sb->region.buf, sb->region.buf_size);
78,824✔
280
            sb->region.buf = NULL;
78,824✔
281
        }
78,824✔
282

283
        for (StreamingBufferRegion *r = sb->region.next; r != NULL;) {
315,385✔
284
            StreamingBufferRegion *next = r->next;
217✔
285
            FREE(cfg, r->buf, r->buf_size);
217✔
286
            FREE(cfg, r, sizeof(*r));
217✔
287
            r = next;
217✔
288
        }
217✔
289
        sb->region.next = NULL;
315,168✔
290
        sb->regions = sb->max_regions = 1;
315,168✔
291
    }
315,168✔
292
}
315,168✔
293

294
void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
295
{
62,923✔
296
    if (sb != NULL) {
62,923✔
297
        StreamingBufferClear(sb, cfg);
26,208✔
298
        FREE(cfg, sb, sizeof(StreamingBuffer));
26,208✔
299
    }
26,208✔
300
}
62,923✔
301

302
#ifdef DEBUG
303
static void SBBPrintList(StreamingBuffer *sb)
304
{
305
    StreamingBufferBlock *sbb = NULL;
306
    RB_FOREACH(sbb, SBB, &sb->sbb_tree) {
307
        SCLogDebug("sbb: offset %" PRIu64 ", len %u", sbb->offset, sbb->len);
308
        StreamingBufferBlock *next = SBB_RB_NEXT(sbb);
309
        if (next) {
310
            if ((sbb->offset + sbb->len) != next->offset) {
311
                SCLogDebug("gap: offset %" PRIu64 ", len %" PRIu64, (sbb->offset + sbb->len),
312
                        next->offset - (sbb->offset + sbb->len));
313
            }
314
        }
315
    }
316
}
317
#endif
318

319
/* setup with gap between 2 blocks
320
 *
321
 * [block][gap][block]
322
 **/
323
static int WARN_UNUSED SBBInit(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
324
        StreamingBufferRegion *region, uint32_t rel_offset, uint32_t data_len)
325
{
4,115✔
326
    DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
4,115✔
327
    DEBUG_VALIDATE_BUG_ON(region->buf_offset > region->stream_offset + rel_offset);
4,115✔
328

329
    /* need to set up 2: existing data block and new data block */
330
    StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
4,115✔
331
    if (sbb == NULL) {
4,115✔
332
        return sc_errno;
×
333
    }
×
334
    sbb->offset = sb->region.stream_offset;
4,115✔
335
    sbb->len = sb->region.buf_offset;
4,115✔
336
    (void)SBB_RB_INSERT(&sb->sbb_tree, sbb);
4,115✔
337
    sb->head = sbb;
4,115✔
338
    sb->sbb_size = sbb->len;
4,115✔
339

340
    StreamingBufferBlock *sbb2 = CALLOC(cfg, 1, sizeof(*sbb2));
4,115✔
341
    if (sbb2 == NULL) {
4,115✔
342
        return sc_errno;
×
343
    }
×
344
    sbb2->offset = region->stream_offset + rel_offset;
4,115✔
345
    sbb2->len = data_len;
4,115✔
346
    DEBUG_VALIDATE_BUG_ON(sbb2->offset < sbb->len);
4,115✔
347
    SCLogDebug("sbb1 %" PRIu64 ", len %u, sbb2 %" PRIu64 ", len %u", sbb->offset, sbb->len,
4,115✔
348
            sbb2->offset, sbb2->len);
4,115✔
349

350
    sb->sbb_size += sbb2->len;
4,115✔
351
    if (SBB_RB_INSERT(&sb->sbb_tree, sbb2) != NULL) {
4,115✔
352
        FREE(cfg, sbb2, sizeof(*sbb2));
×
353
        return SC_EINVAL;
×
354
    }
×
355

356
#ifdef DEBUG
357
    SBBPrintList(sb);
358
#endif
359
    return SC_OK;
4,115✔
360
}
4,115✔
361

362
/* setup with leading gap
363
 *
364
 * [gap][block]
365
 **/
366
static int WARN_UNUSED SBBInitLeadingGap(
367
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset, uint32_t data_len)
368
{
2,094✔
369
    DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
2,094✔
370

371
    StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
2,094✔
372
    if (sbb == NULL) {
2,094✔
373
        return sc_errno;
×
374
    }
×
375
    sbb->offset = offset;
2,094✔
376
    sbb->len = data_len;
2,094✔
377

378
    sb->head = sbb;
2,094✔
379
    sb->sbb_size = sbb->len;
2,094✔
380
    (void)SBB_RB_INSERT(&sb->sbb_tree, sbb);
2,094✔
381

382
    SCLogDebug("sbb %" PRIu64 ", len %u", sbb->offset, sbb->len);
2,094✔
383
#ifdef DEBUG
384
    SBBPrintList(sb);
385
#endif
386
    return SC_OK;
2,094✔
387
}
2,094✔
388

389
static inline void ConsolidateFwd(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
390
        StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa)
391
{
141,940✔
392
    uint64_t sa_re = sa->offset + sa->len;
141,940✔
393
    StreamingBufferBlock *tr, *s = sa;
141,940✔
394
    RB_FOREACH_FROM(tr, SBB, s) {
153,183✔
395
        if (sa == tr)
153,183✔
396
            continue;
141,940✔
397

398
        const uint64_t tr_re = tr->offset + tr->len;
11,243✔
399
        SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u re %" PRIu64, tr, tr->offset, tr->len, tr_re);
11,243✔
400

401
        if (sa_re < tr->offset) {
11,243✔
402
            SCLogDebug("entirely before: %" PRIu64 " < %" PRIu64, sa_re, tr->offset);
10,919✔
403
            break; // entirely before
10,919✔
404
        }
10,919✔
405

406
        /* new block (sa) entirely eclipsed by in tree block (tr)
407
            sa:     [   ]
408
            tr: [           ]
409
            sa:     [   ]
410
            tr:     [       ]
411
            sa:     [   ]
412
            tr: [       ]
413
        */
414
        if (sa->offset >= tr->offset && sa_re <= tr_re) {
324✔
415
            sb->sbb_size -= sa->len;
92✔
416
            sa->len = tr->len;
92✔
417
            sa->offset = tr->offset;
92✔
418
            sa_re = sa->offset + sa->len;
92✔
419
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr,
92✔
420
                    tr->offset, tr->len);
92✔
421
            SBB_RB_REMOVE(tree, tr);
92✔
422
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
92✔
423
            /* new block (sa) entire eclipses in tree block (tr)
424
                sa: [         ]
425
                tr: [         ]
426
                sa: [         ]
427
                tr:    [      ]
428
                sa: [         ]
429
                tr:    [   ]
430
            */
431
        } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
232✔
432
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr,
25✔
433
                    tr->offset, tr->len);
25✔
434
            SBB_RB_REMOVE(tree, tr);
25✔
435
            sb->sbb_size -= tr->len;
25✔
436
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
25✔
437

438
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
25✔
439
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
25✔
440
                    region->buf_size);
25✔
441
            if (sa->offset == region->stream_offset &&
25✔
442
                    sa_re > (region->stream_offset + region->buf_offset)) {
25✔
443
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
3✔
444
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
3✔
445
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
3✔
446
                SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
3✔
447
                           " bo %u sz %u BUF_OFFSET UPDATED",
3✔
448
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
3✔
449
                        region->buf_size);
3✔
450
            }
3✔
451
            /* new block (sa) extended by in tree block (tr)
452
                sa: [         ]
453
                tr:      [         ]
454
                sa: [       ]
455
                tr:         [       ]
456
            */
457
        } else if (sa->offset < tr->offset && // starts before
207✔
458
                   sa_re >= tr->offset && sa_re < tr_re) // ends inside
207✔
459
        {
207✔
460
            // merge. sb->sbb_size includes both so we need to adjust that too.
461
            DEBUG_VALIDATE_BUG_ON(sa->len + tr->len > UINT32_MAX);
207✔
462
            uint32_t combined_len = (uint32_t)(sa->len + tr->len);
207✔
463
            DEBUG_VALIDATE_BUG_ON(tr_re - sa->offset > UINT32_MAX);
207✔
464
            sa->len = (uint32_t)(tr_re - sa->offset);
207✔
465
            sa_re = sa->offset + sa->len;
207✔
466
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len);
207✔
467
            SBB_RB_REMOVE(tree, tr);
207✔
468
            sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
207✔
469
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
207✔
470
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u RESULT", sa, sa->offset, sa->len);
207✔
471
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
207✔
472
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
207✔
473
                    region->buf_size);
207✔
474
            if (sa->offset == region->stream_offset &&
207✔
475
                    sa_re > (region->stream_offset + region->buf_offset)) {
207✔
476
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
104✔
477
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
104✔
478
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
104✔
479
                SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
104✔
480
                           " bo %u sz %u BUF_OFFSET UPDATED",
104✔
481
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
104✔
482
                        region->buf_size);
104✔
483
            }
104✔
484
        }
207✔
485
    }
324✔
486
}
141,940✔
487

488
static inline void ConsolidateBackward(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
489
        StreamingBufferRegion *region, struct SBB *tree, StreamingBufferBlock *sa)
490
{
141,775✔
491
    uint64_t sa_re = sa->offset + sa->len;
141,775✔
492
    StreamingBufferBlock *tr, *s = sa;
141,775✔
493
    RB_FOREACH_REVERSE_FROM(tr, SBB, s) {
406,551✔
494
        if (sa == tr)
406,551✔
495
            continue;
141,775✔
496
        const uint64_t tr_re = tr->offset + tr->len;
264,776✔
497
        SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u", tr, tr->offset, tr->len);
264,776✔
498

499
        if (sa->offset > tr_re)
264,776✔
500
            break; // entirely after
126,685✔
501

502
        /* new block (sa) entirely eclipsed by in tree block (tr)
503
            sa: [         ]
504
            tr: [         ]
505
            sa:    [      ]
506
            tr: [         ]
507
            sa:    [   ]
508
            tr: [         ]
509
        */
510
        if (sa->offset >= tr->offset && sa_re <= tr_re) {
138,091✔
511
            sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting
583✔
512
            sa->len = tr->len;
583✔
513
            sa->offset = tr->offset;
583✔
514
            sa_re = sa->offset + sa->len;
583✔
515
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr,
583✔
516
                    tr->offset, tr->len);
583✔
517
            if (sb->head == tr)
583✔
518
                sb->head = sa;
361✔
519
            SBB_RB_REMOVE(tree, tr);
583✔
520
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
583✔
521
            /* new block (sa) entire eclipses in tree block (tr)
522
                sa: [         ]
523
                tr:    [      ]
524
                sa: [         ]
525
                tr: [      ]
526
                sa: [         ]
527
                tr:    [    ]
528
            */
529
        } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
137,508✔
530
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr,
9✔
531
                    tr->offset, tr->len);
9✔
532
            if (sb->head == tr)
9✔
533
                sb->head = sa;
8✔
534
            SBB_RB_REMOVE(tree, tr);
9✔
535
            sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting
9✔
536
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
9✔
537

538
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
9✔
539
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
9✔
540
                    region->buf_size);
9✔
541

542
            if (sa->offset == region->stream_offset &&
9✔
543
                    sa_re > (region->stream_offset + region->buf_offset)) {
9✔
544
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
8✔
545
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
8✔
546
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
8✔
547
                SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
8✔
548
                           " bo %u sz %u BUF_OFFSET UPDATED",
8✔
549
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
8✔
550
                        region->buf_size);
8✔
551
            }
8✔
552

553
            /* new block (sa) extends in tree block (tr)
554
                sa:     [   ]
555
                tr: [   ]
556
                sa:    [    ]
557
                tr: [   ]
558
            */
559
        } else if (sa->offset > tr->offset && sa_re > tr_re && sa->offset <= tr_re) {
137,499✔
560
            // merge. sb->sbb_size includes both so we need to adjust that too.
561
            DEBUG_VALIDATE_BUG_ON(sa->len + tr->len > UINT32_MAX);
137,499✔
562
            uint32_t combined_len = (uint32_t)(sa->len + tr->len);
137,499✔
563
            DEBUG_VALIDATE_BUG_ON(sa_re - tr->offset > UINT32_MAX);
137,499✔
564
            sa->len = (uint32_t)(sa_re - tr->offset);
137,499✔
565
            sa->offset = tr->offset;
137,499✔
566
            sa_re = sa->offset + sa->len;
137,499✔
567
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len);
137,499✔
568
            if (sb->head == tr)
137,499✔
569
                sb->head = sa;
14,721✔
570
            SBB_RB_REMOVE(tree, tr);
137,499✔
571
            sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
137,499✔
572
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
137,499✔
573

574
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
137,499✔
575
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
137,499✔
576
                    region->buf_size);
137,499✔
577
            if (sa->offset == region->stream_offset &&
137,499✔
578
                    sa_re > (region->stream_offset + region->buf_offset)) {
137,499✔
579
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
6,690✔
580
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
6,690✔
581
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
6,690✔
582
                SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
6,690✔
583
                           " bo %u sz %u BUF_OFFSET UPDATED",
6,690✔
584
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
6,690✔
585
                        region->buf_size);
6,690✔
586
            }
6,690✔
587
        }
137,499✔
588
    }
138,091✔
589
}
141,775✔
590

591
/** \internal
592
 *  \param region the region that holds the new data
593
 */
594
static int SBBUpdate(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
595
        StreamingBufferRegion *region, uint32_t rel_offset, uint32_t len)
596
{
142,178✔
597
    struct SBB *tree = &sb->sbb_tree;
142,178✔
598
    SCLogDebug("* inserting: %u/%u", rel_offset, len);
142,178✔
599

600
    StreamingBufferBlock *sbb = CALLOC(cfg, 1, sizeof(*sbb));
142,178✔
601
    if (sbb == NULL) {
142,178✔
602
        return sc_errno;
×
603
    }
×
604
    sbb->offset = region->stream_offset + rel_offset;
142,178✔
605
    sbb->len = len;
142,178✔
606

607
    StreamingBufferBlock *res = SBB_RB_INSERT(tree, sbb);
142,178✔
608
    if (res) {
142,178✔
609
        // exact overlap
610
        SCLogDebug("* insert failed: exact match in tree with %p %" PRIu64 "/%u", res, res->offset,
238✔
611
                res->len);
238✔
612
        FREE(cfg, sbb, sizeof(StreamingBufferBlock));
238✔
613
        return SC_OK;
238✔
614
    }
238✔
615
    sb->sbb_size += len; // may adjust based on consolidation below
141,940✔
616

617
    /* handle backwards and forwards overlaps */
618
    if (SBB_RB_PREV(sbb) == NULL) {
141,940✔
619
        sb->head = sbb;
165✔
620
    } else {
141,775✔
621
        ConsolidateBackward(sb, cfg, region, tree, sbb);
141,775✔
622
    }
141,775✔
623
    ConsolidateFwd(sb, cfg, region, tree, sbb);
141,940✔
624
#ifdef DEBUG
625
    SBBPrintList(sb);
626
#endif
627
    if (sbb->offset == region->stream_offset) {
141,940✔
628
        SCLogDebug("insert at region head");
7,204✔
629
        region->buf_offset = sbb->len;
7,204✔
630
    }
7,204✔
631
    return SC_OK;
141,940✔
632
}
142,178✔
633

634
static void SBBFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
635
{
315,168✔
636
    StreamingBufferBlock *sbb = NULL, *safe = NULL;
315,168✔
637
    RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
315,168✔
638
        SBB_RB_REMOVE(&sb->sbb_tree, sbb);
13,581✔
639
        sb->sbb_size -= sbb->len;
13,581✔
640
        FREE(cfg, sbb, sizeof(StreamingBufferBlock));
13,581✔
641
    }
13,581✔
642
    sb->head = NULL;
315,168✔
643
}
315,168✔
644

645
static void SBBPrune(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
646
{
20,138✔
647
    SCLogDebug("pruning %p to %" PRIu64, sb, sb->region.stream_offset);
20,138✔
648
    StreamingBufferBlock *sbb = NULL, *safe = NULL;
20,138✔
649
    RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
20,138✔
650
        /* completely beyond window, we're done */
651
        if (sbb->offset >= sb->region.stream_offset) {
4,089✔
652
            sb->head = sbb;
343✔
653
            if (sbb->offset == sb->region.stream_offset) {
343✔
654
                SCLogDebug("set buf_offset to first sbb len %u", sbb->len);
1✔
655
                DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size);
1✔
656
                sb->region.buf_offset = sbb->len;
1✔
657
            }
1✔
658
            break;
343✔
659
        }
343✔
660

661
        /* partly before, partly beyond. Adjust */
662
        if (sbb->offset < sb->region.stream_offset &&
3,746✔
663
                sbb->offset + sbb->len > sb->region.stream_offset) {
3,746✔
664
            DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset - sbb->offset > UINT32_MAX);
3,478✔
665
            uint32_t shrink_by = (uint32_t)(sb->region.stream_offset - sbb->offset);
3,478✔
666
            DEBUG_VALIDATE_BUG_ON(shrink_by > sbb->len);
3,478✔
667
            if (sbb->len >= shrink_by) {
3,478✔
668
                sbb->len -=  shrink_by;
3,478✔
669
                sbb->offset += shrink_by;
3,478✔
670
                sb->sbb_size -= shrink_by;
3,478✔
671
                SCLogDebug("shrunk by %u", shrink_by);
3,478✔
672
                DEBUG_VALIDATE_BUG_ON(sbb->offset != sb->region.stream_offset);
3,478✔
673
            }
3,478✔
674
            sb->head = sbb;
3,478✔
675
            if (sbb->offset == sb->region.stream_offset) {
3,478✔
676
                SCLogDebug("set buf_offset to first sbb len %u", sbb->len);
3,478✔
677
                DEBUG_VALIDATE_BUG_ON(sbb->len > sb->region.buf_size);
3,478✔
678
                sb->region.buf_offset = sbb->len;
3,478✔
679
            }
3,478✔
680
            break;
3,478✔
681
        }
3,478✔
682

683
        SBB_RB_REMOVE(&sb->sbb_tree, sbb);
268✔
684
        /* either we set it again for the next sbb, or there isn't any */
685
        sb->head = NULL;
268✔
686
        sb->sbb_size -= sbb->len;
268✔
687
        SCLogDebug("sb %p removed %p %" PRIu64 ", %u", sb, sbb, sbb->offset, sbb->len);
268✔
688
        FREE(cfg, sbb, sizeof(StreamingBufferBlock));
268✔
689
    }
268✔
690
#ifdef DEBUG
691
    SBBPrintList(sb);
692
#endif
693
}
20,138✔
694

695
static inline uint32_t ToNextMultipleOf(const uint32_t in, const uint32_t m)
696
{
116,617✔
697
    uint32_t r = in;
116,617✔
698
    if (m > 0) {
116,617✔
699
        const uint32_t x = in % m;
116,617✔
700
        if (x != 0) {
116,617✔
701
            r = (in - x) + m;
114,614✔
702
        }
114,614✔
703
    }
116,617✔
704
    return r;
116,617✔
705
}
116,617✔
706

707
static thread_local bool g2s_warn_once = false;
708

709
static inline int WARN_UNUSED GrowRegionToSize(StreamingBuffer *sb,
710
        const StreamingBufferConfig *cfg, StreamingBufferRegion *region, const uint32_t size)
711
{
116,544✔
712
    DEBUG_VALIDATE_BUG_ON(region->buf_size > BIT_U32(30));
116,544✔
713
    if (size > BIT_U32(30)) { // 1GiB
116,544✔
714
        if (!g2s_warn_once) {
×
715
            SCLogWarning("StreamingBuffer::GrowRegionToSize() tried to alloc %u bytes, exceeds "
×
716
                         "limit of %" PRIu32,
×
717
                    size, BIT_U32(30));
×
718
            g2s_warn_once = true;
×
719
        }
×
720
        return SC_ELIMIT;
×
721
    }
×
722

723
    /* try to grow in multiples of cfg->buf_size */
724
    const uint32_t grow = ToNextMultipleOf(size, cfg->buf_size);
116,544✔
725
    SCLogDebug("grow %u", grow);
116,544✔
726
    if (grow <= region->buf_size) {
116,544✔
727
        // do not try to shrink, and do not memset with diff having unsigned underflow
728
        return SC_OK;
54✔
729
    }
54✔
730

731
    void *ptr = REALLOC(cfg, region->buf, region->buf_size, grow);
116,490✔
732
    if (ptr == NULL) {
116,490✔
UNCOV
733
        if (sc_errno == SC_OK)
×
734
            sc_errno = SC_ENOMEM;
×
UNCOV
735
        return sc_errno;
×
UNCOV
736
    }
×
737
    /* for safe printing and general caution, lets memset the
738
     * new data to 0 */
739
    size_t diff = grow - region->buf_size;
116,490✔
740
    void *new_mem = ((char *)ptr) + region->buf_size;
116,490✔
741
    memset(new_mem, 0, diff);
116,490✔
742

743
    region->buf = ptr;
116,490✔
744
    region->buf_size = grow;
116,490✔
745
    SCLogDebug("grown buffer to %u", grow);
116,490✔
746
#ifdef DEBUG
747
    if (region->buf_size > sb->buf_size_max) {
748
        sb->buf_size_max = region->buf_size;
749
    }
750
#endif
751
    return SC_OK;
116,490✔
752
}
116,490✔
753

754
static int WARN_UNUSED GrowToSize(
755
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint32_t size)
756
{
116,471✔
757
    return GrowRegionToSize(sb, cfg, &sb->region, size);
116,471✔
758
}
116,471✔
759

760
static inline bool RegionBeforeOffset(const StreamingBufferRegion *r, const uint64_t o)
761
{
×
762
    return (r->stream_offset + r->buf_size <= o);
×
763
}
×
764

765
static inline bool RegionContainsOffset(const StreamingBufferRegion *r, const uint64_t o)
766
{
×
767
    return (o >= r->stream_offset && (r->stream_offset + r->buf_size) >= o);
×
768
}
×
769

770
/** \internal
771
 *  \brief slide to offset for regions
772
 *
773
 *
774
 *     [ main ] [ gap ] [ aux ] [ gap ] [ aux ]
775
 *                 ^
776
 *     - main reset to 0
777
 *
778
 *
779
 *     [ main ] [ gap ] [ aux ] [ gap ] [ aux ]
780
 *         ^
781
 *     - main shift
782
 *
783
 *     [ main ] [ gap ] [ aux ] [ gap ] [ aux ]
784
 *                          ^
785
 *     - main reset
786
 *     - move aux into main
787
 *     - free aux
788
 *     - shift
789
 *
790
 *     [ main ] [ gap ] [ aux ] [ gap ] [ aux ]
791
 *                      ^
792
 *     - main reset
793
 *     - move aux into main
794
 *     - free aux
795
 *     - no shift
796
 */
797
static inline void StreamingBufferSlideToOffsetWithRegions(
798
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, const uint64_t slide_offset)
799
{
×
800
    ListRegions(sb);
×
801
    DEBUG_VALIDATE_BUG_ON(slide_offset == sb->region.stream_offset);
×
802

803
    SCLogDebug("slide_offset %" PRIu64, slide_offset);
×
804
    SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset,
×
805
            sb->region.buf, sb->region.buf_size, sb->region.buf_offset);
×
806

807
    StreamingBufferRegion *to_shift = NULL;
×
808
    const bool main_is_oow = RegionBeforeOffset(&sb->region, slide_offset);
×
809
    if (main_is_oow) {
×
810
        SCLogDebug("main_is_oow");
×
811
        if (sb->region.buf != NULL) {
×
812
            SCLogDebug("clearing main");
×
813
            FREE(cfg, sb->region.buf, sb->region.buf_size);
×
814
            sb->region.buf = NULL;
×
815
            sb->region.buf_size = 0;
×
816
            sb->region.buf_offset = 0;
×
817
            sb->region.stream_offset = slide_offset;
×
818
        } else {
×
819
            sb->region.stream_offset = slide_offset;
×
820
        }
×
821

822
        /* remove regions that are out of window & select the region to
823
         * become the new main */
824
        StreamingBufferRegion *prev = &sb->region;
×
825
        for (StreamingBufferRegion *r = sb->region.next; r != NULL;) {
×
826
            SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64, r, r->stream_offset,
×
827
                    r->stream_offset + r->buf_offset);
×
828
            StreamingBufferRegion *next = r->next;
×
829
            if (RegionBeforeOffset(r, slide_offset)) {
×
830
                SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> before", r, r->stream_offset,
×
831
                        r->stream_offset + r->buf_offset);
×
832
                DEBUG_VALIDATE_BUG_ON(r == &sb->region);
×
833
                prev->next = next;
×
834

835
                FREE(cfg, r->buf, r->buf_size);
×
836
                FREE(cfg, r, sizeof(*r));
×
837
                sb->regions--;
×
838
                DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
839
            } else if (RegionContainsOffset(r, slide_offset)) {
×
840
                SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> within", r, r->stream_offset,
×
841
                        r->stream_offset + r->buf_offset);
×
842
                /* remove from list, we will xfer contents to main below */
843
                prev->next = next;
×
844
                to_shift = r;
×
845
                break;
×
846
            } else {
×
847
                SCLogDebug("r %p so %" PRIu64 ", re %" PRIu64 " -> post", r, r->stream_offset,
×
848
                        r->stream_offset + r->buf_offset);
×
849
                /* implied beyond slide offset */
850
                DEBUG_VALIDATE_BUG_ON(r->stream_offset < slide_offset);
×
851
                break;
×
852
            }
×
853
            r = next;
×
854
        }
×
855
        SCLogDebug("to_shift %p", to_shift);
×
856

857
        // this region is main, or will xfer its buffer to main
858
        if (to_shift && to_shift != &sb->region) {
×
859
            SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", to_shift->stream_offset,
×
860
                    to_shift->buf, to_shift->buf_size, to_shift->buf_offset);
×
861
            DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL);
×
862

863
            sb->region.buf = to_shift->buf;
×
864
            sb->region.stream_offset = to_shift->stream_offset;
×
865
            sb->region.buf_offset = to_shift->buf_offset;
×
866
            sb->region.buf_size = to_shift->buf_size;
×
867
            sb->region.next = to_shift->next;
×
868

869
            BUG_ON(to_shift == &sb->region);
×
870
            FREE(cfg, to_shift, sizeof(*to_shift));
×
871
            to_shift = &sb->region;
×
872
            sb->regions--;
×
873
            DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
874
        }
×
875

876
    } else {
×
877
        to_shift = &sb->region;
×
878
        SCLogDebug("shift start region %p", to_shift);
×
879
    }
×
880

881
    // this region is main, or will xfer its buffer to main
882
    if (to_shift) {
×
883
        // Do the shift. If new region is exactly at the slide offset we can skip this.
884
        DEBUG_VALIDATE_BUG_ON(to_shift->stream_offset > slide_offset);
×
885
        DEBUG_VALIDATE_BUG_ON(slide_offset - to_shift->stream_offset > UINT32_MAX);
×
886
        const uint32_t s = (uint32_t)(slide_offset - to_shift->stream_offset);
×
887
        if (s > 0) {
×
888
            const uint32_t new_data_size = to_shift->buf_size - s;
×
889
            uint32_t new_mem_size = ToNextMultipleOf(new_data_size, cfg->buf_size);
×
890

891
            /* see if after the slide we'd overlap with the next region. If so, we need
892
             * to consolidate them into one. Error handling is a bit peculiar. We need
893
             * to grow a region, move data from another region into it, then free the
894
             * other region. This could fail if we're close to the memcap. In this case
895
             * we relax our rounding up logic so we only shrink and don't merge the 2
896
             * regions after all. */
897
            if (to_shift->next && slide_offset + new_mem_size >= to_shift->next->stream_offset) {
×
898
                StreamingBufferRegion *start = to_shift;
×
899
                StreamingBufferRegion *next = start->next;
×
900
                const uint64_t next_re = next->stream_offset + next->buf_size;
×
901
                DEBUG_VALIDATE_BUG_ON(next_re - slide_offset > UINT32_MAX);
×
902
                const uint32_t mem_size =
×
903
                        ToNextMultipleOf((uint32_t)(next_re - slide_offset), cfg->buf_size);
×
904

905
                /* using next as the new main */
906
                if (start->buf_size < next->buf_size) {
×
907
                    SCLogDebug("replace main with the next bigger region");
×
908

909
                    DEBUG_VALIDATE_BUG_ON(next->stream_offset - slide_offset > UINT32_MAX);
×
910
                    const uint32_t next_data_offset =
×
911
                            (uint32_t)(next->stream_offset - slide_offset);
×
912
                    const uint32_t prev_buf_size = next->buf_size;
×
913
                    DEBUG_VALIDATE_BUG_ON(slide_offset - start->stream_offset > UINT32_MAX);
×
914
                    const uint32_t start_data_offset =
×
915
                            (uint32_t)(slide_offset - start->stream_offset);
×
916
                    DEBUG_VALIDATE_BUG_ON(start_data_offset > start->buf_size);
×
917
                    if (start_data_offset > start->buf_size) {
×
918
                        new_mem_size = new_data_size;
×
919
                        goto just_main;
×
920
                    }
×
921
                    /* expand "next" to include relevant part of "start" */
922
                    if (GrowRegionToSize(sb, cfg, next, mem_size) != 0) {
×
923
                        new_mem_size = new_data_size;
×
924
                        goto just_main;
×
925
                    }
×
926
                    SCLogDebug("region now sized %u", mem_size);
×
927

928
                    // slide "next":
929
                    // pre-grow: [nextnextnext]
930
                    // post-grow [nextnextnextXXX]
931
                    // post-move [XXXnextnextnext]
932
                    memmove(next->buf + next_data_offset, next->buf, prev_buf_size);
×
933

934
                    // move portion of "start" into "next"
935
                    //
936
                    // start: [ooooookkkkk] (o: old, k: keep)
937
                    // pre-next     [xxxxxnextnextnext]
938
                    // post-next    [kkkkknextnextnext]
939
                    const uint32_t start_data_size = start->buf_size - start_data_offset;
×
940
                    memcpy(next->buf, start->buf + start_data_offset, start_data_size);
×
941

942
                    // free "start"s buffer, we will use the one from "next"
943
                    FREE(cfg, start->buf, start->buf_size);
×
944

945
                    // update "main" to use "next"
946
                    start->stream_offset = slide_offset;
×
947
                    start->buf = next->buf;
×
948
                    start->buf_size = next->buf_size;
×
949
                    start->next = next->next;
×
950

951
                    // free "next"
952
                    FREE(cfg, next, sizeof(*next));
×
953
                    sb->regions--;
×
954
                    DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
955
                    goto done;
×
956
                } else {
×
957
                    /* using "main", expand to include "next" */
958
                    if (mem_size > start->buf_size) {
×
959
                        // Check that start->buf_size is actually not big enough
960
                        // As mem_size computation and earlier checks do not make it clear.
961
                        if (GrowRegionToSize(sb, cfg, start, mem_size) != 0) {
×
962
                            new_mem_size = new_data_size;
×
963
                            goto just_main;
×
964
                        }
×
965
                    }
×
966
                    SCLogDebug("start->buf now size %u", mem_size);
×
967

968
                    // slide "start"
969
                    // pre:     [xxxxxxxAAA]
970
                    // post:    [AAAxxxxxxx]
971
                    SCLogDebug("s %u new_data_size %u", s, new_data_size);
×
972
                    memmove(start->buf, start->buf + s, new_data_size);
×
973

974
                    // copy in "next"
975
                    // pre:     [AAAxxxxxxx]
976
                    //             [BBBBBBB]
977
                    // post:    [AAABBBBBBB]
978
                    SCLogDebug("copy next->buf %p/%u to start->buf offset %u", next->buf,
×
979
                            next->buf_size, new_data_size);
×
980
                    memcpy(start->buf + new_data_size, next->buf, next->buf_size);
×
981

982
                    start->stream_offset = slide_offset;
×
983
                    start->next = next->next;
×
984

985
                    // free "next"
986
                    FREE(cfg, next->buf, next->buf_size);
×
987
                    FREE(cfg, next, sizeof(*next));
×
988
                    sb->regions--;
×
989
                    DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
990
                    goto done;
×
991
                }
×
992
            }
×
993

994
        just_main:
×
995
            SCLogDebug("s %u new_data_size %u", s, new_data_size);
×
996
            memmove(to_shift->buf, to_shift->buf + s, new_data_size);
×
997
            /* shrink memory region. If this fails we keep the old */
998
            void *ptr = REALLOC(cfg, to_shift->buf, to_shift->buf_size, new_mem_size);
×
999
            if (ptr != NULL) {
×
1000
                to_shift->buf = ptr;
×
1001
                to_shift->buf_size = new_mem_size;
×
1002
                SCLogDebug("new buf_size %u", to_shift->buf_size);
×
1003
            }
×
1004
            if (s < to_shift->buf_offset)
×
1005
                to_shift->buf_offset -= s;
×
1006
            else
×
1007
                to_shift->buf_offset = 0;
×
1008
            to_shift->stream_offset = slide_offset;
×
1009
        }
×
1010
    }
×
1011

1012
done:
×
1013
    SCLogDebug("main: offset %" PRIu64 " buf %p size %u offset %u", sb->region.stream_offset,
×
1014
            sb->region.buf, sb->region.buf_size, sb->region.buf_offset);
×
1015
    SCLogDebug("end of slide");
×
1016
}
×
1017

1018
/**
1019
 *  \brief slide to absolute offset
1020
 *  \todo if sliding beyond window, we could perhaps reset?
1021
 */
1022
void StreamingBufferSlideToOffset(
1023
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint64_t offset)
1024
{
24,079✔
1025
    SCLogDebug("sliding to offset %" PRIu64, offset);
24,079✔
1026
    ListRegions(sb);
24,079✔
1027
#ifdef DEBUG
1028
    SBBPrintList(sb);
1029
#endif
1030

1031
    if (sb->region.next) {
24,079✔
1032
        StreamingBufferSlideToOffsetWithRegions(sb, cfg, offset);
×
1033
        SBBPrune(sb, cfg);
×
1034
        SCLogDebug("post SBBPrune");
×
1035
        ListRegions(sb);
×
1036
#ifdef DEBUG
1037
        SBBPrintList(sb);
1038
#endif
1039
        DEBUG_VALIDATE_BUG_ON(sb->region.buf != NULL && sb->region.buf_size == 0);
×
1040
        DEBUG_VALIDATE_BUG_ON(sb->region.buf_offset > sb->region.buf_size);
×
1041
        DEBUG_VALIDATE_BUG_ON(offset > sb->region.stream_offset);
×
1042
        DEBUG_VALIDATE_BUG_ON(sb->head && sb->head->offset == sb->region.stream_offset &&
×
1043
                              sb->head->len > sb->region.buf_offset);
×
1044
        DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset);
×
1045
        return;
×
1046
    }
×
1047

1048
    if (offset > sb->region.stream_offset) {
24,079✔
1049
        DEBUG_VALIDATE_BUG_ON(offset - sb->region.stream_offset > UINT32_MAX);
20,138✔
1050
        const uint32_t slide = (uint32_t)(offset - sb->region.stream_offset);
20,138✔
1051
        if (sb->head != NULL) {
20,138✔
1052
            /* have sbb's, so can't rely on buf_offset for the slide */
1053
            if (slide < sb->region.buf_size) {
3,823✔
1054
                const uint32_t size = sb->region.buf_size - slide;
3,823✔
1055
                SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide,
3,823✔
1056
                        size);
3,823✔
1057
                memmove(sb->region.buf, sb->region.buf + slide, size);
3,823✔
1058
                if (sb->region.buf_offset > slide) {
3,823✔
1059
                    sb->region.buf_offset -= slide;
3,334✔
1060
                } else {
3,334✔
1061
                    sb->region.buf_offset = 0;
489✔
1062
                }
489✔
1063
            } else {
3,823✔
UNCOV
1064
                sb->region.buf_offset = 0;
×
UNCOV
1065
            }
×
1066
            sb->region.stream_offset = offset;
3,823✔
1067
        } else {
16,315✔
1068
            /* no sbb's, so we can use buf_offset */
1069
            if (offset <= sb->region.stream_offset + sb->region.buf_offset) {
16,315✔
1070
                const uint32_t size = sb->region.buf_offset - slide;
16,315✔
1071
                SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide,
16,315✔
1072
                        size);
16,315✔
1073
                memmove(sb->region.buf, sb->region.buf + slide, size);
16,315✔
1074
                sb->region.stream_offset = offset;
16,315✔
1075
                sb->region.buf_offset = size;
16,315✔
1076
            } else {
16,315✔
1077
                /* moved past all data */
UNCOV
1078
                sb->region.stream_offset = offset;
×
UNCOV
1079
                sb->region.buf_offset = 0;
×
UNCOV
1080
            }
×
1081
        }
16,315✔
1082
        SBBPrune(sb, cfg);
20,138✔
1083
    }
20,138✔
1084
#ifdef DEBUG
1085
    SBBPrintList(sb);
1086
#endif
1087
    DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset);
24,079✔
1088
}
24,079✔
1089

1090
static int DataFits(const StreamingBuffer *sb, const uint32_t len)
1091
{
378,513✔
1092
    uint64_t buf_offset64 = sb->region.buf_offset;
378,513✔
1093
    uint64_t len64 = len;
378,513✔
1094
    if (len64 + buf_offset64 > UINT32_MAX) {
378,513✔
UNCOV
1095
        return -1;
×
UNCOV
1096
    }
×
1097
    return sb->region.buf_offset + len <= sb->region.buf_size;
378,513✔
1098
}
378,513✔
1099

1100
int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
1101
        StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
1102
{
44,653✔
1103
    DEBUG_VALIDATE_BUG_ON(seg == NULL);
44,653✔
1104
    DEBUG_VALIDATE_BUG_ON(data_len > BIT_U32(27)); // 128MiB is excessive already
44,653✔
1105

1106
    if (sb->region.buf == NULL) {
44,653✔
1107
        if (InitBuffer(sb, cfg) == -1)
×
1108
            return -1;
×
1109
    }
×
1110

1111
    int r = DataFits(sb, data_len);
44,653✔
1112
    if (r < 0) {
44,653✔
UNCOV
1113
        DEBUG_VALIDATE_BUG_ON(1);
×
UNCOV
1114
        return -1;
×
1115
    } else if (r == 0) {
44,653✔
1116
        if (sb->region.buf_size == 0) {
10,074✔
1117
            if (GrowToSize(sb, cfg, data_len) != SC_OK)
×
1118
                return -1;
×
1119
        } else {
10,074✔
1120
            if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK)
10,074✔
UNCOV
1121
                return -1;
×
1122
        }
10,074✔
1123
    }
10,074✔
1124
    DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
44,653✔
1125
    if (DataFits(sb, data_len) != 1)
44,653✔
1126
        return -1;
×
1127

1128
    memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
44,653✔
1129
    seg->stream_offset = sb->region.stream_offset + sb->region.buf_offset;
44,653✔
1130
    seg->segment_len = data_len;
44,653✔
1131
    uint32_t rel_offset = sb->region.buf_offset;
44,653✔
1132
    sb->region.buf_offset += data_len;
44,653✔
1133

1134
    if (!RB_EMPTY(&sb->sbb_tree)) {
44,653✔
UNCOV
1135
        return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len);
×
1136
    } else {
44,653✔
1137
        return 0;
44,653✔
1138
    }
44,653✔
1139
}
44,653✔
1140

1141
/**
1142
 *  \brief add data w/o tracking a segment
1143
 */
1144
int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
1145
        const uint8_t *data, uint32_t data_len)
1146
{
289,207✔
1147
    DEBUG_VALIDATE_BUG_ON(data_len > BIT_U32(27)); // 128MiB is excessive already
289,207✔
1148

1149
    if (sb->region.buf == NULL) {
289,207✔
1150
        if (InitBuffer(sb, cfg) == -1)
×
1151
            return -1;
×
1152
    }
×
1153

1154
    int r = DataFits(sb, data_len);
289,207✔
1155
    if (r < 0) {
289,207✔
1156
        DEBUG_VALIDATE_BUG_ON(1);
×
1157
        return -1;
×
1158
    } else if (r == 0) {
289,207✔
1159
        if (sb->region.buf_size == 0) {
32,638✔
1160
            if (GrowToSize(sb, cfg, data_len) != SC_OK)
×
1161
                return -1;
×
1162
        } else {
32,638✔
1163
            if (GrowToSize(sb, cfg, sb->region.buf_offset + data_len) != SC_OK)
32,638✔
1164
                return -1;
×
1165
        }
32,638✔
1166
    }
32,638✔
1167
    DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
289,207✔
1168

1169
    memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
289,207✔
1170
    uint32_t rel_offset = sb->region.buf_offset;
289,207✔
1171
    sb->region.buf_offset += data_len;
289,207✔
1172

1173
    if (!RB_EMPTY(&sb->sbb_tree)) {
289,207✔
1174
        return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len);
×
1175
    } else {
289,207✔
1176
        return 0;
289,207✔
1177
    }
289,207✔
1178
}
289,207✔
1179

1180
static int DataFitsAtOffset(
1181
        const StreamingBufferRegion *region, const uint32_t len, const uint32_t offset)
1182
{
642,138✔
1183
    const uint64_t offset64 = offset;
642,138✔
1184
    const uint64_t len64 = len;
642,138✔
1185
    if (offset64 + len64 > UINT32_MAX)
642,138✔
UNCOV
1186
        return -1;
×
1187
    return (offset + len <= region->buf_size);
642,138✔
1188
}
642,138✔
1189

1190
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
1191
static void Validate(const StreamingBuffer *sb)
1192
{
1193
    bool bail = false;
1194
    uint32_t cnt = 0;
1195
    for (const StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) {
1196
        cnt++;
1197
        if (r->next) {
1198
            bail |= ((r->stream_offset + r->buf_size) > r->next->stream_offset);
1199
        }
1200

1201
        bail |= (r->buf != NULL && r->buf_size == 0);
1202
        bail |= (r->buf_offset > r->buf_size);
1203
    }
1204
    // leading gap, so buf_offset should be 0?
1205
    if (sb->head && sb->head->offset > sb->region.stream_offset) {
1206
        SCLogDebug("leading gap of size %" PRIu64, sb->head->offset - sb->region.stream_offset);
1207
        BUG_ON(sb->region.buf_offset != 0);
1208
    }
1209

1210
    if (sb->head && sb->head->offset == sb->region.stream_offset) {
1211
        BUG_ON(sb->head->len > sb->region.buf_offset);
1212
        BUG_ON(sb->head->len < sb->region.buf_offset);
1213
    }
1214
    BUG_ON(sb->regions != cnt);
1215
    BUG_ON(bail);
1216
}
1217
#endif
1218

1219
static void ListRegions(StreamingBuffer *sb)
1220
{
1,623,523✔
1221
    if (sb->region.buf == NULL && sb->region.buf_offset == 0 && sb->region.next == NULL)
1,623,523✔
1222
        return;
284,513✔
1223
#if defined(DEBUG) && DUMP_REGIONS == 1
1224
    uint32_t cnt = 0;
1225
    for (StreamingBufferRegion *r = &sb->region; r != NULL; r = r->next) {
1226
        cnt++;
1227
        char gap[64] = "";
1228
        if (r->next) {
1229
            snprintf(gap, sizeof(gap), "[ gap:%" PRIu64 " ]",
1230
                    r->next->stream_offset - (r->stream_offset + r->buf_size));
1231
        }
1232

1233
        printf("[ %s offset:%" PRIu64 " size:%u offset:%u ]%s", r == &sb->region ? "main" : "aux",
1234
                r->stream_offset, r->buf_size, r->buf_offset, gap);
1235
    }
1236
    printf("(max %u, cnt %u, sb->regions %u)\n", sb->max_regions, cnt, sb->regions);
1237
    bool at_least_one = false;
1238
    uint64_t last_re = sb->region.stream_offset;
1239
    StreamingBufferBlock *sbb = NULL;
1240
    RB_FOREACH(sbb, SBB, &sb->sbb_tree)
1241
    {
1242
        if (last_re != sbb->offset) {
1243
            printf("[ gap:%" PRIu64 " ]", sbb->offset - last_re);
1244
        }
1245
        printf("[ sbb offset:%" PRIu64 " len:%u ]", sbb->offset, sbb->len);
1246
        at_least_one = true;
1247
        last_re = sbb->offset + sbb->len;
1248
    }
1249
    if (at_least_one)
1250
        printf("\n");
1251
#endif
1252
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
1253
    StreamingBufferBlock *sbb2 = NULL;
1254
    RB_FOREACH(sbb2, SBB, &sb->sbb_tree)
1255
    {
1256
        const uint8_t *_data = NULL;
1257
        uint32_t _data_len = 0;
1258
        (void)StreamingBufferSBBGetData(sb, sbb2, &_data, &_data_len);
1259
    }
1260
    Validate(sb);
1261
#endif
1262
}
1,623,523✔
1263

1264
/** \internal
1265
 *  \brief process insert by consolidating the affected regions into one
1266
 *  \note sets sc_errno
1267
 */
1268
static StreamingBufferRegion *BufferInsertAtRegionConsolidate(StreamingBuffer *sb,
1269
        const StreamingBufferConfig *cfg, StreamingBufferRegion *dst,
1270
        StreamingBufferRegion *src_start, StreamingBufferRegion *src_end,
1271
        const uint64_t data_offset, const uint32_t data_len, StreamingBufferRegion *prev,
1272
        uint32_t dst_buf_size)
1273
{
73✔
1274
    int retval;
73✔
1275
#ifdef DEBUG
1276
    const uint64_t data_re = data_offset + data_len;
1277
    SCLogDebug("sb %p dst %p src_start %p src_end %p data_offset %" PRIu64
1278
               "/data_len %u/data_re %" PRIu64,
1279
            sb, dst, src_start, src_end, data_offset, data_len, data_re);
1280
#endif
1281

1282
    // 1. determine size and offset for dst.
1283
    const uint64_t dst_offset = MIN(src_start->stream_offset, data_offset);
73✔
1284
    DEBUG_VALIDATE_BUG_ON(dst_offset < sb->region.stream_offset);
73✔
1285
    const uint32_t dst_size = dst_buf_size;
73✔
1286
    SCLogDebug("dst_size %u", dst_size);
73✔
1287

1288
    // 2. resize dst
1289
    const uint32_t old_size = dst->buf_size;
73✔
1290
    DEBUG_VALIDATE_BUG_ON(dst->stream_offset - dst_offset > UINT32_MAX);
73✔
1291
    const uint32_t dst_copy_offset = (uint32_t)(dst->stream_offset - dst_offset);
73✔
1292
#ifdef DEBUG
1293
    const uint32_t old_offset = dst->buf_offset;
1294
    SCLogDebug("old_size %u, old_offset %u, dst_copy_offset %u", old_size, old_offset,
1295
            dst_copy_offset);
1296
#endif
1297
    if ((retval = GrowRegionToSize(sb, cfg, dst, dst_size)) != SC_OK) {
73✔
1298
        sc_errno = retval;
×
1299
        return NULL;
×
1300
    }
×
1301
    SCLogDebug("resized to %u -> %u", dst_size, dst->buf_size);
73✔
1302
    /* validate that the size is exactly what we asked for */
1303
    DEBUG_VALIDATE_BUG_ON(dst_size != dst->buf_size);
73✔
1304
    if (dst_copy_offset != 0)
73✔
1305
        memmove(dst->buf + dst_copy_offset, dst->buf, old_size);
4✔
1306
    if (dst_offset != dst->stream_offset) {
73✔
1307
        dst->stream_offset = dst_offset;
4✔
1308
        // buf_offset no longer valid, reset.
1309
        dst->buf_offset = 0;
4✔
1310
    }
4✔
1311

1312
    uint32_t new_offset = src_start->buf_offset;
73✔
1313
    if (data_offset == src_start->stream_offset + src_start->buf_offset) {
73✔
1314
        new_offset += data_len;
52✔
1315
    }
52✔
1316

1317
    bool start_is_main = false;
73✔
1318
    if (src_start == &sb->region) {
73✔
1319
        DEBUG_VALIDATE_BUG_ON(src_start->stream_offset != dst_offset);
1✔
1320

1321
        start_is_main = true;
1✔
1322
        SCLogDebug("src_start is main region");
1✔
1323
        if (src_start != dst)
1✔
1324
            memcpy(dst->buf, src_start->buf, src_start->buf_offset);
1✔
1325
        if (src_start == src_end) {
1✔
1326
            SCLogDebug("src_start == src_end == main, we're done");
×
1327
            DEBUG_VALIDATE_BUG_ON(src_start != dst);
×
1328
            return src_start;
×
1329
        }
×
1330
        prev = src_start;
1✔
1331
        src_start = src_start->next; // skip in the loop below
1✔
1332
    }
1✔
1333

1334
    // 3. copy all regions from src_start to dst_start into the new region
1335
    for (StreamingBufferRegion *r = src_start; r != NULL;) {
73✔
1336
        SCLogDebug("r %p %" PRIu64 ", offset %u, len %u, %s, last %s", r, r->stream_offset,
73✔
1337
                r->buf_offset, r->buf_size, r == &sb->region ? "main" : "aux",
73✔
1338
                BOOL2STR(r == src_end));
73✔
1339
        // skip dst
1340
        if (r == dst) {
73✔
1341
            SCLogDebug("skipping r %p as it is 'dst'", r);
73✔
1342
            if (r == src_end)
73✔
1343
                break;
73✔
1344
            prev = r;
×
1345
            r = r->next;
×
1346
            continue;
×
1347
        }
73✔
1348
        DEBUG_VALIDATE_BUG_ON(r->stream_offset - dst_offset > UINT32_MAX);
×
1349
        const uint32_t target_offset = (uint32_t)(r->stream_offset - dst_offset);
×
1350
        SCLogDebug("r %p: target_offset %u", r, target_offset);
×
1351
        DEBUG_VALIDATE_BUG_ON(target_offset > dst->buf_size);
×
1352
        DEBUG_VALIDATE_BUG_ON(target_offset + r->buf_size > dst->buf_size);
×
1353
        memcpy(dst->buf + target_offset, r->buf, r->buf_size);
×
1354

1355
        StreamingBufferRegion *next = r->next;
×
1356
        FREE(cfg, r->buf, r->buf_size);
×
1357
        FREE(cfg, r, sizeof(*r));
×
1358
        sb->regions--;
×
1359
        DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
1360

1361
        DEBUG_VALIDATE_BUG_ON(prev == NULL && src_start != &sb->region);
×
1362
        if (prev != NULL) {
×
1363
            SCLogDebug("setting prev %p next to %p (was %p)", prev, next, prev->next);
×
1364
            prev->next = next;
×
1365
        } else {
×
1366
            SCLogDebug("no prev yet");
×
1367
        }
×
1368

1369
        if (r == src_end)
×
1370
            break;
×
1371
        r = next;
×
1372
    }
×
1373

1374
    /* special handling of main region being the start, but not the
1375
     * region we expand. In this case we'll have main and dst. We will
1376
     * move the buffer from dst into main and free dst. */
1377
    if (start_is_main && dst != &sb->region) {
73✔
1378
        DEBUG_VALIDATE_BUG_ON(sb->region.next != dst);
1✔
1379
        SCLogDebug("start_is_main && dst != main region");
1✔
1380
        FREE(cfg, sb->region.buf, sb->region.buf_size);
1✔
1381
        sb->region.buf = dst->buf;
1✔
1382
        sb->region.buf_size = dst->buf_size;
1✔
1383
        sb->region.buf_offset = new_offset;
1✔
1384
        SCLogDebug("sb->region.buf_offset set to %u", sb->region.buf_offset);
1✔
1385
        sb->region.next = dst->next;
1✔
1386
        FREE(cfg, dst, sizeof(*dst));
1✔
1387
        dst = &sb->region;
1✔
1388
        sb->regions--;
1✔
1389
        DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
1✔
1390
    } else {
72✔
1391
        SCLogDebug("dst: %p next %p", dst, dst->next);
72✔
1392
    }
72✔
1393

1394
    SCLogDebug("returning dst %p stream_offset %" PRIu64 " buf_offset %u buf_size %u", dst,
73✔
1395
            dst->stream_offset, dst->buf_offset, dst->buf_size);
73✔
1396
    return dst;
73✔
1397
}
73✔
1398

1399
/** \note sets sc_errno */
1400
static StreamingBufferRegion *BufferInsertAtRegionDo(StreamingBuffer *sb,
1401
        const StreamingBufferConfig *cfg, const uint64_t offset, const uint32_t len)
1402
{
81✔
1403
    SCLogDebug("offset %" PRIu64 ", len %u", offset, len);
81✔
1404
    StreamingBufferRegion *start_prev = NULL;
81✔
1405
    StreamingBufferRegion *start =
81✔
1406
            FindFirstRegionForOffset(cfg, &sb->region, offset, len, &start_prev);
81✔
1407
    if (start) {
81✔
1408
        const uint64_t insert_re = offset + len;
73✔
1409
        const uint64_t insert_start_offset = MIN(start->stream_offset, offset);
73✔
1410
        uint64_t insert_adjusted_re = insert_re;
73✔
1411

1412
        SCLogDebug("start region %p/%" PRIu64 "/%u", start, start->stream_offset, start->buf_size);
73✔
1413
        StreamingBufferRegion *big = FindLargestRegionForOffset(cfg, start, offset, len);
73✔
1414
        DEBUG_VALIDATE_BUG_ON(big == NULL);
73✔
1415
        if (big == NULL) {
73✔
1416
            sc_errno = SC_EINVAL;
×
1417
            return NULL;
×
1418
        }
×
1419
        SCLogDebug("big region %p/%" PRIu64 "/%u", big, big->stream_offset, big->buf_size);
73✔
1420
        StreamingBufferRegion *end = FindRightEdge(cfg, big, offset, len);
73✔
1421
        DEBUG_VALIDATE_BUG_ON(end == NULL);
73✔
1422
        if (end == NULL) {
73✔
1423
            sc_errno = SC_EINVAL;
×
1424
            return NULL;
×
1425
        }
×
1426
        insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size));
73✔
1427

1428
        DEBUG_VALIDATE_BUG_ON(insert_adjusted_re - insert_start_offset > UINT32_MAX);
73✔
1429
        uint32_t new_buf_size = ToNextMultipleOf(
73✔
1430
                (uint32_t)(insert_adjusted_re - insert_start_offset), cfg->buf_size);
73✔
1431
        SCLogDebug("new_buf_size %u", new_buf_size);
73✔
1432

1433
        /* see if our new buf size + cfg->buf_size margin leads to an overlap with the next region.
1434
         * If so, include that in the consolidation. */
1435
        if (end->next != NULL && new_buf_size + insert_start_offset > end->next->stream_offset) {
73✔
1436
            SCLogDebug("adjusted end from %p to %p", end, end->next);
×
1437
            end = end->next;
×
1438
            insert_adjusted_re = MAX(insert_adjusted_re, (end->stream_offset + end->buf_size));
×
1439
            DEBUG_VALIDATE_BUG_ON(insert_adjusted_re - insert_start_offset > UINT32_MAX);
×
1440
            new_buf_size = ToNextMultipleOf(
×
1441
                    (uint32_t)(insert_adjusted_re - insert_start_offset), cfg->buf_size);
×
1442
            SCLogDebug("new_buf_size %u", new_buf_size);
×
1443
        }
×
1444

1445
        SCLogDebug("end region %p/%" PRIu64 "/%u", end, end->stream_offset, end->buf_size);
73✔
1446
        /* sets sc_errno */
1447
        StreamingBufferRegion *ret = BufferInsertAtRegionConsolidate(
73✔
1448
                sb, cfg, big, start, end, offset, len, start_prev, new_buf_size);
73✔
1449
        return ret;
73✔
1450
    } else {
73✔
1451
        /* if there was no region we can use we add a new region and insert it */
1452
        StreamingBufferRegion *append = &sb->region;
8✔
1453
        for (StreamingBufferRegion *r = append; r != NULL; r = r->next) {
20✔
1454
            if (r->stream_offset > offset) {
16✔
1455
                break;
4✔
1456
            } else {
12✔
1457
                append = r;
12✔
1458
            }
12✔
1459
        }
16✔
1460

1461
        SCLogDebug("no matching region found, append to %p (%s)", append,
8✔
1462
                append == &sb->region ? "main" : "aux");
8✔
1463
        /* sets sc_errno */
1464
        StreamingBufferRegion *add = InitBufferRegion(sb, cfg, len);
8✔
1465
        if (add == NULL)
8✔
1466
            return NULL;
×
1467
        add->stream_offset = offset;
8✔
1468
        add->next = append->next;
8✔
1469
        append->next = add;
8✔
1470
        SCLogDebug("new region %p offset %" PRIu64, add, add->stream_offset);
8✔
1471
        return add;
8✔
1472
    }
8✔
1473
}
81✔
1474

1475
/** \internal
1476
 *  \brief return the region to put the new data in
1477
 *
1478
 *  Will find an existing region, expand it if needed. If no existing region exists or is
1479
 *  a good fit, it will try to set up a new region. If the region then overlaps or gets
1480
 *  too close to the next, merge them.
1481
 *
1482
 *  \note sets sc_errno
1483
 */
1484
static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb,
1485
        const StreamingBufferConfig *cfg, const uint32_t data_len, const uint64_t data_offset)
1486
{
642,138✔
1487
    SCLogDebug("data_offset %" PRIu64 ", data_len %u, re %" PRIu64, data_offset, data_len,
642,138✔
1488
            data_offset + data_len);
642,138✔
1489
    ListRegions(sb);
642,138✔
1490

1491
    if (RegionsIntersect(cfg, &sb->region, data_offset, data_offset + data_len)) {
642,138✔
1492
        SCLogDebug("data_offset %" PRIu64 ", data_len %u intersects with main region (next %p)",
641,848✔
1493
                data_offset, data_len, sb->region.next);
641,848✔
1494
        if (sb->region.next == NULL ||
641,848✔
1495
                !RegionsIntersect(cfg, sb->region.next, data_offset, data_offset + data_len)) {
641,848✔
1496
            SCLogDebug(
641,847✔
1497
                    "data_offset %" PRIu64
641,847✔
1498
                    ", data_len %u intersects with main region, no next or way before next region",
641,847✔
1499
                    data_offset, data_len);
641,847✔
1500
            if (sb->region.buf == NULL) {
641,847✔
1501
                int r;
52,615✔
1502
                if ((r = InitBuffer(sb, cfg)) != SC_OK) { // TODO init with size
52,615✔
1503
                    sc_errno = r;
×
1504
                    return NULL;
×
1505
                }
×
1506
            }
52,615✔
1507
            return &sb->region;
641,847✔
1508
        }
641,847✔
1509
    } else if (sb->region.next == NULL) {
641,848✔
1510
        /* InitBufferRegion sets sc_errno */
1511
        StreamingBufferRegion *aux_r = sb->region.next = InitBufferRegion(sb, cfg, data_len);
210✔
1512
        if (aux_r == NULL)
210✔
1513
            return NULL;
×
1514
        aux_r->stream_offset = data_offset;
210✔
1515
        DEBUG_VALIDATE_BUG_ON(data_len > aux_r->buf_size);
210✔
1516
        SCLogDebug("created new region %p with offset %" PRIu64 ", size %u", aux_r,
210✔
1517
                aux_r->stream_offset, aux_r->buf_size);
210✔
1518
        return aux_r;
210✔
1519
    }
210✔
1520
    /* BufferInsertAtRegionDo sets sc_errno */
1521
    StreamingBufferRegion *blob = BufferInsertAtRegionDo(sb, cfg, data_offset, data_len);
81✔
1522
    SCLogDebug("blob %p (%s)", blob, blob == &sb->region ? "main" : "aux");
81✔
1523
    return blob;
81✔
1524
}
642,138✔
1525

1526
/**
1527
 *  \param offset offset relative to StreamingBuffer::stream_offset
1528
 *
1529
 *  \return SC_OK in case of success
1530
 *  \return SC_E* errors otherwise
1531
 */
1532
int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
1533
        StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset)
1534
{
642,138✔
1535
    DEBUG_VALIDATE_BUG_ON(seg == NULL);
642,138✔
1536
    DEBUG_VALIDATE_BUG_ON(data_len > BIT_U32(27)); // 128MiB is excessive already
642,138✔
1537
    DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset);
642,138✔
1538
    if (offset < sb->region.stream_offset) {
642,138✔
1539
        return SC_EINVAL;
×
1540
    }
×
1541

1542
    StreamingBufferRegion *region = BufferInsertAtRegion(sb, cfg, data_len, offset);
642,138✔
1543
    if (region == NULL) {
642,138✔
1544
        return sc_errno;
×
1545
    }
×
1546

1547
    const bool region_is_main = region == &sb->region;
642,138✔
1548

1549
    SCLogDebug("inserting %" PRIu64 "/%u using %s region %p", offset, data_len,
642,138✔
1550
            region == &sb->region ? "main" : "aux", region);
642,138✔
1551

1552
    DEBUG_VALIDATE_BUG_ON(offset - region->stream_offset > UINT32_MAX);
642,138✔
1553
    uint32_t rel_offset = (uint32_t)(offset - region->stream_offset);
642,138✔
1554
    int r = DataFitsAtOffset(region, data_len, rel_offset);
642,138✔
1555
    if (r < 0) {
642,138✔
UNCOV
1556
        DEBUG_VALIDATE_BUG_ON(1);
×
UNCOV
1557
        return SC_ELIMIT;
×
1558
    } else if (r == 0) {
642,138✔
1559
        if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK)
73,759✔
1560
            return r;
×
1561
    }
73,759✔
1562
    DEBUG_VALIDATE_BUG_ON(DataFitsAtOffset(region, data_len, rel_offset) != 1);
642,138✔
1563

1564
    SCLogDebug("offset %" PRIu64 " data_len %u, rel_offset %u into region offset %" PRIu64
642,138✔
1565
               ", buf_offset %u, buf_size %u",
642,138✔
1566
            offset, data_len, rel_offset, region->stream_offset, region->buf_offset,
642,138✔
1567
            region->buf_size);
642,138✔
1568
    memcpy(region->buf + rel_offset, data, data_len);
642,138✔
1569
    seg->stream_offset = offset;
642,138✔
1570
    seg->segment_len = data_len;
642,138✔
1571

1572
    SCLogDebug("rel_offset %u region->stream_offset %" PRIu64 ", buf_offset %u", rel_offset,
642,138✔
1573
            region->stream_offset, region->buf_offset);
642,138✔
1574

1575
    if (RB_EMPTY(&sb->sbb_tree)) {
642,138✔
1576
        SCLogDebug("empty sbb list");
499,960✔
1577

1578
        if (region_is_main) {
499,960✔
1579
            if (sb->region.stream_offset == offset) {
499,805✔
1580
                SCLogDebug("empty sbb list: block exactly what was expected, fall through");
52,148✔
1581
                /* empty list, data is exactly what is expected (append),
1582
                 * so do nothing.
1583
                 * Update buf_offset if needed, but in case of overlaps it might be beyond us. */
1584
                sb->region.buf_offset = MAX(sb->region.buf_offset, rel_offset + data_len);
52,148✔
1585
            } else if ((rel_offset + data_len) <= sb->region.buf_offset) {
447,657✔
1586
                SCLogDebug("empty sbb list: block is within existing main data region");
770✔
1587
            } else {
446,887✔
1588
                if (sb->region.buf_offset && rel_offset == sb->region.buf_offset) {
446,887✔
1589
                    SCLogDebug("exactly at expected offset");
440,674✔
1590
                    // nothing to do
1591
                    sb->region.buf_offset = rel_offset + data_len;
440,674✔
1592

1593
                } else if (rel_offset < sb->region.buf_offset) {
440,674✔
1594
                    // nothing to do
1595

1596
                    SCLogDebug("before expected offset: %u < sb->region.buf_offset %u", rel_offset,
159✔
1597
                            sb->region.buf_offset);
159✔
1598
                    if (rel_offset + data_len > sb->region.buf_offset) {
159✔
1599
                        SCLogDebug("before expected offset, ends after: %u < sb->region.buf_offset "
159✔
1600
                                   "%u, %u > %u",
159✔
1601
                                rel_offset, sb->region.buf_offset, rel_offset + data_len,
159✔
1602
                                sb->region.buf_offset);
159✔
1603
                        sb->region.buf_offset = rel_offset + data_len;
159✔
1604
                    }
159✔
1605

1606
                } else if (sb->region.buf_offset) {
6,054✔
1607
                    SCLogDebug("beyond expected offset: SBBInit");
4,016✔
1608
                    /* existing data, but there is a gap between us */
1609
                    if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
4,016✔
1610
                        return r;
×
1611
                } else {
4,016✔
1612
                    /* gap before data in empty list */
1613
                    SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
2,038✔
1614
                    if ((r = SBBInitLeadingGap(sb, cfg, offset, data_len)) != SC_OK)
2,038✔
1615
                        return r;
×
1616
                }
2,038✔
1617
            }
446,887✔
1618
        } else {
499,805✔
1619
            if (sb->region.buf_offset) {
155✔
1620
                /* existing data, but there is a gap between us */
1621
                SCLogDebug("empty sbb list, no data in main: use SBBInit");
99✔
1622
                if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
99✔
1623
                    return r;
×
1624
            } else {
99✔
1625
                /* gap before data in empty list */
1626
                SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
56✔
1627
                if ((r = SBBInitLeadingGap(sb, cfg, offset, data_len)) != SC_OK)
56✔
1628
                    return r;
×
1629
            }
56✔
1630
            if (rel_offset == region->buf_offset) {
155✔
1631
                SCLogDebug("pre region->buf_offset %u", region->buf_offset);
155✔
1632
                region->buf_offset = rel_offset + data_len;
155✔
1633
                SCLogDebug("post region->buf_offset %u", region->buf_offset);
155✔
1634
            }
155✔
1635
        }
155✔
1636
    } else {
499,960✔
1637
        SCLogDebug("updating sbb tree");
142,178✔
1638
        /* already have blocks, so append new block based on new data */
1639
        if ((r = SBBUpdate(sb, cfg, region, rel_offset, data_len)) != SC_OK)
142,178✔
1640
            return r;
×
1641
    }
142,178✔
1642
    DEBUG_VALIDATE_BUG_ON(!region_is_main && sb->head == NULL);
642,138✔
1643

1644
    ListRegions(sb);
642,138✔
1645
    if (RB_EMPTY(&sb->sbb_tree)) {
642,138✔
1646
        DEBUG_VALIDATE_BUG_ON(offset + data_len > sb->region.stream_offset + sb->region.buf_offset);
493,751✔
1647
    }
493,751✔
1648

1649
    return SC_OK;
642,138✔
1650
}
642,138✔
1651

1652
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb,
1653
                                         const StreamingBufferSegment *seg)
1654
{
863,138✔
1655
    if (seg->stream_offset < sb->region.stream_offset) {
863,138✔
1656
        if (seg->stream_offset + seg->segment_len <= sb->region.stream_offset) {
149,063✔
1657
            return 1;
80,979✔
1658
        }
80,979✔
1659
    }
149,063✔
1660
    return 0;
782,159✔
1661
}
863,138✔
1662

1663
static inline const StreamingBufferRegion *GetRegionForOffset(
1664
        const StreamingBuffer *sb, const uint64_t offset)
1665
{
1,643,033✔
1666
    if (sb == NULL)
1,643,033✔
1667
        return NULL;
5✔
1668
    if (sb->region.next == NULL) {
1,643,028✔
1669
        return &sb->region;
1,640,258✔
1670
    }
1,640,258✔
1671
    if (offset >= sb->region.stream_offset &&
2,770✔
1672
            offset < (sb->region.stream_offset + sb->region.buf_size)) {
2,770✔
1673
        return &sb->region;
2,556✔
1674
    }
2,556✔
1675
    for (const StreamingBufferRegion *r = sb->region.next; r != NULL; r = r->next) {
223✔
1676
        if (offset >= r->stream_offset && offset < (r->stream_offset + r->buf_size)) {
223✔
1677
            return r;
214✔
1678
        }
214✔
1679
    }
223✔
UNCOV
1680
    return NULL;
×
1681
}
214✔
1682

1683
/** \brief get the data for one SBB */
1684
void StreamingBufferSBBGetData(const StreamingBuffer *sb,
1685
                               const StreamingBufferBlock *sbb,
1686
                               const uint8_t **data, uint32_t *data_len)
1687
{
261,746✔
1688
    const StreamingBufferRegion *region = GetRegionForOffset(sb, sbb->offset);
261,746✔
1689
    SCLogDebug("first find our region (offset %" PRIu64 ") -> %p", sbb->offset, region);
261,746✔
1690
    if (region) {
261,746✔
1691
        SCLogDebug("region %p found %" PRIu64 "/%u/%u", region, region->stream_offset,
261,746✔
1692
                region->buf_size, region->buf_offset);
261,746✔
1693
        DEBUG_VALIDATE_BUG_ON(
261,746✔
1694
                region->stream_offset == sbb->offset && region->buf_offset > sbb->len);
261,746✔
1695
        // buf_offset should match first sbb len if it has the same offset
1696

1697
        if (sbb->offset >= region->stream_offset) {
261,746✔
1698
            SCLogDebug("1");
261,746✔
1699
            uint64_t offset = sbb->offset - region->stream_offset;
261,746✔
1700
            *data = region->buf + offset;
261,746✔
1701
            DEBUG_VALIDATE_BUG_ON(offset + sbb->len > region->buf_size);
261,746✔
1702
            *data_len = sbb->len;
261,746✔
1703
            return;
261,746✔
1704
        } else {
261,746✔
1705
            SCLogDebug("2");
×
1706
            uint32_t offset = (uint32_t)(region->stream_offset - sbb->offset);
×
1707
            if (offset < sbb->len) {
×
1708
                *data = region->buf;
×
1709
                *data_len = sbb->len - offset;
×
1710
                return;
×
1711
            }
×
1712
            SCLogDebug("3");
×
1713
        }
×
1714
    }
261,746✔
1715
    *data = NULL;
×
1716
    *data_len = 0;
×
1717
}
×
1718

1719
/** \brief get the data for one SBB */
1720
void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb,
1721
                                       const StreamingBufferBlock *sbb,
1722
                                       const uint8_t **data, uint32_t *data_len,
1723
                                       uint64_t offset)
1724
{
112,336✔
1725
    /* validate that we are looking for a offset within the sbb */
1726
    DEBUG_VALIDATE_BUG_ON(!(offset >= sbb->offset && offset < (sbb->offset + sbb->len)));
112,336✔
1727
    if (!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))) {
112,336✔
1728
        *data = NULL;
×
1729
        *data_len = 0;
×
1730
        return;
×
1731
    }
×
1732

1733
    const StreamingBufferRegion *region = GetRegionForOffset(sb, offset);
112,336✔
1734
    if (region) {
112,336✔
1735
        DEBUG_VALIDATE_BUG_ON(sbb->len - (offset - sbb->offset) > UINT32_MAX);
112,336✔
1736
        uint32_t sbblen = (uint32_t)(sbb->len - (offset - sbb->offset));
112,336✔
1737

1738
        if (offset >= region->stream_offset) {
112,336✔
1739
            uint32_t data_offset = (uint32_t)(offset - region->stream_offset);
112,336✔
1740
            *data = region->buf + data_offset;
112,336✔
1741
            if (data_offset + sbblen > region->buf_size) {
112,336✔
1742
                *data_len = region->buf_size - data_offset;
×
1743
            } else {
112,336✔
1744
                *data_len = sbblen;
112,336✔
1745
            }
112,336✔
1746
            DEBUG_VALIDATE_BUG_ON(*data_len > sbblen);
112,336✔
1747
            return;
112,336✔
1748
        } else {
112,336✔
1749
            uint32_t data_offset = (uint32_t)(region->stream_offset - sbb->offset);
×
1750
            if (data_offset < sbblen) {
×
1751
                *data = region->buf;
×
1752
                *data_len = sbblen - data_offset;
×
1753
                DEBUG_VALIDATE_BUG_ON(*data_len > sbblen);
×
1754
                return;
×
1755
            }
×
1756
        }
×
1757
    }
112,336✔
1758

1759
    *data = NULL;
×
1760
    *data_len = 0;
×
1761
}
×
1762

1763
void StreamingBufferSegmentGetData(const StreamingBuffer *sb,
1764
                                   const StreamingBufferSegment *seg,
1765
                                   const uint8_t **data, uint32_t *data_len)
1766
{
5,822✔
1767
    const StreamingBufferRegion *region = GetRegionForOffset(sb, seg->stream_offset);
5,822✔
1768
    if (region) {
5,822✔
1769
        if (seg->stream_offset >= region->stream_offset) {
5,822✔
1770
            uint32_t offset = (uint32_t)(seg->stream_offset - region->stream_offset);
5,822✔
1771
            *data = region->buf + offset;
5,822✔
1772
            if (offset + seg->segment_len > region->buf_size) {
5,822✔
1773
                *data_len = region->buf_size - offset;
×
1774
            } else {
5,822✔
1775
                *data_len = seg->segment_len;
5,822✔
1776
            }
5,822✔
1777
            SCLogDebug("*data_len %u", *data_len);
5,822✔
1778
            return;
5,822✔
1779
        } else {
5,822✔
UNCOV
1780
            uint32_t offset = (uint32_t)(region->stream_offset - seg->stream_offset);
×
UNCOV
1781
            if (offset < seg->segment_len) {
×
UNCOV
1782
                *data = region->buf;
×
UNCOV
1783
                *data_len = seg->segment_len - offset;
×
UNCOV
1784
                SCLogDebug("*data_len %u", *data_len);
×
UNCOV
1785
                return;
×
UNCOV
1786
            }
×
UNCOV
1787
        }
×
1788
    }
5,822✔
UNCOV
1789
    *data = NULL;
×
UNCOV
1790
    *data_len = 0;
×
UNCOV
1791
}
×
1792

1793
/**
1794
 *  \retval 1 data is the same
1795
 *  \retval 0 data is different
1796
 */
1797
int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb,
1798
                                         const StreamingBufferSegment *seg,
1799
                                         const uint8_t *rawdata, uint32_t rawdata_len)
UNCOV
1800
{
×
UNCOV
1801
    const uint8_t *segdata = NULL;
×
UNCOV
1802
    uint32_t segdata_len = 0;
×
UNCOV
1803
    StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len);
×
UNCOV
1804
    if (segdata && segdata_len &&
×
UNCOV
1805
        segdata_len == rawdata_len &&
×
UNCOV
1806
        memcmp(segdata, rawdata, segdata_len) == 0)
×
UNCOV
1807
    {
×
UNCOV
1808
        return 1;
×
UNCOV
1809
    }
×
1810
    return 0;
×
UNCOV
1811
}
×
1812

1813
int StreamingBufferGetData(const StreamingBuffer *sb,
1814
        const uint8_t **data, uint32_t *data_len,
1815
        uint64_t *stream_offset)
1816
{
31,591✔
1817
    if (sb != NULL && sb->region.buf != NULL) {
31,591✔
1818
        *data = sb->region.buf;
31,547✔
1819
        *data_len = sb->region.buf_offset;
31,547✔
1820
        *stream_offset = sb->region.stream_offset;
31,547✔
1821
        return 1;
31,547✔
1822
    } else {
31,547✔
1823
        *data = NULL;
44✔
1824
        *data_len = 0;
44✔
1825
        *stream_offset = 0;
44✔
1826
        return 0;
44✔
1827
    }
44✔
1828
}
31,591✔
1829

1830
int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb,
1831
        const uint8_t **data, uint32_t *data_len,
1832
        uint64_t offset)
1833
{
1,263,129✔
1834
    const StreamingBufferRegion *region = GetRegionForOffset(sb, offset);
1,263,129✔
1835
    if (region != NULL && region->buf != NULL && offset >= region->stream_offset &&
1,263,129✔
1836
            offset < (region->stream_offset + region->buf_offset)) {
1,263,129✔
1837
        DEBUG_VALIDATE_BUG_ON(offset - region->stream_offset > UINT32_MAX);
493,613✔
1838
        uint32_t skip = (uint32_t)(offset - region->stream_offset);
493,613✔
1839
        *data = region->buf + skip;
493,613✔
1840
        *data_len = region->buf_offset - skip;
493,613✔
1841
        return 1;
493,613✔
1842
    } else {
769,516✔
1843
        *data = NULL;
769,516✔
1844
        *data_len = 0;
769,516✔
1845
        return 0;
769,516✔
1846
    }
769,516✔
1847
}
1,263,129✔
1848

1849
/**
1850
 *  \retval 1 data is the same
1851
 *  \retval 0 data is different
1852
 */
1853
int StreamingBufferCompareRawData(const StreamingBuffer *sb,
1854
                                  const uint8_t *rawdata, uint32_t rawdata_len)
UNCOV
1855
{
×
UNCOV
1856
    const uint8_t *sbdata = NULL;
×
UNCOV
1857
    uint32_t sbdata_len = 0;
×
UNCOV
1858
    uint64_t offset = 0;
×
UNCOV
1859
    StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset);
×
UNCOV
1860
    if (offset == 0 &&
×
UNCOV
1861
        sbdata && sbdata_len &&
×
UNCOV
1862
        sbdata_len == rawdata_len &&
×
UNCOV
1863
        memcmp(sbdata, rawdata, sbdata_len) == 0)
×
UNCOV
1864
    {
×
UNCOV
1865
        return 1;
×
UNCOV
1866
    }
×
1867
    SCLogDebug("sbdata_len %u, offset %" PRIu64, sbdata_len, offset);
×
1868
    printf("got:\n");
×
1869
    PrintRawDataFp(stdout, sbdata,sbdata_len);
×
1870
    printf("wanted:\n");
×
1871
    PrintRawDataFp(stdout, rawdata,rawdata_len);
×
1872
    return 0;
×
UNCOV
1873
}
×
1874

1875
#ifdef UNITTESTS
1876
static void Dump(StreamingBuffer *sb)
1877
{
1878
    PrintRawDataFp(stdout, sb->region.buf, sb->region.buf_offset);
1879
}
1880

1881
static void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg)
1882
{
1883
    const uint8_t *data = NULL;
1884
    uint32_t data_len = 0;
1885
    StreamingBufferSegmentGetData(sb, seg, &data, &data_len);
1886
    if (data && data_len) {
1887
        PrintRawDataFp(stdout, data, data_len);
1888
    }
1889
}
1890

1891
static int StreamingBufferTest02(void)
1892
{
1893
    StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
1894
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
1895
    FAIL_IF(sb == NULL);
1896

1897
    StreamingBufferSegment seg1;
1898
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1899
    StreamingBufferSegment seg2;
1900
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8) != 0);
1901
    FAIL_IF(sb->region.stream_offset != 0);
1902
    FAIL_IF(sb->region.buf_offset != 16);
1903
    FAIL_IF(seg1.stream_offset != 0);
1904
    FAIL_IF(seg2.stream_offset != 8);
1905
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1906
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1907
    Dump(sb);
1908
    DumpSegment(sb, &seg1);
1909
    DumpSegment(sb, &seg2);
1910
    FAIL_IF_NOT_NULL(sb->head);
1911
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1912

1913
    StreamingBufferSlideToOffset(sb, &cfg, 6);
1914
    FAIL_IF_NOT_NULL(sb->head);
1915
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1916

1917
    StreamingBufferSegment seg3;
1918
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6) != 0);
1919
    FAIL_IF(sb->region.stream_offset != 6);
1920
    FAIL_IF(sb->region.buf_offset != 16);
1921
    FAIL_IF(seg3.stream_offset != 16);
1922
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1923
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1924
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1925
    Dump(sb);
1926
    DumpSegment(sb, &seg1);
1927
    DumpSegment(sb, &seg2);
1928
    DumpSegment(sb, &seg3);
1929
    FAIL_IF_NOT_NULL(sb->head);
1930
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1931

1932
    StreamingBufferSlideToOffset(sb, &cfg, 12);
1933
    FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1934
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1935
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1936
    Dump(sb);
1937
    DumpSegment(sb, &seg1);
1938
    DumpSegment(sb, &seg2);
1939
    DumpSegment(sb, &seg3);
1940
    FAIL_IF_NOT_NULL(sb->head);
1941
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1942

1943
    StreamingBufferFree(sb, &cfg);
1944
    PASS;
1945
}
1946

1947
static int StreamingBufferTest03(void)
1948
{
1949
    StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
1950
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
1951
    FAIL_IF(sb == NULL);
1952

1953
    StreamingBufferSegment seg1;
1954
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1955
    StreamingBufferSegment seg2;
1956
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
1957
    FAIL_IF(sb->region.stream_offset != 0);
1958
    FAIL_IF(sb->region.buf_offset != 8);
1959
    FAIL_IF(seg1.stream_offset != 0);
1960
    FAIL_IF(seg2.stream_offset != 14);
1961
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1962
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1963
    Dump(sb);
1964
    DumpSegment(sb, &seg1);
1965
    DumpSegment(sb, &seg2);
1966
    FAIL_IF_NULL(sb->head);
1967
    FAIL_IF_NOT(sb->sbb_size == 16);
1968
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1969

1970
    StreamingBufferSegment seg3;
1971
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
1972
    FAIL_IF(sb->region.stream_offset != 0);
1973
    FAIL_IF(sb->region.buf_offset != 22);
1974
    FAIL_IF(seg3.stream_offset != 8);
1975
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1976
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1977
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1978
    Dump(sb);
1979
    DumpSegment(sb, &seg1);
1980
    DumpSegment(sb, &seg2);
1981
    DumpSegment(sb, &seg3);
1982
    FAIL_IF_NULL(sb->head);
1983
    FAIL_IF_NOT(sb->sbb_size == 22);
1984
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1985

1986
    StreamingBufferSlideToOffset(sb, &cfg, 10);
1987
    FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1988
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1989
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1990
    Dump(sb);
1991
    DumpSegment(sb, &seg1);
1992
    DumpSegment(sb, &seg2);
1993
    DumpSegment(sb, &seg3);
1994
    FAIL_IF_NULL(sb->head);
1995
    FAIL_IF_NOT(sb->sbb_size == 12);
1996
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1997

1998
    StreamingBufferFree(sb, &cfg);
1999
    PASS;
2000
}
2001

2002
static int StreamingBufferTest04(void)
2003
{
2004
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2005
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2006
    FAIL_IF(sb == NULL);
2007

2008
    StreamingBufferSegment seg1;
2009
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
2010
    FAIL_IF(!RB_EMPTY(&sb->sbb_tree));
2011
    StreamingBufferSegment seg2;
2012
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
2013
    FAIL_IF(sb->region.stream_offset != 0);
2014
    FAIL_IF(sb->region.buf_offset != 8);
2015
    FAIL_IF(seg1.stream_offset != 0);
2016
    FAIL_IF(seg2.stream_offset != 14);
2017
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
2018
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
2019
    FAIL_IF(RB_EMPTY(&sb->sbb_tree));
2020
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2021
    FAIL_IF(sbb1 != sb->head);
2022
    FAIL_IF_NULL(sbb1);
2023
    FAIL_IF(sbb1->offset != 0);
2024
    FAIL_IF(sbb1->len != 8);
2025
    StreamingBufferBlock *sbb2 = SBB_RB_NEXT(sbb1);
2026
    FAIL_IF_NULL(sbb2);
2027
    FAIL_IF(sbb2 == sb->head);
2028
    FAIL_IF(sbb2->offset != 14);
2029
    FAIL_IF(sbb2->len != 8);
2030
    Dump(sb);
2031
    DumpSegment(sb, &seg1);
2032
    DumpSegment(sb, &seg2);
2033
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2034

2035
    StreamingBufferSegment seg3;
2036
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
2037
    FAIL_IF(sb->region.stream_offset != 0);
2038
    FAIL_IF(sb->region.buf_offset != 22);
2039
    FAIL_IF(seg3.stream_offset != 8);
2040
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
2041
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
2042
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
2043
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2044
    FAIL_IF_NULL(sbb1);
2045
    FAIL_IF(sbb1 != sb->head);
2046
    FAIL_IF(sbb1->offset != 0);
2047
    FAIL_IF(sbb1->len != 22);
2048
    FAIL_IF(SBB_RB_NEXT(sbb1));
2049
    Dump(sb);
2050
    DumpSegment(sb, &seg1);
2051
    DumpSegment(sb, &seg2);
2052
    DumpSegment(sb, &seg3);
2053
    FAIL_IF_NULL(sb->head);
2054
    FAIL_IF_NOT(sb->sbb_size == 22);
2055
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2056

2057
    /* far ahead of curve: */
2058
    StreamingBufferSegment seg4;
2059
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0);
2060
    FAIL_IF(sb->region.stream_offset != 0);
2061
    FAIL_IF(sb->region.buf_offset != 22);
2062
    FAIL_IF(sb->region.buf_size != 128);
2063
    FAIL_IF(seg4.stream_offset != 124);
2064
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
2065
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
2066
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
2067
    FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4));
2068
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2069
    FAIL_IF_NULL(sbb1);
2070
    FAIL_IF(sbb1 != sb->head);
2071
    FAIL_IF(sbb1->offset != 0);
2072
    FAIL_IF(sbb1->len != 22);
2073
    FAIL_IF(!SBB_RB_NEXT(sbb1));
2074
    Dump(sb);
2075
    DumpSegment(sb, &seg1);
2076
    DumpSegment(sb, &seg2);
2077
    DumpSegment(sb, &seg3);
2078
    DumpSegment(sb, &seg4);
2079
    FAIL_IF_NULL(sb->head);
2080
    FAIL_IF_NOT(sb->sbb_size == 25);
2081
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2082

2083
    FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8));
2084
    FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8));
2085
    FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6));
2086
    FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3));
2087

2088
    StreamingBufferFree(sb, &cfg);
2089
    PASS;
2090
}
2091

2092
/** \test lots of gaps in block list */
2093
static int StreamingBufferTest06(void)
2094
{
2095
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2096
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2097
    FAIL_IF(sb == NULL);
2098

2099
    StreamingBufferSegment seg1;
2100
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"A", 1) != 0);
2101
    StreamingBufferSegment seg2;
2102
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"C", 1, 2) != 0);
2103
    Dump(sb);
2104
    FAIL_IF_NULL(sb->head);
2105
    FAIL_IF_NOT(sb->sbb_size == 2);
2106
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2107

2108
    StreamingBufferSegment seg3;
2109
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0);
2110
    Dump(sb);
2111
    FAIL_IF_NULL(sb->head);
2112
    FAIL_IF_NOT(sb->sbb_size == 3);
2113
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2114

2115
    StreamingBufferSegment seg4;
2116
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0);
2117
    Dump(sb);
2118
    FAIL_IF_NULL(sb->head);
2119
    FAIL_IF_NOT(sb->sbb_size == 4);
2120
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2121

2122
    StreamingBufferSegment seg5;
2123
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
2124
    Dump(sb);
2125
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2126
    FAIL_IF_NULL(sbb1);
2127
    FAIL_IF(sbb1->offset != 0);
2128
    FAIL_IF(sbb1->len != 10);
2129
    FAIL_IF(SBB_RB_NEXT(sbb1));
2130
    FAIL_IF_NULL(sb->head);
2131
    FAIL_IF_NOT(sb->sbb_size == 10);
2132
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2133

2134
    StreamingBufferSegment seg6;
2135
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
2136
    Dump(sb);
2137
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2138
    FAIL_IF_NULL(sbb1);
2139
    FAIL_IF(sbb1->offset != 0);
2140
    FAIL_IF(sbb1->len != 10);
2141
    FAIL_IF(SBB_RB_NEXT(sbb1));
2142
    FAIL_IF_NULL(sb->head);
2143
    FAIL_IF_NOT(sb->sbb_size == 10);
2144
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2145

2146
    StreamingBufferFree(sb, &cfg);
2147
    PASS;
2148
}
2149

2150
/** \test lots of gaps in block list */
2151
static int StreamingBufferTest07(void)
2152
{
2153
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2154
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2155
    FAIL_IF(sb == NULL);
2156

2157
    StreamingBufferSegment seg1;
2158
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0);
2159
    StreamingBufferSegment seg2;
2160
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0);
2161
    Dump(sb);
2162
    FAIL_IF_NULL(sb->head);
2163
    FAIL_IF_NOT(sb->sbb_size == 2);
2164
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2165

2166
    StreamingBufferSegment seg3;
2167
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0);
2168
    Dump(sb);
2169
    FAIL_IF_NULL(sb->head);
2170
    FAIL_IF_NOT(sb->sbb_size == 3);
2171
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2172

2173
    StreamingBufferSegment seg4;
2174
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0);
2175
    Dump(sb);
2176
    FAIL_IF_NULL(sb->head);
2177
    FAIL_IF_NOT(sb->sbb_size == 4);
2178
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2179

2180
    StreamingBufferSegment seg5;
2181
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
2182
    Dump(sb);
2183
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2184
    FAIL_IF_NULL(sbb1);
2185
    FAIL_IF(sbb1->offset != 0);
2186
    FAIL_IF(sbb1->len != 10);
2187
    FAIL_IF(SBB_RB_NEXT(sbb1));
2188
    FAIL_IF_NULL(sb->head);
2189
    FAIL_IF_NOT(sb->sbb_size == 10);
2190
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2191

2192
    StreamingBufferSegment seg6;
2193
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
2194
    Dump(sb);
2195
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2196
    FAIL_IF_NULL(sbb1);
2197
    FAIL_IF(sbb1->offset != 0);
2198
    FAIL_IF(sbb1->len != 10);
2199
    FAIL_IF(SBB_RB_NEXT(sbb1));
2200
    FAIL_IF_NULL(sb->head);
2201
    FAIL_IF_NOT(sb->sbb_size == 10);
2202
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2203

2204
    StreamingBufferFree(sb, &cfg);
2205
    PASS;
2206
}
2207

2208
/** \test lots of gaps in block list */
2209
static int StreamingBufferTest08(void)
2210
{
2211
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2212
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2213
    FAIL_IF(sb == NULL);
2214

2215
    StreamingBufferSegment seg1;
2216
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0);
2217
    StreamingBufferSegment seg2;
2218
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0);
2219
    Dump(sb);
2220
    FAIL_IF_NULL(sb->head);
2221
    FAIL_IF_NOT(sb->sbb_size == 2);
2222
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2223

2224
    StreamingBufferSegment seg3;
2225
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"F", 1, 5) != 0);
2226
    Dump(sb);
2227
    FAIL_IF_NULL(sb->head);
2228
    FAIL_IF_NOT(sb->sbb_size == 3);
2229
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2230

2231
    StreamingBufferSegment seg4;
2232
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"H", 1, 7) != 0);
2233
    Dump(sb);
2234
    FAIL_IF_NULL(sb->head);
2235
    FAIL_IF_NOT(sb->sbb_size == 4);
2236
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2237

2238
    StreamingBufferSegment seg5;
2239
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
2240
    Dump(sb);
2241
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2242
    FAIL_IF_NULL(sbb1);
2243
    FAIL_IF(sbb1->offset != 0);
2244
    FAIL_IF(sbb1->len != 10);
2245
    FAIL_IF(SBB_RB_NEXT(sbb1));
2246
    FAIL_IF_NULL(sb->head);
2247
    FAIL_IF_NOT(sb->sbb_size == 10);
2248
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2249

2250
    StreamingBufferSegment seg6;
2251
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10) != 0);
2252
    Dump(sb);
2253
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2254
    FAIL_IF_NULL(sbb1);
2255
    FAIL_IF(sbb1->offset != 0);
2256
    FAIL_IF(sbb1->len != 20);
2257
    FAIL_IF(SBB_RB_NEXT(sbb1));
2258
    FAIL_IF_NULL(sb->head);
2259
    FAIL_IF_NOT(sb->sbb_size == 20);
2260
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2261

2262
    StreamingBufferFree(sb, &cfg);
2263
    PASS;
2264
}
2265

2266
/** \test lots of gaps in block list */
2267
static int StreamingBufferTest09(void)
2268
{
2269
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2270
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2271
    FAIL_IF(sb == NULL);
2272

2273
    StreamingBufferSegment seg1;
2274
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"B", 1, 1) != 0);
2275
    StreamingBufferSegment seg2;
2276
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0);
2277
    Dump(sb);
2278
    FAIL_IF_NULL(sb->head);
2279
    FAIL_IF_NOT(sb->sbb_size == 2);
2280
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2281

2282
    StreamingBufferSegment seg3;
2283
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0);
2284
    Dump(sb);
2285
    FAIL_IF_NULL(sb->head);
2286
    FAIL_IF_NOT(sb->sbb_size == 3);
2287
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2288

2289
    StreamingBufferSegment seg4;
2290
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"F", 1, 5) != 0);
2291
    Dump(sb);
2292
    FAIL_IF_NULL(sb->head);
2293
    FAIL_IF_NOT(sb->sbb_size == 4);
2294
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2295

2296
    StreamingBufferSegment seg5;
2297
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
2298
    Dump(sb);
2299
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2300
    FAIL_IF_NULL(sbb1);
2301
    FAIL_IF(sbb1->offset != 0);
2302
    FAIL_IF(sbb1->len != 10);
2303
    FAIL_IF(SBB_RB_NEXT(sbb1));
2304
    FAIL_IF_NULL(sb->head);
2305
    FAIL_IF_NOT(sb->sbb_size == 10);
2306
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2307

2308
    StreamingBufferSegment seg6;
2309
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
2310
    Dump(sb);
2311
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2312
    FAIL_IF_NULL(sbb1);
2313
    FAIL_IF(sbb1->offset != 0);
2314
    FAIL_IF(sbb1->len != 10);
2315
    FAIL_IF(SBB_RB_NEXT(sbb1));
2316
    FAIL_IF_NULL(sb->head);
2317
    FAIL_IF_NOT(sb->sbb_size == 10);
2318
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2319

2320
    StreamingBufferFree(sb, &cfg);
2321
    PASS;
2322
}
2323

2324
/** \test lots of gaps in block list */
2325
static int StreamingBufferTest10(void)
2326
{
2327
    StreamingBufferConfig cfg = { 16, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2328
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2329
    FAIL_IF(sb == NULL);
2330

2331
    StreamingBufferSegment seg1;
2332
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg1, (const uint8_t *)"A", 1, 0) != 0);
2333
    Dump(sb);
2334
    StreamingBufferSegment seg2;
2335
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg2, (const uint8_t *)"D", 1, 3) != 0);
2336
    Dump(sb);
2337
    StreamingBufferSegment seg3;
2338
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg3, (const uint8_t *)"H", 1, 7) != 0);
2339
    Dump(sb);
2340
    FAIL_IF_NULL(sb->head);
2341
    FAIL_IF_NOT(sb->sbb_size == 3);
2342

2343
    StreamingBufferSegment seg4;
2344
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg4, (const uint8_t *)"B", 1, 1) != 0);
2345
    Dump(sb);
2346
    StreamingBufferSegment seg5;
2347
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg5, (const uint8_t *)"C", 1, 2) != 0);
2348
    Dump(sb);
2349
    StreamingBufferSegment seg6;
2350
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg6, (const uint8_t *)"G", 1, 6) != 0);
2351
    Dump(sb);
2352
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2353
    FAIL_IF_NULL(sb->head);
2354
    FAIL_IF_NOT(sb->sbb_size == 6);
2355

2356
    StreamingBufferSegment seg7;
2357
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg7, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
2358
    Dump(sb);
2359
    StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2360
    FAIL_IF_NULL(sbb1);
2361
    FAIL_IF(sbb1->offset != 0);
2362
    FAIL_IF(sbb1->len != 10);
2363
    FAIL_IF(SBB_RB_NEXT(sbb1));
2364
    FAIL_IF_NULL(sb->head);
2365
    FAIL_IF_NOT(sb->sbb_size == 10);
2366

2367
    StreamingBufferSegment seg8;
2368
    FAIL_IF(StreamingBufferInsertAt(sb, &cfg, &seg8, (const uint8_t *)"abcdefghij", 10, 0) != 0);
2369
    Dump(sb);
2370
    sbb1 = RB_MIN(SBB, &sb->sbb_tree);
2371
    FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
2372
    FAIL_IF_NULL(sbb1);
2373
    FAIL_IF(sbb1->offset != 0);
2374
    FAIL_IF(sbb1->len != 10);
2375
    FAIL_IF(SBB_RB_NEXT(sbb1));
2376
    FAIL_IF_NULL(sb->head);
2377
    FAIL_IF_NOT(sb->sbb_size == 10);
2378

2379
    StreamingBufferFree(sb, &cfg);
2380
    PASS;
2381
}
2382

2383
static int StreamingBufferTest11(void)
2384
{
2385
    StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
2386
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2387
    FAIL_IF(sb == NULL);
2388

2389
    StreamingBufferSegment seg1;
2390
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
2391
    StreamingBufferSegment seg2;
2392
    unsigned int data_len = 0xffffffff;
2393
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"unused", data_len) != -1);
2394
    FAIL_IF(StreamingBufferInsertAt(
2395
                    sb, &cfg, &seg2, (const uint8_t *)"abcdefghij", data_len, 100000) != SC_ELIMIT);
2396
    StreamingBufferFree(sb, &cfg);
2397
    PASS;
2398
}
2399

2400
static const char *dummy_conf_string = "%YAML 1.1\n"
2401
                                       "---\n"
2402
                                       "\n"
2403
                                       "app-layer:\n"
2404
                                       "  protocols:\n"
2405
                                       "    http:\n"
2406
                                       "      enabled: yes\n"
2407
                                       "      memcap: 88\n"
2408
                                       "\n";
2409

2410
static int StreamingBufferTest12(void)
2411
{
2412
    SCConfCreateContextBackup();
2413
    SCConfInit();
2414
    HtpConfigCreateBackup();
2415
    SCConfYamlLoadString((const char *)dummy_conf_string, strlen(dummy_conf_string));
2416
    HTPConfigure();
2417

2418
    StreamingBufferConfig cfg = { 8, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, HTPCalloc, HTPRealloc,
2419
        HTPFree };
2420
    StreamingBuffer *sb = StreamingBufferInit(&cfg);
2421
    FAIL_IF(sb == NULL);
2422

2423
    StreamingBufferSegment seg1;
2424
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGHIJKLMNOP", 16) != 0);
2425

2426
    StreamingBufferSegment seg2;
2427
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2,
2428
                    (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",
2429
                    52) != -1);
2430
    FAIL_IF(sc_errno != SC_ELIMIT);
2431

2432
    StreamingBufferFree(sb, &cfg);
2433
    HTPFreeConfig();
2434
    SCConfDeInit();
2435
    HtpConfigRestoreBackup();
2436
    SCConfRestoreContextBackup();
2437

2438
    PASS;
2439
}
2440
#endif
2441

2442
void StreamingBufferRegisterTests(void)
UNCOV
2443
{
×
2444
#ifdef UNITTESTS
2445
    UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02);
2446
    UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03);
2447
    UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04);
2448
    UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06);
2449
    UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07);
2450
    UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
2451
    UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
2452
    UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
2453
    UtRegisterTest("StreamingBufferTest11 Bug 6903", StreamingBufferTest11);
2454
    UtRegisterTest("StreamingBufferTest12 Bug 6782", StreamingBufferTest12);
2455
#endif
UNCOV
2456
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc