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