suricata
app-layer-htp-range.c
Go to the documentation of this file.
1/* Copyright (C) 2024 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/**
19 * \file
20 *
21 * \author Philippe Antoine <p.antoine@catenacyber.fr>
22 */
23
24#include "suricata-common.h"
25#include "app-layer-htp-range.h"
26#include "util-misc.h" //ParseSizeStringU64
27#include "util-thash.h" //HashTable
28#include "util-memcmp.h" //SCBufferCmp
29#include "util-hash-lookup3.h" //hashlittle_safe
30#include "util-validate.h" //DEBUG_VALIDATE_BUG_ON
31#include "util-byte.h" //StringParseUint32
32
37
38// globals
40
41static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b);
42
43#define CONTAINER_URLRANGE_HASH_SIZE 256
44
45int HTPByteRangeSetMemcap(uint64_t size)
46{
47 if (size == 0 || (uint64_t)SC_ATOMIC_GET(ContainerUrlRangeList.ht->memuse) < size) {
49 return 1;
50 }
51
52 return 0;
53}
54
56{
57 uint64_t tmpval = SC_ATOMIC_GET(ContainerUrlRangeList.ht->config.memcap);
58 return tmpval;
59}
60
62{
63 uint64_t tmpval = SC_ATOMIC_GET(ContainerUrlRangeList.ht->memuse);
64 return tmpval;
65}
66
68{
69 // lexical order : start, buflen, offset
70 if (a->start > b->start)
71 return 1;
72 if (a->start < b->start)
73 return -1;
74 if (a->buflen > b->buflen)
75 return 1;
76 if (a->buflen < b->buflen)
77 return -1;
78 if (a->offset > b->offset)
79 return 1;
80 if (a->offset < b->offset)
81 return -1;
82 return 0;
83}
84
86
87static int ContainerUrlRangeSet(void *dst, void *src)
88{
91 dst_s->len = src_s->len;
92 dst_s->key = SCMalloc(dst_s->len);
93 if (dst_s->key == NULL)
94 return -1;
95 memcpy(dst_s->key, src_s->key, dst_s->len);
96 dst_s->files = FileContainerAlloc();
97 if (dst_s->files == NULL) {
98 SCFree(dst_s->key);
99 return -1;
100 }
101 RB_INIT(&dst_s->fragment_tree);
102 dst_s->flags = 0;
103 dst_s->lastsize = 0;
104 dst_s->totalsize = 0;
105 dst_s->hdata = NULL;
106 dst_s->error = false;
107 return 0;
108}
109
110static bool ContainerUrlRangeCompare(void *a, void *b)
111{
112 const HttpRangeContainerFile *as = a;
113 const HttpRangeContainerFile *bs = b;
114
115 /* ranges in the error state should not be found so they can
116 * be evicted */
117 if (as->error || bs->error) {
118 return false;
119 }
120
121 if (SCBufferCmp(as->key, as->len, bs->key, bs->len) == 0) {
122 return true;
123 }
124 return false;
125}
126
127static uint32_t ContainerUrlRangeHash(uint32_t hash_seed, void *s)
128{
129 HttpRangeContainerFile *cur = s;
130 uint32_t h = hashlittle_safe(cur->key, cur->len, hash_seed);
131 return h;
132}
133
134// base data stays in hash
135static void ContainerUrlRangeFree(void *s)
136{
137 HttpRangeContainerBuffer *range = NULL, *tmp = NULL;
138
140 SCFree(cu->key);
141 cu->key = NULL;
142 FileContainerFree(cu->files, cu->sbcfg);
143 cu->files = NULL;
144 RB_FOREACH_SAFE (range, HTTP_RANGES, &cu->fragment_tree, tmp) {
145 RB_REMOVE(HTTP_RANGES, &cu->fragment_tree, range);
146 SCFree(range->buffer);
147 (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen);
148 SCFree(range);
149 }
150}
151
152static inline bool ContainerValueRangeTimeout(void *data, const SCTime_t ts)
153{
154 HttpRangeContainerFile *cu = data;
155 // we only timeout if we have no flow referencing us
156 if (SCTIME_CMP_GTE(ts, cu->expire) || cu->error) {
157 DEBUG_VALIDATE_BUG_ON(cu->files == NULL);
158 return true;
159 }
160 return false;
161}
162
163static void ContainerUrlRangeUpdate(HttpRangeContainerFile *cu, SCTime_t expire)
164{
165 cu->expire = expire;
166}
167
168#define HTTP_RANGE_DEFAULT_TIMEOUT 60
169#define HTTP_RANGE_DEFAULT_MEMCAP 100 * 1024 * 1024
170
172{
173 SCLogDebug("containers start");
174 const char *str = NULL;
175 uint64_t memcap = HTTP_RANGE_DEFAULT_MEMCAP;
176 uint32_t timeout = HTTP_RANGE_DEFAULT_TIMEOUT;
177 if (SCConfGet("app-layer.protocols.http.byterange.memcap", &str) == 1) {
178 if (ParseSizeStringU64(str, &memcap) < 0) {
179 SCLogWarning("memcap value cannot be deduced: %s,"
180 " resetting to default",
181 str);
182 memcap = 0;
183 }
184 }
185 if (SCConfGet("app-layer.protocols.http.byterange.timeout", &str) == 1) {
186 size_t slen = strlen(str);
187 if (slen > UINT16_MAX || StringParseUint32(&timeout, 10, (uint16_t)slen, str) <= 0) {
188 SCLogWarning("timeout value cannot be deduced: %s,"
189 " resetting to default",
190 str);
191 timeout = 0;
192 }
193 }
194
195 ContainerUrlRangeList.ht = THashInit("app-layer.protocols.http.byterange",
196 sizeof(HttpRangeContainerFile), ContainerUrlRangeSet, ContainerUrlRangeFree,
197 ContainerUrlRangeHash, ContainerUrlRangeCompare, ContainerValueRangeTimeout, NULL,
198 false, memcap, CONTAINER_URLRANGE_HASH_SIZE);
200
201 SCLogDebug("containers started");
202}
203
208
213
214/**
215 * \returns locked data
216 */
217static void *HttpRangeContainerUrlGet(const uint8_t *key, uint32_t keylen, const Flow *f)
218{
219 const SCTime_t ts = f->lastts;
221 memset(&lookup, 0, sizeof(lookup));
222 // cast so as not to have const in the structure
223 lookup.key = (uint8_t *)key;
224 lookup.len = keylen;
226 if (res.data) {
227 // nothing more to do if (res.is_new)
228 ContainerUrlRangeUpdate(res.data->data, SCTIME_ADD_SECS(ts, ContainerUrlRangeList.timeout));
230 c->hdata = res.data;
231 SCLogDebug("c %p", c);
232 return res.data->data;
233 }
234 return NULL;
235}
236
237static HttpRangeContainerBlock *HttpRangeOpenFileAux(HttpRangeContainerFile *c, uint64_t start,
238 uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name,
239 uint16_t name_len, uint16_t flags)
240{
241 if (c->files != NULL && c->files->tail == NULL) {
242 /* this is the first request, we open a single file in the file container
243 * this could be part of ContainerUrlRangeSet if we could have
244 * all the arguments there
245 */
246 if (FileOpenFileWithId(c->files, sbcfg, 0, name, name_len, NULL, 0, flags) != 0) {
247 SCLogDebug("open file for range failed");
248 return NULL;
249 }
250 }
252 if (curf == NULL) {
253 c->error = true;
254 return NULL;
255 }
256 curf->files = NULL;
257 if (total > c->totalsize) {
258 // we grow to the maximum size indicated by different range requests
259 // we could add some warning/app-layer event in this case where
260 // different range requests indicate different total sizes
261 c->totalsize = total;
262 }
263 const uint64_t buflen = end - start + 1;
264
265 /* The big part of this function is now to decide which kind of HttpRangeContainerBlock
266 * we will return :
267 * - skipping already processed data
268 * - storing out of order data for later use
269 * - directly appending to the file if we are at the right offset
270 */
271 if (start == c->lastsize && c->files != NULL) {
272 // easy case : append to current file
273 curf->container = c;
274 // If we see 2 duplicate range requests with the same range,
275 // the first one takes the ownership of the files container
276 // protected by the lock from caller HTPFileOpenWithRange
277 curf->files = c->files;
278 c->files = NULL;
279 return curf;
280 } else if (start < c->lastsize && c->lastsize - start >= buflen) {
281 // only overlap
282 // redundant to be explicit that this block is independent
283 curf->toskip = buflen;
284 return curf;
285 } else if (start < c->lastsize && c->lastsize - start < buflen && c->files != NULL) {
286 // some overlap, then some data to append to the file
287 curf->toskip = c->lastsize - start;
288 curf->files = c->files;
289 c->files = NULL;
290 curf->container = c;
291 return curf;
292 }
293 // Because we are not in the previous cases, we will store the data for later use
294
295 // block/range to be inserted in ordered linked list
297 // skips this range
298 curf->toskip = buflen;
299 return curf;
300 }
301 curf->container = c;
302
304 if (range == NULL) {
305 c->error = true;
306 SCFree(curf);
307 return NULL;
308 }
309
310 (void)SC_ATOMIC_ADD(ContainerUrlRangeList.ht->memuse, buflen);
311 range->buffer = SCMalloc(buflen);
312 if (range->buffer == NULL) {
313 c->error = true;
314 SCFree(curf);
315 SCFree(range);
316 (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, buflen);
317 return NULL;
318 }
319 range->buflen = buflen;
320 range->start = start;
321 range->offset = 0;
322 range->gap = 0;
323 curf->current = range;
324 return curf;
325}
326
327static HttpRangeContainerBlock *HttpRangeOpenFile(HttpRangeContainerFile *c, uint64_t start,
328 uint64_t end, uint64_t total, const StreamingBufferConfig *sbcfg, const uint8_t *name,
329 uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t len)
330{
332 HttpRangeOpenFileAux(c, start, end, total, sbcfg, name, name_len, flags);
333 if (r) {
334 if (HttpRangeAppendData(sbcfg, r, data, len) < 0) {
335 SCLogDebug("Failed to append data while opening");
336 }
337 }
338 return r;
339}
340
341HttpRangeContainerBlock *HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen,
342 const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg,
343 const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data,
344 uint32_t data_len)
345{
346 HttpRangeContainerFile *file_range_container = HttpRangeContainerUrlGet(key, keylen, f);
347 if (file_range_container == NULL) {
348 // probably reached memcap
349 return NULL;
350 }
351 file_range_container->sbcfg = sbcfg;
352
353 HttpRangeContainerBlock *r = HttpRangeOpenFile(file_range_container, crparsed->start,
354 crparsed->end, crparsed->size, sbcfg, name, name_len, flags, data, data_len);
355 SCLogDebug("s->file_range == %p", r);
356 if (r == NULL) {
357 THashDecrUsecnt(file_range_container->hdata);
359 SC_ATOMIC_GET(file_range_container->hdata->use_cnt) > (uint32_t)INT_MAX);
360 THashDataUnlock(file_range_container->hdata);
361
362 // probably reached memcap
363 return NULL;
364 /* in some cases we don't take a reference, so decr use cnt */
365 } else if (r->container == NULL) {
366 THashDecrUsecnt(file_range_container->hdata);
367 } else {
368 SCLogDebug("container %p use_cnt %u", r, SC_ATOMIC_GET(r->container->hdata->use_cnt));
369 DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(r->container->hdata->use_cnt) > (uint32_t)INT_MAX);
370 }
371
372 /* we're done, so unlock. But since we have a reference in s->file_range keep use_cnt. */
373 THashDataUnlock(file_range_container->hdata);
374 return r;
375}
376
378 const uint8_t *data, uint32_t len)
379{
380 if (len == 0) {
381 return 0;
382 }
383 // first check if we need to skip all bytes
384 if (c->toskip >= len) {
385 c->toskip -= len;
386 return 0;
387 }
388 // then if we need to skip only some bytes
389 if (c->toskip > 0) {
390 int r = 0;
391 if (c->files) {
392 if (data == NULL) {
393 // gap overlapping already known data
394 r = FileAppendData(c->files, sbcfg, NULL, (uint32_t)(len - c->toskip));
395 } else {
396 r = FileAppendData(c->files, sbcfg, data + c->toskip, (uint32_t)(len - c->toskip));
397 }
398 }
399 c->toskip = 0;
400 return r;
401 }
402 // If we are owning the file to append to it, let's do it
403 if (c->files) {
404 SCLogDebug("update files (FileAppendData)");
405 return FileAppendData(c->files, sbcfg, data, len);
406 }
407 // Maybe we were in the skipping case,
408 // but we get more data than expected and had set c->toskip = 0
409 // so we need to check for last case with something to do
410 if (c->current) {
411 // So we have a current allocated buffer to copy to
412 // in the case of an unordered range being handled
413 SCLogDebug("update current: adding %u bytes to block %p", len, c);
414 // GAP "data"
415 if (data == NULL) {
416 // just save the length of the gap
417 c->current->gap += len;
418 // data, but we're not yet complete
419 } else if (c->current->offset + len < c->current->buflen) {
420 memcpy(c->current->buffer + c->current->offset, data, len);
421 c->current->offset += len;
422 // data, we're complete
423 } else if (c->current->offset + len == c->current->buflen) {
424 memcpy(c->current->buffer + c->current->offset, data, len);
425 c->current->offset += len;
426 // data, more than expected
427 } else {
428 memcpy(c->current->buffer + c->current->offset, data,
429 c->current->buflen - c->current->offset);
430 c->current->offset = c->current->buflen;
431 }
432 }
433 return 0;
434}
435
436static void HttpRangeFileClose(
437 const StreamingBufferConfig *sbcfg, HttpRangeContainerFile *c, uint16_t flags)
438{
439 SCLogDebug("closing range %p flags %04x", c, flags);
440 DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(c->hdata->use_cnt) == 0);
441 // move ownership of file c->files->head to caller
442 FileCloseFile(c->files, sbcfg, NULL, 0, c->flags | flags);
443 c->files->head = NULL;
444 c->files->tail = NULL;
445}
446
447/**
448 * \note if `f` is non-NULL, the ownership of the file is transferred to the caller.
449 */
451{
452 SCLogDebug("c %p c->container %p c->current %p", c, c->container, c->current);
453
455
456 /* we're processing an OOO chunk, won't be able to get us a full file just yet */
457 if (c->current) {
458 SCLogDebug("processing ooo chunk as c->current is set %p", c->current);
459 // some out-or-order range is finished
460 if (c->container->lastsize >= c->current->start + c->current->offset) {
461 // if the range has become obsolete because we received the data already
462 // we just free it
464 SCFree(c->current->buffer);
465 SCFree(c->current);
466 c->current = NULL;
467 SCLogDebug("c->current was obsolete");
468 return NULL;
469 } else {
470 /* otherwise insert in red and black tree. If res != NULL, the insert
471 failed because its a dup. */
473 HTTP_RANGES_RB_INSERT(&c->container->fragment_tree, c->current);
474 if (res) {
475 SCLogDebug("duplicate range fragment");
477 SCFree(c->current->buffer);
478 SCFree(c->current);
479 c->current = NULL;
480 return NULL;
481 }
482 SCLogDebug("inserted range fragment");
483 c->current = NULL;
484 if (c->container->files == NULL) {
485 // we have to wait for the flow owning the file
486 return NULL;
487 }
488 if (c->container->files->tail == NULL) {
489 // file has already been closed meanwhile
490 return NULL;
491 }
492 // keep on going, maybe this out of order chunk
493 // became the missing part between open and close
494 }
495 SCLogDebug("c->current was set, file incomplete so return NULL");
496 } else if (c->toskip > 0) {
497 // was only an overlapping range, truncated before new bytes
498 SCLogDebug("c->toskip %" PRIu64, c->toskip);
499 if (c->files) {
500 // if we expected new bytes after overlap
501 c->container->files = c->files;
502 c->files = NULL;
503 }
504 return NULL;
505 } else {
506 // we just finished an in-order block
507 DEBUG_VALIDATE_BUG_ON(c->files == NULL);
508 // move back the ownership of the file container to HttpRangeContainerFile
509 c->container->files = c->files;
510 c->files = NULL;
512 }
513
514 File *f = c->container->files->tail;
515
516 /* See if we can use our stored fragments to (partly) reconstruct the file */
517 HttpRangeContainerBuffer *range, *safe = NULL;
518 RB_FOREACH_SAFE (range, HTTP_RANGES, &c->container->fragment_tree, safe) {
519 if (f->size < range->start) {
520 // this next range is not reached yet
521 break;
522 }
523 if (f->size == range->start) {
524 // a new range just begins where we ended, append it
525 if (range->gap > 0) {
526 // if the range had a gap, begin by it
527 uint32_t gap = range->gap <= UINT32_MAX ? (uint32_t)range->gap : UINT32_MAX;
528 if (FileAppendData(c->container->files, sbcfg, NULL, gap) != 0) {
529 c->container->lastsize = f->size;
530 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
531 c->container->error = true;
532 return f;
533 }
534 }
535 if (range->offset > UINT32_MAX) {
536 c->container->lastsize = f->size;
537 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
538 c->container->error = true;
539 return f;
540 } else if (FileAppendData(c->container->files, sbcfg, range->buffer,
541 (uint32_t)range->offset) != 0) {
542 c->container->lastsize = f->size;
543 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
544 c->container->error = true;
545 return f;
546 }
547 } else {
548 // the range starts before where we ended
549 uint64_t overlap = f->size - range->start;
550 if (overlap < range->offset) {
551 if (range->gap > 0) {
552 // if the range had a gap, begin by it
553 uint32_t gap = range->gap <= UINT32_MAX ? (uint32_t)range->gap : UINT32_MAX;
554 if (FileAppendData(c->container->files, sbcfg, NULL, gap) != 0) {
555 c->container->lastsize = f->size;
556 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
557 c->container->error = true;
558 return f;
559 }
560 }
561 // And the range ends beyond where we ended
562 // in this case of overlap, only add the extra data
563 if (range->offset - overlap > UINT32_MAX) {
564 c->container->lastsize = f->size;
565 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
566 c->container->error = true;
567 return f;
568 } else if (FileAppendData(c->container->files, sbcfg, range->buffer + overlap,
569 (uint32_t)(range->offset - overlap)) != 0) {
570 c->container->lastsize = f->size;
571 HttpRangeFileClose(sbcfg, c->container, flags | FILE_TRUNCATED);
572 c->container->error = true;
573 return f;
574 }
575 }
576 }
577 /* Remove this range from the tree */
578 HTTP_RANGES_RB_REMOVE(&c->container->fragment_tree, range);
579 (void)SC_ATOMIC_SUB(ContainerUrlRangeList.ht->memuse, range->buflen);
580 SCFree(range->buffer);
581 SCFree(range);
582 }
583 // wait until we merged all the buffers to update known size
584 c->container->lastsize = f->size;
585
586 if (f->size >= c->container->totalsize) {
587 // we finished the whole file
588 HttpRangeFileClose(sbcfg, c->container, flags);
589 } else {
590 // we are expecting more ranges
591 f = NULL;
592 SCLogDebug("expecting more use_cnt %u", SC_ATOMIC_GET(c->container->hdata->use_cnt));
593 }
594 SCLogDebug("returning f %p (c:%p container:%p)", f, c, c->container);
595 return f;
596}
597
598static void HttpRangeBlockDerefContainer(HttpRangeContainerBlock *b)
599{
600 if (b && b->container) {
603 b->container = NULL;
604 }
605}
606
608{
609 if (b) {
610 DEBUG_VALIDATE_BUG_ON(b->container == NULL && b->files != NULL);
611 const StreamingBufferConfig *sbcfg = b->container ? b->container->sbcfg : NULL;
612
613 HttpRangeBlockDerefContainer(b);
614
615 if (b->current) {
617 SCFree(b->current->buffer);
618 SCFree(b->current);
619 }
620 // we did not move ownership of the file container back to HttpRangeContainerFile
621 DEBUG_VALIDATE_BUG_ON(b->files != NULL);
622 if (b->files != NULL) {
623 FileContainerFree(b->files, sbcfg);
624 b->files = NULL;
625 }
626 SCFree(b);
627 }
628}
uint8_t len
uint16_t dst
uint16_t src
int HTPByteRangeSetMemcap(uint64_t size)
void HttpRangeContainersDestroy(void)
ContainerTHashTable ContainerUrlRangeList
uint32_t HttpRangeContainersTimeoutHash(const SCTime_t ts)
void HttpRangeFreeBlock(HttpRangeContainerBlock *b)
int HttpRangeContainerBufferCompare(HttpRangeContainerBuffer *a, HttpRangeContainerBuffer *b)
#define CONTAINER_URLRANGE_HASH_SIZE
#define HTTP_RANGE_DEFAULT_TIMEOUT
void HttpRangeContainersInit(void)
#define HTTP_RANGE_DEFAULT_MEMCAP
File * HttpRangeClose(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, uint16_t flags)
int HttpRangeAppendData(const StreamingBufferConfig *sbcfg, HttpRangeContainerBlock *c, const uint8_t *data, uint32_t len)
uint64_t HTPByteRangeMemcapGlobalCounter(void)
uint64_t HTPByteRangeMemuseGlobalCounter(void)
HttpRangeContainerBlock * HttpRangeContainerOpenFile(const uint8_t *key, uint32_t keylen, const Flow *f, const HTTPContentRange *crparsed, const StreamingBufferConfig *sbcfg, const uint8_t *name, uint16_t name_len, uint16_t flags, const uint8_t *data, uint32_t data_len)
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint8_t flags
Definition decode-gre.h:0
uint64_t ts
THashTableContext * ht
uint64_t size
Definition util-file.h:102
Flow data structure.
Definition flow.h:356
SCTime_t lastts
Definition flow.h:410
HttpRangeContainerBuffer * current
HttpRangeContainerFile * container
const StreamingBufferConfig * sbcfg
struct HTTP_RANGES fragment_tree
THashData * data
Definition util-thash.h:192
void * data
Definition util-thash.h:92
THashConfig config
Definition util-thash.h:151
#define str(s)
const char * name
#define RB_FOREACH_SAFE(x, name, head, y)
Definition tree.h:791
#define RB_REMOVE(name, x, y)
Definition tree.h:773
#define RB_INIT(root)
Definition tree.h:308
#define RB_GENERATE(name, type, field, cmp)
Definition tree.h:421
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition util-file.c:766
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition util-file.c:480
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition util-file.c:1062
void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg)
Free a FileContainer.
Definition util-file.c:516
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition util-file.c:967
#define FILE_TRUNCATED
Definition util-file.h:45
uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval)
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition util-misc.c:190
uint64_t offset
uint32_t THashExpire(THashTableContext *ctx, const SCTime_t ts)
expire data from the hash Walk the hash table and remove data that is exprired according to the DataE...
Definition util-thash.c:423
THashTableContext * THashInit(const char *cnf_prefix, uint32_t data_size, int(*DataSet)(void *, void *), void(*DataFree)(void *), uint32_t(*DataHash)(uint32_t, void *), bool(*DataCompare)(void *, void *), bool(*DataExpired)(void *, SCTime_t), uint32_t(*DataSize)(void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
Definition util-thash.c:302
struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data)
Definition util-thash.c:618
void THashShutdown(THashTableContext *ctx)
shutdown the flow engine
Definition util-thash.c:354
#define THashDecrUsecnt(h)
Definition util-thash.h:170
#define THASH_CHECK_MEMCAP(ctx, size)
check if a memory alloc would fit in the memcap
Definition util-thash.h:164
#define SCTIME_CMP_GTE(a, b)
Definition util-time.h:103
#define SCTIME_ADD_SECS(ts, s)
Definition util-time.h:64
#define DEBUG_VALIDATE_BUG_ON(exp)