Coverage Report

Created: 2026-07-16 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/stream.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Packet interface
4
 * Copyright (C) 1999 Kunihiro Ishiguro
5
 */
6
7
#include <zebra.h>
8
#include <stddef.h>
9
#include <pthread.h>
10
11
#include "stream.h"
12
#include "memory.h"
13
#include "network.h"
14
#include "prefix.h"
15
#include "log.h"
16
#include "frr_pthread.h"
17
#include "lib_errors.h"
18
19
8
DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream");
20
8
DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO");
21
8
22
8
/* Tests whether a position is valid */
23
2.68M
#define GETP_VALID(S, G) ((G) <= (S)->endp)
24
63.5k
#define PUT_AT_VALID(S,G) GETP_VALID(S,G)
25
1.27M
#define ENDP_VALID(S, E) ((E) <= (S)->size)
26
27
/* asserting sanity checks. Following must be true before
28
 * stream functions are called:
29
 *
30
 * Following must always be true of stream elements
31
 * before and after calls to stream functions:
32
 *
33
 * getp <= endp <= size
34
 *
35
 * Note that after a stream function is called following may be true:
36
 * if (getp == endp) then stream is no longer readable
37
 * if (endp == size) then stream is no longer writeable
38
 *
39
 * It is valid to put to anywhere within the size of the stream, but only
40
 * using stream_put..._at() functions.
41
 */
42
#define STREAM_WARN_OFFSETS(S)                                                 \
43
116
  do {                                                                   \
44
116
    flog_warn(EC_LIB_STREAM,              \
45
116
        "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu", \
46
116
        (void *)(S), (unsigned long)(S)->size,         \
47
116
        (unsigned long)(S)->getp, (unsigned long)(S)->endp); \
48
116
    zlog_backtrace(LOG_WARNING);               \
49
116
  } while (0)
50
51
#define STREAM_VERIFY_SANE(S)                                                  \
52
1.27M
  do {                                                                   \
53
1.27M
    if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) { \
54
0
      STREAM_WARN_OFFSETS(S);                                \
55
0
    }                                                              \
56
1.27M
    assert(GETP_VALID(S, (S)->getp));                              \
57
1.27M
    assert(ENDP_VALID(S, (S)->endp));                              \
58
1.27M
  } while (0)
59
60
#define STREAM_BOUND_WARN(S, WHAT)                                             \
61
0
  do {                                                                   \
62
0
    flog_warn(EC_LIB_STREAM, "%s: Attempt to %s out of bounds",    \
63
0
        __func__, (WHAT));                                   \
64
0
    STREAM_WARN_OFFSETS(S);                                        \
65
0
    assert(0);                                                     \
66
0
  } while (0)
67
68
#define STREAM_BOUND_WARN2(S, WHAT)                                            \
69
116
  do {                                                                   \
70
116
    flog_warn(EC_LIB_STREAM, "%s: Attempt to %s out of bounds",    \
71
116
        __func__, (WHAT));                                   \
72
116
    STREAM_WARN_OFFSETS(S);                                        \
73
116
  } while (0)
74
75
/* XXX: Deprecated macro: do not use */
76
#define CHECK_SIZE(S, Z)                                                       \
77
4.38k
  do {                                                                   \
78
4.38k
    if (((S)->endp + (Z)) > (S)->size) {                           \
79
0
      flog_warn(                                             \
80
0
        EC_LIB_STREAM,                                 \
81
0
        "CHECK_SIZE: truncating requested size %lu",   \
82
0
        (unsigned long)(Z));                           \
83
0
      STREAM_WARN_OFFSETS(S);                                \
84
0
      (Z) = (S)->size - (S)->endp;                           \
85
0
    }                                                              \
86
4.38k
  } while (0);
87
88
/* Make stream buffer. */
89
struct stream *stream_new(size_t size)
90
7.94k
{
91
7.94k
  struct stream *s;
92
93
7.94k
  assert(size > 0);
94
95
7.94k
  s = XMALLOC(MTYPE_STREAM, sizeof(struct stream) + size);
96
97
7.94k
  s->getp = s->endp = 0;
98
7.94k
  s->next = NULL;
99
7.94k
  s->size = size;
100
7.94k
  return s;
101
7.94k
}
102
103
/* Free it now. */
104
void stream_free(struct stream *s)
105
7.72k
{
106
7.72k
  if (!s)
107
2
    return;
108
109
7.72k
  XFREE(MTYPE_STREAM, s);
110
7.72k
}
111
112
struct stream *stream_copy(struct stream *dest, const struct stream *src)
113
507
{
114
507
  STREAM_VERIFY_SANE(src);
115
116
507
  assert(dest != NULL);
117
507
  assert(STREAM_SIZE(dest) >= src->endp);
118
119
507
  dest->endp = src->endp;
120
507
  dest->getp = src->getp;
121
122
507
  memcpy(dest->data, src->data, src->endp);
123
124
507
  return dest;
125
507
}
126
127
struct stream *stream_dup(const struct stream *s)
128
437
{
129
437
  struct stream *snew;
130
131
437
  STREAM_VERIFY_SANE(s);
132
133
437
  snew = stream_new(s->endp);
134
135
437
  return (stream_copy(snew, s));
136
437
}
137
138
struct stream *stream_dupcat(const struct stream *s1, const struct stream *s2,
139
           size_t offset)
140
0
{
141
0
  struct stream *new;
142
143
0
  STREAM_VERIFY_SANE(s1);
144
0
  STREAM_VERIFY_SANE(s2);
145
146
0
  if ((new = stream_new(s1->endp + s2->endp)) == NULL)
147
0
    return NULL;
148
149
0
  memcpy(new->data, s1->data, offset);
150
0
  memcpy(new->data + offset, s2->data, s2->endp);
151
0
  memcpy(new->data + offset + s2->endp, s1->data + offset,
152
0
         (s1->endp - offset));
153
0
  new->endp = s1->endp + s2->endp;
154
0
  return new;
155
0
}
156
157
size_t stream_resize_inplace(struct stream **sptr, size_t newsize)
158
0
{
159
0
  struct stream *orig = *sptr;
160
161
0
  STREAM_VERIFY_SANE(orig);
162
163
0
  orig = XREALLOC(MTYPE_STREAM, orig, sizeof(struct stream) + newsize);
164
165
0
  orig->size = newsize;
166
167
0
  if (orig->endp > orig->size)
168
0
    orig->endp = orig->size;
169
0
  if (orig->getp > orig->endp)
170
0
    orig->getp = orig->endp;
171
172
0
  STREAM_VERIFY_SANE(orig);
173
174
0
  *sptr = orig;
175
0
  return orig->size;
176
0
}
177
178
size_t stream_get_getp(const struct stream *s)
179
14.1k
{
180
14.1k
  STREAM_VERIFY_SANE(s);
181
14.1k
  return s->getp;
182
14.1k
}
183
184
size_t stream_get_endp(const struct stream *s)
185
67.7k
{
186
67.7k
  STREAM_VERIFY_SANE(s);
187
67.7k
  return s->endp;
188
67.7k
}
189
190
size_t stream_get_size(const struct stream *s)
191
0
{
192
0
  STREAM_VERIFY_SANE(s);
193
0
  return s->size;
194
0
}
195
196
/* Stream structre' stream pointer related functions.  */
197
void stream_set_getp(struct stream *s, size_t pos)
198
646
{
199
646
  STREAM_VERIFY_SANE(s);
200
201
646
  if (!GETP_VALID(s, pos)) {
202
0
    STREAM_BOUND_WARN(s, "set getp");
203
0
    pos = s->endp;
204
0
  }
205
206
646
  s->getp = pos;
207
646
}
208
209
void stream_set_endp(struct stream *s, size_t pos)
210
0
{
211
0
  STREAM_VERIFY_SANE(s);
212
213
0
  if (!ENDP_VALID(s, pos)) {
214
0
    STREAM_BOUND_WARN(s, "set endp");
215
0
    return;
216
0
  }
217
218
  /*
219
   * Make sure the current read pointer is not beyond the new endp.
220
   */
221
0
  if (s->getp > pos) {
222
0
    STREAM_BOUND_WARN(s, "set endp");
223
0
    return;
224
0
  }
225
226
0
  s->endp = pos;
227
0
  STREAM_VERIFY_SANE(s);
228
0
}
229
230
/* Forward pointer. */
231
void stream_forward_getp(struct stream *s, size_t size)
232
63.0k
{
233
63.0k
  STREAM_VERIFY_SANE(s);
234
235
63.0k
  if (!GETP_VALID(s, s->getp + size)) {
236
0
    STREAM_BOUND_WARN(s, "seek getp");
237
0
    return;
238
0
  }
239
240
63.0k
  s->getp += size;
241
63.0k
}
242
243
bool stream_forward_getp2(struct stream *s, size_t size)
244
5
{
245
5
  STREAM_VERIFY_SANE(s);
246
247
5
  if (!GETP_VALID(s, s->getp + size))
248
0
    return false;
249
250
5
  s->getp += size;
251
252
5
  return true;
253
5
}
254
255
void stream_rewind_getp(struct stream *s, size_t size)
256
90
{
257
90
  STREAM_VERIFY_SANE(s);
258
259
90
  if (size > s->getp || !GETP_VALID(s, s->getp - size)) {
260
0
    STREAM_BOUND_WARN(s, "rewind getp");
261
0
    return;
262
0
  }
263
264
90
  s->getp -= size;
265
90
}
266
267
bool stream_rewind_getp2(struct stream *s, size_t size)
268
0
{
269
0
  STREAM_VERIFY_SANE(s);
270
271
0
  if (size > s->getp || !GETP_VALID(s, s->getp - size))
272
0
    return false;
273
274
0
  s->getp -= size;
275
276
0
  return true;
277
0
}
278
279
void stream_forward_endp(struct stream *s, size_t size)
280
144
{
281
144
  STREAM_VERIFY_SANE(s);
282
283
144
  if (!ENDP_VALID(s, s->endp + size)) {
284
0
    STREAM_BOUND_WARN(s, "seek endp");
285
0
    return;
286
0
  }
287
288
144
  s->endp += size;
289
144
}
290
291
bool stream_forward_endp2(struct stream *s, size_t size)
292
0
{
293
0
  STREAM_VERIFY_SANE(s);
294
295
0
  if (!ENDP_VALID(s, s->endp + size))
296
0
    return false;
297
298
0
  s->endp += size;
299
300
0
  return true;
301
0
}
302
303
/* Copy from stream to destination. */
304
bool stream_get2(void *dst, struct stream *s, size_t size)
305
14.0k
{
306
14.0k
  STREAM_VERIFY_SANE(s);
307
308
14.0k
  if (STREAM_READABLE(s) < size) {
309
33
    STREAM_BOUND_WARN2(s, "get");
310
33
    return false;
311
33
  }
312
313
14.0k
  memcpy(dst, s->data + s->getp, size);
314
14.0k
  s->getp += size;
315
316
14.0k
  return true;
317
14.0k
}
318
319
void stream_get(void *dst, struct stream *s, size_t size)
320
1.04k
{
321
1.04k
  STREAM_VERIFY_SANE(s);
322
323
1.04k
  if (STREAM_READABLE(s) < size) {
324
0
    STREAM_BOUND_WARN(s, "get");
325
0
    return;
326
0
  }
327
328
1.04k
  memcpy(dst, s->data + s->getp, size);
329
1.04k
  s->getp += size;
330
1.04k
}
331
332
/* Get next character from the stream. */
333
bool stream_getc2(struct stream *s, uint8_t *byte)
334
22.7k
{
335
22.7k
  STREAM_VERIFY_SANE(s);
336
337
22.7k
  if (STREAM_READABLE(s) < sizeof(uint8_t)) {
338
1
    STREAM_BOUND_WARN2(s, "get char");
339
1
    return false;
340
1
  }
341
22.7k
  *byte = s->data[s->getp++];
342
343
22.7k
  return true;
344
22.7k
}
345
346
uint8_t stream_getc(struct stream *s)
347
22.3k
{
348
22.3k
  uint8_t c;
349
350
22.3k
  STREAM_VERIFY_SANE(s);
351
352
22.3k
  if (STREAM_READABLE(s) < sizeof(uint8_t)) {
353
0
    STREAM_BOUND_WARN(s, "get char");
354
0
    return 0;
355
0
  }
356
22.3k
  c = s->data[s->getp++];
357
358
22.3k
  return c;
359
22.3k
}
360
361
/* Get next character from the stream. */
362
uint8_t stream_getc_from(struct stream *s, size_t from)
363
0
{
364
0
  uint8_t c;
365
366
0
  STREAM_VERIFY_SANE(s);
367
368
0
  if (!GETP_VALID(s, from + sizeof(uint8_t))) {
369
0
    STREAM_BOUND_WARN(s, "get char");
370
0
    return 0;
371
0
  }
372
373
0
  c = s->data[from];
374
375
0
  return c;
376
0
}
377
378
bool stream_getw2(struct stream *s, uint16_t *word)
379
18.0k
{
380
18.0k
  STREAM_VERIFY_SANE(s);
381
382
18.0k
  if (STREAM_READABLE(s) < sizeof(uint16_t)) {
383
2
    STREAM_BOUND_WARN2(s, "get ");
384
2
    return false;
385
2
  }
386
387
18.0k
  *word = s->data[s->getp++] << 8;
388
18.0k
  *word |= s->data[s->getp++];
389
390
18.0k
  return true;
391
18.0k
}
392
393
/* Get next word from the stream. */
394
uint16_t stream_getw(struct stream *s)
395
5.32k
{
396
5.32k
  uint16_t w;
397
398
5.32k
  STREAM_VERIFY_SANE(s);
399
400
5.32k
  if (STREAM_READABLE(s) < sizeof(uint16_t)) {
401
0
    STREAM_BOUND_WARN(s, "get ");
402
0
    return 0;
403
0
  }
404
405
5.32k
  w = s->data[s->getp++] << 8;
406
5.32k
  w |= s->data[s->getp++];
407
408
5.32k
  return w;
409
5.32k
}
410
411
/* Get next word from the stream. */
412
uint16_t stream_getw_from(struct stream *s, size_t from)
413
0
{
414
0
  uint16_t w;
415
416
0
  STREAM_VERIFY_SANE(s);
417
418
0
  if (!GETP_VALID(s, from + sizeof(uint16_t))) {
419
0
    STREAM_BOUND_WARN(s, "get ");
420
0
    return 0;
421
0
  }
422
423
0
  w = s->data[from++] << 8;
424
0
  w |= s->data[from];
425
426
0
  return w;
427
0
}
428
429
/* Get next 3-byte from the stream. */
430
uint32_t stream_get3_from(struct stream *s, size_t from)
431
0
{
432
0
  uint32_t l;
433
434
0
  STREAM_VERIFY_SANE(s);
435
436
0
  if (!GETP_VALID(s, from + 3)) {
437
0
    STREAM_BOUND_WARN(s, "get 3byte");
438
0
    return 0;
439
0
  }
440
441
0
  l = s->data[from++] << 16;
442
0
  l |= s->data[from++] << 8;
443
0
  l |= s->data[from];
444
445
0
  return l;
446
0
}
447
448
uint32_t stream_get3(struct stream *s)
449
55
{
450
55
  uint32_t l;
451
452
55
  STREAM_VERIFY_SANE(s);
453
454
55
  if (STREAM_READABLE(s) < 3) {
455
0
    STREAM_BOUND_WARN(s, "get 3byte");
456
0
    return 0;
457
0
  }
458
459
55
  l = s->data[s->getp++] << 16;
460
55
  l |= s->data[s->getp++] << 8;
461
55
  l |= s->data[s->getp++];
462
463
55
  return l;
464
55
}
465
466
/* Get next long word from the stream. */
467
uint32_t stream_getl_from(struct stream *s, size_t from)
468
0
{
469
0
  uint32_t l;
470
471
0
  STREAM_VERIFY_SANE(s);
472
473
0
  if (!GETP_VALID(s, from + sizeof(uint32_t))) {
474
0
    STREAM_BOUND_WARN(s, "get long");
475
0
    return 0;
476
0
  }
477
478
0
  l = (unsigned)(s->data[from++]) << 24;
479
0
  l |= s->data[from++] << 16;
480
0
  l |= s->data[from++] << 8;
481
0
  l |= s->data[from];
482
483
0
  return l;
484
0
}
485
486
/* Copy from stream at specific location to destination. */
487
void stream_get_from(void *dst, struct stream *s, size_t from, size_t size)
488
5
{
489
5
  STREAM_VERIFY_SANE(s);
490
491
5
  if (!GETP_VALID(s, from + size)) {
492
0
    STREAM_BOUND_WARN(s, "get from");
493
0
    return;
494
0
  }
495
496
5
  memcpy(dst, s->data + from, size);
497
5
}
498
499
bool stream_getl2(struct stream *s, uint32_t *l)
500
83.0k
{
501
83.0k
  STREAM_VERIFY_SANE(s);
502
503
83.0k
  if (STREAM_READABLE(s) < sizeof(uint32_t)) {
504
73
    STREAM_BOUND_WARN2(s, "get long");
505
73
    return false;
506
73
  }
507
508
82.9k
  *l = (unsigned int)(s->data[s->getp++]) << 24;
509
82.9k
  *l |= s->data[s->getp++] << 16;
510
82.9k
  *l |= s->data[s->getp++] << 8;
511
82.9k
  *l |= s->data[s->getp++];
512
513
82.9k
  return true;
514
83.0k
}
515
516
uint32_t stream_getl(struct stream *s)
517
20.5k
{
518
20.5k
  uint32_t l;
519
520
20.5k
  STREAM_VERIFY_SANE(s);
521
522
20.5k
  if (STREAM_READABLE(s) < sizeof(uint32_t)) {
523
0
    STREAM_BOUND_WARN(s, "get long");
524
0
    return 0;
525
0
  }
526
527
20.5k
  l = (unsigned)(s->data[s->getp++]) << 24;
528
20.5k
  l |= s->data[s->getp++] << 16;
529
20.5k
  l |= s->data[s->getp++] << 8;
530
20.5k
  l |= s->data[s->getp++];
531
532
20.5k
  return l;
533
20.5k
}
534
535
/* Get next quad word from the stream. */
536
uint64_t stream_getq_from(struct stream *s, size_t from)
537
0
{
538
0
  uint64_t q;
539
540
0
  STREAM_VERIFY_SANE(s);
541
542
0
  if (!GETP_VALID(s, from + sizeof(uint64_t))) {
543
0
    STREAM_BOUND_WARN(s, "get quad");
544
0
    return 0;
545
0
  }
546
547
0
  q = ((uint64_t)s->data[from++]) << 56;
548
0
  q |= ((uint64_t)s->data[from++]) << 48;
549
0
  q |= ((uint64_t)s->data[from++]) << 40;
550
0
  q |= ((uint64_t)s->data[from++]) << 32;
551
0
  q |= ((uint64_t)s->data[from++]) << 24;
552
0
  q |= ((uint64_t)s->data[from++]) << 16;
553
0
  q |= ((uint64_t)s->data[from++]) << 8;
554
0
  q |= ((uint64_t)s->data[from++]);
555
556
0
  return q;
557
0
}
558
559
uint64_t stream_getq(struct stream *s)
560
0
{
561
0
  uint64_t q;
562
563
0
  STREAM_VERIFY_SANE(s);
564
565
0
  if (STREAM_READABLE(s) < sizeof(uint64_t)) {
566
0
    STREAM_BOUND_WARN(s, "get quad");
567
0
    return 0;
568
0
  }
569
570
0
  q = ((uint64_t)s->data[s->getp++]) << 56;
571
0
  q |= ((uint64_t)s->data[s->getp++]) << 48;
572
0
  q |= ((uint64_t)s->data[s->getp++]) << 40;
573
0
  q |= ((uint64_t)s->data[s->getp++]) << 32;
574
0
  q |= ((uint64_t)s->data[s->getp++]) << 24;
575
0
  q |= ((uint64_t)s->data[s->getp++]) << 16;
576
0
  q |= ((uint64_t)s->data[s->getp++]) << 8;
577
0
  q |= ((uint64_t)s->data[s->getp++]);
578
579
0
  return q;
580
0
}
581
582
bool stream_getq2(struct stream *s, uint64_t *q)
583
7.14k
{
584
7.14k
  STREAM_VERIFY_SANE(s);
585
586
7.14k
  if (STREAM_READABLE(s) < sizeof(uint64_t)) {
587
7
    STREAM_BOUND_WARN2(s, "get uint64");
588
7
    return false;
589
7
  }
590
591
7.13k
  *q = ((uint64_t)s->data[s->getp++]) << 56;
592
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 48;
593
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 40;
594
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 32;
595
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 24;
596
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 16;
597
7.13k
  *q |= ((uint64_t)s->data[s->getp++]) << 8;
598
7.13k
  *q |= ((uint64_t)s->data[s->getp++]);
599
600
7.13k
  return true;
601
7.14k
}
602
603
/* Get next long word from the stream. */
604
uint32_t stream_get_ipv4(struct stream *s)
605
27.8k
{
606
27.8k
  uint32_t l;
607
608
27.8k
  STREAM_VERIFY_SANE(s);
609
610
27.8k
  if (STREAM_READABLE(s) < sizeof(uint32_t)) {
611
0
    STREAM_BOUND_WARN(s, "get ipv4");
612
0
    return 0;
613
0
  }
614
615
27.8k
  memcpy(&l, s->data + s->getp, sizeof(uint32_t));
616
27.8k
  s->getp += sizeof(uint32_t);
617
618
27.8k
  return l;
619
27.8k
}
620
621
bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip)
622
7
{
623
7
  uint16_t ipa_len = 0;
624
625
7
  STREAM_VERIFY_SANE(s);
626
627
  /* Get address type. */
628
7
  if (STREAM_READABLE(s) < sizeof(uint16_t)) {
629
0
    STREAM_BOUND_WARN2(s, "get ipaddr");
630
0
    return false;
631
0
  }
632
7
  ip->ipa_type = stream_getw(s);
633
634
  /* Get address value. */
635
7
  switch (ip->ipa_type) {
636
1
  case IPADDR_V4:
637
1
    ipa_len = IPV4_MAX_BYTELEN;
638
1
    break;
639
0
  case IPADDR_V6:
640
0
    ipa_len = IPV6_MAX_BYTELEN;
641
0
    break;
642
0
  case IPADDR_NONE:
643
0
    flog_err(EC_LIB_DEVELOPMENT,
644
0
       "%s: unknown ip address-family: %u", __func__,
645
0
       ip->ipa_type);
646
0
    return false;
647
7
  }
648
7
  if (STREAM_READABLE(s) < ipa_len) {
649
0
    STREAM_BOUND_WARN2(s, "get ipaddr");
650
0
    return false;
651
0
  }
652
7
  memcpy(&ip->ip, s->data + s->getp, ipa_len);
653
7
  s->getp += ipa_len;
654
655
7
  return true;
656
7
}
657
658
float stream_getf(struct stream *s)
659
0
{
660
0
  union {
661
0
    float r;
662
0
    uint32_t d;
663
0
  } u;
664
0
  u.d = stream_getl(s);
665
0
  return u.r;
666
0
}
667
668
double stream_getd(struct stream *s)
669
0
{
670
0
  union {
671
0
    double r;
672
0
    uint64_t d;
673
0
  } u;
674
0
  u.d = stream_getq(s);
675
0
  return u.r;
676
0
}
677
678
/* Copy from source to stream.
679
 *
680
 * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
681
 * around. This should be fixed once the stream updates are working.
682
 *
683
 * stream_write() is saner
684
 */
685
void stream_put(struct stream *s, const void *src, size_t size)
686
4.26k
{
687
688
  /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
689
4.26k
  CHECK_SIZE(s, size);
690
691
4.26k
  STREAM_VERIFY_SANE(s);
692
693
4.26k
  if (STREAM_WRITEABLE(s) < size) {
694
0
    STREAM_BOUND_WARN(s, "put");
695
0
    return;
696
0
  }
697
698
4.26k
  if (src)
699
4.26k
    memcpy(s->data + s->endp, src, size);
700
0
  else
701
0
    memset(s->data + s->endp, 0, size);
702
703
4.26k
  s->endp += size;
704
4.26k
}
705
706
/* Put character to the stream. */
707
int stream_putc(struct stream *s, uint8_t c)
708
322k
{
709
322k
  STREAM_VERIFY_SANE(s);
710
711
322k
  if (STREAM_WRITEABLE(s) < sizeof(uint8_t)) {
712
0
    STREAM_BOUND_WARN(s, "put");
713
0
    return 0;
714
0
  }
715
716
322k
  s->data[s->endp++] = c;
717
322k
  return sizeof(uint8_t);
718
322k
}
719
720
/* Put word to the stream. */
721
int stream_putw(struct stream *s, uint16_t w)
722
253k
{
723
253k
  STREAM_VERIFY_SANE(s);
724
725
253k
  if (STREAM_WRITEABLE(s) < sizeof(uint16_t)) {
726
0
    STREAM_BOUND_WARN(s, "put");
727
0
    return 0;
728
0
  }
729
730
253k
  s->data[s->endp++] = (uint8_t)(w >> 8);
731
253k
  s->data[s->endp++] = (uint8_t)w;
732
733
253k
  return 2;
734
253k
}
735
736
/* Put long word to the stream. */
737
int stream_put3(struct stream *s, uint32_t l)
738
0
{
739
0
  STREAM_VERIFY_SANE(s);
740
741
0
  if (STREAM_WRITEABLE(s) < 3) {
742
0
    STREAM_BOUND_WARN(s, "put");
743
0
    return 0;
744
0
  }
745
746
0
  s->data[s->endp++] = (uint8_t)(l >> 16);
747
0
  s->data[s->endp++] = (uint8_t)(l >> 8);
748
0
  s->data[s->endp++] = (uint8_t)l;
749
750
0
  return 3;
751
0
}
752
753
/* Put long word to the stream. */
754
int stream_putl(struct stream *s, uint32_t l)
755
66.4k
{
756
66.4k
  STREAM_VERIFY_SANE(s);
757
758
66.4k
  if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
759
0
    STREAM_BOUND_WARN(s, "put");
760
0
    return 0;
761
0
  }
762
763
66.4k
  s->data[s->endp++] = (uint8_t)(l >> 24);
764
66.4k
  s->data[s->endp++] = (uint8_t)(l >> 16);
765
66.4k
  s->data[s->endp++] = (uint8_t)(l >> 8);
766
66.4k
  s->data[s->endp++] = (uint8_t)l;
767
768
66.4k
  return 4;
769
66.4k
}
770
771
/* Put quad word to the stream. */
772
int stream_putq(struct stream *s, uint64_t q)
773
0
{
774
0
  STREAM_VERIFY_SANE(s);
775
776
0
  if (STREAM_WRITEABLE(s) < sizeof(uint64_t)) {
777
0
    STREAM_BOUND_WARN(s, "put quad");
778
0
    return 0;
779
0
  }
780
781
0
  s->data[s->endp++] = (uint8_t)(q >> 56);
782
0
  s->data[s->endp++] = (uint8_t)(q >> 48);
783
0
  s->data[s->endp++] = (uint8_t)(q >> 40);
784
0
  s->data[s->endp++] = (uint8_t)(q >> 32);
785
0
  s->data[s->endp++] = (uint8_t)(q >> 24);
786
0
  s->data[s->endp++] = (uint8_t)(q >> 16);
787
0
  s->data[s->endp++] = (uint8_t)(q >> 8);
788
0
  s->data[s->endp++] = (uint8_t)q;
789
790
0
  return 8;
791
0
}
792
793
int stream_putf(struct stream *s, float f)
794
0
{
795
0
  union {
796
0
    float i;
797
0
    uint32_t o;
798
0
  } u;
799
0
  u.i = f;
800
0
  return stream_putl(s, u.o);
801
0
}
802
803
int stream_putd(struct stream *s, double d)
804
0
{
805
0
  union {
806
0
    double i;
807
0
    uint64_t o;
808
0
  } u;
809
0
  u.i = d;
810
0
  return stream_putq(s, u.o);
811
0
}
812
813
int stream_putc_at(struct stream *s, size_t putp, uint8_t c)
814
70
{
815
70
  STREAM_VERIFY_SANE(s);
816
817
70
  if (!PUT_AT_VALID(s, putp + sizeof(uint8_t))) {
818
0
    STREAM_BOUND_WARN(s, "put");
819
0
    return 0;
820
0
  }
821
822
70
  s->data[putp] = c;
823
824
70
  return 1;
825
70
}
826
827
int stream_putw_at(struct stream *s, size_t putp, uint16_t w)
828
63.5k
{
829
63.5k
  STREAM_VERIFY_SANE(s);
830
831
63.5k
  if (!PUT_AT_VALID(s, putp + sizeof(uint16_t))) {
832
0
    STREAM_BOUND_WARN(s, "put");
833
0
    return 0;
834
0
  }
835
836
63.5k
  s->data[putp] = (uint8_t)(w >> 8);
837
63.5k
  s->data[putp + 1] = (uint8_t)w;
838
839
63.5k
  return 2;
840
63.5k
}
841
842
int stream_put3_at(struct stream *s, size_t putp, uint32_t l)
843
0
{
844
0
  STREAM_VERIFY_SANE(s);
845
846
0
  if (!PUT_AT_VALID(s, putp + 3)) {
847
0
    STREAM_BOUND_WARN(s, "put");
848
0
    return 0;
849
0
  }
850
0
  s->data[putp] = (uint8_t)(l >> 16);
851
0
  s->data[putp + 1] = (uint8_t)(l >> 8);
852
0
  s->data[putp + 2] = (uint8_t)l;
853
854
0
  return 3;
855
0
}
856
857
int stream_putl_at(struct stream *s, size_t putp, uint32_t l)
858
0
{
859
0
  STREAM_VERIFY_SANE(s);
860
861
0
  if (!PUT_AT_VALID(s, putp + sizeof(uint32_t))) {
862
0
    STREAM_BOUND_WARN(s, "put");
863
0
    return 0;
864
0
  }
865
0
  s->data[putp] = (uint8_t)(l >> 24);
866
0
  s->data[putp + 1] = (uint8_t)(l >> 16);
867
0
  s->data[putp + 2] = (uint8_t)(l >> 8);
868
0
  s->data[putp + 3] = (uint8_t)l;
869
870
0
  return 4;
871
0
}
872
873
int stream_putq_at(struct stream *s, size_t putp, uint64_t q)
874
0
{
875
0
  STREAM_VERIFY_SANE(s);
876
877
0
  if (!PUT_AT_VALID(s, putp + sizeof(uint64_t))) {
878
0
    STREAM_BOUND_WARN(s, "put");
879
0
    return 0;
880
0
  }
881
0
  s->data[putp] = (uint8_t)(q >> 56);
882
0
  s->data[putp + 1] = (uint8_t)(q >> 48);
883
0
  s->data[putp + 2] = (uint8_t)(q >> 40);
884
0
  s->data[putp + 3] = (uint8_t)(q >> 32);
885
0
  s->data[putp + 4] = (uint8_t)(q >> 24);
886
0
  s->data[putp + 5] = (uint8_t)(q >> 16);
887
0
  s->data[putp + 6] = (uint8_t)(q >> 8);
888
0
  s->data[putp + 7] = (uint8_t)q;
889
890
0
  return 8;
891
0
}
892
893
/* Put long word to the stream. */
894
int stream_put_ipv4(struct stream *s, uint32_t l)
895
246
{
896
246
  STREAM_VERIFY_SANE(s);
897
898
246
  if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
899
0
    STREAM_BOUND_WARN(s, "put");
900
0
    return 0;
901
0
  }
902
246
  memcpy(s->data + s->endp, &l, sizeof(uint32_t));
903
246
  s->endp += sizeof(uint32_t);
904
905
246
  return sizeof(uint32_t);
906
246
}
907
908
/* Put long word to the stream. */
909
int stream_put_in_addr(struct stream *s, const struct in_addr *addr)
910
62.6k
{
911
62.6k
  STREAM_VERIFY_SANE(s);
912
913
62.6k
  if (STREAM_WRITEABLE(s) < sizeof(uint32_t)) {
914
0
    STREAM_BOUND_WARN(s, "put");
915
0
    return 0;
916
0
  }
917
918
62.6k
  memcpy(s->data + s->endp, addr, sizeof(uint32_t));
919
62.6k
  s->endp += sizeof(uint32_t);
920
921
62.6k
  return sizeof(uint32_t);
922
62.6k
}
923
924
bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip)
925
2
{
926
2
  stream_putw(s, ip->ipa_type);
927
928
2
  switch (ip->ipa_type) {
929
0
  case IPADDR_V4:
930
0
    stream_put_in_addr(s, &ip->ipaddr_v4);
931
0
    break;
932
0
  case IPADDR_V6:
933
0
    stream_write(s, (uint8_t *)&ip->ipaddr_v6, 16);
934
0
    break;
935
0
  case IPADDR_NONE:
936
0
    flog_err(EC_LIB_DEVELOPMENT,
937
0
       "%s: unknown ip address-family: %u", __func__,
938
0
       ip->ipa_type);
939
0
    return false;
940
2
  }
941
942
2
  return true;
943
2
}
944
945
/* Put in_addr at location in the stream. */
946
int stream_put_in_addr_at(struct stream *s, size_t putp,
947
        const struct in_addr *addr)
948
0
{
949
0
  STREAM_VERIFY_SANE(s);
950
951
0
  if (!PUT_AT_VALID(s, putp + 4)) {
952
0
    STREAM_BOUND_WARN(s, "put");
953
0
    return 0;
954
0
  }
955
956
0
  memcpy(&s->data[putp], addr, 4);
957
0
  return 4;
958
0
}
959
960
/* Put in6_addr at location in the stream. */
961
int stream_put_in6_addr_at(struct stream *s, size_t putp,
962
         const struct in6_addr *addr)
963
0
{
964
0
  STREAM_VERIFY_SANE(s);
965
966
0
  if (!PUT_AT_VALID(s, putp + 16)) {
967
0
    STREAM_BOUND_WARN(s, "put");
968
0
    return 0;
969
0
  }
970
971
0
  memcpy(&s->data[putp], addr, 16);
972
0
  return 16;
973
0
}
974
975
/* Put prefix by nlri type format. */
976
int stream_put_prefix_addpath(struct stream *s, const struct prefix *p,
977
            bool addpath_capable, uint32_t addpath_tx_id)
978
1.19k
{
979
1.19k
  size_t psize;
980
1.19k
  size_t psize_with_addpath;
981
982
1.19k
  STREAM_VERIFY_SANE(s);
983
984
1.19k
  psize = PSIZE(p->prefixlen);
985
986
1.19k
  if (addpath_capable)
987
0
    psize_with_addpath = psize + 4;
988
1.19k
  else
989
1.19k
    psize_with_addpath = psize;
990
991
1.19k
  if (STREAM_WRITEABLE(s) < (psize_with_addpath + sizeof(uint8_t))) {
992
0
    STREAM_BOUND_WARN(s, "put");
993
0
    return 0;
994
0
  }
995
996
1.19k
  if (addpath_capable) {
997
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
998
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
999
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
1000
0
    s->data[s->endp++] = (uint8_t)addpath_tx_id;
1001
0
  }
1002
1003
1.19k
  s->data[s->endp++] = p->prefixlen;
1004
1.19k
  memcpy(s->data + s->endp, &p->u.prefix, psize);
1005
1.19k
  s->endp += psize;
1006
1007
1.19k
  return psize;
1008
1.19k
}
1009
1010
int stream_put_prefix(struct stream *s, const struct prefix *p)
1011
1.19k
{
1012
1.19k
  return stream_put_prefix_addpath(s, p, 0, 0);
1013
1.19k
}
1014
1015
/* Put NLRI with label */
1016
int stream_put_labeled_prefix(struct stream *s, const struct prefix *p,
1017
            mpls_label_t *label, bool addpath_capable,
1018
            uint32_t addpath_tx_id)
1019
0
{
1020
0
  size_t psize;
1021
0
  size_t psize_with_addpath;
1022
0
  uint8_t *label_pnt = (uint8_t *)label;
1023
1024
0
  STREAM_VERIFY_SANE(s);
1025
1026
0
  psize = PSIZE(p->prefixlen);
1027
0
  psize_with_addpath = psize + (addpath_capable ? 4 : 0);
1028
1029
0
  if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) {
1030
0
    STREAM_BOUND_WARN(s, "put");
1031
0
    return 0;
1032
0
  }
1033
1034
0
  if (addpath_capable) {
1035
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
1036
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
1037
0
    s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
1038
0
    s->data[s->endp++] = (uint8_t)addpath_tx_id;
1039
0
  }
1040
1041
0
  stream_putc(s, (p->prefixlen + 24));
1042
0
  stream_putc(s, label_pnt[0]);
1043
0
  stream_putc(s, label_pnt[1]);
1044
0
  stream_putc(s, label_pnt[2]);
1045
0
  memcpy(s->data + s->endp, &p->u.prefix, psize);
1046
0
  s->endp += psize;
1047
1048
0
  return (psize + 3);
1049
0
}
1050
1051
/* Read size from fd. */
1052
int stream_read(struct stream *s, int fd, size_t size)
1053
0
{
1054
0
  int nbytes;
1055
1056
0
  STREAM_VERIFY_SANE(s);
1057
1058
0
  if (STREAM_WRITEABLE(s) < size) {
1059
0
    STREAM_BOUND_WARN(s, "put");
1060
0
    return 0;
1061
0
  }
1062
1063
0
  nbytes = readn(fd, s->data + s->endp, size);
1064
1065
0
  if (nbytes > 0)
1066
0
    s->endp += nbytes;
1067
1068
0
  return nbytes;
1069
0
}
1070
1071
ssize_t stream_read_try(struct stream *s, int fd, size_t size)
1072
0
{
1073
0
  ssize_t nbytes;
1074
1075
0
  STREAM_VERIFY_SANE(s);
1076
1077
0
  if (STREAM_WRITEABLE(s) < size) {
1078
0
    STREAM_BOUND_WARN(s, "put");
1079
    /* Fatal (not transient) error, since retrying will not help
1080
       (stream is too small to contain the desired data). */
1081
0
    return -1;
1082
0
  }
1083
1084
0
  nbytes = read(fd, s->data + s->endp, size);
1085
0
  if (nbytes >= 0) {
1086
0
    s->endp += nbytes;
1087
0
    return nbytes;
1088
0
  }
1089
  /* Error: was it transient (return -2) or fatal (return -1)? */
1090
0
  if (ERRNO_IO_RETRY(errno))
1091
0
    return -2;
1092
0
  flog_err(EC_LIB_SOCKET, "%s: read failed on fd %d: %s", __func__, fd,
1093
0
     safe_strerror(errno));
1094
0
  return -1;
1095
0
}
1096
1097
/* Read up to size bytes into the stream from the fd, using recvmsgfrom
1098
 * whose arguments match the remaining arguments to this function
1099
 */
1100
ssize_t stream_recvfrom(struct stream *s, int fd, size_t size, int flags,
1101
      struct sockaddr *from, socklen_t *fromlen)
1102
0
{
1103
0
  ssize_t nbytes;
1104
1105
0
  STREAM_VERIFY_SANE(s);
1106
1107
0
  if (STREAM_WRITEABLE(s) < size) {
1108
0
    STREAM_BOUND_WARN(s, "put");
1109
    /* Fatal (not transient) error, since retrying will not help
1110
       (stream is too small to contain the desired data). */
1111
0
    return -1;
1112
0
  }
1113
1114
0
  nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, fromlen);
1115
0
  if (nbytes >= 0) {
1116
0
    s->endp += nbytes;
1117
0
    return nbytes;
1118
0
  }
1119
  /* Error: was it transient (return -2) or fatal (return -1)? */
1120
0
  if (ERRNO_IO_RETRY(errno))
1121
0
    return -2;
1122
0
  flog_err(EC_LIB_SOCKET, "%s: read failed on fd %d: %s", __func__, fd,
1123
0
     safe_strerror(errno));
1124
0
  return -1;
1125
0
}
1126
1127
/* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
1128
 * from endp.
1129
 * First iovec will be used to receive the data.
1130
 * Stream need not be empty.
1131
 */
1132
ssize_t stream_recvmsg(struct stream *s, int fd, struct msghdr *msgh, int flags,
1133
           size_t size)
1134
0
{
1135
0
  int nbytes;
1136
0
  struct iovec *iov;
1137
1138
0
  STREAM_VERIFY_SANE(s);
1139
0
  assert(msgh->msg_iovlen > 0);
1140
1141
0
  if (STREAM_WRITEABLE(s) < size) {
1142
0
    STREAM_BOUND_WARN(s, "put");
1143
    /* This is a logic error in the calling code: the stream is too
1144
       small
1145
       to hold the desired data! */
1146
0
    return -1;
1147
0
  }
1148
1149
0
  iov = &(msgh->msg_iov[0]);
1150
0
  iov->iov_base = (s->data + s->endp);
1151
0
  iov->iov_len = size;
1152
1153
0
  nbytes = recvmsg(fd, msgh, flags);
1154
1155
0
  if (nbytes > 0)
1156
0
    s->endp += nbytes;
1157
1158
0
  return nbytes;
1159
0
}
1160
1161
/* Write data to buffer. */
1162
size_t stream_write(struct stream *s, const void *ptr, size_t size)
1163
122
{
1164
1165
122
  CHECK_SIZE(s, size);
1166
1167
122
  STREAM_VERIFY_SANE(s);
1168
1169
122
  if (STREAM_WRITEABLE(s) < size) {
1170
0
    STREAM_BOUND_WARN(s, "put");
1171
0
    return 0;
1172
0
  }
1173
1174
122
  memcpy(s->data + s->endp, ptr, size);
1175
122
  s->endp += size;
1176
1177
122
  return size;
1178
122
}
1179
1180
/* Return current read pointer.
1181
 * DEPRECATED!
1182
 * Use stream_get_pnt_to if you must, but decoding streams properly
1183
 * is preferred
1184
 */
1185
uint8_t *stream_pnt(struct stream *s)
1186
73.3k
{
1187
73.3k
  STREAM_VERIFY_SANE(s);
1188
73.3k
  return s->data + s->getp;
1189
73.3k
}
1190
1191
/* Check does this stream empty? */
1192
int stream_empty(struct stream *s)
1193
0
{
1194
0
  STREAM_VERIFY_SANE(s);
1195
1196
0
  return (s->endp == 0);
1197
0
}
1198
1199
/* Reset stream. */
1200
void stream_reset(struct stream *s)
1201
60.8k
{
1202
60.8k
  STREAM_VERIFY_SANE(s);
1203
1204
60.8k
  s->getp = s->endp = 0;
1205
60.8k
}
1206
1207
/* Write stream contens to the file discriptor. */
1208
int stream_flush(struct stream *s, int fd)
1209
0
{
1210
0
  int nbytes;
1211
1212
0
  STREAM_VERIFY_SANE(s);
1213
1214
0
  nbytes = write(fd, s->data + s->getp, s->endp - s->getp);
1215
1216
0
  return nbytes;
1217
0
}
1218
1219
void stream_hexdump(const struct stream *s)
1220
0
{
1221
0
  zlog_hexdump(s->data, s->endp);
1222
0
}
1223
1224
/* Stream first in first out queue. */
1225
1226
struct stream_fifo *stream_fifo_new(void)
1227
559
{
1228
559
  struct stream_fifo *new;
1229
1230
559
  new = XMALLOC(MTYPE_STREAM_FIFO, sizeof(struct stream_fifo));
1231
559
  stream_fifo_init(new);
1232
559
  return new;
1233
559
}
1234
1235
void stream_fifo_init(struct stream_fifo *fifo)
1236
835
{
1237
835
  memset(fifo, 0, sizeof(struct stream_fifo));
1238
835
  pthread_mutex_init(&fifo->mtx, NULL);
1239
835
}
1240
1241
/* Add new stream to fifo. */
1242
void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
1243
740
{
1244
#if defined DEV_BUILD
1245
  size_t max, curmax;
1246
#endif
1247
1248
740
  if (fifo->tail)
1249
2
    fifo->tail->next = s;
1250
738
  else
1251
738
    fifo->head = s;
1252
1253
740
  fifo->tail = s;
1254
740
  fifo->tail->next = NULL;
1255
740
#if !defined DEV_BUILD
1256
740
  atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
1257
#else
1258
  max = atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
1259
  curmax = atomic_load_explicit(&fifo->max_count, memory_order_relaxed);
1260
  if (max > curmax)
1261
    atomic_store_explicit(&fifo->max_count, max,
1262
              memory_order_relaxed);
1263
#endif
1264
740
}
1265
1266
void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
1267
0
{
1268
0
  frr_with_mutex (&fifo->mtx) {
1269
0
    stream_fifo_push(fifo, s);
1270
0
  }
1271
0
}
1272
1273
/* Delete first stream from fifo. */
1274
struct stream *stream_fifo_pop(struct stream_fifo *fifo)
1275
280
{
1276
280
  struct stream *s;
1277
1278
280
  s = fifo->head;
1279
1280
280
  if (s) {
1281
278
    fifo->head = s->next;
1282
1283
278
    if (fifo->head == NULL)
1284
278
      fifo->tail = NULL;
1285
1286
278
    atomic_fetch_sub_explicit(&fifo->count, 1,
1287
278
            memory_order_release);
1288
1289
    /* ensure stream is scrubbed of references to this fifo */
1290
278
    s->next = NULL;
1291
278
  }
1292
1293
280
  return s;
1294
280
}
1295
1296
struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo)
1297
0
{
1298
0
  struct stream *ret;
1299
1300
0
  frr_with_mutex (&fifo->mtx) {
1301
0
    ret = stream_fifo_pop(fifo);
1302
0
  }
1303
1304
0
  return ret;
1305
0
}
1306
1307
struct stream *stream_fifo_head(struct stream_fifo *fifo)
1308
828
{
1309
828
  return fifo->head;
1310
828
}
1311
1312
struct stream *stream_fifo_head_safe(struct stream_fifo *fifo)
1313
0
{
1314
0
  struct stream *ret;
1315
1316
0
  frr_with_mutex (&fifo->mtx) {
1317
0
    ret = stream_fifo_head(fifo);
1318
0
  }
1319
1320
0
  return ret;
1321
0
}
1322
1323
void stream_fifo_clean(struct stream_fifo *fifo)
1324
1.28k
{
1325
1.28k
  struct stream *s;
1326
1.28k
  struct stream *next;
1327
1328
1.74k
  for (s = fifo->head; s; s = next) {
1329
459
    next = s->next;
1330
459
    stream_free(s);
1331
459
  }
1332
1.28k
  fifo->head = fifo->tail = NULL;
1333
1.28k
  atomic_store_explicit(&fifo->count, 0, memory_order_release);
1334
1.28k
}
1335
1336
void stream_fifo_clean_safe(struct stream_fifo *fifo)
1337
0
{
1338
0
  frr_with_mutex (&fifo->mtx) {
1339
0
    stream_fifo_clean(fifo);
1340
0
  }
1341
0
}
1342
1343
size_t stream_fifo_count_safe(struct stream_fifo *fifo)
1344
2
{
1345
2
  return atomic_load_explicit(&fifo->count, memory_order_acquire);
1346
2
}
1347
1348
void stream_fifo_deinit(struct stream_fifo *fifo)
1349
828
{
1350
828
  stream_fifo_clean(fifo);
1351
828
  pthread_mutex_destroy(&fifo->mtx);
1352
828
}
1353
1354
void stream_fifo_free(struct stream_fifo *fifo)
1355
552
{
1356
552
  stream_fifo_deinit(fifo);
1357
552
  XFREE(MTYPE_STREAM_FIFO, fifo);
1358
552
}
1359
1360
void stream_pulldown(struct stream *s)
1361
0
{
1362
0
  size_t rlen = STREAM_READABLE(s);
1363
1364
  /* No more data, so just move the pointers. */
1365
0
  if (rlen == 0) {
1366
0
    stream_reset(s);
1367
0
    return;
1368
0
  }
1369
1370
  /* Move the available data to the beginning. */
1371
0
  memmove(s->data, &s->data[s->getp], rlen);
1372
0
  s->getp = 0;
1373
0
  s->endp = rlen;
1374
0
}