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