1 /* Copyright (C) 2015-2016 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
24 /**
25 * \file
26 *
27 * \author Victor Julien <victor@inliniac.net>
28 *
29 * \brief Streaming Buffer API
30 */
31
32 /* memory handling wrappers. If config doesn't define it's own set of
33 * functions, use the defaults */
34 #define MALLOC(cfg, s) \
35 (cfg)->Malloc ? (cfg)->Malloc((s)) : SCMalloc((s))
36 #define CALLOC(cfg, n, s) \
37 (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : SCCalloc((n), (s))
38 #define REALLOC(cfg, ptr, orig_s, s) \
39 (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : SCRealloc((ptr), (s))
40 #define FREE(cfg, ptr, s) \
41 (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr))
42
43 static void SBBFree(StreamingBuffer *sb);
44
45 RB_GENERATE(SBB, StreamingBufferBlock, rb, SBBCompare);
46
SBBCompare(struct StreamingBufferBlock * a,struct StreamingBufferBlock * b)47 int SBBCompare(struct StreamingBufferBlock *a, struct StreamingBufferBlock *b)
48 {
49 SCLogDebug("a %"PRIu64" len %u, b %"PRIu64" len %u",
50 a->offset, a->len, b->offset, b->len);
51
52 if (a->offset > b->offset)
53 SCReturnInt(1);
54 else if (a->offset < b->offset)
55 SCReturnInt(-1);
56 else {
57 if (a->len == 0 || b->len == 0 || a->len == b->len)
58 SCReturnInt(0);
59 else if (a->len > b->len)
60 SCReturnInt(1);
61 else
62 SCReturnInt(-1);
63 }
64 }
65
66 /* inclusive compare function that also considers the right edge,
67 * not just the offset. */
InclusiveCompare(StreamingBufferBlock * lookup,StreamingBufferBlock * intree)68 static inline int InclusiveCompare(StreamingBufferBlock *lookup, StreamingBufferBlock *intree) {
69 const uint64_t lre = lookup->offset + lookup->len;
70 const uint64_t tre = intree->offset + intree->len;
71 if (lre <= intree->offset) // entirely before
72 return -1;
73 else if (lre >= intree->offset && lookup->offset < tre && lre <= tre) // (some) overlap
74 return 0;
75 else
76 return 1; // entirely after
77 }
78
SBB_RB_FIND_INCLUSIVE(struct SBB * head,StreamingBufferBlock * elm)79 StreamingBufferBlock *SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm)
80 {
81 SCLogDebug("looking up %"PRIu64, elm->offset);
82
83 struct StreamingBufferBlock *tmp = RB_ROOT(head);
84 struct StreamingBufferBlock *res = NULL;
85 while (tmp) {
86 SCLogDebug("compare with %"PRIu64"/%u", tmp->offset, tmp->len);
87 const int comp = InclusiveCompare(elm, tmp);
88 SCLogDebug("compare result: %d", comp);
89 if (comp < 0) {
90 res = tmp;
91 tmp = RB_LEFT(tmp, rb);
92 } else if (comp > 0) {
93 tmp = RB_RIGHT(tmp, rb);
94 } else {
95 return tmp;
96 }
97 }
98 return res;
99 }
100
101
InitBuffer(StreamingBuffer * sb)102 static inline int InitBuffer(StreamingBuffer *sb)
103 {
104 sb->buf = CALLOC(sb->cfg, 1, sb->cfg->buf_size);
105 if (sb->buf == NULL) {
106 return -1;
107 }
108 sb->buf_size = sb->cfg->buf_size;
109 return 0;
110 }
111
StreamingBufferInit(const StreamingBufferConfig * cfg)112 StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg)
113 {
114 StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer));
115 if (sb != NULL) {
116 sb->buf_size = cfg->buf_size;
117 sb->cfg = cfg;
118
119 if (cfg->buf_size > 0) {
120 if (InitBuffer(sb) == 0) {
121 return sb;
122 }
123 FREE(cfg, sb, sizeof(StreamingBuffer));
124 /* implied buf_size == 0 */
125 } else {
126 return sb;
127 }
128 }
129 return NULL;
130 }
131
StreamingBufferClear(StreamingBuffer * sb)132 void StreamingBufferClear(StreamingBuffer *sb)
133 {
134 if (sb != NULL) {
135 SCLogDebug("sb->buf_size %u max %u", sb->buf_size, sb->buf_size_max);
136
137 SBBFree(sb);
138 if (sb->buf != NULL) {
139 FREE(sb->cfg, sb->buf, sb->buf_size);
140 sb->buf = NULL;
141 }
142 }
143 }
144
StreamingBufferFree(StreamingBuffer * sb)145 void StreamingBufferFree(StreamingBuffer *sb)
146 {
147 if (sb != NULL) {
148 StreamingBufferClear(sb);
149 FREE(sb->cfg, sb, sizeof(StreamingBuffer));
150 }
151 }
152
153 #ifdef DEBUG
SBBPrintList(StreamingBuffer * sb)154 static void SBBPrintList(StreamingBuffer *sb)
155 {
156 StreamingBufferBlock *sbb = NULL;
157 RB_FOREACH(sbb, SBB, &sb->sbb_tree) {
158 SCLogDebug("sbb: offset %"PRIu64", len %u", sbb->offset, sbb->len);
159 StreamingBufferBlock *next = SBB_RB_NEXT(sbb);
160 if (next) {
161 if ((sbb->offset + sbb->len) != next->offset) {
162 SCLogDebug("gap: offset %"PRIu64", len %"PRIu64, (sbb->offset + sbb->len),
163 next->offset - (sbb->offset + sbb->len));
164 }
165 }
166 }
167 }
168 #endif
169
170 /* setup with gap between 2 blocks
171 *
172 * [block][gap][block]
173 **/
SBBInit(StreamingBuffer * sb,uint32_t rel_offset,uint32_t data_len)174 static void SBBInit(StreamingBuffer *sb,
175 uint32_t rel_offset, uint32_t data_len)
176 {
177 DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
178 DEBUG_VALIDATE_BUG_ON(sb->buf_offset > sb->stream_offset + rel_offset);
179
180 /* need to set up 2: existing data block and new data block */
181 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
182 if (sbb == NULL) {
183 return;
184 }
185 sbb->offset = sb->stream_offset;
186 sbb->len = sb->buf_offset;
187
188 StreamingBufferBlock *sbb2 = CALLOC(sb->cfg, 1, sizeof(*sbb2));
189 if (sbb2 == NULL) {
190 FREE(sb->cfg, sbb, sizeof(*sbb));
191 return;
192 }
193 sbb2->offset = sb->stream_offset + rel_offset;
194 sbb2->len = data_len;
195
196 sb->head = sbb;
197 sb->sbb_size = sbb->len + sbb2->len;
198 SBB_RB_INSERT(&sb->sbb_tree, sbb);
199 SBB_RB_INSERT(&sb->sbb_tree, sbb2);
200
201 SCLogDebug("sbb1 %"PRIu64", len %u, sbb2 %"PRIu64", len %u",
202 sbb->offset, sbb->len, sbb2->offset, sbb2->len);
203 #ifdef DEBUG
204 SBBPrintList(sb);
205 #endif
206 BUG_ON(sbb2->offset < sbb->len);
207 }
208
209 /* setup with leading gap
210 *
211 * [gap][block]
212 **/
SBBInitLeadingGap(StreamingBuffer * sb,uint64_t offset,uint32_t data_len)213 static void SBBInitLeadingGap(StreamingBuffer *sb,
214 uint64_t offset, uint32_t data_len)
215 {
216 DEBUG_VALIDATE_BUG_ON(!RB_EMPTY(&sb->sbb_tree));
217
218 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
219 if (sbb == NULL)
220 return;
221 sbb->offset = offset;
222 sbb->len = data_len;
223
224 sb->head = sbb;
225 sb->sbb_size = sbb->len;
226 SBB_RB_INSERT(&sb->sbb_tree, sbb);
227
228 SCLogDebug("sbb %"PRIu64", len %u",
229 sbb->offset, sbb->len);
230 #ifdef DEBUG
231 SBBPrintList(sb);
232 #endif
233 }
234
ConsolidateFwd(StreamingBuffer * sb,struct SBB * tree,StreamingBufferBlock * sa)235 static inline void ConsolidateFwd(StreamingBuffer *sb,
236 struct SBB *tree, StreamingBufferBlock *sa)
237 {
238 uint64_t sa_re = sa->offset + sa->len;
239 StreamingBufferBlock *tr, *s = sa;
240 RB_FOREACH_FROM(tr, SBB, s) {
241 if (sa == tr)
242 continue;
243
244 const uint64_t tr_re = tr->offset + tr->len;
245 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u re %"PRIu64,
246 tr, tr->offset, tr->len, tr_re);
247
248 if (sa_re < tr->offset)
249 break; // entirely before
250
251 /*
252 sa: [ ]
253 tr: [ ]
254 sa: [ ]
255 tr: [ ]
256 sa: [ ]
257 tr: [ ]
258 */
259 if (sa->offset >= tr->offset && sa_re <= tr_re) {
260 sb->sbb_size -= sa->len;
261 sa->len = tr->len;
262 sa->offset = tr->offset;
263 sa_re = sa->offset + sa->len;
264 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED2", tr, tr->offset, tr->len);
265 SBB_RB_REMOVE(tree, tr);
266 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
267 /*
268 sa: [ ]
269 tr: [ ]
270 sa: [ ]
271 tr: [ ]
272 sa: [ ]
273 tr: [ ]
274 */
275 } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
276 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED", tr, tr->offset, tr->len);
277 SBB_RB_REMOVE(tree, tr);
278 sb->sbb_size -= tr->len;
279 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
280 /*
281 sa: [ ]
282 tr: [ ]
283 sa: [ ]
284 tr: [ ]
285 */
286 } else if (sa->offset < tr->offset && // starts before
287 sa_re >= tr->offset && sa_re < tr_re) // ends inside
288 {
289 // merge. sb->sbb_size includes both so we need to adjust that too.
290 uint32_t combined_len = sa->len + tr->len;
291 sa->len = tr_re - sa->offset;
292 sa_re = sa->offset + sa->len;
293 SCLogDebug("-> (fwd) tr %p %"PRIu64"/%u REMOVED MERGED", tr, tr->offset, tr->len);
294 SBB_RB_REMOVE(tree, tr);
295 sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
296 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
297 }
298 }
299 }
300
ConsolidateBackward(StreamingBuffer * sb,struct SBB * tree,StreamingBufferBlock * sa)301 static inline void ConsolidateBackward(StreamingBuffer *sb,
302 struct SBB *tree, StreamingBufferBlock *sa)
303 {
304 uint64_t sa_re = sa->offset + sa->len;
305 StreamingBufferBlock *tr, *s = sa;
306 RB_FOREACH_REVERSE_FROM(tr, SBB, s) {
307 if (sa == tr)
308 continue;
309 const uint64_t tr_re = tr->offset + tr->len;
310 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u", tr, tr->offset, tr->len);
311
312 if (sa->offset > tr_re)
313 break; // entirely after
314
315 if (sa->offset >= tr->offset && sa_re <= tr_re) {
316 sb->sbb_size -= sa->len; // sa entirely eclipsed so remove double accounting
317 sa->len = tr->len;
318 sa->offset = tr->offset;
319 sa_re = sa->offset + sa->len;
320 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED2", tr, tr->offset, tr->len);
321 if (sb->head == tr)
322 sb->head = sa;
323 SBB_RB_REMOVE(tree, tr);
324 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
325 /*
326 sa: [ ]
327 tr: [ ]
328 sa: [ ]
329 tr: [ ]
330 sa: [ ]
331 tr: [ ]
332 */
333 } else if (sa->offset <= tr->offset && sa_re >= tr_re) {
334 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED ECLIPSED", tr, tr->offset, tr->len);
335 if (sb->head == tr)
336 sb->head = sa;
337 SBB_RB_REMOVE(tree, tr);
338 sb->sbb_size -= tr->len; // tr entirely eclipsed so remove double accounting
339 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
340 /*
341 sa: [ ]
342 tr: [ ]
343 sa: [ ]
344 tr: [ ]
345 */
346 } else if (sa->offset > tr->offset && sa_re > tr_re && sa->offset <= tr_re) {
347 // merge. sb->sbb_size includes both so we need to adjust that too.
348 uint32_t combined_len = sa->len + tr->len;
349 sa->len = sa_re - tr->offset;
350 sa->offset = tr->offset;
351 sa_re = sa->offset + sa->len;
352 SCLogDebug("-> (bwd) tr %p %"PRIu64"/%u REMOVED MERGED", tr, tr->offset, tr->len);
353 if (sb->head == tr)
354 sb->head = sa;
355 SBB_RB_REMOVE(tree, tr);
356 sb->sbb_size -= (combined_len - sa->len); // remove what we added twice
357 FREE(sb->cfg, tr, sizeof(StreamingBufferBlock));
358 }
359 }
360 }
361
Insert(StreamingBuffer * sb,struct SBB * tree,uint32_t rel_offset,uint32_t len)362 static int Insert(StreamingBuffer *sb, struct SBB *tree,
363 uint32_t rel_offset, uint32_t len)
364 {
365 SCLogDebug("* inserting: %u/%u\n", rel_offset, len);
366
367 StreamingBufferBlock *sbb = CALLOC(sb->cfg, 1, sizeof(*sbb));
368 if (sbb == NULL)
369 return -1;
370 sbb->offset = sb->stream_offset + rel_offset;
371 sbb->len = len;
372 StreamingBufferBlock *res = SBB_RB_INSERT(tree, sbb);
373 if (res) {
374 // exact overlap
375 SCLogDebug("* insert failed: exact match in tree with %p %"PRIu64"/%u", res, res->offset, res->len);
376 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
377 return 0;
378 }
379 sb->sbb_size += len; // may adjust based on consolidation below
380 if (SBB_RB_PREV(sbb) == NULL) {
381 sb->head = sbb;
382 } else {
383 ConsolidateBackward(sb, tree, sbb);
384 }
385 ConsolidateFwd(sb, tree, sbb);
386 #ifdef DEBUG
387 SBBPrintList(sb);
388 #endif
389 return 0;
390 }
391
SBBUpdate(StreamingBuffer * sb,uint32_t rel_offset,uint32_t data_len)392 static void SBBUpdate(StreamingBuffer *sb,
393 uint32_t rel_offset, uint32_t data_len)
394 {
395 Insert(sb, &sb->sbb_tree, rel_offset, data_len);
396 }
397
SBBFree(StreamingBuffer * sb)398 static void SBBFree(StreamingBuffer *sb)
399 {
400 StreamingBufferBlock *sbb = NULL, *safe = NULL;
401 RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
402 SBB_RB_REMOVE(&sb->sbb_tree, sbb);
403 sb->sbb_size -= sbb->len;
404 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
405 }
406 sb->head = NULL;
407 }
408
SBBPrune(StreamingBuffer * sb)409 static void SBBPrune(StreamingBuffer *sb)
410 {
411 SCLogDebug("pruning %p to %"PRIu64, sb, sb->stream_offset);
412 StreamingBufferBlock *sbb = NULL, *safe = NULL;
413 RB_FOREACH_SAFE(sbb, SBB, &sb->sbb_tree, safe) {
414 /* completely beyond window, we're done */
415 if (sbb->offset > sb->stream_offset) {
416 sb->head = sbb;
417 break;
418 }
419
420 /* partly before, partly beyond. Adjust */
421 if (sbb->offset < sb->stream_offset &&
422 sbb->offset + sbb->len > sb->stream_offset) {
423 uint32_t shrink_by = sb->stream_offset - sbb->offset;
424 DEBUG_VALIDATE_BUG_ON(shrink_by > sbb->len);
425 if (sbb->len >= shrink_by) {
426 sbb->len -= shrink_by;
427 sbb->offset += shrink_by;
428 sb->sbb_size -= shrink_by;
429 DEBUG_VALIDATE_BUG_ON(sbb->offset != sb->stream_offset);
430 }
431 sb->head = sbb;
432 break;
433 }
434
435 SBB_RB_REMOVE(&sb->sbb_tree, sbb);
436 /* either we set it again for the next sbb, or there isn't any */
437 sb->head = NULL;
438 sb->sbb_size -= sbb->len;
439 SCLogDebug("sb %p removed %p %"PRIu64", %u", sb, sbb, sbb->offset, sbb->len);
440 FREE(sb->cfg, sbb, sizeof(StreamingBufferBlock));
441 }
442 }
443
444 /**
445 * \internal
446 * \brief move buffer forward by 'slide'
447 */
AutoSlide(StreamingBuffer * sb)448 static void AutoSlide(StreamingBuffer *sb)
449 {
450 uint32_t size = sb->cfg->buf_slide;
451 uint32_t slide = sb->buf_offset - size;
452 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
453 memmove(sb->buf, sb->buf+slide, size);
454 sb->stream_offset += slide;
455 sb->buf_offset = size;
456 SBBPrune(sb);
457 }
458
459 static int WARN_UNUSED
GrowToSize(StreamingBuffer * sb,uint32_t size)460 GrowToSize(StreamingBuffer *sb, uint32_t size)
461 {
462 /* try to grow in multiples of sb->cfg->buf_size */
463 uint32_t x = sb->cfg->buf_size ? size % sb->cfg->buf_size : 0;
464 uint32_t base = size - x;
465 uint32_t grow = base + sb->cfg->buf_size;
466
467 void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow);
468 if (ptr == NULL)
469 return -1;
470
471 /* for safe printing and general caution, lets memset the
472 * new data to 0 */
473 size_t diff = grow - sb->buf_size;
474 void *new_mem = ((char *)ptr) + sb->buf_size;
475 memset(new_mem, 0, diff);
476
477 sb->buf = ptr;
478 sb->buf_size = grow;
479 SCLogDebug("grown buffer to %u", grow);
480 #ifdef DEBUG
481 if (sb->buf_size > sb->buf_size_max) {
482 sb->buf_size_max = sb->buf_size;
483 }
484 #endif
485 return 0;
486 }
487
488 /** \internal
489 * \brief try to double the buffer size
490 * \retval 0 ok
491 * \retval -1 failed, buffer unchanged
492 */
Grow(StreamingBuffer * sb)493 static int WARN_UNUSED Grow(StreamingBuffer *sb)
494 {
495 uint32_t grow = sb->buf_size * 2;
496 void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow);
497 if (ptr == NULL)
498 return -1;
499
500 /* for safe printing and general caution, lets memset the
501 * new data to 0 */
502 size_t diff = grow - sb->buf_size;
503 void *new_mem = ((char *)ptr) + sb->buf_size;
504 memset(new_mem, 0, diff);
505
506 sb->buf = ptr;
507 sb->buf_size = grow;
508 SCLogDebug("grown buffer to %u", grow);
509 #ifdef DEBUG
510 if (sb->buf_size > sb->buf_size_max) {
511 sb->buf_size_max = sb->buf_size;
512 }
513 #endif
514 return 0;
515 }
516
517 /**
518 * \brief slide to absolute offset
519 * \todo if sliding beyond window, we could perhaps reset?
520 */
StreamingBufferSlideToOffset(StreamingBuffer * sb,uint64_t offset)521 void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset)
522 {
523 if (offset > sb->stream_offset &&
524 offset <= sb->stream_offset + sb->buf_offset)
525 {
526 uint32_t slide = offset - sb->stream_offset;
527 uint32_t size = sb->buf_offset - slide;
528 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
529 memmove(sb->buf, sb->buf+slide, size);
530 sb->stream_offset += slide;
531 sb->buf_offset = size;
532 SBBPrune(sb);
533 }
534 }
535
StreamingBufferSlide(StreamingBuffer * sb,uint32_t slide)536 void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide)
537 {
538 uint32_t size = sb->buf_offset - slide;
539 SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size);
540 memmove(sb->buf, sb->buf+slide, size);
541 sb->stream_offset += slide;
542 sb->buf_offset = size;
543 SBBPrune(sb);
544 }
545
546 #define DATA_FITS(sb, len) \
547 ((sb)->buf_offset + (len) <= (sb)->buf_size)
548
StreamingBufferAppendRaw(StreamingBuffer * sb,const uint8_t * data,uint32_t data_len)549 StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint8_t *data, uint32_t data_len)
550 {
551 if (sb->buf == NULL) {
552 if (InitBuffer(sb) == -1)
553 return NULL;
554 }
555
556 if (!DATA_FITS(sb, data_len)) {
557 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
558 AutoSlide(sb);
559 if (sb->buf_size == 0) {
560 if (GrowToSize(sb, data_len) != 0)
561 return NULL;
562 } else {
563 while (!DATA_FITS(sb, data_len)) {
564 if (Grow(sb) != 0) {
565 return NULL;
566 }
567 }
568 }
569 }
570 if (!DATA_FITS(sb, data_len)) {
571 return NULL;
572 }
573
574 StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment));
575 if (seg != NULL) {
576 memcpy(sb->buf + sb->buf_offset, data, data_len);
577 seg->stream_offset = sb->stream_offset + sb->buf_offset;
578 seg->segment_len = data_len;
579 uint32_t rel_offset = sb->buf_offset;
580 sb->buf_offset += data_len;
581
582 if (!RB_EMPTY(&sb->sbb_tree)) {
583 SBBUpdate(sb, rel_offset, data_len);
584 }
585 return seg;
586 }
587 return NULL;
588 }
589
StreamingBufferAppend(StreamingBuffer * sb,StreamingBufferSegment * seg,const uint8_t * data,uint32_t data_len)590 int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg,
591 const uint8_t *data, uint32_t data_len)
592 {
593 BUG_ON(seg == NULL);
594
595 if (sb->buf == NULL) {
596 if (InitBuffer(sb) == -1)
597 return -1;
598 }
599
600 if (!DATA_FITS(sb, data_len)) {
601 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
602 AutoSlide(sb);
603 if (sb->buf_size == 0) {
604 if (GrowToSize(sb, data_len) != 0)
605 return -1;
606 } else {
607 while (!DATA_FITS(sb, data_len)) {
608 if (Grow(sb) != 0) {
609 return -1;
610 }
611 }
612 }
613 }
614 if (!DATA_FITS(sb, data_len)) {
615 return -1;
616 }
617
618 memcpy(sb->buf + sb->buf_offset, data, data_len);
619 seg->stream_offset = sb->stream_offset + sb->buf_offset;
620 seg->segment_len = data_len;
621 uint32_t rel_offset = sb->buf_offset;
622 sb->buf_offset += data_len;
623
624 if (!RB_EMPTY(&sb->sbb_tree)) {
625 SBBUpdate(sb, rel_offset, data_len);
626 }
627 return 0;
628 }
629
630 /**
631 * \brief add data w/o tracking a segment
632 */
StreamingBufferAppendNoTrack(StreamingBuffer * sb,const uint8_t * data,uint32_t data_len)633 int StreamingBufferAppendNoTrack(StreamingBuffer *sb,
634 const uint8_t *data, uint32_t data_len)
635 {
636 if (sb->buf == NULL) {
637 if (InitBuffer(sb) == -1)
638 return -1;
639 }
640
641 if (!DATA_FITS(sb, data_len)) {
642 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE)
643 AutoSlide(sb);
644 if (sb->buf_size == 0) {
645 if (GrowToSize(sb, data_len) != 0)
646 return -1;
647 } else {
648 while (!DATA_FITS(sb, data_len)) {
649 if (Grow(sb) != 0) {
650 return -1;
651 }
652 }
653 }
654 }
655 if (!DATA_FITS(sb, data_len)) {
656 return -1;
657 }
658
659 memcpy(sb->buf + sb->buf_offset, data, data_len);
660 uint32_t rel_offset = sb->buf_offset;
661 sb->buf_offset += data_len;
662
663 if (!RB_EMPTY(&sb->sbb_tree)) {
664 SBBUpdate(sb, rel_offset, data_len);
665 }
666 return 0;
667 }
668
669 #define DATA_FITS_AT_OFFSET(sb, len, offset) \
670 ((offset) + (len) <= (sb)->buf_size)
671
672 /**
673 * \param offset offset relative to StreamingBuffer::stream_offset
674 */
StreamingBufferInsertAt(StreamingBuffer * sb,StreamingBufferSegment * seg,const uint8_t * data,uint32_t data_len,uint64_t offset)675 int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg,
676 const uint8_t *data, uint32_t data_len,
677 uint64_t offset)
678 {
679 BUG_ON(seg == NULL);
680
681 if (offset < sb->stream_offset)
682 return -1;
683
684 if (sb->buf == NULL) {
685 if (InitBuffer(sb) == -1)
686 return -1;
687 }
688
689 uint32_t rel_offset = offset - sb->stream_offset;
690 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
691 if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) {
692 AutoSlide(sb);
693 rel_offset = offset - sb->stream_offset;
694 }
695 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
696 if (GrowToSize(sb, (rel_offset + data_len)) != 0)
697 return -1;
698 }
699 }
700 if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) {
701 return -1;
702 }
703
704 memcpy(sb->buf + rel_offset, data, data_len);
705 seg->stream_offset = offset;
706 seg->segment_len = data_len;
707
708 SCLogDebug("rel_offset %u sb->stream_offset %"PRIu64", buf_offset %u",
709 rel_offset, sb->stream_offset, sb->buf_offset);
710
711 if (RB_EMPTY(&sb->sbb_tree)) {
712 SCLogDebug("empty sbb list");
713
714 if (sb->stream_offset == offset) {
715 SCLogDebug("empty sbb list: block exactly what was expected, fall through");
716 /* empty list, data is exactly what is expected (append),
717 * so do nothing */
718 } else if ((rel_offset + data_len) <= sb->buf_offset) {
719 SCLogDebug("empty sbb list: block is within existing region");
720 } else {
721 if (sb->buf_offset && rel_offset == sb->buf_offset) {
722 // nothing to do
723 } else if (rel_offset < sb->buf_offset) {
724 // nothing to do
725 } else if (sb->buf_offset) {
726 /* existing data, but there is a gap between us */
727 SBBInit(sb, rel_offset, data_len);
728 } else {
729 /* gap before data in empty list */
730 SCLogDebug("empty sbb list: invoking SBBInitLeadingGap");
731 SBBInitLeadingGap(sb, offset, data_len);
732 }
733 }
734 } else {
735 /* already have blocks, so append new block based on new data */
736 SBBUpdate(sb, rel_offset, data_len);
737 }
738
739 if (rel_offset + data_len > sb->buf_offset)
740 sb->buf_offset = rel_offset + data_len;
741
742 return 0;
743 }
744
StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer * sb,const StreamingBufferSegment * seg)745 int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb,
746 const StreamingBufferSegment *seg)
747 {
748 if (seg->stream_offset < sb->stream_offset) {
749 if (seg->stream_offset + seg->segment_len <= sb->stream_offset) {
750 return 1;
751 }
752 }
753 return 0;
754 }
755
756 /** \brief get the data for one SBB */
StreamingBufferSBBGetData(const StreamingBuffer * sb,const StreamingBufferBlock * sbb,const uint8_t ** data,uint32_t * data_len)757 void StreamingBufferSBBGetData(const StreamingBuffer *sb,
758 const StreamingBufferBlock *sbb,
759 const uint8_t **data, uint32_t *data_len)
760 {
761 if (sbb->offset >= sb->stream_offset) {
762 uint64_t offset = sbb->offset - sb->stream_offset;
763 *data = sb->buf + offset;
764 if (offset + sbb->len > sb->buf_offset)
765 *data_len = sb->buf_offset - offset;
766 else
767 *data_len = sbb->len;
768 return;
769 } else {
770 uint64_t offset = sb->stream_offset - sbb->offset;
771 if (offset < sbb->len) {
772 *data = sb->buf;
773 *data_len = sbb->len - offset;
774 return;
775 }
776 }
777 *data = NULL;
778 *data_len = 0;
779 return;
780 }
781
782 /** \brief get the data for one SBB */
StreamingBufferSBBGetDataAtOffset(const StreamingBuffer * sb,const StreamingBufferBlock * sbb,const uint8_t ** data,uint32_t * data_len,uint64_t offset)783 void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb,
784 const StreamingBufferBlock *sbb,
785 const uint8_t **data, uint32_t *data_len,
786 uint64_t offset)
787 {
788 if (offset >= sbb->offset && offset < (sbb->offset + sbb->len)) {
789 uint32_t sbblen = sbb->len - (offset - sbb->offset);
790
791 if (offset >= sb->stream_offset) {
792 uint64_t data_offset = offset - sb->stream_offset;
793 *data = sb->buf + data_offset;
794 if (data_offset + sbblen > sb->buf_size)
795 *data_len = sb->buf_size - data_offset;
796 else
797 *data_len = sbblen;
798 BUG_ON(*data_len > sbblen);
799 return;
800 } else {
801 uint64_t data_offset = sb->stream_offset - sbb->offset;
802 if (data_offset < sbblen) {
803 *data = sb->buf;
804 *data_len = sbblen - data_offset;
805 BUG_ON(*data_len > sbblen);
806 return;
807 }
808 }
809 }
810
811 *data = NULL;
812 *data_len = 0;
813 return;
814 }
815
StreamingBufferSegmentGetData(const StreamingBuffer * sb,const StreamingBufferSegment * seg,const uint8_t ** data,uint32_t * data_len)816 void StreamingBufferSegmentGetData(const StreamingBuffer *sb,
817 const StreamingBufferSegment *seg,
818 const uint8_t **data, uint32_t *data_len)
819 {
820 if (likely(sb->buf)) {
821 if (seg->stream_offset >= sb->stream_offset) {
822 uint64_t offset = seg->stream_offset - sb->stream_offset;
823 *data = sb->buf + offset;
824 if (offset + seg->segment_len > sb->buf_size)
825 *data_len = sb->buf_size - offset;
826 else
827 *data_len = seg->segment_len;
828 return;
829 } else {
830 uint64_t offset = sb->stream_offset - seg->stream_offset;
831 if (offset < seg->segment_len) {
832 *data = sb->buf;
833 *data_len = seg->segment_len - offset;
834 return;
835 }
836 }
837 }
838 *data = NULL;
839 *data_len = 0;
840 return;
841 }
842
843 /**
844 * \retval 1 data is the same
845 * \retval 0 data is different
846 */
StreamingBufferSegmentCompareRawData(const StreamingBuffer * sb,const StreamingBufferSegment * seg,const uint8_t * rawdata,uint32_t rawdata_len)847 int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb,
848 const StreamingBufferSegment *seg,
849 const uint8_t *rawdata, uint32_t rawdata_len)
850 {
851 const uint8_t *segdata = NULL;
852 uint32_t segdata_len = 0;
853 StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len);
854 if (segdata && segdata_len &&
855 segdata_len == rawdata_len &&
856 memcmp(segdata, rawdata, segdata_len) == 0)
857 {
858 return 1;
859 }
860 return 0;
861 }
862
StreamingBufferGetData(const StreamingBuffer * sb,const uint8_t ** data,uint32_t * data_len,uint64_t * stream_offset)863 int StreamingBufferGetData(const StreamingBuffer *sb,
864 const uint8_t **data, uint32_t *data_len,
865 uint64_t *stream_offset)
866 {
867 if (sb != NULL && sb->buf != NULL) {
868 *data = sb->buf;
869 *data_len = sb->buf_offset;
870 *stream_offset = sb->stream_offset;
871 return 1;
872 } else {
873 *data = NULL;
874 *data_len = 0;
875 *stream_offset = 0;
876 return 0;
877 }
878 }
879
StreamingBufferGetDataAtOffset(const StreamingBuffer * sb,const uint8_t ** data,uint32_t * data_len,uint64_t offset)880 int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb,
881 const uint8_t **data, uint32_t *data_len,
882 uint64_t offset)
883 {
884 if (sb != NULL && sb->buf != NULL &&
885 offset >= sb->stream_offset &&
886 offset < (sb->stream_offset + sb->buf_offset))
887 {
888 uint32_t skip = offset - sb->stream_offset;
889 *data = sb->buf + skip;
890 *data_len = sb->buf_offset - skip;
891 return 1;
892 } else {
893 *data = NULL;
894 *data_len = 0;
895 return 0;
896 }
897 }
898
899 /**
900 * \retval 1 data is the same
901 * \retval 0 data is different
902 */
StreamingBufferCompareRawData(const StreamingBuffer * sb,const uint8_t * rawdata,uint32_t rawdata_len)903 int StreamingBufferCompareRawData(const StreamingBuffer *sb,
904 const uint8_t *rawdata, uint32_t rawdata_len)
905 {
906 const uint8_t *sbdata = NULL;
907 uint32_t sbdata_len = 0;
908 uint64_t offset = 0;
909 StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset);
910 if (offset == 0 &&
911 sbdata && sbdata_len &&
912 sbdata_len == rawdata_len &&
913 memcmp(sbdata, rawdata, sbdata_len) == 0)
914 {
915 return 1;
916 }
917 SCLogDebug("sbdata_len %u, offset %"PRIu64, sbdata_len, offset);
918 printf("got:\n");
919 PrintRawDataFp(stdout, sbdata,sbdata_len);
920 printf("wanted:\n");
921 PrintRawDataFp(stdout, rawdata,rawdata_len);
922 return 0;
923 }
924
925 #ifdef UNITTESTS
Dump(StreamingBuffer * sb)926 static void Dump(StreamingBuffer *sb)
927 {
928 PrintRawDataFp(stdout, sb->buf, sb->buf_offset);
929 }
930
DumpSegment(StreamingBuffer * sb,StreamingBufferSegment * seg)931 static void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg)
932 {
933 const uint8_t *data = NULL;
934 uint32_t data_len = 0;
935 StreamingBufferSegmentGetData(sb, seg, &data, &data_len);
936 if (data && data_len) {
937 PrintRawDataFp(stdout, data, data_len);
938 }
939 }
940
StreamingBufferTest01(void)941 static int StreamingBufferTest01(void)
942 {
943 StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 16, NULL, NULL, NULL, NULL };
944 StreamingBuffer *sb = StreamingBufferInit(&cfg);
945 FAIL_IF(sb == NULL);
946
947 StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(sb, (const uint8_t *)"ABCDEFGH", 8);
948 StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(sb, (const uint8_t *)"01234567", 8);
949 FAIL_IF(sb->stream_offset != 0);
950 FAIL_IF(sb->buf_offset != 16);
951 FAIL_IF(seg1->stream_offset != 0);
952 FAIL_IF(seg2->stream_offset != 8);
953 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg1));
954 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
955 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg1,(const uint8_t *)"ABCDEFGH", 8));
956 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg2,(const uint8_t *)"01234567", 8));
957 Dump(sb);
958 FAIL_IF_NOT_NULL(sb->head);
959 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
960
961 StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(sb, (const uint8_t *)"QWERTY", 6);
962 FAIL_IF(sb->stream_offset != 8);
963 FAIL_IF(sb->buf_offset != 14);
964 FAIL_IF(seg3->stream_offset != 16);
965 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
966 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
967 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
968 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg3,(const uint8_t *)"QWERTY", 6));
969 Dump(sb);
970 FAIL_IF_NOT_NULL(sb->head);
971 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
972
973 StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(sb, (const uint8_t *)"KLM", 3);
974 FAIL_IF(sb->stream_offset != 14);
975 FAIL_IF(sb->buf_offset != 11);
976 FAIL_IF(seg4->stream_offset != 22);
977 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
978 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2));
979 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
980 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
981 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg4,(const uint8_t *)"KLM", 3));
982 Dump(sb);
983 FAIL_IF_NOT_NULL(sb->head);
984 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
985
986 StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(sb, (const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27);
987 FAIL_IF(sb->stream_offset != 17);
988 FAIL_IF(sb->buf_offset != 35);
989 FAIL_IF(seg5->stream_offset != 25);
990 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
991 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2));
992 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
993 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
994 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5));
995 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg5,(const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27));
996 Dump(sb);
997 FAIL_IF_NOT_NULL(sb->head);
998 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
999
1000 StreamingBufferSegment *seg6 = StreamingBufferAppendRaw(sb, (const uint8_t *)"UVWXYZ", 6);
1001 FAIL_IF(sb->stream_offset != 17);
1002 FAIL_IF(sb->buf_offset != 41);
1003 FAIL_IF(seg6->stream_offset != 52);
1004 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1));
1005 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2));
1006 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3));
1007 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4));
1008 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5));
1009 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg6));
1010 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg6,(const uint8_t *)"UVWXYZ", 6));
1011 Dump(sb);
1012 FAIL_IF_NOT_NULL(sb->head);
1013 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1014
1015 SCFree(seg1);
1016 SCFree(seg2);
1017 SCFree(seg3);
1018 SCFree(seg4);
1019 SCFree(seg5);
1020 SCFree(seg6);
1021 StreamingBufferFree(sb);
1022 PASS;
1023 }
1024
StreamingBufferTest02(void)1025 static int StreamingBufferTest02(void)
1026 {
1027 StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL };
1028 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1029 FAIL_IF(sb == NULL);
1030
1031 StreamingBufferSegment seg1;
1032 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1033 StreamingBufferSegment seg2;
1034 FAIL_IF(StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8) != 0);
1035 FAIL_IF(sb->stream_offset != 0);
1036 FAIL_IF(sb->buf_offset != 16);
1037 FAIL_IF(seg1.stream_offset != 0);
1038 FAIL_IF(seg2.stream_offset != 8);
1039 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1040 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1041 Dump(sb);
1042 DumpSegment(sb, &seg1);
1043 DumpSegment(sb, &seg2);
1044 FAIL_IF_NOT_NULL(sb->head);
1045 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1046
1047 StreamingBufferSlide(sb, 6);
1048 FAIL_IF_NOT_NULL(sb->head);
1049 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1050
1051 StreamingBufferSegment seg3;
1052 FAIL_IF(StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6) != 0);
1053 FAIL_IF(sb->stream_offset != 6);
1054 FAIL_IF(sb->buf_offset != 16);
1055 FAIL_IF(seg3.stream_offset != 16);
1056 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1057 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1058 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1059 Dump(sb);
1060 DumpSegment(sb, &seg1);
1061 DumpSegment(sb, &seg2);
1062 DumpSegment(sb, &seg3);
1063 FAIL_IF_NOT_NULL(sb->head);
1064 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1065
1066 StreamingBufferSlide(sb, 6);
1067 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1068 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1069 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1070 Dump(sb);
1071 DumpSegment(sb, &seg1);
1072 DumpSegment(sb, &seg2);
1073 DumpSegment(sb, &seg3);
1074 FAIL_IF_NOT_NULL(sb->head);
1075 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1076
1077 StreamingBufferFree(sb);
1078 PASS;
1079 }
1080
StreamingBufferTest03(void)1081 static int StreamingBufferTest03(void)
1082 {
1083 StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL };
1084 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1085 FAIL_IF(sb == NULL);
1086
1087 StreamingBufferSegment seg1;
1088 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1089 StreamingBufferSegment seg2;
1090 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
1091 FAIL_IF(sb->stream_offset != 0);
1092 FAIL_IF(sb->buf_offset != 22);
1093 FAIL_IF(seg1.stream_offset != 0);
1094 FAIL_IF(seg2.stream_offset != 14);
1095 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1096 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1097 Dump(sb);
1098 DumpSegment(sb, &seg1);
1099 DumpSegment(sb, &seg2);
1100 FAIL_IF_NULL(sb->head);
1101 FAIL_IF_NOT(sb->sbb_size == 16);
1102 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1103
1104 StreamingBufferSegment seg3;
1105 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
1106 FAIL_IF(sb->stream_offset != 0);
1107 FAIL_IF(sb->buf_offset != 22);
1108 FAIL_IF(seg3.stream_offset != 8);
1109 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1110 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1111 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1112 Dump(sb);
1113 DumpSegment(sb, &seg1);
1114 DumpSegment(sb, &seg2);
1115 DumpSegment(sb, &seg3);
1116 FAIL_IF_NULL(sb->head);
1117 FAIL_IF_NOT(sb->sbb_size == 22);
1118 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1119
1120 StreamingBufferSlide(sb, 10);
1121 FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1122 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1123 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1124 Dump(sb);
1125 DumpSegment(sb, &seg1);
1126 DumpSegment(sb, &seg2);
1127 DumpSegment(sb, &seg3);
1128 FAIL_IF_NULL(sb->head);
1129 FAIL_IF_NOT(sb->sbb_size == 12);
1130 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1131
1132 StreamingBufferFree(sb);
1133 PASS;
1134 }
1135
StreamingBufferTest04(void)1136 static int StreamingBufferTest04(void)
1137 {
1138 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1139 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1140 FAIL_IF(sb == NULL);
1141
1142 StreamingBufferSegment seg1;
1143 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
1144 FAIL_IF(!RB_EMPTY(&sb->sbb_tree));
1145 StreamingBufferSegment seg2;
1146 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0);
1147 FAIL_IF(sb->stream_offset != 0);
1148 FAIL_IF(sb->buf_offset != 22);
1149 FAIL_IF(seg1.stream_offset != 0);
1150 FAIL_IF(seg2.stream_offset != 14);
1151 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1152 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1153 FAIL_IF(RB_EMPTY(&sb->sbb_tree));
1154 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1155 FAIL_IF(sbb1 != sb->head);
1156 FAIL_IF_NULL(sbb1);
1157 FAIL_IF(sbb1->offset != 0);
1158 FAIL_IF(sbb1->len != 8);
1159 StreamingBufferBlock *sbb2 = SBB_RB_NEXT(sbb1);
1160 FAIL_IF_NULL(sbb2);
1161 FAIL_IF(sbb2 == sb->head);
1162 FAIL_IF(sbb2->offset != 14);
1163 FAIL_IF(sbb2->len != 8);
1164 Dump(sb);
1165 DumpSegment(sb, &seg1);
1166 DumpSegment(sb, &seg2);
1167 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1168
1169 StreamingBufferSegment seg3;
1170 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0);
1171 FAIL_IF(sb->stream_offset != 0);
1172 FAIL_IF(sb->buf_offset != 22);
1173 FAIL_IF(seg3.stream_offset != 8);
1174 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1175 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1176 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1177 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1178 FAIL_IF_NULL(sbb1);
1179 FAIL_IF(sbb1 != sb->head);
1180 FAIL_IF(sbb1->offset != 0);
1181 FAIL_IF(sbb1->len != 22);
1182 FAIL_IF(SBB_RB_NEXT(sbb1));
1183 Dump(sb);
1184 DumpSegment(sb, &seg1);
1185 DumpSegment(sb, &seg2);
1186 DumpSegment(sb, &seg3);
1187 FAIL_IF_NULL(sb->head);
1188 FAIL_IF_NOT(sb->sbb_size == 22);
1189 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1190
1191 /* far ahead of curve: */
1192 StreamingBufferSegment seg4;
1193 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0);
1194 FAIL_IF(sb->stream_offset != 0);
1195 FAIL_IF(sb->buf_offset != 127);
1196 FAIL_IF(sb->buf_size != 128);
1197 FAIL_IF(seg4.stream_offset != 124);
1198 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1));
1199 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2));
1200 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3));
1201 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4));
1202 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1203 FAIL_IF_NULL(sbb1);
1204 FAIL_IF(sbb1 != sb->head);
1205 FAIL_IF(sbb1->offset != 0);
1206 FAIL_IF(sbb1->len != 22);
1207 FAIL_IF(!SBB_RB_NEXT(sbb1));
1208 Dump(sb);
1209 DumpSegment(sb, &seg1);
1210 DumpSegment(sb, &seg2);
1211 DumpSegment(sb, &seg3);
1212 DumpSegment(sb, &seg4);
1213 FAIL_IF_NULL(sb->head);
1214 FAIL_IF_NOT(sb->sbb_size == 25);
1215 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1216
1217 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8));
1218 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8));
1219 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6));
1220 FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3));
1221
1222 StreamingBufferFree(sb);
1223 PASS;
1224 }
1225
StreamingBufferTest05(void)1226 static int StreamingBufferTest05(void)
1227 {
1228 StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 32, NULL, NULL, NULL, NULL };
1229 StreamingBuffer sb = STREAMING_BUFFER_INITIALIZER(&cfg);
1230
1231 StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"AAAAAAAA", 8);
1232 StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"BBBBBBBB", 8);
1233 StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"CCCCCCCC", 8);
1234 StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"DDDDDDDD", 8);
1235 FAIL_IF(sb.stream_offset != 0);
1236 FAIL_IF(sb.buf_offset != 32);
1237 FAIL_IF(seg1->stream_offset != 0);
1238 FAIL_IF(seg2->stream_offset != 8);
1239 FAIL_IF(seg3->stream_offset != 16);
1240 FAIL_IF(seg4->stream_offset != 24);
1241 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg1));
1242 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg2));
1243 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg3));
1244 FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg4));
1245 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg1,(const uint8_t *)"AAAAAAAA", 8));
1246 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg2,(const uint8_t *)"BBBBBBBB", 8));
1247 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg3,(const uint8_t *)"CCCCCCCC", 8));
1248 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg4,(const uint8_t *)"DDDDDDDD", 8));
1249 Dump(&sb);
1250 FAIL_IF_NOT(sb.head == RB_MIN(SBB, &sb.sbb_tree));
1251 StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"EEEEEEEE", 8);
1252 FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg5,(const uint8_t *)"EEEEEEEE", 8));
1253 Dump(&sb);
1254 FAIL_IF_NOT(sb.head == RB_MIN(SBB, &sb.sbb_tree));
1255
1256 SCFree(seg1);
1257 SCFree(seg2);
1258 SCFree(seg3);
1259 SCFree(seg4);
1260 SCFree(seg5);
1261 StreamingBufferClear(&sb);
1262 PASS;
1263 }
1264
1265 /** \test lots of gaps in block list */
StreamingBufferTest06(void)1266 static int StreamingBufferTest06(void)
1267 {
1268 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1269 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1270 FAIL_IF(sb == NULL);
1271
1272 StreamingBufferSegment seg1;
1273 FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"A", 1) != 0);
1274 StreamingBufferSegment seg2;
1275 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"C", 1, 2) != 0);
1276 Dump(sb);
1277 FAIL_IF_NULL(sb->head);
1278 FAIL_IF_NOT(sb->sbb_size == 2);
1279 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1280
1281 StreamingBufferSegment seg3;
1282 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1283 Dump(sb);
1284 FAIL_IF_NULL(sb->head);
1285 FAIL_IF_NOT(sb->sbb_size == 3);
1286 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1287
1288 StreamingBufferSegment seg4;
1289 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1290 Dump(sb);
1291 FAIL_IF_NULL(sb->head);
1292 FAIL_IF_NOT(sb->sbb_size == 4);
1293 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1294
1295 StreamingBufferSegment seg5;
1296 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1297 Dump(sb);
1298 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1299 FAIL_IF_NULL(sbb1);
1300 FAIL_IF(sbb1->offset != 0);
1301 FAIL_IF(sbb1->len != 10);
1302 FAIL_IF(SBB_RB_NEXT(sbb1));
1303 FAIL_IF_NULL(sb->head);
1304 FAIL_IF_NOT(sb->sbb_size == 10);
1305 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1306
1307 StreamingBufferSegment seg6;
1308 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1309 Dump(sb);
1310 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1311 FAIL_IF_NULL(sbb1);
1312 FAIL_IF(sbb1->offset != 0);
1313 FAIL_IF(sbb1->len != 10);
1314 FAIL_IF(SBB_RB_NEXT(sbb1));
1315 FAIL_IF_NULL(sb->head);
1316 FAIL_IF_NOT(sb->sbb_size == 10);
1317 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1318
1319 StreamingBufferFree(sb);
1320 PASS;
1321 }
1322
1323 /** \test lots of gaps in block list */
StreamingBufferTest07(void)1324 static int StreamingBufferTest07(void)
1325 {
1326 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1327 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1328 FAIL_IF(sb == NULL);
1329
1330 StreamingBufferSegment seg1;
1331 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1332 StreamingBufferSegment seg2;
1333 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1334 Dump(sb);
1335 FAIL_IF_NULL(sb->head);
1336 FAIL_IF_NOT(sb->sbb_size == 2);
1337 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1338
1339 StreamingBufferSegment seg3;
1340 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1341 Dump(sb);
1342 FAIL_IF_NULL(sb->head);
1343 FAIL_IF_NOT(sb->sbb_size == 3);
1344 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1345
1346 StreamingBufferSegment seg4;
1347 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1348 Dump(sb);
1349 FAIL_IF_NULL(sb->head);
1350 FAIL_IF_NOT(sb->sbb_size == 4);
1351 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1352
1353 StreamingBufferSegment seg5;
1354 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1355 Dump(sb);
1356 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1357 FAIL_IF_NULL(sbb1);
1358 FAIL_IF(sbb1->offset != 0);
1359 FAIL_IF(sbb1->len != 10);
1360 FAIL_IF(SBB_RB_NEXT(sbb1));
1361 FAIL_IF_NULL(sb->head);
1362 FAIL_IF_NOT(sb->sbb_size == 10);
1363 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1364
1365 StreamingBufferSegment seg6;
1366 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1367 Dump(sb);
1368 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1369 FAIL_IF_NULL(sbb1);
1370 FAIL_IF(sbb1->offset != 0);
1371 FAIL_IF(sbb1->len != 10);
1372 FAIL_IF(SBB_RB_NEXT(sbb1));
1373 FAIL_IF_NULL(sb->head);
1374 FAIL_IF_NOT(sb->sbb_size == 10);
1375 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1376
1377 StreamingBufferFree(sb);
1378 PASS;
1379 }
1380
1381 /** \test lots of gaps in block list */
StreamingBufferTest08(void)1382 static int StreamingBufferTest08(void)
1383 {
1384 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1385 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1386 FAIL_IF(sb == NULL);
1387
1388 StreamingBufferSegment seg1;
1389 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1390 StreamingBufferSegment seg2;
1391 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1392 Dump(sb);
1393 FAIL_IF_NULL(sb->head);
1394 FAIL_IF_NOT(sb->sbb_size == 2);
1395 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1396
1397 StreamingBufferSegment seg3;
1398 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"F", 1, 5) != 0);
1399 Dump(sb);
1400 FAIL_IF_NULL(sb->head);
1401 FAIL_IF_NOT(sb->sbb_size == 3);
1402 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1403
1404 StreamingBufferSegment seg4;
1405 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"H", 1, 7) != 0);
1406 Dump(sb);
1407 FAIL_IF_NULL(sb->head);
1408 FAIL_IF_NOT(sb->sbb_size == 4);
1409 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1410
1411 StreamingBufferSegment seg5;
1412 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1413 Dump(sb);
1414 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1415 FAIL_IF_NULL(sbb1);
1416 FAIL_IF(sbb1->offset != 0);
1417 FAIL_IF(sbb1->len != 10);
1418 FAIL_IF(SBB_RB_NEXT(sbb1));
1419 FAIL_IF_NULL(sb->head);
1420 FAIL_IF_NOT(sb->sbb_size == 10);
1421 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1422
1423 StreamingBufferSegment seg6;
1424 FAIL_IF(StreamingBufferAppend(sb, &seg6, (const uint8_t *)"abcdefghij", 10) != 0);
1425 Dump(sb);
1426 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1427 FAIL_IF_NULL(sbb1);
1428 FAIL_IF(sbb1->offset != 0);
1429 FAIL_IF(sbb1->len != 20);
1430 FAIL_IF(SBB_RB_NEXT(sbb1));
1431 FAIL_IF_NULL(sb->head);
1432 FAIL_IF_NOT(sb->sbb_size == 20);
1433 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1434
1435 StreamingBufferFree(sb);
1436 PASS;
1437 }
1438
1439 /** \test lots of gaps in block list */
StreamingBufferTest09(void)1440 static int StreamingBufferTest09(void)
1441 {
1442 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1443 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1444 FAIL_IF(sb == NULL);
1445
1446 StreamingBufferSegment seg1;
1447 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"B", 1, 1) != 0);
1448 StreamingBufferSegment seg2;
1449 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1450 Dump(sb);
1451 FAIL_IF_NULL(sb->head);
1452 FAIL_IF_NOT(sb->sbb_size == 2);
1453 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1454
1455 StreamingBufferSegment seg3;
1456 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"H", 1, 7) != 0);
1457 Dump(sb);
1458 FAIL_IF_NULL(sb->head);
1459 FAIL_IF_NOT(sb->sbb_size == 3);
1460 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1461
1462 StreamingBufferSegment seg4;
1463 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"F", 1, 5) != 0);
1464 Dump(sb);
1465 FAIL_IF_NULL(sb->head);
1466 FAIL_IF_NOT(sb->sbb_size == 4);
1467 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1468
1469 StreamingBufferSegment seg5;
1470 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1471 Dump(sb);
1472 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1473 FAIL_IF_NULL(sbb1);
1474 FAIL_IF(sbb1->offset != 0);
1475 FAIL_IF(sbb1->len != 10);
1476 FAIL_IF(SBB_RB_NEXT(sbb1));
1477 FAIL_IF_NULL(sb->head);
1478 FAIL_IF_NOT(sb->sbb_size == 10);
1479 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1480
1481 StreamingBufferSegment seg6;
1482 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1483 Dump(sb);
1484 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1485 FAIL_IF_NULL(sbb1);
1486 FAIL_IF(sbb1->offset != 0);
1487 FAIL_IF(sbb1->len != 10);
1488 FAIL_IF(SBB_RB_NEXT(sbb1));
1489 FAIL_IF_NULL(sb->head);
1490 FAIL_IF_NOT(sb->sbb_size == 10);
1491 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1492
1493 StreamingBufferFree(sb);
1494 PASS;
1495 }
1496
1497 /** \test lots of gaps in block list */
StreamingBufferTest10(void)1498 static int StreamingBufferTest10(void)
1499 {
1500 StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL };
1501 StreamingBuffer *sb = StreamingBufferInit(&cfg);
1502 FAIL_IF(sb == NULL);
1503
1504 StreamingBufferSegment seg1;
1505 FAIL_IF(StreamingBufferInsertAt(sb, &seg1, (const uint8_t *)"A", 1, 0) != 0);
1506 Dump(sb);
1507 StreamingBufferSegment seg2;
1508 FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"D", 1, 3) != 0);
1509 Dump(sb);
1510 StreamingBufferSegment seg3;
1511 FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"H", 1, 7) != 0);
1512 Dump(sb);
1513 FAIL_IF_NULL(sb->head);
1514 FAIL_IF_NOT(sb->sbb_size == 3);
1515
1516 StreamingBufferSegment seg4;
1517 FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"B", 1, 1) != 0);
1518 Dump(sb);
1519 StreamingBufferSegment seg5;
1520 FAIL_IF(StreamingBufferInsertAt(sb, &seg5, (const uint8_t *)"C", 1, 2) != 0);
1521 Dump(sb);
1522 StreamingBufferSegment seg6;
1523 FAIL_IF(StreamingBufferInsertAt(sb, &seg6, (const uint8_t *)"G", 1, 6) != 0);
1524 Dump(sb);
1525 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1526 FAIL_IF_NULL(sb->head);
1527 FAIL_IF_NOT(sb->sbb_size == 6);
1528
1529 StreamingBufferSegment seg7;
1530 FAIL_IF(StreamingBufferInsertAt(sb, &seg7, (const uint8_t *)"ABCDEFGHIJ", 10, 0) != 0);
1531 Dump(sb);
1532 StreamingBufferBlock *sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1533 FAIL_IF_NULL(sbb1);
1534 FAIL_IF(sbb1->offset != 0);
1535 FAIL_IF(sbb1->len != 10);
1536 FAIL_IF(SBB_RB_NEXT(sbb1));
1537 FAIL_IF_NULL(sb->head);
1538 FAIL_IF_NOT(sb->sbb_size == 10);
1539
1540 StreamingBufferSegment seg8;
1541 FAIL_IF(StreamingBufferInsertAt(sb, &seg8, (const uint8_t *)"abcdefghij", 10, 0) != 0);
1542 Dump(sb);
1543 sbb1 = RB_MIN(SBB, &sb->sbb_tree);
1544 FAIL_IF_NOT(sb->head == RB_MIN(SBB, &sb->sbb_tree));
1545 FAIL_IF_NULL(sbb1);
1546 FAIL_IF(sbb1->offset != 0);
1547 FAIL_IF(sbb1->len != 10);
1548 FAIL_IF(SBB_RB_NEXT(sbb1));
1549 FAIL_IF_NULL(sb->head);
1550 FAIL_IF_NOT(sb->sbb_size == 10);
1551
1552 StreamingBufferFree(sb);
1553 PASS;
1554 }
1555
1556 #endif
1557
StreamingBufferRegisterTests(void)1558 void StreamingBufferRegisterTests(void)
1559 {
1560 #ifdef UNITTESTS
1561 UtRegisterTest("StreamingBufferTest01", StreamingBufferTest01);
1562 UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02);
1563 UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03);
1564 UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04);
1565 UtRegisterTest("StreamingBufferTest05", StreamingBufferTest05);
1566 UtRegisterTest("StreamingBufferTest06", StreamingBufferTest06);
1567 UtRegisterTest("StreamingBufferTest07", StreamingBufferTest07);
1568 UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
1569 UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
1570 UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
1571 #endif
1572 }
1573