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