]> git.proxmox.com Git - mirror_frr.git/blame - lib/stream.c
2005-04-29 Paul Jakma <paul.jakma@sun.com>
[mirror_frr.git] / lib / stream.c
CommitLineData
050c013a 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 *
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 */
22
050c013a 23#include <stddef.h>
718e3744 24#include <zebra.h>
25
26#include "stream.h"
27#include "memory.h"
28#include "network.h"
29#include "prefix.h"
050c013a 30#include "log.h"
718e3744 31
050c013a 32/* Tests whether a position is valid */
33#define GETP_VALID(S,G) \
34 ((G) <= (S)->endp)
35#define PUT_AT_VALID(S,G) GETP_VALID(S,G)
36#define ENDP_VALID(S,E) \
37 ((E) <= (S)->size)
718e3744 38
050c013a 39/* asserting sanity checks. Following must be true before
40 * stream functions are called:
41 *
42 * Following must always be true of stream elements
43 * before and after calls to stream functions:
44 *
45 * getp <= endp <= size
46 *
47 * Note that after a stream function is called following may be true:
48 * if (getp == endp) then stream is no longer readable
49 * if (endp == size) then stream is no longer writeable
50 *
51 * It is valid to put to anywhere within the size of the stream, but only
52 * using stream_put..._at() functions.
53 */
54#define STREAM_WARN_OFFSETS(S) \
55 zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \
56 (S), \
57 (unsigned long) (S)->size, \
58 (unsigned long) (S)->getp, \
59 (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__, (WHAT)); \
72 STREAM_WARN_OFFSETS(S); \
73 assert (0); \
74 } while (0)
75
76/* XXX: Deprecated macro: do not use */
718e3744 77#define CHECK_SIZE(S, Z) \
050c013a 78 do { \
79 if (((S)->endp + (Z)) > (S)->size) \
80 { \
81 zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \
82 (unsigned long) (Z)); \
83 STREAM_WARN_OFFSETS(S); \
84 (Z) = (S)->size - (S)->endp; \
85 } \
86 } while (0);
718e3744 87
88/* Make stream buffer. */
89struct stream *
90stream_new (size_t size)
91{
92 struct stream *s;
93
0e43a2bc 94 assert (size > 0);
95
96 if (size == 0)
050c013a 97 {
98 zlog_warn ("stream_new(): called with 0 size!");
99 return NULL;
100 }
0e43a2bc 101
109ac96f 102 s = XCALLOC (MTYPE_STREAM, offsetof(struct stream, data[size]));
718e3744 103
050c013a 104 if (s == NULL)
105 return s;
106
718e3744 107 s->size = size;
108 return s;
109}
110
111/* Free it now. */
112void
113stream_free (struct stream *s)
114{
718e3744 115 XFREE (MTYPE_STREAM, s);
116}
050c013a 117
118struct stream *
119stream_copy (struct stream *new, struct stream *src)
120{
121 STREAM_VERIFY_SANE (src);
122
123 assert (new != NULL);
124 assert (STREAM_SIZE(new) >= src->endp);
125
126 new->endp = src->endp;
127 new->getp = src->getp;
128
129 memcpy (new->data, src->data, src->endp);
130
131 return new;
132}
133
134struct stream *
135stream_dup (struct stream *s)
136{
137 struct stream *new;
138
139 STREAM_VERIFY_SANE (s);
140
141 if ( (new = stream_new (s->endp)) == NULL)
142 return NULL;
143
144 return (stream_copy (new, s));
145}
718e3744 146\f
f2e6c429 147size_t
718e3744 148stream_get_getp (struct stream *s)
149{
050c013a 150 STREAM_VERIFY_SANE(s);
718e3744 151 return s->getp;
152}
153
f2e6c429 154size_t
718e3744 155stream_get_endp (struct stream *s)
156{
050c013a 157 STREAM_VERIFY_SANE(s);
718e3744 158 return s->endp;
159}
160
f2e6c429 161size_t
718e3744 162stream_get_size (struct stream *s)
163{
050c013a 164 STREAM_VERIFY_SANE(s);
718e3744 165 return s->size;
166}
167
168/* Stream structre' stream pointer related functions. */
169void
f2e6c429 170stream_set_getp (struct stream *s, size_t pos)
718e3744 171{
050c013a 172 STREAM_VERIFY_SANE(s);
173
174 if (!GETP_VALID (s, pos))
175 {
176 STREAM_BOUND_WARN (s, "set getp");
177 pos = s->endp;
178 }
179
718e3744 180 s->getp = pos;
181}
182
9985f83c 183/* Forward pointer. */
718e3744 184void
050c013a 185stream_forward_getp (struct stream *s, size_t size)
718e3744 186{
050c013a 187 STREAM_VERIFY_SANE(s);
188
189 if (!GETP_VALID (s, s->getp + size))
190 {
191 STREAM_BOUND_WARN (s, "seek getp");
192 return;
193 }
194
9985f83c 195 s->getp += size;
718e3744 196}
197
718e3744 198void
050c013a 199stream_forward_endp (struct stream *s, size_t size)
718e3744 200{
050c013a 201 STREAM_VERIFY_SANE(s);
202
203 if (!ENDP_VALID (s, s->endp + size))
204 {
205 STREAM_BOUND_WARN (s, "seek endp");
206 return;
207 }
208
9985f83c 209 s->endp += size;
718e3744 210}
211\f
212/* Copy from stream to destination. */
213void
214stream_get (void *dst, struct stream *s, size_t size)
215{
050c013a 216 STREAM_VERIFY_SANE(s);
217
218 if (STREAM_READABLE(s) < size)
219 {
220 STREAM_BOUND_WARN (s, "get");
221 return;
222 }
223
718e3744 224 memcpy (dst, s->data + s->getp, size);
225 s->getp += size;
226}
227
228/* Get next character from the stream. */
229u_char
230stream_getc (struct stream *s)
231{
232 u_char c;
050c013a 233
234 STREAM_VERIFY_SANE (s);
235
236 if (STREAM_READABLE(s) < sizeof (u_char))
237 {
238 STREAM_BOUND_WARN (s, "get char");
239 return 0;
240 }
241 c = s->data[s->getp++];
242
718e3744 243 return c;
244}
245
246/* Get next character from the stream. */
247u_char
f2e6c429 248stream_getc_from (struct stream *s, size_t from)
718e3744 249{
250 u_char c;
251
050c013a 252 STREAM_VERIFY_SANE(s);
253
254 if (!GETP_VALID (s, from + sizeof (u_char)))
255 {
256 STREAM_BOUND_WARN (s, "get char");
257 return 0;
258 }
259
718e3744 260 c = s->data[from];
050c013a 261
718e3744 262 return c;
263}
264
265/* Get next word from the stream. */
266u_int16_t
267stream_getw (struct stream *s)
268{
269 u_int16_t w;
270
050c013a 271 STREAM_VERIFY_SANE (s);
272
273 if (STREAM_READABLE (s) < sizeof (u_int16_t))
274 {
275 STREAM_BOUND_WARN (s, "get ");
276 return 0;
277 }
278
718e3744 279 w = s->data[s->getp++] << 8;
280 w |= s->data[s->getp++];
050c013a 281
718e3744 282 return w;
283}
284
285/* Get next word from the stream. */
286u_int16_t
f2e6c429 287stream_getw_from (struct stream *s, size_t from)
718e3744 288{
289 u_int16_t w;
290
050c013a 291 STREAM_VERIFY_SANE(s);
292
293 if (!GETP_VALID (s, from + sizeof (u_int16_t)))
294 {
295 STREAM_BOUND_WARN (s, "get ");
296 return 0;
297 }
298
718e3744 299 w = s->data[from++] << 8;
300 w |= s->data[from];
050c013a 301
718e3744 302 return w;
303}
304
305/* Get next long word from the stream. */
050c013a 306u_int32_t
307stream_getl_from (struct stream *s, size_t from)
308{
309 u_int32_t l;
310
311 STREAM_VERIFY_SANE(s);
312
313 if (!GETP_VALID (s, from + sizeof (u_int32_t)))
314 {
315 STREAM_BOUND_WARN (s, "get long");
316 return 0;
317 }
318
319 l = s->data[from++] << 24;
320 l |= s->data[from++] << 16;
321 l |= s->data[from++] << 8;
322 l |= s->data[from];
323
324 return l;
325}
326
718e3744 327u_int32_t
328stream_getl (struct stream *s)
329{
330 u_int32_t l;
331
050c013a 332 STREAM_VERIFY_SANE(s);
333
334 if (STREAM_READABLE (s) < sizeof (u_int32_t))
335 {
336 STREAM_BOUND_WARN (s, "get long");
337 return 0;
338 }
339
718e3744 340 l = s->data[s->getp++] << 24;
341 l |= s->data[s->getp++] << 16;
342 l |= s->data[s->getp++] << 8;
343 l |= s->data[s->getp++];
050c013a 344
718e3744 345 return l;
346}
718e3744 347/* Get next long word from the stream. */
348u_int32_t
349stream_get_ipv4 (struct stream *s)
350{
351 u_int32_t l;
352
050c013a 353 STREAM_VERIFY_SANE(s);
354
355 if (STREAM_READABLE (s) < sizeof(u_int32_t))
356 {
357 STREAM_BOUND_WARN (s, "get ipv4");
358 return 0;
359 }
360
361 memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
362 s->getp += sizeof(u_int32_t);
718e3744 363
364 return l;
365}
366\f
050c013a 367/* Copy to source to stream.
368 *
369 * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
370 * around. This should be fixed once the stream updates are working.
371 */
718e3744 372void
373stream_put (struct stream *s, void *src, size_t size)
374{
375
050c013a 376 /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
718e3744 377 CHECK_SIZE(s, size);
050c013a 378
379 STREAM_VERIFY_SANE(s);
380
381 if (STREAM_WRITEABLE (s) < size)
382 {
383 STREAM_BOUND_WARN (s, "put");
384 return;
385 }
386
718e3744 387 if (src)
9985f83c 388 memcpy (s->data + s->endp, src, size);
718e3744 389 else
9985f83c 390 memset (s->data + s->endp, 0, size);
718e3744 391
9985f83c 392 s->endp += size;
718e3744 393}
394
395/* Put character to the stream. */
396int
397stream_putc (struct stream *s, u_char c)
398{
050c013a 399 STREAM_VERIFY_SANE(s);
400
401 if (STREAM_WRITEABLE (s) < sizeof(u_char))
402 {
403 STREAM_BOUND_WARN (s, "put");
404 return 0;
405 }
406
407 s->data[s->endp++] = c;
408 return sizeof (u_char);
718e3744 409}
410
411/* Put word to the stream. */
412int
413stream_putw (struct stream *s, u_int16_t w)
414{
050c013a 415 STREAM_VERIFY_SANE (s);
718e3744 416
050c013a 417 if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
418 {
419 STREAM_BOUND_WARN (s, "put");
420 return 0;
421 }
422
9985f83c 423 s->data[s->endp++] = (u_char)(w >> 8);
424 s->data[s->endp++] = (u_char) w;
718e3744 425
718e3744 426 return 2;
427}
428
429/* Put long word to the stream. */
430int
431stream_putl (struct stream *s, u_int32_t l)
432{
050c013a 433 STREAM_VERIFY_SANE (s);
718e3744 434
050c013a 435 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
436 {
437 STREAM_BOUND_WARN (s, "put");
438 return 0;
439 }
440
9985f83c 441 s->data[s->endp++] = (u_char)(l >> 24);
442 s->data[s->endp++] = (u_char)(l >> 16);
443 s->data[s->endp++] = (u_char)(l >> 8);
444 s->data[s->endp++] = (u_char)l;
718e3744 445
718e3744 446 return 4;
447}
448
449int
f2e6c429 450stream_putc_at (struct stream *s, size_t putp, u_char c)
718e3744 451{
050c013a 452 STREAM_VERIFY_SANE(s);
453
454 if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
455 {
456 STREAM_BOUND_WARN (s, "put");
457 return 0;
458 }
459
718e3744 460 s->data[putp] = c;
050c013a 461
718e3744 462 return 1;
463}
464
465int
f2e6c429 466stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
718e3744 467{
050c013a 468 STREAM_VERIFY_SANE(s);
469
470 if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
471 {
472 STREAM_BOUND_WARN (s, "put");
473 return 0;
474 }
475
718e3744 476 s->data[putp] = (u_char)(w >> 8);
477 s->data[putp + 1] = (u_char) w;
050c013a 478
718e3744 479 return 2;
480}
481
482int
f2e6c429 483stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
718e3744 484{
050c013a 485 STREAM_VERIFY_SANE(s);
486
487 if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
488 {
489 STREAM_BOUND_WARN (s, "put");
490 return 0;
491 }
718e3744 492 s->data[putp] = (u_char)(l >> 24);
493 s->data[putp + 1] = (u_char)(l >> 16);
494 s->data[putp + 2] = (u_char)(l >> 8);
495 s->data[putp + 3] = (u_char)l;
050c013a 496
718e3744 497 return 4;
498}
499
500/* Put long word to the stream. */
501int
502stream_put_ipv4 (struct stream *s, u_int32_t l)
503{
050c013a 504 STREAM_VERIFY_SANE(s);
505
506 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
507 {
508 STREAM_BOUND_WARN (s, "put");
509 return 0;
510 }
511 memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
512 s->endp += sizeof (u_int32_t);
718e3744 513
050c013a 514 return sizeof (u_int32_t);
718e3744 515}
516
517/* Put long word to the stream. */
518int
519stream_put_in_addr (struct stream *s, struct in_addr *addr)
520{
050c013a 521 STREAM_VERIFY_SANE(s);
522
523 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
524 {
525 STREAM_BOUND_WARN (s, "put");
526 return 0;
527 }
718e3744 528
050c013a 529 memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
530 s->endp += sizeof (u_int32_t);
718e3744 531
050c013a 532 return sizeof (u_int32_t);
718e3744 533}
534
535/* Put prefix by nlri type format. */
536int
537stream_put_prefix (struct stream *s, struct prefix *p)
538{
050c013a 539 size_t psize;
540
541 STREAM_VERIFY_SANE(s);
542
718e3744 543 psize = PSIZE (p->prefixlen);
050c013a 544
545 if (STREAM_WRITEABLE (s) < psize)
546 {
547 STREAM_BOUND_WARN (s, "put");
548 return 0;
549 }
550
718e3744 551 stream_putc (s, p->prefixlen);
9985f83c 552 memcpy (s->data + s->endp, &p->u.prefix, psize);
553 s->endp += psize;
718e3744 554
718e3744 555 return psize;
556}
557\f
558/* Read size from fd. */
559int
560stream_read (struct stream *s, int fd, size_t size)
561{
562 int nbytes;
563
050c013a 564 STREAM_VERIFY_SANE(s);
565
566 if (STREAM_WRITEABLE (s) < size)
567 {
568 STREAM_BOUND_WARN (s, "put");
569 return 0;
570 }
571
9985f83c 572 nbytes = readn (fd, s->data + s->endp, size);
718e3744 573
574 if (nbytes > 0)
9985f83c 575 s->endp += nbytes;
576
718e3744 577 return nbytes;
578}
579
580/* Read size from fd. */
581int
582stream_read_unblock (struct stream *s, int fd, size_t size)
583{
584 int nbytes;
585 int val;
050c013a 586
587 STREAM_VERIFY_SANE(s);
588
589 if (STREAM_WRITEABLE (s) < size)
590 {
591 STREAM_BOUND_WARN (s, "put");
592 return 0;
593 }
594
718e3744 595 val = fcntl (fd, F_GETFL, 0);
596 fcntl (fd, F_SETFL, val|O_NONBLOCK);
9985f83c 597 nbytes = read (fd, s->data + s->endp, size);
718e3744 598 fcntl (fd, F_SETFL, val);
599
600 if (nbytes > 0)
9985f83c 601 s->endp += nbytes;
602
718e3744 603 return nbytes;
604}
605
262feb1a 606ssize_t
607stream_read_try(struct stream *s, int fd, size_t size)
608{
609 ssize_t nbytes;
610
611 STREAM_VERIFY_SANE(s);
612
613 if (STREAM_WRITEABLE(s) < size)
614 {
615 STREAM_BOUND_WARN (s, "put");
616 /* Fatal (not transient) error, since retrying will not help
617 (stream is too small to contain the desired data). */
618 return -1;
619 }
620
621 if ((nbytes = read(fd, s->data + s->endp, size)) >= 0)
622 {
623 s->endp += nbytes;
624 return nbytes;
625 }
626 /* Error: was it transient (return -2) or fatal (return -1)? */
81fb3240 627 if (ERRNO_IO_RETRY(errno))
628 return -2;
629 zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
630 return -1;
262feb1a 631}
632
050c013a 633/* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
634 * from endp.
635 * First iovec will be used to receive the data.
636 * Stream need not be empty.
637 */
638int
639stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags,
640 size_t size)
641{
642 int nbytes;
643 struct iovec *iov;
644
645 STREAM_VERIFY_SANE(s);
646 assert (msgh->msg_iovlen > 0);
647
648 if (STREAM_WRITEABLE (s) < size)
649 {
650 STREAM_BOUND_WARN (s, "put");
262feb1a 651 /* This is a logic error in the calling code: the stream is too small
652 to hold the desired data! */
653 return -1;
050c013a 654 }
655
656 iov = &(msgh->msg_iov[0]);
657 iov->iov_base = (s->data + s->endp);
658 iov->iov_len = size;
659
660 nbytes = recvmsg (fd, msgh, flags);
661
662 if (nbytes > 0)
663 s->endp += nbytes;
664
665 return nbytes;
666}
667
718e3744 668/* Write data to buffer. */
669int
670stream_write (struct stream *s, u_char *ptr, size_t size)
671{
672
673 CHECK_SIZE(s, size);
674
050c013a 675 STREAM_VERIFY_SANE(s);
676
677 if (STREAM_WRITEABLE (s) < size)
678 {
679 STREAM_BOUND_WARN (s, "put");
680 return 0;
681 }
682
9985f83c 683 memcpy (s->data + s->endp, ptr, size);
684 s->endp += size;
685
718e3744 686 return size;
687}
688
050c013a 689/* Return current read pointer.
690 * DEPRECATED!
691 * Use stream_get_pnt_to if you must, but decoding streams properly
692 * is preferred
693 */
718e3744 694u_char *
695stream_pnt (struct stream *s)
696{
050c013a 697 STREAM_VERIFY_SANE(s);
718e3744 698 return s->data + s->getp;
699}
700
701/* Check does this stream empty? */
702int
703stream_empty (struct stream *s)
704{
050c013a 705 STREAM_VERIFY_SANE(s);
706
707 return (s->endp == 0);
718e3744 708}
709
710/* Reset stream. */
711void
712stream_reset (struct stream *s)
713{
050c013a 714 STREAM_VERIFY_SANE (s);
715
716 s->getp = s->endp = 0;
718e3744 717}
718
719/* Write stream contens to the file discriptor. */
720int
721stream_flush (struct stream *s, int fd)
722{
723 int nbytes;
050c013a 724
725 STREAM_VERIFY_SANE(s);
726
718e3744 727 nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
050c013a 728
718e3744 729 return nbytes;
730}
731\f
732/* Stream first in first out queue. */
733
734struct stream_fifo *
81fb3240 735stream_fifo_new (void)
718e3744 736{
737 struct stream_fifo *new;
738
739 new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
740 return new;
741}
742
743/* Add new stream to fifo. */
744void
745stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
746{
747 if (fifo->tail)
748 fifo->tail->next = s;
749 else
750 fifo->head = s;
751
752 fifo->tail = s;
753
754 fifo->count++;
755}
756
757/* Delete first stream from fifo. */
758struct stream *
759stream_fifo_pop (struct stream_fifo *fifo)
760{
761 struct stream *s;
762
763 s = fifo->head;
764
765 if (s)
766 {
767 fifo->head = s->next;
768
769 if (fifo->head == NULL)
770 fifo->tail = NULL;
771 }
772
773 fifo->count--;
774
775 return s;
776}
777
778/* Return first fifo entry. */
779struct stream *
780stream_fifo_head (struct stream_fifo *fifo)
781{
782 return fifo->head;
783}
784
785void
786stream_fifo_clean (struct stream_fifo *fifo)
787{
788 struct stream *s;
789 struct stream *next;
790
791 for (s = fifo->head; s; s = next)
792 {
793 next = s->next;
794 stream_free (s);
795 }
796 fifo->head = fifo->tail = NULL;
797 fifo->count = 0;
798}
799
800void
801stream_fifo_free (struct stream_fifo *fifo)
802{
803 stream_fifo_clean (fifo);
804 XFREE (MTYPE_STREAM_FIFO, fifo);
805}