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