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