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

OISF / suricata / 22550902417

01 Mar 2026 07:32PM UTC coverage: 68.401% (-5.3%) from 73.687%
22550902417

Pull #14922

github

web-flow
github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14922: github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

218243 of 319063 relevant lines covered (68.4%)

3284926.58 hits per line

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

69.11
/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
{
519✔
44
    void *ptrmem = SCRealloc(ptr, size);
519✔
45
    if (unlikely(ptrmem == NULL)) {
519✔
46
        sc_errno = SC_ENOMEM;
×
47
    }
×
48
    return ptrmem;
519✔
49
}
519✔
50

51
static void *CallocFunc(const size_t nm, const size_t sz)
52
{
865✔
53
    void *ptrmem = SCCalloc(nm, sz);
865✔
54
    if (unlikely(ptrmem == NULL)) {
865✔
55
        sc_errno = SC_ENOMEM;
×
56
    }
×
57
    return ptrmem;
865✔
58
}
865✔
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))
17,827✔
64
#define REALLOC(cfg, ptr, orig_s, s)                                                               \
65
    (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : ReallocFunc((ptr), (s))
14,223✔
66
#define FREE(cfg, ptr, s) \
67
    (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr))
17,834✔
68

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

71
RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare);
23,333,730✔
72

23,333,730✔
73
int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b)
23,333,730✔
74
{
23,333,730✔
75
    SCLogDebug("a %" PRIu64 " len %u, b %" PRIu64 " len %u", a->offset, a->len, b->offset, b->len);
4,422✔
76

77
    if (a->offset > b->offset)
4,422✔
78
        SCReturnInt(1);
3,707✔
79
    else if (a->offset < b->offset)
715✔
80
        SCReturnInt(-1);
611✔
81
    else {
104✔
82
        if (a->len == 0 || b->len == 0 || a->len ==  b->len)
104✔
83
            SCReturnInt(0);
28✔
84
        else if (a->len > b->len)
76✔
85
            SCReturnInt(1);
27✔
86
        else
49✔
87
            SCReturnInt(-1);
49✔
88
    }
104✔
89
}
4,422✔
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) {
5,195✔
94
    const uint64_t lre = lookup->offset + lookup->len;
5,195✔
95
    const uint64_t tre = intree->offset + intree->len;
5,195✔
96
    if (lre <= intree->offset)   // entirely before
5,195✔
97
        return -1;
1,265✔
98
    else if (lookup->offset < tre && lre <= tre) // (some) overlap
3,930✔
99
        return 0;
1,520✔
100
    else
2,410✔
101
        return 1;   // entirely after
2,410✔
102
}
5,195✔
103

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

108
    struct StreamingBufferBlock *tmp = RB_ROOT(head);
3,816✔
109
    struct StreamingBufferBlock *res = NULL;
3,816✔
110
    while (tmp) {
7,491✔
111
        SCLogDebug("compare with %" PRIu64 "/%u", tmp->offset, tmp->len);
5,195✔
112
        const int comp = InclusiveCompare(elm, tmp);
5,195✔
113
        SCLogDebug("compare result: %d", comp);
5,195✔
114
        if (comp < 0) {
5,195✔
115
            res = tmp;
1,265✔
116
            tmp = RB_LEFT(tmp, rb);
1,265✔
117
        } else if (comp > 0) {
3,930✔
118
            tmp = RB_RIGHT(tmp, rb);
2,410✔
119
        } else {
2,417✔
120
            return tmp;
1,520✔
121
        }
1,520✔
122
    }
5,195✔
123
    return res;
2,296✔
124
}
3,816✔
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
{
66,461✔
133
    /* create the data range for the region, adding the max gap */
134
    const uint64_t reg_o =
66,461✔
135
            r->stream_offset > cfg->region_gap ? (r->stream_offset - cfg->region_gap) : 0;
66,461✔
136
    const uint64_t reg_re = r->stream_offset + r->buf_size + cfg->region_gap;
66,461✔
137
    SCLogDebug("r %p: %" PRIu64 "/%" PRIu64 " - adjusted %" PRIu64 "/%" PRIu64, r, r->stream_offset,
66,461✔
138
            r->stream_offset + r->buf_size, reg_o, reg_re);
66,461✔
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) {
66,461✔
145
        return false;
×
146
    }
×
147
    return true;
66,461✔
148
}
66,461✔
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
{
×
157
    const uint64_t data_re = offset + len;
×
158
    SCLogDebug("looking for first region matching %" PRIu64 "/%" PRIu64, offset, data_re);
×
159

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

172
static StreamingBufferRegion *FindLargestRegionForOffset(const StreamingBufferConfig *cfg,
173
        StreamingBufferRegion *r, const uint64_t offset, const uint32_t len)
174
{
×
175
    const uint64_t data_re = offset + len;
×
176
    SCLogDebug("starting at %p/%" PRIu64 ", offset %" PRIu64 ", data_re %" PRIu64, r,
×
177
            r->stream_offset, offset, data_re);
×
178
    StreamingBufferRegion *candidate = r;
×
179
    for (; r != NULL; r = r->next) {
×
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))
×
186
            return candidate;
×
187

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

196
static StreamingBufferRegion *FindRightEdge(const StreamingBufferConfig *cfg,
197
        StreamingBufferRegion *r, const uint64_t offset, const uint32_t len)
198
{
×
199
    const uint64_t data_re = offset + len;
×
200
    StreamingBufferRegion *candidate = r;
×
201
    for (; r != NULL; r = r->next) {
×
202
        if (!RegionsIntersect(cfg, r, offset, data_re)) {
×
203
            SCLogDebug(
×
204
                    "r %p is out of scope: %" PRIu64 "/%u/%" PRIu64, r, offset, len, offset + len);
×
205
            return candidate;
×
206
        }
×
207
        candidate = r;
×
208
    }
×
209
    return candidate;
×
210
}
×
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
{
×
216
    if ((cfg->max_regions != 0 && sb->regions >= cfg->max_regions) || (sb->regions == UINT16_MAX)) {
×
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));
×
223
    if (aux_r == NULL) {
×
224
        return NULL;
×
225
    }
×
226

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

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

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

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

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

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

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

276
        SBBFree(sb, cfg);
23,277,667✔
277
        ListRegions(sb);
23,277,667✔
278
        if (sb->region.buf != NULL) {
23,277,667✔
279
            FREE(cfg, sb->region.buf, sb->region.buf_size);
9,716✔
280
            sb->region.buf = NULL;
9,716✔
281
        }
9,716✔
282

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

294
void StreamingBufferFree(StreamingBuffer *sb, const StreamingBufferConfig *cfg)
295
{
12,299✔
296
    if (sb != NULL) {
12,299✔
297
        StreamingBufferClear(sb, cfg);
4,765✔
298
        FREE(cfg, sb, sizeof(StreamingBuffer));
4,765✔
299
    }
4,765✔
300
}
12,299✔
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
{
165✔
326
    DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
165✔
327
    DEBUG_VALIDATE_BUG_ON(region->buf_offset > region->stream_offset + rel_offset);
165✔
328

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

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

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

356
#ifdef DEBUG
357
    SBBPrintList(sb);
358
#endif
359
    return SC_OK;
165✔
360
}
165✔
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
{
100✔
369
    DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
100✔
370

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

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

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

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

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

401
        if (sa_re < tr->offset) {
730✔
402
            SCLogDebug("entirely before: %" PRIu64 " < %" PRIu64, sa_re, tr->offset);
312✔
403
            break; // entirely before
312✔
404
        }
312✔
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) {
418✔
415
            sb->sbb_size -= sa->len;
49✔
416
            sa->len = tr->len;
49✔
417
            sa->offset = tr->offset;
49✔
418
            sa_re = sa->offset + sa->len;
49✔
419
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr,
49✔
420
                    tr->offset, tr->len);
49✔
421
            SBB_RB_REMOVE(tree, tr);
49✔
422
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
49✔
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) {
369✔
432
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr,
152✔
433
                    tr->offset, tr->len);
152✔
434
            SBB_RB_REMOVE(tree, tr);
152✔
435
            sb->sbb_size -= tr->len;
152✔
436
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
152✔
437

438
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
152✔
439
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
152✔
440
                    region->buf_size);
152✔
441
            if (sa->offset == region->stream_offset &&
152✔
442
                    sa_re > (region->stream_offset + region->buf_offset)) {
152✔
443
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
30✔
444
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
30✔
445
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
30✔
446
                SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
30✔
447
                           " bo %u sz %u BUF_OFFSET UPDATED",
30✔
448
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
30✔
449
                        region->buf_size);
30✔
450
            }
30✔
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
280✔
458
                   sa_re >= tr->offset && sa_re < tr_re) // ends inside
217✔
459
        {
217✔
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);
217✔
462
            uint32_t combined_len = (uint32_t)(sa->len + tr->len);
217✔
463
            DEBUG_VALIDATE_BUG_ON(tr_re - sa->offset > UINT32_MAX);
217✔
464
            sa->len = (uint32_t)(tr_re - sa->offset);
217✔
465
            sa_re = sa->offset + sa->len;
217✔
466
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len);
217✔
467
            SBB_RB_REMOVE(tree, tr);
217✔
468
            sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
217✔
469
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
217✔
470
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u RESULT", sa, sa->offset, sa->len);
217✔
471
            SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
217✔
472
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
217✔
473
                    region->buf_size);
217✔
474
            if (sa->offset == region->stream_offset &&
217✔
475
                    sa_re > (region->stream_offset + region->buf_offset)) {
217✔
476
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
152✔
477
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
152✔
478
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
152✔
479
                SCLogDebug("-> (fwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
152✔
480
                           " bo %u sz %u BUF_OFFSET UPDATED",
152✔
481
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
152✔
482
                        region->buf_size);
152✔
483
            }
152✔
484
        }
217✔
485
    }
418✔
486
}
2,894✔
487

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

499
        if (sa->offset > tr_re)
3,445✔
500
            break; // entirely after
979✔
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) {
2,467✔
511
            sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting
146✔
512
            sa->len = tr->len;
146✔
513
            sa->offset = tr->offset;
146✔
514
            sa_re = sa->offset + sa->len;
146✔
515
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (sa overlapped by tr)", tr,
146✔
516
                    tr->offset, tr->len);
146✔
517
            if (sb->head == tr)
146✔
518
                sb->head = sa;
96✔
519
            SBB_RB_REMOVE(tree, tr);
146✔
520
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
146✔
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) {
2,320✔
530
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED ECLIPSED (tr overlapped by sa)", tr,
27✔
531
                    tr->offset, tr->len);
27✔
532
            if (sb->head == tr)
27✔
533
                sb->head = sa;
27✔
534
            SBB_RB_REMOVE(tree, tr);
27✔
535
            sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting
27✔
536
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
27✔
537

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

542
            if (sa->offset == region->stream_offset &&
27✔
543
                    sa_re > (region->stream_offset + region->buf_offset)) {
27✔
544
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
27✔
545
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
27✔
546
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
27✔
547
                SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
27✔
548
                           " bo %u sz %u BUF_OFFSET UPDATED",
27✔
549
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
27✔
550
                        region->buf_size);
27✔
551
            }
27✔
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) {
2,294✔
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);
2,294✔
562
            uint32_t combined_len = (uint32_t)(sa->len + tr->len);
2,294✔
563
            DEBUG_VALIDATE_BUG_ON(sa_re - tr->offset > UINT32_MAX);
2,294✔
564
            sa->len = (uint32_t)(sa_re - tr->offset);
2,294✔
565
            sa->offset = tr->offset;
2,294✔
566
            sa_re = sa->offset + sa->len;
2,294✔
567
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u REMOVED MERGED", tr, tr->offset, tr->len);
2,294✔
568
            if (sb->head == tr)
2,294✔
569
                sb->head = sa;
1,687✔
570
            SBB_RB_REMOVE(tree, tr);
2,294✔
571
            sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
2,294✔
572
            FREE(cfg, tr, sizeof(StreamingBufferBlock));
2,294✔
573

574
            SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64 " bo %u sz %u", sa,
2,294✔
575
                    sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
2,294✔
576
                    region->buf_size);
2,294✔
577
            if (sa->offset == region->stream_offset &&
2,294✔
578
                    sa_re > (region->stream_offset + region->buf_offset)) {
2,294✔
579
                DEBUG_VALIDATE_BUG_ON(sa_re < region->stream_offset);
1,524✔
580
                DEBUG_VALIDATE_BUG_ON(sa_re - region->stream_offset > UINT32_MAX);
1,524✔
581
                region->buf_offset = (uint32_t)(sa_re - region->stream_offset);
1,524✔
582
                SCLogDebug("-> (bwd) tr %p %" PRIu64 "/%u region %p so %" PRIu64
1,524✔
583
                           " bo %u sz %u BUF_OFFSET UPDATED",
1,524✔
584
                        sa, sa->offset, sa->len, region, region->stream_offset, region->buf_offset,
1,524✔
585
                        region->buf_size);
1,524✔
586
            }
1,524✔
587
        }
2,294✔
588
    }
2,466✔
589
}
2,788✔
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
{
2,923✔
597
    struct SBB *tree = &sb->sbb_tree;
2,923✔
598
    SCLogDebug("* inserting: %u/%u", rel_offset, len);
2,923✔
599

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

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

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

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

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

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

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

695
static inline uint32_t ToNextMultipleOf(const uint32_t in, const uint32_t m)
696
{
14,217✔
697
    uint32_t r = in;
14,217✔
698
    if (m > 0) {
14,217✔
699
        const uint32_t x = in % m;
14,216✔
700
        if (x != 0) {
14,216✔
701
            r = (in - x) + m;
13,791✔
702
        }
13,791✔
703
    }
14,216✔
704
    return r;
14,217✔
705
}
14,217✔
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
{
14,223✔
712
    DEBUG_VALIDATE_BUG_ON(region->buf_size > BIT_U32(30));
14,223✔
713
    if (size > BIT_U32(30)) { // 1GiB
14,223✔
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);
14,223✔
725
    SCLogDebug("grow %u", grow);
14,223✔
726
    if (grow <= region->buf_size) {
14,223✔
727
        // do not try to shrink, and do not memset with diff having unsigned underflow
728
        return SC_OK;
×
729
    }
×
730

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

743
    region->buf = ptr;
14,222✔
744
    region->buf_size = grow;
14,222✔
745
    SCLogDebug("grown buffer to %u", grow);
14,222✔
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;
14,222✔
752
}
14,223✔
753

754
static int WARN_UNUSED GrowToSize(
755
        StreamingBuffer *sb, const StreamingBufferConfig *cfg, uint32_t size)
756
{
14,221✔
757
    return GrowRegionToSize(sb, cfg, &sb->region, size);
14,221✔
758
}
14,221✔
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
{
22,174✔
1025
    SCLogDebug("sliding to offset %" PRIu64, offset);
22,174✔
1026
    ListRegions(sb);
22,174✔
1027
#ifdef DEBUG
1028
    SBBPrintList(sb);
1029
#endif
1030

1031
    if (sb->region.next) {
22,174✔
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) {
22,174✔
1049
        DEBUG_VALIDATE_BUG_ON(offset - sb->region.stream_offset > UINT32_MAX);
21,957✔
1050
        const uint32_t slide = (uint32_t)(offset - sb->region.stream_offset);
21,957✔
1051
        if (sb->head != NULL) {
21,957✔
1052
            /* have sbb's, so can't rely on buf_offset for the slide */
1053
            if (slide < sb->region.buf_size) {
897✔
1054
                const uint32_t size = sb->region.buf_size - slide;
895✔
1055
                SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide,
895✔
1056
                        size);
895✔
1057
                memmove(sb->region.buf, sb->region.buf + slide, size);
895✔
1058
                if (sb->region.buf_offset > slide) {
895✔
1059
                    sb->region.buf_offset -= slide;
751✔
1060
                } else {
751✔
1061
                    sb->region.buf_offset = 0;
144✔
1062
                }
144✔
1063
            } else {
895✔
1064
                sb->region.buf_offset = 0;
2✔
1065
            }
2✔
1066
            sb->region.stream_offset = offset;
897✔
1067
        } else {
21,060✔
1068
            /* no sbb's, so we can use buf_offset */
1069
            if (offset <= sb->region.stream_offset + sb->region.buf_offset) {
21,060✔
1070
                const uint32_t size = sb->region.buf_offset - slide;
21,060✔
1071
                SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide,
21,060✔
1072
                        size);
21,060✔
1073
                memmove(sb->region.buf, sb->region.buf + slide, size);
21,060✔
1074
                sb->region.stream_offset = offset;
21,060✔
1075
                sb->region.buf_offset = size;
21,060✔
1076
            } else {
21,060✔
1077
                /* moved past all data */
1078
                sb->region.stream_offset = offset;
×
1079
                sb->region.buf_offset = 0;
×
1080
            }
×
1081
        }
21,060✔
1082
        SBBPrune(sb, cfg);
21,957✔
1083
    }
21,957✔
1084
#ifdef DEBUG
1085
    SBBPrintList(sb);
1086
#endif
1087
    DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset);
22,174✔
1088
}
22,174✔
1089

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

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

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

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

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

1134
    if (!RB_EMPTY(&sb->sbb_tree)) {
10,227✔
1135
        return SBBUpdate(sb, cfg, &sb->region, rel_offset, data_len);
1✔
1136
    } else {
10,226✔
1137
        return 0;
10,226✔
1138
    }
10,226✔
1139
}
10,227✔
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
{
71,671✔
1147
    DEBUG_VALIDATE_BUG_ON(data_len > BIT_U32(27)); // 128MiB is excessive already
71,671✔
1148

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

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

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

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

1180
static int DataFitsAtOffset(
1181
        const StreamingBufferRegion *region, const uint32_t len, const uint32_t offset)
1182
{
66,463✔
1183
    const uint64_t offset64 = offset;
66,463✔
1184
    const uint64_t len64 = len;
66,463✔
1185
    if (offset64 + len64 > UINT32_MAX)
66,463✔
1186
        return -1;
1✔
1187
    return (offset + len <= region->buf_size);
66,462✔
1188
}
66,463✔
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
{
23,432,752✔
1221
    if (sb->region.buf == NULL && sb->region.buf_offset == 0 && sb->region.next == NULL)
23,432,752✔
1222
        return;
23,272,731✔
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
}
23,432,752✔
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
{
×
1274
    int retval;
×
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);
×
1284
    DEBUG_VALIDATE_BUG_ON(dst_offset < sb->region.stream_offset);
×
1285
    const uint32_t dst_size = dst_buf_size;
×
1286
    SCLogDebug("dst_size %u", dst_size);
×
1287

1288
    // 2. resize dst
1289
    const uint32_t old_size = dst->buf_size;
×
1290
    DEBUG_VALIDATE_BUG_ON(dst->stream_offset - dst_offset > UINT32_MAX);
×
1291
    const uint32_t dst_copy_offset = (uint32_t)(dst->stream_offset - dst_offset);
×
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) {
×
1298
        sc_errno = retval;
×
1299
        return NULL;
×
1300
    }
×
1301
    SCLogDebug("resized to %u -> %u", dst_size, dst->buf_size);
×
1302
    /* validate that the size is exactly what we asked for */
1303
    DEBUG_VALIDATE_BUG_ON(dst_size != dst->buf_size);
×
1304
    if (dst_copy_offset != 0)
×
1305
        memmove(dst->buf + dst_copy_offset, dst->buf, old_size);
×
1306
    if (dst_offset != dst->stream_offset) {
×
1307
        dst->stream_offset = dst_offset;
×
1308
        // buf_offset no longer valid, reset.
1309
        dst->buf_offset = 0;
×
1310
    }
×
1311

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

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

1321
        start_is_main = true;
×
1322
        SCLogDebug("src_start is main region");
×
1323
        if (src_start != dst)
×
1324
            memcpy(dst->buf, src_start->buf, src_start->buf_offset);
×
1325
        if (src_start == src_end) {
×
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;
×
1331
        src_start = src_start->next; // skip in the loop below
×
1332
    }
×
1333

1334
    // 3. copy all regions from src_start to dst_start into the new region
1335
    for (StreamingBufferRegion *r = src_start; r != NULL;) {
×
1336
        SCLogDebug("r %p %" PRIu64 ", offset %u, len %u, %s, last %s", r, r->stream_offset,
×
1337
                r->buf_offset, r->buf_size, r == &sb->region ? "main" : "aux",
×
1338
                BOOL2STR(r == src_end));
×
1339
        // skip dst
1340
        if (r == dst) {
×
1341
            SCLogDebug("skipping r %p as it is 'dst'", r);
×
1342
            if (r == src_end)
×
1343
                break;
×
1344
            prev = r;
×
1345
            r = r->next;
×
1346
            continue;
×
1347
        }
×
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) {
×
1378
        DEBUG_VALIDATE_BUG_ON(sb->region.next != dst);
×
1379
        SCLogDebug("start_is_main && dst != main region");
×
1380
        FREE(cfg, sb->region.buf, sb->region.buf_size);
×
1381
        sb->region.buf = dst->buf;
×
1382
        sb->region.buf_size = dst->buf_size;
×
1383
        sb->region.buf_offset = new_offset;
×
1384
        SCLogDebug("sb->region.buf_offset set to %u", sb->region.buf_offset);
×
1385
        sb->region.next = dst->next;
×
1386
        FREE(cfg, dst, sizeof(*dst));
×
1387
        dst = &sb->region;
×
1388
        sb->regions--;
×
1389
        DEBUG_VALIDATE_BUG_ON(sb->regions == 0);
×
1390
    } else {
×
1391
        SCLogDebug("dst: %p next %p", dst, dst->next);
×
1392
    }
×
1393

1394
    SCLogDebug("returning dst %p stream_offset %" PRIu64 " buf_offset %u buf_size %u", dst,
×
1395
            dst->stream_offset, dst->buf_offset, dst->buf_size);
×
1396
    return dst;
×
1397
}
×
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
{
×
1403
    SCLogDebug("offset %" PRIu64 ", len %u", offset, len);
×
1404
    StreamingBufferRegion *start_prev = NULL;
×
1405
    StreamingBufferRegion *start =
×
1406
            FindFirstRegionForOffset(cfg, &sb->region, offset, len, &start_prev);
×
1407
    if (start) {
×
1408
        const uint64_t insert_re = offset + len;
×
1409
        const uint64_t insert_start_offset = MIN(start->stream_offset, offset);
×
1410
        uint64_t insert_adjusted_re = insert_re;
×
1411

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

1428
        DEBUG_VALIDATE_BUG_ON(insert_adjusted_re - insert_start_offset > UINT32_MAX);
×
1429
        uint32_t new_buf_size = ToNextMultipleOf(
×
1430
                (uint32_t)(insert_adjusted_re - insert_start_offset), cfg->buf_size);
×
1431
        SCLogDebug("new_buf_size %u", new_buf_size);
×
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) {
×
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);
×
1446
        /* sets sc_errno */
1447
        StreamingBufferRegion *ret = BufferInsertAtRegionConsolidate(
×
1448
                sb, cfg, big, start, end, offset, len, start_prev, new_buf_size);
×
1449
        return ret;
×
1450
    } else {
×
1451
        /* if there was no region we can use we add a new region and insert it */
1452
        StreamingBufferRegion *append = &sb->region;
×
1453
        for (StreamingBufferRegion *r = append; r != NULL; r = r->next) {
×
1454
            if (r->stream_offset > offset) {
×
1455
                break;
×
1456
            } else {
×
1457
                append = r;
×
1458
            }
×
1459
        }
×
1460

1461
        SCLogDebug("no matching region found, append to %p (%s)", append,
×
1462
                append == &sb->region ? "main" : "aux");
×
1463
        /* sets sc_errno */
1464
        StreamingBufferRegion *add = InitBufferRegion(sb, cfg, len);
×
1465
        if (add == NULL)
×
1466
            return NULL;
×
1467
        add->stream_offset = offset;
×
1468
        add->next = append->next;
×
1469
        append->next = add;
×
1470
        SCLogDebug("new region %p offset %" PRIu64, add, add->stream_offset);
×
1471
        return add;
×
1472
    }
×
1473
}
×
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
{
66,473✔
1487
    SCLogDebug("data_offset %" PRIu64 ", data_len %u, re %" PRIu64, data_offset, data_len,
66,473✔
1488
            data_offset + data_len);
66,473✔
1489
    ListRegions(sb);
66,473✔
1490

1491
    if (RegionsIntersect(cfg, &sb->region, data_offset, data_offset + data_len)) {
66,473✔
1492
        SCLogDebug("data_offset %" PRIu64 ", data_len %u intersects with main region (next %p)",
66,448✔
1493
                data_offset, data_len, sb->region.next);
66,448✔
1494
        if (sb->region.next == NULL ||
66,448✔
1495
                !RegionsIntersect(cfg, sb->region.next, data_offset, data_offset + data_len)) {
66,448✔
1496
            SCLogDebug(
66,439✔
1497
                    "data_offset %" PRIu64
66,439✔
1498
                    ", data_len %u intersects with main region, no next or way before next region",
66,439✔
1499
                    data_offset, data_len);
66,439✔
1500
            if (sb->region.buf == NULL) {
66,439✔
1501
                int r;
4,944✔
1502
                if ((r = InitBuffer(sb, cfg)) != SC_OK) { // TODO init with size
4,944✔
1503
                    sc_errno = r;
×
1504
                    return NULL;
×
1505
                }
×
1506
            }
4,944✔
1507
            return &sb->region;
66,439✔
1508
        }
66,439✔
1509
    } else if (sb->region.next == NULL) {
66,448✔
1510
        /* InitBufferRegion sets sc_errno */
1511
        StreamingBufferRegion *aux_r = sb->region.next = InitBufferRegion(sb, cfg, data_len);
×
1512
        if (aux_r == NULL)
×
1513
            return NULL;
×
1514
        aux_r->stream_offset = data_offset;
×
1515
        DEBUG_VALIDATE_BUG_ON(data_len > aux_r->buf_size);
×
1516
        SCLogDebug("created new region %p with offset %" PRIu64 ", size %u", aux_r,
×
1517
                aux_r->stream_offset, aux_r->buf_size);
×
1518
        return aux_r;
×
1519
    }
×
1520
    /* BufferInsertAtRegionDo sets sc_errno */
1521
    StreamingBufferRegion *blob = BufferInsertAtRegionDo(sb, cfg, data_offset, data_len);
34✔
1522
    SCLogDebug("blob %p (%s)", blob, blob == &sb->region ? "main" : "aux");
34✔
1523
    return blob;
34✔
1524
}
66,473✔
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
{
66,482✔
1535
    DEBUG_VALIDATE_BUG_ON(seg == NULL);
66,482✔
1536
    DEBUG_VALIDATE_BUG_ON(data_len > BIT_U32(27)); // 128MiB is excessive already
66,482✔
1537
    DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset);
66,482✔
1538
    if (offset < sb->region.stream_offset) {
66,482✔
1539
        return SC_EINVAL;
×
1540
    }
×
1541

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

1547
    const bool region_is_main = region == &sb->region;
66,482✔
1548

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

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

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

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

1575
    if (RB_EMPTY(&sb->sbb_tree)) {
66,481✔
1576
        SCLogDebug("empty sbb list");
63,568✔
1577

1578
        if (region_is_main) {
63,568✔
1579
            if (sb->region.stream_offset == offset) {
63,568✔
1580
                SCLogDebug("empty sbb list: block exactly what was expected, fall through");
7,393✔
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);
7,393✔
1585
            } else if ((rel_offset + data_len) <= sb->region.buf_offset) {
56,180✔
1586
                SCLogDebug("empty sbb list: block is within existing main data region");
126✔
1587
            } else {
56,049✔
1588
                if (sb->region.buf_offset && rel_offset == sb->region.buf_offset) {
56,049✔
1589
                    SCLogDebug("exactly at expected offset");
55,784✔
1590
                    // nothing to do
1591
                    sb->region.buf_offset = rel_offset + data_len;
55,784✔
1592

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

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

1606
                } else if (sb->region.buf_offset) {
257✔
1607
                    SCLogDebug("beyond expected offset: SBBInit");
165✔
1608
                    /* existing data, but there is a gap between us */
1609
                    if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
165✔
1610
                        return r;
×
1611
                } else {
176✔
1612
                    /* gap before data in empty list */
1613
                    SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
92✔
1614
                    if ((r = SBBInitLeadingGap(sb, cfg, offset, data_len)) != SC_OK)
92✔
1615
                        return r;
×
1616
                }
92✔
1617
            }
56,049✔
1618
        } else {
63,568✔
1619
            if (sb->region.buf_offset) {
×
1620
                /* existing data, but there is a gap between us */
1621
                SCLogDebug("empty sbb list, no data in main: use SBBInit");
×
1622
                if ((r = SBBInit(sb, cfg, region, rel_offset, data_len)) != SC_OK)
×
1623
                    return r;
×
1624
            } else {
×
1625
                /* gap before data in empty list */
1626
                SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
×
1627
                if ((r = SBBInitLeadingGap(sb, cfg, offset, data_len)) != SC_OK)
×
1628
                    return r;
×
1629
            }
×
1630
            if (rel_offset == region->buf_offset) {
×
1631
                SCLogDebug("pre region->buf_offset %u", region->buf_offset);
×
1632
                region->buf_offset = rel_offset + data_len;
×
1633
                SCLogDebug("post region->buf_offset %u", region->buf_offset);
×
1634
            }
×
1635
        }
×
1636
    } else {
64,030✔
1637
        SCLogDebug("updating sbb tree");
2,913✔
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)
2,913✔
1640
            return r;
×
1641
    }
2,913✔
1642
    DEBUG_VALIDATE_BUG_ON(!region_is_main && sb->head == NULL);
66,481✔
1643

1644
    ListRegions(sb);
66,481✔
1645
    if (RB_EMPTY(&sb->sbb_tree)) {
66,481✔
1646
        DEBUG_VALIDATE_BUG_ON(offset + data_len > sb->region.stream_offset + sb->region.buf_offset);
63,291✔
1647
    }
63,291✔
1648

1649
    return SC_OK;
66,481✔
1650
}
66,481✔
1651

1652
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb,
1653
                                         const StreamingBufferSegment *seg)
1654
{
403,667✔
1655
    if (seg->stream_offset < sb->region.stream_offset) {
403,667✔
1656
        if (seg->stream_offset + seg->segment_len <= sb->region.stream_offset) {
66,210✔
1657
            return 1;
59,775✔
1658
        }
59,775✔
1659
    }
66,210✔
1660
    return 0;
343,892✔
1661
}
403,667✔
1662

1663
static inline const StreamingBufferRegion *GetRegionForOffset(
1664
        const StreamingBuffer *sb, const uint64_t offset)
1665
{
690,695✔
1666
    if (sb == NULL)
690,695✔
1667
        return NULL;
×
1668
    if (sb->region.next == NULL) {
690,724✔
1669
        return &sb->region;
690,724✔
1670
    }
690,724✔
1671
    if (offset >= sb->region.stream_offset &&
2,147,483,647✔
1672
            offset < (sb->region.stream_offset + sb->region.buf_size)) {
2,147,483,647✔
1673
        return &sb->region;
×
1674
    }
×
1675
    for (const StreamingBufferRegion *r = sb->region.next; r != NULL; r = r->next) {
2,147,483,647✔
1676
        if (offset >= r->stream_offset && offset < (r->stream_offset + r->buf_size)) {
×
1677
            return r;
×
1678
        }
×
1679
    }
×
1680
    return NULL;
2,147,483,647✔
1681
}
2,147,483,647✔
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
{
1,343✔
1688
    const StreamingBufferRegion *region = GetRegionForOffset(sb, sbb->offset);
1,343✔
1689
    SCLogDebug("first find our region (offset %" PRIu64 ") -> %p", sbb->offset, region);
1,343✔
1690
    if (region) {
1,343✔
1691
        SCLogDebug("region %p found %" PRIu64 "/%u/%u", region, region->stream_offset,
1,343✔
1692
                region->buf_size, region->buf_offset);
1,343✔
1693
        DEBUG_VALIDATE_BUG_ON(
1,343✔
1694
                region->stream_offset == sbb->offset && region->buf_offset > sbb->len);
1,343✔
1695
        // buf_offset should match first sbb len if it has the same offset
1696

1697
        if (sbb->offset >= region->stream_offset) {
1,343✔
1698
            SCLogDebug("1");
1,343✔
1699
            uint64_t offset = sbb->offset - region->stream_offset;
1,343✔
1700
            *data = region->buf + offset;
1,343✔
1701
            DEBUG_VALIDATE_BUG_ON(offset + sbb->len > region->buf_size);
1,343✔
1702
            *data_len = sbb->len;
1,343✔
1703
            return;
1,343✔
1704
        } else {
1,343✔
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
    }
1,343✔
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
{
997✔
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)));
997✔
1727
    if (!(offset >= sbb->offset && offset < (sbb->offset + sbb->len))) {
997✔
1728
        *data = NULL;
×
1729
        *data_len = 0;
×
1730
        return;
×
1731
    }
×
1732

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

1738
        if (offset >= region->stream_offset) {
997✔
1739
            uint32_t data_offset = (uint32_t)(offset - region->stream_offset);
997✔
1740
            *data = region->buf + data_offset;
997✔
1741
            if (data_offset + sbblen > region->buf_size) {
997✔
1742
                *data_len = region->buf_size - data_offset;
×
1743
            } else {
997✔
1744
                *data_len = sbblen;
997✔
1745
            }
997✔
1746
            DEBUG_VALIDATE_BUG_ON(*data_len > sbblen);
997✔
1747
            return;
997✔
1748
        } else {
997✔
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
    }
997✔
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
{
522✔
1767
    const StreamingBufferRegion *region = GetRegionForOffset(sb, seg->stream_offset);
522✔
1768
    if (region) {
522✔
1769
        if (seg->stream_offset >= region->stream_offset) {
522✔
1770
            uint32_t offset = (uint32_t)(seg->stream_offset - region->stream_offset);
516✔
1771
            *data = region->buf + offset;
516✔
1772
            if (offset + seg->segment_len > region->buf_size) {
516✔
1773
                *data_len = region->buf_size - offset;
×
1774
            } else {
516✔
1775
                *data_len = seg->segment_len;
516✔
1776
            }
516✔
1777
            SCLogDebug("*data_len %u", *data_len);
516✔
1778
            return;
516✔
1779
        } else {
516✔
1780
            uint32_t offset = (uint32_t)(region->stream_offset - seg->stream_offset);
6✔
1781
            if (offset < seg->segment_len) {
6✔
1782
                *data = region->buf;
4✔
1783
                *data_len = seg->segment_len - offset;
4✔
1784
                SCLogDebug("*data_len %u", *data_len);
4✔
1785
                return;
4✔
1786
            }
4✔
1787
        }
6✔
1788
    }
522✔
1789
    *data = NULL;
2✔
1790
    *data_len = 0;
2✔
1791
}
2✔
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)
1800
{
10✔
1801
    const uint8_t *segdata = NULL;
10✔
1802
    uint32_t segdata_len = 0;
10✔
1803
    StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len);
10✔
1804
    if (segdata && segdata_len &&
10✔
1805
        segdata_len == rawdata_len &&
10✔
1806
        memcmp(segdata, rawdata, segdata_len) == 0)
10✔
1807
    {
10✔
1808
        return 1;
10✔
1809
    }
10✔
1810
    return 0;
×
1811
}
10✔
1812

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

1830
int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb,
1831
        const uint8_t **data, uint32_t *data_len,
1832
        uint64_t offset)
1833
{
687,898✔
1834
    const StreamingBufferRegion *region = GetRegionForOffset(sb, offset);
687,898✔
1835
    if (region != NULL && region->buf != NULL && offset >= region->stream_offset &&
687,898✔
1836
            offset < (region->stream_offset + region->buf_offset)) {
687,898✔
1837
        DEBUG_VALIDATE_BUG_ON(offset - region->stream_offset > UINT32_MAX);
72,320✔
1838
        uint32_t skip = (uint32_t)(offset - region->stream_offset);
72,320✔
1839
        *data = region->buf + skip;
72,320✔
1840
        *data_len = region->buf_offset - skip;
72,320✔
1841
        return 1;
72,320✔
1842
    } else {
615,742✔
1843
        *data = NULL;
615,578✔
1844
        *data_len = 0;
615,578✔
1845
        return 0;
615,578✔
1846
    }
615,578✔
1847
}
687,898✔
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)
1855
{
28✔
1856
    const uint8_t *sbdata = NULL;
28✔
1857
    uint32_t sbdata_len = 0;
28✔
1858
    uint64_t offset = 0;
28✔
1859
    StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset);
28✔
1860
    if (offset == 0 &&
28✔
1861
        sbdata && sbdata_len &&
28✔
1862
        sbdata_len == rawdata_len &&
28✔
1863
        memcmp(sbdata, rawdata, sbdata_len) == 0)
28✔
1864
    {
28✔
1865
        return 1;
28✔
1866
    }
28✔
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;
×
1873
}
28✔
1874

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2389
    StreamingBufferSegment seg1;
1✔
2390
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1✔
2391
    StreamingBufferSegment seg2;
1✔
2392
    unsigned int data_len = 0xffffffff;
1✔
2393
    FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"unused", data_len) != -1);
1✔
2394
    FAIL_IF(StreamingBufferInsertAt(
1✔
2395
                    sb, &cfg, &seg2, (const uint8_t *)"abcdefghij", data_len, 100000) != SC_ELIMIT);
1✔
2396
    StreamingBufferFree(sb, &cfg);
1✔
2397
    PASS;
1✔
2398
}
1✔
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
{
1✔
2412
    SCConfCreateContextBackup();
1✔
2413
    SCConfInit();
1✔
2414
    HtpConfigCreateBackup();
1✔
2415
    SCConfYamlLoadString((const char *)dummy_conf_string, strlen(dummy_conf_string));
1✔
2416
    HTPConfigure();
1✔
2417

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

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

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

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

2438
    PASS;
1✔
2439
}
1✔
2440
#endif
2441

2442
void StreamingBufferRegisterTests(void)
2443
{
1✔
2444
#ifdef UNITTESTS
1✔
2445
    UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02);
1✔
2446
    UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03);
1✔
2447
    UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04);
1✔
2448
    UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06);
1✔
2449
    UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07);
1✔
2450
    UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
1✔
2451
    UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
1✔
2452
    UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
1✔
2453
    UtRegisterTest("StreamingBufferTest11 Bug 6903", StreamingBufferTest11);
1✔
2454
    UtRegisterTest("StreamingBufferTest12 Bug 6782", StreamingBufferTest12);
1✔
2455
#endif
1✔
2456
}
1✔
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