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