blob: 4d4f867dd89669eb53d2bae5ca0a88a4156365d8 [file] [log] [blame]
paul050c0132005-02-14 23:47:47 +00001 /*
paul718e3742002-12-13 20:15:29 +00002 * 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
23#include <zebra.h>
David Lamparter821df2c2015-09-15 01:53:09 -070024#include <stddef.h>
Paul Jakmad41e7b92015-05-19 15:38:43 +010025/* primarily for __STDC_IEC_559__ with clang */
26#include <features.h>
paul718e3742002-12-13 20:15:29 +000027
28#include "stream.h"
29#include "memory.h"
30#include "network.h"
31#include "prefix.h"
paul050c0132005-02-14 23:47:47 +000032#include "log.h"
paul718e3742002-12-13 20:15:29 +000033
paul050c0132005-02-14 23:47:47 +000034/* Tests whether a position is valid */
35#define GETP_VALID(S,G) \
36 ((G) <= (S)->endp)
37#define PUT_AT_VALID(S,G) GETP_VALID(S,G)
38#define ENDP_VALID(S,E) \
39 ((E) <= (S)->size)
paul718e3742002-12-13 20:15:29 +000040
paul050c0132005-02-14 23:47:47 +000041/* 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 */
56#define STREAM_WARN_OFFSETS(S) \
Subbaiah Venkatad5310502012-03-24 13:10:19 -070057 zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
David Lampartereed3c482015-03-03 08:51:53 +010058 (void *)(S), \
paul050c0132005-02-14 23:47:47 +000059 (unsigned long) (S)->size, \
60 (unsigned long) (S)->getp, \
61 (unsigned long) (S)->endp)\
paul718e3742002-12-13 20:15:29 +000062
paul050c0132005-02-14 23:47:47 +000063#define STREAM_VERIFY_SANE(S) \
64 do { \
Wenjian Ma1ed8ce42015-06-19 10:53:26 +080065 if ( !(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp)) ) \
paul050c0132005-02-14 23:47:47 +000066 STREAM_WARN_OFFSETS(S); \
67 assert ( GETP_VALID(S, (S)->getp) ); \
68 assert ( ENDP_VALID(S, (S)->endp) ); \
69 } while (0)
70
71#define STREAM_BOUND_WARN(S, WHAT) \
72 do { \
73 zlog_warn ("%s: Attempt to %s out of bounds", __func__, (WHAT)); \
74 STREAM_WARN_OFFSETS(S); \
75 assert (0); \
76 } while (0)
77
78/* XXX: Deprecated macro: do not use */
paul718e3742002-12-13 20:15:29 +000079#define CHECK_SIZE(S, Z) \
paul050c0132005-02-14 23:47:47 +000080 do { \
81 if (((S)->endp + (Z)) > (S)->size) \
82 { \
83 zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \
84 (unsigned long) (Z)); \
85 STREAM_WARN_OFFSETS(S); \
86 (Z) = (S)->size - (S)->endp; \
87 } \
88 } while (0);
paul718e3742002-12-13 20:15:29 +000089
90/* Make stream buffer. */
91struct stream *
92stream_new (size_t size)
93{
94 struct stream *s;
95
paul0e43a2b2004-12-22 00:15:34 +000096 assert (size > 0);
97
98 if (size == 0)
paul050c0132005-02-14 23:47:47 +000099 {
100 zlog_warn ("stream_new(): called with 0 size!");
101 return NULL;
102 }
paul0e43a2b2004-12-22 00:15:34 +0000103
paul4b201d42006-01-10 14:35:19 +0000104 s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
paul718e3742002-12-13 20:15:29 +0000105
paul050c0132005-02-14 23:47:47 +0000106 if (s == NULL)
107 return s;
108
paul4b201d42006-01-10 14:35:19 +0000109 if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL)
110 {
111 XFREE (MTYPE_STREAM, s);
112 return NULL;
113 }
114
paul718e3742002-12-13 20:15:29 +0000115 s->size = size;
116 return s;
117}
118
119/* Free it now. */
120void
121stream_free (struct stream *s)
122{
paul4b201d42006-01-10 14:35:19 +0000123 if (!s)
124 return;
125
126 XFREE (MTYPE_STREAM_DATA, s->data);
paul718e3742002-12-13 20:15:29 +0000127 XFREE (MTYPE_STREAM, s);
128}
paul050c0132005-02-14 23:47:47 +0000129
130struct stream *
131stream_copy (struct stream *new, struct stream *src)
132{
133 STREAM_VERIFY_SANE (src);
134
135 assert (new != NULL);
136 assert (STREAM_SIZE(new) >= src->endp);
137
138 new->endp = src->endp;
139 new->getp = src->getp;
140
141 memcpy (new->data, src->data, src->endp);
142
143 return new;
144}
145
146struct stream *
147stream_dup (struct stream *s)
148{
149 struct stream *new;
150
151 STREAM_VERIFY_SANE (s);
152
153 if ( (new = stream_new (s->endp)) == NULL)
154 return NULL;
155
156 return (stream_copy (new, s));
157}
paul4b201d42006-01-10 14:35:19 +0000158
Pradosh Mohapatra8c71e482014-01-15 06:57:57 +0000159struct stream *
160stream_dupcat (struct stream *s1, struct stream *s2, size_t offset)
161{
162 struct stream *new;
163
164 STREAM_VERIFY_SANE (s1);
165 STREAM_VERIFY_SANE (s2);
166
167 if ( (new = stream_new (s1->endp + s2->endp)) == NULL)
168 return NULL;
169
170 memcpy (new->data, s1->data, offset);
171 memcpy (new->data + offset, s2->data, s2->endp);
172 memcpy (new->data + offset + s2->endp, s1->data + offset,
173 (s1->endp - offset));
174 new->endp = s1->endp + s2->endp;
175 return new;
176}
177
paul4b201d42006-01-10 14:35:19 +0000178size_t
179stream_resize (struct stream *s, size_t newsize)
180{
181 u_char *newdata;
182 STREAM_VERIFY_SANE (s);
183
184 newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize);
185
186 if (newdata == NULL)
187 return s->size;
188
189 s->data = newdata;
190 s->size = newsize;
191
192 if (s->endp > s->size)
193 s->endp = s->size;
194 if (s->getp > s->endp)
195 s->getp = s->endp;
196
197 STREAM_VERIFY_SANE (s);
198
199 return s->size;
200}
David Lamparter6b0655a2014-06-04 06:53:35 +0200201
paulf2e6c422005-02-12 14:35:49 +0000202size_t
paul718e3742002-12-13 20:15:29 +0000203stream_get_getp (struct stream *s)
204{
paul050c0132005-02-14 23:47:47 +0000205 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000206 return s->getp;
207}
208
paulf2e6c422005-02-12 14:35:49 +0000209size_t
paul718e3742002-12-13 20:15:29 +0000210stream_get_endp (struct stream *s)
211{
paul050c0132005-02-14 23:47:47 +0000212 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000213 return s->endp;
214}
215
paulf2e6c422005-02-12 14:35:49 +0000216size_t
paul718e3742002-12-13 20:15:29 +0000217stream_get_size (struct stream *s)
218{
paul050c0132005-02-14 23:47:47 +0000219 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000220 return s->size;
221}
222
223/* Stream structre' stream pointer related functions. */
224void
paulf2e6c422005-02-12 14:35:49 +0000225stream_set_getp (struct stream *s, size_t pos)
paul718e3742002-12-13 20:15:29 +0000226{
paul050c0132005-02-14 23:47:47 +0000227 STREAM_VERIFY_SANE(s);
228
229 if (!GETP_VALID (s, pos))
230 {
231 STREAM_BOUND_WARN (s, "set getp");
232 pos = s->endp;
233 }
234
paul718e3742002-12-13 20:15:29 +0000235 s->getp = pos;
236}
237
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700238void
239stream_set_endp (struct stream *s, size_t pos)
240{
241 STREAM_VERIFY_SANE(s);
242
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700243 if (!ENDP_VALID(s, pos))
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700244 {
245 STREAM_BOUND_WARN (s, "set endp");
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700246 return;
247 }
248
249 /*
250 * Make sure the current read pointer is not beyond the new endp.
251 */
252 if (s->getp > pos)
253 {
254 STREAM_BOUND_WARN(s, "set endp");
255 return;
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700256 }
257
258 s->endp = pos;
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700259 STREAM_VERIFY_SANE(s);
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700260}
261
paul718e3742002-12-13 20:15:29 +0000262/* Forward pointer. */
263void
paul050c0132005-02-14 23:47:47 +0000264stream_forward_getp (struct stream *s, size_t size)
paul718e3742002-12-13 20:15:29 +0000265{
paul050c0132005-02-14 23:47:47 +0000266 STREAM_VERIFY_SANE(s);
267
268 if (!GETP_VALID (s, s->getp + size))
269 {
270 STREAM_BOUND_WARN (s, "seek getp");
271 return;
272 }
273
paul718e3742002-12-13 20:15:29 +0000274 s->getp += size;
275}
paul9985f832005-02-09 15:51:56 +0000276
277void
paul050c0132005-02-14 23:47:47 +0000278stream_forward_endp (struct stream *s, size_t size)
paul9985f832005-02-09 15:51:56 +0000279{
paul050c0132005-02-14 23:47:47 +0000280 STREAM_VERIFY_SANE(s);
281
282 if (!ENDP_VALID (s, s->endp + size))
283 {
284 STREAM_BOUND_WARN (s, "seek endp");
285 return;
286 }
287
paul9985f832005-02-09 15:51:56 +0000288 s->endp += size;
289}
David Lamparter6b0655a2014-06-04 06:53:35 +0200290
paul718e3742002-12-13 20:15:29 +0000291/* Copy from stream to destination. */
292void
293stream_get (void *dst, struct stream *s, size_t size)
294{
paul050c0132005-02-14 23:47:47 +0000295 STREAM_VERIFY_SANE(s);
296
297 if (STREAM_READABLE(s) < size)
298 {
299 STREAM_BOUND_WARN (s, "get");
300 return;
301 }
302
paul718e3742002-12-13 20:15:29 +0000303 memcpy (dst, s->data + s->getp, size);
304 s->getp += size;
305}
306
307/* Get next character from the stream. */
308u_char
309stream_getc (struct stream *s)
310{
311 u_char c;
paul050c0132005-02-14 23:47:47 +0000312
313 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000314
paul050c0132005-02-14 23:47:47 +0000315 if (STREAM_READABLE(s) < sizeof (u_char))
316 {
317 STREAM_BOUND_WARN (s, "get char");
318 return 0;
319 }
320 c = s->data[s->getp++];
321
paul718e3742002-12-13 20:15:29 +0000322 return c;
323}
324
325/* Get next character from the stream. */
326u_char
paulf2e6c422005-02-12 14:35:49 +0000327stream_getc_from (struct stream *s, size_t from)
paul718e3742002-12-13 20:15:29 +0000328{
329 u_char c;
330
paul050c0132005-02-14 23:47:47 +0000331 STREAM_VERIFY_SANE(s);
332
333 if (!GETP_VALID (s, from + sizeof (u_char)))
334 {
335 STREAM_BOUND_WARN (s, "get char");
336 return 0;
337 }
338
paul718e3742002-12-13 20:15:29 +0000339 c = s->data[from];
paul050c0132005-02-14 23:47:47 +0000340
paul718e3742002-12-13 20:15:29 +0000341 return c;
342}
343
344/* Get next word from the stream. */
345u_int16_t
346stream_getw (struct stream *s)
347{
348 u_int16_t w;
349
paul050c0132005-02-14 23:47:47 +0000350 STREAM_VERIFY_SANE (s);
351
352 if (STREAM_READABLE (s) < sizeof (u_int16_t))
353 {
354 STREAM_BOUND_WARN (s, "get ");
355 return 0;
356 }
357
paul718e3742002-12-13 20:15:29 +0000358 w = s->data[s->getp++] << 8;
359 w |= s->data[s->getp++];
paul050c0132005-02-14 23:47:47 +0000360
paul718e3742002-12-13 20:15:29 +0000361 return w;
362}
363
364/* Get next word from the stream. */
365u_int16_t
paulf2e6c422005-02-12 14:35:49 +0000366stream_getw_from (struct stream *s, size_t from)
paul718e3742002-12-13 20:15:29 +0000367{
368 u_int16_t w;
369
paul050c0132005-02-14 23:47:47 +0000370 STREAM_VERIFY_SANE(s);
371
372 if (!GETP_VALID (s, from + sizeof (u_int16_t)))
373 {
374 STREAM_BOUND_WARN (s, "get ");
375 return 0;
376 }
377
paul718e3742002-12-13 20:15:29 +0000378 w = s->data[from++] << 8;
379 w |= s->data[from];
paul050c0132005-02-14 23:47:47 +0000380
paul718e3742002-12-13 20:15:29 +0000381 return w;
382}
383
384/* Get next long word from the stream. */
385u_int32_t
paul050c0132005-02-14 23:47:47 +0000386stream_getl_from (struct stream *s, size_t from)
387{
388 u_int32_t l;
389
390 STREAM_VERIFY_SANE(s);
391
392 if (!GETP_VALID (s, from + sizeof (u_int32_t)))
393 {
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;
404}
405
406u_int32_t
paul718e3742002-12-13 20:15:29 +0000407stream_getl (struct stream *s)
408{
409 u_int32_t l;
410
paul050c0132005-02-14 23:47:47 +0000411 STREAM_VERIFY_SANE(s);
412
413 if (STREAM_READABLE (s) < sizeof (u_int32_t))
414 {
415 STREAM_BOUND_WARN (s, "get long");
416 return 0;
417 }
418
paul718e3742002-12-13 20:15:29 +0000419 l = s->data[s->getp++] << 24;
420 l |= s->data[s->getp++] << 16;
421 l |= s->data[s->getp++] << 8;
422 l |= s->data[s->getp++];
paul050c0132005-02-14 23:47:47 +0000423
paul718e3742002-12-13 20:15:29 +0000424 return l;
425}
paul4b201d42006-01-10 14:35:19 +0000426
427/* Get next quad word from the stream. */
428uint64_t
429stream_getq_from (struct stream *s, size_t from)
430{
paul581a02a2006-01-19 20:22:16 +0000431 uint64_t q;
paul4b201d42006-01-10 14:35:19 +0000432
433 STREAM_VERIFY_SANE(s);
434
435 if (!GETP_VALID (s, from + sizeof (uint64_t)))
436 {
437 STREAM_BOUND_WARN (s, "get quad");
438 return 0;
439 }
440
441 q = ((uint64_t) s->data[from++]) << 56;
442 q |= ((uint64_t) s->data[from++]) << 48;
443 q |= ((uint64_t) s->data[from++]) << 40;
444 q |= ((uint64_t) s->data[from++]) << 32;
445 q |= ((uint64_t) s->data[from++]) << 24;
446 q |= ((uint64_t) s->data[from++]) << 16;
447 q |= ((uint64_t) s->data[from++]) << 8;
448 q |= ((uint64_t) s->data[from++]);
449
450 return q;
451}
452
453uint64_t
454stream_getq (struct stream *s)
455{
456 uint64_t q;
457
458 STREAM_VERIFY_SANE(s);
459
460 if (STREAM_READABLE (s) < sizeof (uint64_t))
461 {
462 STREAM_BOUND_WARN (s, "get quad");
463 return 0;
464 }
465
466 q = ((uint64_t) s->data[s->getp++]) << 56;
467 q |= ((uint64_t) s->data[s->getp++]) << 48;
468 q |= ((uint64_t) s->data[s->getp++]) << 40;
469 q |= ((uint64_t) s->data[s->getp++]) << 32;
470 q |= ((uint64_t) s->data[s->getp++]) << 24;
471 q |= ((uint64_t) s->data[s->getp++]) << 16;
472 q |= ((uint64_t) s->data[s->getp++]) << 8;
473 q |= ((uint64_t) s->data[s->getp++]);
474
475 return q;
476}
477
paul718e3742002-12-13 20:15:29 +0000478/* Get next long word from the stream. */
479u_int32_t
480stream_get_ipv4 (struct stream *s)
481{
482 u_int32_t l;
483
paul050c0132005-02-14 23:47:47 +0000484 STREAM_VERIFY_SANE(s);
485
486 if (STREAM_READABLE (s) < sizeof(u_int32_t))
487 {
488 STREAM_BOUND_WARN (s, "get ipv4");
489 return 0;
490 }
491
492 memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
493 s->getp += sizeof(u_int32_t);
paul718e3742002-12-13 20:15:29 +0000494
495 return l;
496}
David Lamparter6b0655a2014-06-04 06:53:35 +0200497
Paul Jakmad41e7b92015-05-19 15:38:43 +0100498float
499stream_getf (struct stream *s)
500{
501#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
502/* we can safely assume 'float' is in the single precision
503 IEC 60559 binary format in host order */
504 union {
505 float r;
506 uint32_t d;
507 } u;
508 u.d = stream_getl (s);
509 return u.r;
510#else
511#error "Please supply stream_getf implementation for this platform"
512#endif
513}
514
515double
516stream_getd (struct stream *s)
517{
518#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
519 union {
520 double r;
521 uint64_t d;
522 } u;
523 u.d = stream_getq (s);
524 return u.r;
525#else
526#error "Please supply stream_getd implementation for this platform"
527#endif
528}
529
paul050c0132005-02-14 23:47:47 +0000530/* Copy to source to stream.
531 *
532 * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
533 * around. This should be fixed once the stream updates are working.
paul0dab9302005-05-03 09:07:56 +0000534 *
535 * stream_write() is saner
paul050c0132005-02-14 23:47:47 +0000536 */
paul718e3742002-12-13 20:15:29 +0000537void
Paul Jakma3d52bb82008-06-07 20:42:07 +0000538stream_put (struct stream *s, const void *src, size_t size)
paul718e3742002-12-13 20:15:29 +0000539{
540
paul050c0132005-02-14 23:47:47 +0000541 /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
paul718e3742002-12-13 20:15:29 +0000542 CHECK_SIZE(s, size);
paul050c0132005-02-14 23:47:47 +0000543
544 STREAM_VERIFY_SANE(s);
545
546 if (STREAM_WRITEABLE (s) < size)
547 {
548 STREAM_BOUND_WARN (s, "put");
549 return;
550 }
551
paul718e3742002-12-13 20:15:29 +0000552 if (src)
paul9985f832005-02-09 15:51:56 +0000553 memcpy (s->data + s->endp, src, size);
paul718e3742002-12-13 20:15:29 +0000554 else
paul9985f832005-02-09 15:51:56 +0000555 memset (s->data + s->endp, 0, size);
paul718e3742002-12-13 20:15:29 +0000556
paul9985f832005-02-09 15:51:56 +0000557 s->endp += size;
paul718e3742002-12-13 20:15:29 +0000558}
559
560/* Put character to the stream. */
561int
562stream_putc (struct stream *s, u_char c)
563{
paul050c0132005-02-14 23:47:47 +0000564 STREAM_VERIFY_SANE(s);
565
566 if (STREAM_WRITEABLE (s) < sizeof(u_char))
567 {
568 STREAM_BOUND_WARN (s, "put");
569 return 0;
570 }
571
572 s->data[s->endp++] = c;
573 return sizeof (u_char);
paul718e3742002-12-13 20:15:29 +0000574}
575
576/* Put word to the stream. */
577int
578stream_putw (struct stream *s, u_int16_t w)
579{
paul050c0132005-02-14 23:47:47 +0000580 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000581
paul050c0132005-02-14 23:47:47 +0000582 if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
583 {
584 STREAM_BOUND_WARN (s, "put");
585 return 0;
586 }
587
paul9985f832005-02-09 15:51:56 +0000588 s->data[s->endp++] = (u_char)(w >> 8);
589 s->data[s->endp++] = (u_char) w;
paul718e3742002-12-13 20:15:29 +0000590
paul718e3742002-12-13 20:15:29 +0000591 return 2;
592}
593
594/* Put long word to the stream. */
595int
596stream_putl (struct stream *s, u_int32_t l)
597{
paul050c0132005-02-14 23:47:47 +0000598 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000599
paul050c0132005-02-14 23:47:47 +0000600 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
601 {
602 STREAM_BOUND_WARN (s, "put");
603 return 0;
604 }
605
paul9985f832005-02-09 15:51:56 +0000606 s->data[s->endp++] = (u_char)(l >> 24);
607 s->data[s->endp++] = (u_char)(l >> 16);
608 s->data[s->endp++] = (u_char)(l >> 8);
609 s->data[s->endp++] = (u_char)l;
paul718e3742002-12-13 20:15:29 +0000610
paul718e3742002-12-13 20:15:29 +0000611 return 4;
612}
613
paul4b201d42006-01-10 14:35:19 +0000614/* Put quad word to the stream. */
615int
616stream_putq (struct stream *s, uint64_t q)
617{
618 STREAM_VERIFY_SANE (s);
619
620 if (STREAM_WRITEABLE (s) < sizeof (uint64_t))
621 {
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;
636}
637
paul718e3742002-12-13 20:15:29 +0000638int
Paul Jakmad41e7b92015-05-19 15:38:43 +0100639stream_putf (struct stream *s, float f)
640{
641#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
642/* we can safely assume 'float' is in the single precision
643 IEC 60559 binary format in host order */
644 union {
645 float i;
646 uint32_t o;
647 } u;
648 u.i = f;
649 return stream_putl (s, u.o);
650#else
651#error "Please supply stream_putf implementation for this platform"
652#endif
653}
654
655int
656stream_putd (struct stream *s, double d)
657{
658#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
659 union {
660 double i;
661 uint64_t o;
662 } u;
663 u.i = d;
664 return stream_putq (s, u.o);
665#else
666#error "Please supply stream_putd implementation for this platform"
667#endif
668}
669
670int
paulf2e6c422005-02-12 14:35:49 +0000671stream_putc_at (struct stream *s, size_t putp, u_char c)
paul718e3742002-12-13 20:15:29 +0000672{
paul050c0132005-02-14 23:47:47 +0000673 STREAM_VERIFY_SANE(s);
674
675 if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
676 {
677 STREAM_BOUND_WARN (s, "put");
678 return 0;
679 }
680
paul718e3742002-12-13 20:15:29 +0000681 s->data[putp] = c;
paul050c0132005-02-14 23:47:47 +0000682
paul718e3742002-12-13 20:15:29 +0000683 return 1;
684}
685
686int
paulf2e6c422005-02-12 14:35:49 +0000687stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
paul718e3742002-12-13 20:15:29 +0000688{
paul050c0132005-02-14 23:47:47 +0000689 STREAM_VERIFY_SANE(s);
690
691 if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
692 {
693 STREAM_BOUND_WARN (s, "put");
694 return 0;
695 }
696
paul718e3742002-12-13 20:15:29 +0000697 s->data[putp] = (u_char)(w >> 8);
698 s->data[putp + 1] = (u_char) w;
paul050c0132005-02-14 23:47:47 +0000699
paul718e3742002-12-13 20:15:29 +0000700 return 2;
701}
702
703int
paulf2e6c422005-02-12 14:35:49 +0000704stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
paul718e3742002-12-13 20:15:29 +0000705{
paul050c0132005-02-14 23:47:47 +0000706 STREAM_VERIFY_SANE(s);
707
708 if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
709 {
710 STREAM_BOUND_WARN (s, "put");
711 return 0;
712 }
paul718e3742002-12-13 20:15:29 +0000713 s->data[putp] = (u_char)(l >> 24);
714 s->data[putp + 1] = (u_char)(l >> 16);
715 s->data[putp + 2] = (u_char)(l >> 8);
716 s->data[putp + 3] = (u_char)l;
paul050c0132005-02-14 23:47:47 +0000717
paul718e3742002-12-13 20:15:29 +0000718 return 4;
719}
720
paul4b201d42006-01-10 14:35:19 +0000721int
722stream_putq_at (struct stream *s, size_t putp, uint64_t q)
723{
724 STREAM_VERIFY_SANE(s);
725
726 if (!PUT_AT_VALID (s, putp + sizeof (uint64_t)))
727 {
728 STREAM_BOUND_WARN (s, "put");
729 return 0;
730 }
731 s->data[putp] = (u_char)(q >> 56);
732 s->data[putp + 1] = (u_char)(q >> 48);
733 s->data[putp + 2] = (u_char)(q >> 40);
734 s->data[putp + 3] = (u_char)(q >> 32);
735 s->data[putp + 4] = (u_char)(q >> 24);
736 s->data[putp + 5] = (u_char)(q >> 16);
737 s->data[putp + 6] = (u_char)(q >> 8);
738 s->data[putp + 7] = (u_char)q;
739
740 return 8;
741}
742
paul718e3742002-12-13 20:15:29 +0000743/* Put long word to the stream. */
744int
745stream_put_ipv4 (struct stream *s, u_int32_t l)
746{
paul050c0132005-02-14 23:47:47 +0000747 STREAM_VERIFY_SANE(s);
748
749 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
750 {
751 STREAM_BOUND_WARN (s, "put");
752 return 0;
753 }
754 memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
755 s->endp += sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000756
paul050c0132005-02-14 23:47:47 +0000757 return sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000758}
759
760/* Put long word to the stream. */
761int
762stream_put_in_addr (struct stream *s, struct in_addr *addr)
763{
paul050c0132005-02-14 23:47:47 +0000764 STREAM_VERIFY_SANE(s);
765
766 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
767 {
768 STREAM_BOUND_WARN (s, "put");
769 return 0;
770 }
paul718e3742002-12-13 20:15:29 +0000771
paul050c0132005-02-14 23:47:47 +0000772 memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
773 s->endp += sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000774
paul050c0132005-02-14 23:47:47 +0000775 return sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000776}
777
778/* Put prefix by nlri type format. */
779int
780stream_put_prefix (struct stream *s, struct prefix *p)
781{
paul050c0132005-02-14 23:47:47 +0000782 size_t psize;
783
784 STREAM_VERIFY_SANE(s);
785
paul718e3742002-12-13 20:15:29 +0000786 psize = PSIZE (p->prefixlen);
paul050c0132005-02-14 23:47:47 +0000787
Jorge Boncompte [DTI2]af514772013-07-31 16:16:05 +0000788 if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char)))
paul050c0132005-02-14 23:47:47 +0000789 {
790 STREAM_BOUND_WARN (s, "put");
791 return 0;
792 }
793
Jorge Boncompte [DTI2]af514772013-07-31 16:16:05 +0000794 s->data[s->endp++] = p->prefixlen;
paul9985f832005-02-09 15:51:56 +0000795 memcpy (s->data + s->endp, &p->u.prefix, psize);
796 s->endp += psize;
paul718e3742002-12-13 20:15:29 +0000797
paul718e3742002-12-13 20:15:29 +0000798 return psize;
799}
David Lamparter6b0655a2014-06-04 06:53:35 +0200800
paul718e3742002-12-13 20:15:29 +0000801/* Read size from fd. */
802int
803stream_read (struct stream *s, int fd, size_t size)
804{
805 int nbytes;
806
paul050c0132005-02-14 23:47:47 +0000807 STREAM_VERIFY_SANE(s);
808
809 if (STREAM_WRITEABLE (s) < size)
810 {
811 STREAM_BOUND_WARN (s, "put");
812 return 0;
813 }
814
paul9985f832005-02-09 15:51:56 +0000815 nbytes = readn (fd, s->data + s->endp, size);
paul718e3742002-12-13 20:15:29 +0000816
817 if (nbytes > 0)
paul9985f832005-02-09 15:51:56 +0000818 s->endp += nbytes;
819
paul718e3742002-12-13 20:15:29 +0000820 return nbytes;
821}
822
ajs262feb12005-02-16 20:35:47 +0000823ssize_t
824stream_read_try(struct stream *s, int fd, size_t size)
825{
826 ssize_t nbytes;
827
828 STREAM_VERIFY_SANE(s);
829
830 if (STREAM_WRITEABLE(s) < size)
831 {
832 STREAM_BOUND_WARN (s, "put");
833 /* Fatal (not transient) error, since retrying will not help
834 (stream is too small to contain the desired data). */
835 return -1;
836 }
837
838 if ((nbytes = read(fd, s->data + s->endp, size)) >= 0)
839 {
840 s->endp += nbytes;
841 return nbytes;
842 }
843 /* Error: was it transient (return -2) or fatal (return -1)? */
ajs81fb3242005-02-24 16:02:53 +0000844 if (ERRNO_IO_RETRY(errno))
845 return -2;
846 zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
847 return -1;
ajs262feb12005-02-16 20:35:47 +0000848}
849
paul0dab9302005-05-03 09:07:56 +0000850/* Read up to size bytes into the stream from the fd, using recvmsgfrom
851 * whose arguments match the remaining arguments to this function
852 */
853ssize_t
854stream_recvfrom (struct stream *s, int fd, size_t size, int flags,
855 struct sockaddr *from, socklen_t *fromlen)
856{
857 ssize_t nbytes;
858
859 STREAM_VERIFY_SANE(s);
860
861 if (STREAM_WRITEABLE(s) < size)
862 {
863 STREAM_BOUND_WARN (s, "put");
864 /* Fatal (not transient) error, since retrying will not help
865 (stream is too small to contain the desired data). */
866 return -1;
867 }
868
869 if ((nbytes = recvfrom (fd, s->data + s->endp, size,
870 flags, from, fromlen)) >= 0)
871 {
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, safe_strerror(errno));
879 return -1;
880}
881
paul050c0132005-02-14 23:47:47 +0000882/* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
883 * from endp.
884 * First iovec will be used to receive the data.
885 * Stream need not be empty.
886 */
paul0dab9302005-05-03 09:07:56 +0000887ssize_t
paul050c0132005-02-14 23:47:47 +0000888stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags,
889 size_t size)
890{
891 int nbytes;
892 struct iovec *iov;
893
894 STREAM_VERIFY_SANE(s);
895 assert (msgh->msg_iovlen > 0);
896
897 if (STREAM_WRITEABLE (s) < size)
898 {
899 STREAM_BOUND_WARN (s, "put");
ajs262feb12005-02-16 20:35:47 +0000900 /* This is a logic error in the calling code: the stream is too small
901 to hold the desired data! */
902 return -1;
paul050c0132005-02-14 23:47:47 +0000903 }
904
905 iov = &(msgh->msg_iov[0]);
906 iov->iov_base = (s->data + s->endp);
907 iov->iov_len = size;
908
909 nbytes = recvmsg (fd, msgh, flags);
910
911 if (nbytes > 0)
912 s->endp += nbytes;
913
914 return nbytes;
915}
916
paul718e3742002-12-13 20:15:29 +0000917/* Write data to buffer. */
paul0dab9302005-05-03 09:07:56 +0000918size_t
Paul Jakma3d52bb82008-06-07 20:42:07 +0000919stream_write (struct stream *s, const void *ptr, size_t size)
paul718e3742002-12-13 20:15:29 +0000920{
921
922 CHECK_SIZE(s, size);
923
paul050c0132005-02-14 23:47:47 +0000924 STREAM_VERIFY_SANE(s);
925
926 if (STREAM_WRITEABLE (s) < size)
927 {
928 STREAM_BOUND_WARN (s, "put");
929 return 0;
930 }
931
paul9985f832005-02-09 15:51:56 +0000932 memcpy (s->data + s->endp, ptr, size);
933 s->endp += size;
934
paul718e3742002-12-13 20:15:29 +0000935 return size;
936}
937
paul050c0132005-02-14 23:47:47 +0000938/* Return current read pointer.
939 * DEPRECATED!
940 * Use stream_get_pnt_to if you must, but decoding streams properly
941 * is preferred
942 */
paul718e3742002-12-13 20:15:29 +0000943u_char *
944stream_pnt (struct stream *s)
945{
paul050c0132005-02-14 23:47:47 +0000946 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000947 return s->data + s->getp;
948}
949
950/* Check does this stream empty? */
951int
952stream_empty (struct stream *s)
953{
paul050c0132005-02-14 23:47:47 +0000954 STREAM_VERIFY_SANE(s);
955
956 return (s->endp == 0);
paul718e3742002-12-13 20:15:29 +0000957}
958
959/* Reset stream. */
960void
961stream_reset (struct stream *s)
962{
paul050c0132005-02-14 23:47:47 +0000963 STREAM_VERIFY_SANE (s);
964
965 s->getp = s->endp = 0;
paul718e3742002-12-13 20:15:29 +0000966}
967
968/* Write stream contens to the file discriptor. */
969int
970stream_flush (struct stream *s, int fd)
971{
972 int nbytes;
paul050c0132005-02-14 23:47:47 +0000973
974 STREAM_VERIFY_SANE(s);
975
paul718e3742002-12-13 20:15:29 +0000976 nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
paul050c0132005-02-14 23:47:47 +0000977
paul718e3742002-12-13 20:15:29 +0000978 return nbytes;
979}
David Lamparter6b0655a2014-06-04 06:53:35 +0200980
paul718e3742002-12-13 20:15:29 +0000981/* Stream first in first out queue. */
982
983struct stream_fifo *
ajs81fb3242005-02-24 16:02:53 +0000984stream_fifo_new (void)
paul718e3742002-12-13 20:15:29 +0000985{
986 struct stream_fifo *new;
987
988 new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
989 return new;
990}
991
992/* Add new stream to fifo. */
993void
994stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
995{
996 if (fifo->tail)
997 fifo->tail->next = s;
998 else
999 fifo->head = s;
1000
1001 fifo->tail = s;
1002
1003 fifo->count++;
1004}
1005
1006/* Delete first stream from fifo. */
1007struct stream *
1008stream_fifo_pop (struct stream_fifo *fifo)
1009{
1010 struct stream *s;
1011
1012 s = fifo->head;
1013
1014 if (s)
1015 {
1016 fifo->head = s->next;
1017
1018 if (fifo->head == NULL)
1019 fifo->tail = NULL;
paul718e3742002-12-13 20:15:29 +00001020
Subbaiah Venkatad5310502012-03-24 13:10:19 -07001021 fifo->count--;
1022 }
paul718e3742002-12-13 20:15:29 +00001023
1024 return s;
1025}
1026
1027/* Return first fifo entry. */
1028struct stream *
1029stream_fifo_head (struct stream_fifo *fifo)
1030{
1031 return fifo->head;
1032}
1033
1034void
1035stream_fifo_clean (struct stream_fifo *fifo)
1036{
1037 struct stream *s;
1038 struct stream *next;
1039
1040 for (s = fifo->head; s; s = next)
1041 {
1042 next = s->next;
1043 stream_free (s);
1044 }
1045 fifo->head = fifo->tail = NULL;
1046 fifo->count = 0;
1047}
1048
1049void
1050stream_fifo_free (struct stream_fifo *fifo)
1051{
1052 stream_fifo_clean (fifo);
1053 XFREE (MTYPE_STREAM_FIFO, fifo);
1054}