blob: ed677c1372fe742d4b28c1f4217e3c288465b2b7 [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>
paul718e3742002-12-13 20:15:29 +000025
26#include "stream.h"
27#include "memory.h"
28#include "network.h"
29#include "prefix.h"
paul050c0132005-02-14 23:47:47 +000030#include "log.h"
paul718e3742002-12-13 20:15:29 +000031
paul050c0132005-02-14 23:47:47 +000032/* 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)
paul718e3742002-12-13 20:15:29 +000038
paul050c0132005-02-14 23:47:47 +000039/* 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) \
Subbaiah Venkatad5310502012-03-24 13:10:19 -070055 zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
David Lampartereed3c482015-03-03 08:51:53 +010056 (void *)(S), \
paul050c0132005-02-14 23:47:47 +000057 (unsigned long) (S)->size, \
58 (unsigned long) (S)->getp, \
59 (unsigned long) (S)->endp)\
paul718e3742002-12-13 20:15:29 +000060
paul050c0132005-02-14 23:47:47 +000061#define STREAM_VERIFY_SANE(S) \
62 do { \
Wenjian Ma1ed8ce42015-06-19 10:53:26 +080063 if ( !(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp)) ) \
paul050c0132005-02-14 23:47:47 +000064 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 */
paul718e3742002-12-13 20:15:29 +000077#define CHECK_SIZE(S, Z) \
paul050c0132005-02-14 23:47:47 +000078 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);
paul718e3742002-12-13 20:15:29 +000087
88/* Make stream buffer. */
89struct stream *
90stream_new (size_t size)
91{
92 struct stream *s;
93
paul0e43a2b2004-12-22 00:15:34 +000094 assert (size > 0);
95
96 if (size == 0)
paul050c0132005-02-14 23:47:47 +000097 {
98 zlog_warn ("stream_new(): called with 0 size!");
99 return NULL;
100 }
paul0e43a2b2004-12-22 00:15:34 +0000101
paul4b201d42006-01-10 14:35:19 +0000102 s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
paul718e3742002-12-13 20:15:29 +0000103
paul050c0132005-02-14 23:47:47 +0000104 if (s == NULL)
105 return s;
106
paul4b201d42006-01-10 14:35:19 +0000107 if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL)
108 {
109 XFREE (MTYPE_STREAM, s);
110 return NULL;
111 }
112
paul718e3742002-12-13 20:15:29 +0000113 s->size = size;
114 return s;
115}
116
117/* Free it now. */
118void
119stream_free (struct stream *s)
120{
paul4b201d42006-01-10 14:35:19 +0000121 if (!s)
122 return;
123
124 XFREE (MTYPE_STREAM_DATA, s->data);
paul718e3742002-12-13 20:15:29 +0000125 XFREE (MTYPE_STREAM, s);
126}
paul050c0132005-02-14 23:47:47 +0000127
128struct stream *
129stream_copy (struct stream *new, struct stream *src)
130{
131 STREAM_VERIFY_SANE (src);
132
133 assert (new != NULL);
134 assert (STREAM_SIZE(new) >= src->endp);
135
136 new->endp = src->endp;
137 new->getp = src->getp;
138
139 memcpy (new->data, src->data, src->endp);
140
141 return new;
142}
143
144struct stream *
145stream_dup (struct stream *s)
146{
147 struct stream *new;
148
149 STREAM_VERIFY_SANE (s);
150
151 if ( (new = stream_new (s->endp)) == NULL)
152 return NULL;
153
154 return (stream_copy (new, s));
155}
paul4b201d42006-01-10 14:35:19 +0000156
Pradosh Mohapatra8c71e482014-01-15 06:57:57 +0000157struct stream *
158stream_dupcat (struct stream *s1, struct stream *s2, size_t offset)
159{
160 struct stream *new;
161
162 STREAM_VERIFY_SANE (s1);
163 STREAM_VERIFY_SANE (s2);
164
165 if ( (new = stream_new (s1->endp + s2->endp)) == NULL)
166 return NULL;
167
168 memcpy (new->data, s1->data, offset);
169 memcpy (new->data + offset, s2->data, s2->endp);
170 memcpy (new->data + offset + s2->endp, s1->data + offset,
171 (s1->endp - offset));
172 new->endp = s1->endp + s2->endp;
173 return new;
174}
175
paul4b201d42006-01-10 14:35:19 +0000176size_t
177stream_resize (struct stream *s, size_t newsize)
178{
179 u_char *newdata;
180 STREAM_VERIFY_SANE (s);
181
182 newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize);
183
184 if (newdata == NULL)
185 return s->size;
186
187 s->data = newdata;
188 s->size = newsize;
189
190 if (s->endp > s->size)
191 s->endp = s->size;
192 if (s->getp > s->endp)
193 s->getp = s->endp;
194
195 STREAM_VERIFY_SANE (s);
196
197 return s->size;
198}
David Lamparter6b0655a2014-06-04 06:53:35 +0200199
paulf2e6c422005-02-12 14:35:49 +0000200size_t
paul718e3742002-12-13 20:15:29 +0000201stream_get_getp (struct stream *s)
202{
paul050c0132005-02-14 23:47:47 +0000203 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000204 return s->getp;
205}
206
paulf2e6c422005-02-12 14:35:49 +0000207size_t
paul718e3742002-12-13 20:15:29 +0000208stream_get_endp (struct stream *s)
209{
paul050c0132005-02-14 23:47:47 +0000210 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000211 return s->endp;
212}
213
paulf2e6c422005-02-12 14:35:49 +0000214size_t
paul718e3742002-12-13 20:15:29 +0000215stream_get_size (struct stream *s)
216{
paul050c0132005-02-14 23:47:47 +0000217 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000218 return s->size;
219}
220
221/* Stream structre' stream pointer related functions. */
222void
paulf2e6c422005-02-12 14:35:49 +0000223stream_set_getp (struct stream *s, size_t pos)
paul718e3742002-12-13 20:15:29 +0000224{
paul050c0132005-02-14 23:47:47 +0000225 STREAM_VERIFY_SANE(s);
226
227 if (!GETP_VALID (s, pos))
228 {
229 STREAM_BOUND_WARN (s, "set getp");
230 pos = s->endp;
231 }
232
paul718e3742002-12-13 20:15:29 +0000233 s->getp = pos;
234}
235
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700236void
237stream_set_endp (struct stream *s, size_t pos)
238{
239 STREAM_VERIFY_SANE(s);
240
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700241 if (!ENDP_VALID(s, pos))
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700242 {
243 STREAM_BOUND_WARN (s, "set endp");
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700244 return;
245 }
246
247 /*
248 * Make sure the current read pointer is not beyond the new endp.
249 */
250 if (s->getp > pos)
251 {
252 STREAM_BOUND_WARN(s, "set endp");
253 return;
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700254 }
255
256 s->endp = pos;
Avneesh Sachdev4effc292012-05-05 17:42:43 -0700257 STREAM_VERIFY_SANE(s);
Subbaiah Venkatad5310502012-03-24 13:10:19 -0700258}
259
paul718e3742002-12-13 20:15:29 +0000260/* Forward pointer. */
261void
paul050c0132005-02-14 23:47:47 +0000262stream_forward_getp (struct stream *s, size_t size)
paul718e3742002-12-13 20:15:29 +0000263{
paul050c0132005-02-14 23:47:47 +0000264 STREAM_VERIFY_SANE(s);
265
266 if (!GETP_VALID (s, s->getp + size))
267 {
268 STREAM_BOUND_WARN (s, "seek getp");
269 return;
270 }
271
paul718e3742002-12-13 20:15:29 +0000272 s->getp += size;
273}
paul9985f832005-02-09 15:51:56 +0000274
275void
paul050c0132005-02-14 23:47:47 +0000276stream_forward_endp (struct stream *s, size_t size)
paul9985f832005-02-09 15:51:56 +0000277{
paul050c0132005-02-14 23:47:47 +0000278 STREAM_VERIFY_SANE(s);
279
280 if (!ENDP_VALID (s, s->endp + size))
281 {
282 STREAM_BOUND_WARN (s, "seek endp");
283 return;
284 }
285
paul9985f832005-02-09 15:51:56 +0000286 s->endp += size;
287}
David Lamparter6b0655a2014-06-04 06:53:35 +0200288
paul718e3742002-12-13 20:15:29 +0000289/* Copy from stream to destination. */
290void
291stream_get (void *dst, struct stream *s, size_t size)
292{
paul050c0132005-02-14 23:47:47 +0000293 STREAM_VERIFY_SANE(s);
294
295 if (STREAM_READABLE(s) < size)
296 {
297 STREAM_BOUND_WARN (s, "get");
298 return;
299 }
300
paul718e3742002-12-13 20:15:29 +0000301 memcpy (dst, s->data + s->getp, size);
302 s->getp += size;
303}
304
305/* Get next character from the stream. */
306u_char
307stream_getc (struct stream *s)
308{
309 u_char c;
paul050c0132005-02-14 23:47:47 +0000310
311 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000312
paul050c0132005-02-14 23:47:47 +0000313 if (STREAM_READABLE(s) < sizeof (u_char))
314 {
315 STREAM_BOUND_WARN (s, "get char");
316 return 0;
317 }
318 c = s->data[s->getp++];
319
paul718e3742002-12-13 20:15:29 +0000320 return c;
321}
322
323/* Get next character from the stream. */
324u_char
paulf2e6c422005-02-12 14:35:49 +0000325stream_getc_from (struct stream *s, size_t from)
paul718e3742002-12-13 20:15:29 +0000326{
327 u_char c;
328
paul050c0132005-02-14 23:47:47 +0000329 STREAM_VERIFY_SANE(s);
330
331 if (!GETP_VALID (s, from + sizeof (u_char)))
332 {
333 STREAM_BOUND_WARN (s, "get char");
334 return 0;
335 }
336
paul718e3742002-12-13 20:15:29 +0000337 c = s->data[from];
paul050c0132005-02-14 23:47:47 +0000338
paul718e3742002-12-13 20:15:29 +0000339 return c;
340}
341
342/* Get next word from the stream. */
343u_int16_t
344stream_getw (struct stream *s)
345{
346 u_int16_t w;
347
paul050c0132005-02-14 23:47:47 +0000348 STREAM_VERIFY_SANE (s);
349
350 if (STREAM_READABLE (s) < sizeof (u_int16_t))
351 {
352 STREAM_BOUND_WARN (s, "get ");
353 return 0;
354 }
355
paul718e3742002-12-13 20:15:29 +0000356 w = s->data[s->getp++] << 8;
357 w |= s->data[s->getp++];
paul050c0132005-02-14 23:47:47 +0000358
paul718e3742002-12-13 20:15:29 +0000359 return w;
360}
361
362/* Get next word from the stream. */
363u_int16_t
paulf2e6c422005-02-12 14:35:49 +0000364stream_getw_from (struct stream *s, size_t from)
paul718e3742002-12-13 20:15:29 +0000365{
366 u_int16_t w;
367
paul050c0132005-02-14 23:47:47 +0000368 STREAM_VERIFY_SANE(s);
369
370 if (!GETP_VALID (s, from + sizeof (u_int16_t)))
371 {
372 STREAM_BOUND_WARN (s, "get ");
373 return 0;
374 }
375
paul718e3742002-12-13 20:15:29 +0000376 w = s->data[from++] << 8;
377 w |= s->data[from];
paul050c0132005-02-14 23:47:47 +0000378
paul718e3742002-12-13 20:15:29 +0000379 return w;
380}
381
382/* Get next long word from the stream. */
383u_int32_t
paul050c0132005-02-14 23:47:47 +0000384stream_getl_from (struct stream *s, size_t from)
385{
386 u_int32_t l;
387
388 STREAM_VERIFY_SANE(s);
389
390 if (!GETP_VALID (s, from + sizeof (u_int32_t)))
391 {
392 STREAM_BOUND_WARN (s, "get long");
393 return 0;
394 }
395
396 l = s->data[from++] << 24;
397 l |= s->data[from++] << 16;
398 l |= s->data[from++] << 8;
399 l |= s->data[from];
400
401 return l;
402}
403
404u_int32_t
paul718e3742002-12-13 20:15:29 +0000405stream_getl (struct stream *s)
406{
407 u_int32_t l;
408
paul050c0132005-02-14 23:47:47 +0000409 STREAM_VERIFY_SANE(s);
410
411 if (STREAM_READABLE (s) < sizeof (u_int32_t))
412 {
413 STREAM_BOUND_WARN (s, "get long");
414 return 0;
415 }
416
paul718e3742002-12-13 20:15:29 +0000417 l = s->data[s->getp++] << 24;
418 l |= s->data[s->getp++] << 16;
419 l |= s->data[s->getp++] << 8;
420 l |= s->data[s->getp++];
paul050c0132005-02-14 23:47:47 +0000421
paul718e3742002-12-13 20:15:29 +0000422 return l;
423}
paul4b201d42006-01-10 14:35:19 +0000424
425/* Get next quad word from the stream. */
426uint64_t
427stream_getq_from (struct stream *s, size_t from)
428{
paul581a02a2006-01-19 20:22:16 +0000429 uint64_t q;
paul4b201d42006-01-10 14:35:19 +0000430
431 STREAM_VERIFY_SANE(s);
432
433 if (!GETP_VALID (s, from + sizeof (uint64_t)))
434 {
435 STREAM_BOUND_WARN (s, "get quad");
436 return 0;
437 }
438
439 q = ((uint64_t) s->data[from++]) << 56;
440 q |= ((uint64_t) s->data[from++]) << 48;
441 q |= ((uint64_t) s->data[from++]) << 40;
442 q |= ((uint64_t) s->data[from++]) << 32;
443 q |= ((uint64_t) s->data[from++]) << 24;
444 q |= ((uint64_t) s->data[from++]) << 16;
445 q |= ((uint64_t) s->data[from++]) << 8;
446 q |= ((uint64_t) s->data[from++]);
447
448 return q;
449}
450
451uint64_t
452stream_getq (struct stream *s)
453{
454 uint64_t q;
455
456 STREAM_VERIFY_SANE(s);
457
458 if (STREAM_READABLE (s) < sizeof (uint64_t))
459 {
460 STREAM_BOUND_WARN (s, "get quad");
461 return 0;
462 }
463
464 q = ((uint64_t) s->data[s->getp++]) << 56;
465 q |= ((uint64_t) s->data[s->getp++]) << 48;
466 q |= ((uint64_t) s->data[s->getp++]) << 40;
467 q |= ((uint64_t) s->data[s->getp++]) << 32;
468 q |= ((uint64_t) s->data[s->getp++]) << 24;
469 q |= ((uint64_t) s->data[s->getp++]) << 16;
470 q |= ((uint64_t) s->data[s->getp++]) << 8;
471 q |= ((uint64_t) s->data[s->getp++]);
472
473 return q;
474}
475
paul718e3742002-12-13 20:15:29 +0000476/* Get next long word from the stream. */
477u_int32_t
478stream_get_ipv4 (struct stream *s)
479{
480 u_int32_t l;
481
paul050c0132005-02-14 23:47:47 +0000482 STREAM_VERIFY_SANE(s);
483
484 if (STREAM_READABLE (s) < sizeof(u_int32_t))
485 {
486 STREAM_BOUND_WARN (s, "get ipv4");
487 return 0;
488 }
489
490 memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
491 s->getp += sizeof(u_int32_t);
paul718e3742002-12-13 20:15:29 +0000492
493 return l;
494}
David Lamparter6b0655a2014-06-04 06:53:35 +0200495
Paul Jakmad41e7b92015-05-19 15:38:43 +0100496float
497stream_getf (struct stream *s)
498{
Paul Jakmaa3b161b2016-08-01 15:13:58 +0100499#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1
500#warning "Unknown floating-point format, __func__ may be wrong"
501#endif
502/* we assume 'float' is in the single precision IEC 60559 binary
503 format, in host byte order */
Paul Jakmad41e7b92015-05-19 15:38:43 +0100504 union {
505 float r;
506 uint32_t d;
507 } u;
508 u.d = stream_getl (s);
509 return u.r;
Paul Jakmad41e7b92015-05-19 15:38:43 +0100510}
511
512double
513stream_getd (struct stream *s)
514{
Paul Jakmaa3b161b2016-08-01 15:13:58 +0100515#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1
516#warning "Unknown floating-point format, __func__ may be wrong"
517#endif
Paul Jakmad41e7b92015-05-19 15:38:43 +0100518 union {
519 double r;
520 uint64_t d;
521 } u;
522 u.d = stream_getq (s);
523 return u.r;
Paul Jakmad41e7b92015-05-19 15:38:43 +0100524}
525
paul050c0132005-02-14 23:47:47 +0000526/* Copy to source to stream.
527 *
528 * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
529 * around. This should be fixed once the stream updates are working.
paul0dab9302005-05-03 09:07:56 +0000530 *
531 * stream_write() is saner
paul050c0132005-02-14 23:47:47 +0000532 */
paul718e3742002-12-13 20:15:29 +0000533void
Paul Jakma3d52bb82008-06-07 20:42:07 +0000534stream_put (struct stream *s, const void *src, size_t size)
paul718e3742002-12-13 20:15:29 +0000535{
536
paul050c0132005-02-14 23:47:47 +0000537 /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
paul718e3742002-12-13 20:15:29 +0000538 CHECK_SIZE(s, size);
paul050c0132005-02-14 23:47:47 +0000539
540 STREAM_VERIFY_SANE(s);
541
542 if (STREAM_WRITEABLE (s) < size)
543 {
544 STREAM_BOUND_WARN (s, "put");
545 return;
546 }
547
paul718e3742002-12-13 20:15:29 +0000548 if (src)
paul9985f832005-02-09 15:51:56 +0000549 memcpy (s->data + s->endp, src, size);
paul718e3742002-12-13 20:15:29 +0000550 else
paul9985f832005-02-09 15:51:56 +0000551 memset (s->data + s->endp, 0, size);
paul718e3742002-12-13 20:15:29 +0000552
paul9985f832005-02-09 15:51:56 +0000553 s->endp += size;
paul718e3742002-12-13 20:15:29 +0000554}
555
556/* Put character to the stream. */
557int
558stream_putc (struct stream *s, u_char c)
559{
paul050c0132005-02-14 23:47:47 +0000560 STREAM_VERIFY_SANE(s);
561
562 if (STREAM_WRITEABLE (s) < sizeof(u_char))
563 {
564 STREAM_BOUND_WARN (s, "put");
565 return 0;
566 }
567
568 s->data[s->endp++] = c;
569 return sizeof (u_char);
paul718e3742002-12-13 20:15:29 +0000570}
571
572/* Put word to the stream. */
573int
574stream_putw (struct stream *s, u_int16_t w)
575{
paul050c0132005-02-14 23:47:47 +0000576 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000577
paul050c0132005-02-14 23:47:47 +0000578 if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
579 {
580 STREAM_BOUND_WARN (s, "put");
581 return 0;
582 }
583
paul9985f832005-02-09 15:51:56 +0000584 s->data[s->endp++] = (u_char)(w >> 8);
585 s->data[s->endp++] = (u_char) w;
paul718e3742002-12-13 20:15:29 +0000586
paul718e3742002-12-13 20:15:29 +0000587 return 2;
588}
589
590/* Put long word to the stream. */
591int
592stream_putl (struct stream *s, u_int32_t l)
593{
paul050c0132005-02-14 23:47:47 +0000594 STREAM_VERIFY_SANE (s);
paul718e3742002-12-13 20:15:29 +0000595
paul050c0132005-02-14 23:47:47 +0000596 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
597 {
598 STREAM_BOUND_WARN (s, "put");
599 return 0;
600 }
601
paul9985f832005-02-09 15:51:56 +0000602 s->data[s->endp++] = (u_char)(l >> 24);
603 s->data[s->endp++] = (u_char)(l >> 16);
604 s->data[s->endp++] = (u_char)(l >> 8);
605 s->data[s->endp++] = (u_char)l;
paul718e3742002-12-13 20:15:29 +0000606
paul718e3742002-12-13 20:15:29 +0000607 return 4;
608}
609
paul4b201d42006-01-10 14:35:19 +0000610/* Put quad word to the stream. */
611int
612stream_putq (struct stream *s, uint64_t q)
613{
614 STREAM_VERIFY_SANE (s);
615
616 if (STREAM_WRITEABLE (s) < sizeof (uint64_t))
617 {
618 STREAM_BOUND_WARN (s, "put quad");
619 return 0;
620 }
621
622 s->data[s->endp++] = (u_char)(q >> 56);
623 s->data[s->endp++] = (u_char)(q >> 48);
624 s->data[s->endp++] = (u_char)(q >> 40);
625 s->data[s->endp++] = (u_char)(q >> 32);
626 s->data[s->endp++] = (u_char)(q >> 24);
627 s->data[s->endp++] = (u_char)(q >> 16);
628 s->data[s->endp++] = (u_char)(q >> 8);
629 s->data[s->endp++] = (u_char)q;
630
631 return 8;
632}
633
paul718e3742002-12-13 20:15:29 +0000634int
Paul Jakmad41e7b92015-05-19 15:38:43 +0100635stream_putf (struct stream *s, float f)
636{
Paul Jakmaa3b161b2016-08-01 15:13:58 +0100637#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1
638#warning "Unknown floating-point format, __func__ may be wrong"
639#endif
640
Paul Jakmad41e7b92015-05-19 15:38:43 +0100641/* we can safely assume 'float' is in the single precision
642 IEC 60559 binary format in host order */
643 union {
644 float i;
645 uint32_t o;
646 } u;
647 u.i = f;
648 return stream_putl (s, u.o);
Paul Jakmad41e7b92015-05-19 15:38:43 +0100649}
650
651int
652stream_putd (struct stream *s, double d)
653{
Paul Jakmaa3b161b2016-08-01 15:13:58 +0100654#if !defined(__STDC_IEC_559__) && __GCC_IEC_559 < 1
655#warning "Unknown floating-point format, __func__ may be wrong"
656#endif
Paul Jakmad41e7b92015-05-19 15:38:43 +0100657 union {
658 double i;
659 uint64_t o;
660 } u;
661 u.i = d;
662 return stream_putq (s, u.o);
Paul Jakmad41e7b92015-05-19 15:38:43 +0100663}
664
665int
paulf2e6c422005-02-12 14:35:49 +0000666stream_putc_at (struct stream *s, size_t putp, u_char c)
paul718e3742002-12-13 20:15:29 +0000667{
paul050c0132005-02-14 23:47:47 +0000668 STREAM_VERIFY_SANE(s);
669
670 if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
671 {
672 STREAM_BOUND_WARN (s, "put");
673 return 0;
674 }
675
paul718e3742002-12-13 20:15:29 +0000676 s->data[putp] = c;
paul050c0132005-02-14 23:47:47 +0000677
paul718e3742002-12-13 20:15:29 +0000678 return 1;
679}
680
681int
paulf2e6c422005-02-12 14:35:49 +0000682stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
paul718e3742002-12-13 20:15:29 +0000683{
paul050c0132005-02-14 23:47:47 +0000684 STREAM_VERIFY_SANE(s);
685
686 if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
687 {
688 STREAM_BOUND_WARN (s, "put");
689 return 0;
690 }
691
paul718e3742002-12-13 20:15:29 +0000692 s->data[putp] = (u_char)(w >> 8);
693 s->data[putp + 1] = (u_char) w;
paul050c0132005-02-14 23:47:47 +0000694
paul718e3742002-12-13 20:15:29 +0000695 return 2;
696}
697
698int
paulf2e6c422005-02-12 14:35:49 +0000699stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
paul718e3742002-12-13 20:15:29 +0000700{
paul050c0132005-02-14 23:47:47 +0000701 STREAM_VERIFY_SANE(s);
702
703 if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
704 {
705 STREAM_BOUND_WARN (s, "put");
706 return 0;
707 }
paul718e3742002-12-13 20:15:29 +0000708 s->data[putp] = (u_char)(l >> 24);
709 s->data[putp + 1] = (u_char)(l >> 16);
710 s->data[putp + 2] = (u_char)(l >> 8);
711 s->data[putp + 3] = (u_char)l;
paul050c0132005-02-14 23:47:47 +0000712
paul718e3742002-12-13 20:15:29 +0000713 return 4;
714}
715
paul4b201d42006-01-10 14:35:19 +0000716int
717stream_putq_at (struct stream *s, size_t putp, uint64_t q)
718{
719 STREAM_VERIFY_SANE(s);
720
721 if (!PUT_AT_VALID (s, putp + sizeof (uint64_t)))
722 {
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;
736}
737
paul718e3742002-12-13 20:15:29 +0000738/* Put long word to the stream. */
739int
740stream_put_ipv4 (struct stream *s, u_int32_t l)
741{
paul050c0132005-02-14 23:47:47 +0000742 STREAM_VERIFY_SANE(s);
743
744 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
745 {
746 STREAM_BOUND_WARN (s, "put");
747 return 0;
748 }
749 memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
750 s->endp += sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000751
paul050c0132005-02-14 23:47:47 +0000752 return sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000753}
754
755/* Put long word to the stream. */
756int
757stream_put_in_addr (struct stream *s, struct in_addr *addr)
758{
paul050c0132005-02-14 23:47:47 +0000759 STREAM_VERIFY_SANE(s);
760
761 if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
762 {
763 STREAM_BOUND_WARN (s, "put");
764 return 0;
765 }
paul718e3742002-12-13 20:15:29 +0000766
paul050c0132005-02-14 23:47:47 +0000767 memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
768 s->endp += sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000769
paul050c0132005-02-14 23:47:47 +0000770 return sizeof (u_int32_t);
paul718e3742002-12-13 20:15:29 +0000771}
772
773/* Put prefix by nlri type format. */
774int
775stream_put_prefix (struct stream *s, struct prefix *p)
776{
paul050c0132005-02-14 23:47:47 +0000777 size_t psize;
778
779 STREAM_VERIFY_SANE(s);
780
paul718e3742002-12-13 20:15:29 +0000781 psize = PSIZE (p->prefixlen);
paul050c0132005-02-14 23:47:47 +0000782
Jorge Boncompte [DTI2]af514772013-07-31 16:16:05 +0000783 if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char)))
paul050c0132005-02-14 23:47:47 +0000784 {
785 STREAM_BOUND_WARN (s, "put");
786 return 0;
787 }
788
Jorge Boncompte [DTI2]af514772013-07-31 16:16:05 +0000789 s->data[s->endp++] = p->prefixlen;
paul9985f832005-02-09 15:51:56 +0000790 memcpy (s->data + s->endp, &p->u.prefix, psize);
791 s->endp += psize;
paul718e3742002-12-13 20:15:29 +0000792
paul718e3742002-12-13 20:15:29 +0000793 return psize;
794}
David Lamparter6b0655a2014-06-04 06:53:35 +0200795
paul718e3742002-12-13 20:15:29 +0000796/* Read size from fd. */
797int
798stream_read (struct stream *s, int fd, size_t size)
799{
800 int nbytes;
801
paul050c0132005-02-14 23:47:47 +0000802 STREAM_VERIFY_SANE(s);
803
804 if (STREAM_WRITEABLE (s) < size)
805 {
806 STREAM_BOUND_WARN (s, "put");
807 return 0;
808 }
809
paul9985f832005-02-09 15:51:56 +0000810 nbytes = readn (fd, s->data + s->endp, size);
paul718e3742002-12-13 20:15:29 +0000811
812 if (nbytes > 0)
paul9985f832005-02-09 15:51:56 +0000813 s->endp += nbytes;
814
paul718e3742002-12-13 20:15:29 +0000815 return nbytes;
816}
817
ajs262feb12005-02-16 20:35:47 +0000818ssize_t
819stream_read_try(struct stream *s, int fd, size_t size)
820{
821 ssize_t nbytes;
822
823 STREAM_VERIFY_SANE(s);
824
825 if (STREAM_WRITEABLE(s) < size)
826 {
827 STREAM_BOUND_WARN (s, "put");
828 /* Fatal (not transient) error, since retrying will not help
829 (stream is too small to contain the desired data). */
830 return -1;
831 }
832
833 if ((nbytes = read(fd, s->data + s->endp, size)) >= 0)
834 {
835 s->endp += nbytes;
836 return nbytes;
837 }
838 /* Error: was it transient (return -2) or fatal (return -1)? */
ajs81fb3242005-02-24 16:02:53 +0000839 if (ERRNO_IO_RETRY(errno))
840 return -2;
841 zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
842 return -1;
ajs262feb12005-02-16 20:35:47 +0000843}
844
paul0dab9302005-05-03 09:07:56 +0000845/* Read up to size bytes into the stream from the fd, using recvmsgfrom
846 * whose arguments match the remaining arguments to this function
847 */
848ssize_t
849stream_recvfrom (struct stream *s, int fd, size_t size, int flags,
850 struct sockaddr *from, socklen_t *fromlen)
851{
852 ssize_t nbytes;
853
854 STREAM_VERIFY_SANE(s);
855
856 if (STREAM_WRITEABLE(s) < size)
857 {
858 STREAM_BOUND_WARN (s, "put");
859 /* Fatal (not transient) error, since retrying will not help
860 (stream is too small to contain the desired data). */
861 return -1;
862 }
863
864 if ((nbytes = recvfrom (fd, s->data + s->endp, size,
865 flags, from, fromlen)) >= 0)
866 {
867 s->endp += nbytes;
868 return nbytes;
869 }
870 /* Error: was it transient (return -2) or fatal (return -1)? */
871 if (ERRNO_IO_RETRY(errno))
872 return -2;
873 zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
874 return -1;
875}
876
paul050c0132005-02-14 23:47:47 +0000877/* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
878 * from endp.
879 * First iovec will be used to receive the data.
880 * Stream need not be empty.
881 */
paul0dab9302005-05-03 09:07:56 +0000882ssize_t
paul050c0132005-02-14 23:47:47 +0000883stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags,
884 size_t size)
885{
886 int nbytes;
887 struct iovec *iov;
888
889 STREAM_VERIFY_SANE(s);
890 assert (msgh->msg_iovlen > 0);
891
892 if (STREAM_WRITEABLE (s) < size)
893 {
894 STREAM_BOUND_WARN (s, "put");
ajs262feb12005-02-16 20:35:47 +0000895 /* This is a logic error in the calling code: the stream is too small
896 to hold the desired data! */
897 return -1;
paul050c0132005-02-14 23:47:47 +0000898 }
899
900 iov = &(msgh->msg_iov[0]);
901 iov->iov_base = (s->data + s->endp);
902 iov->iov_len = size;
903
904 nbytes = recvmsg (fd, msgh, flags);
905
906 if (nbytes > 0)
907 s->endp += nbytes;
908
909 return nbytes;
910}
911
paul718e3742002-12-13 20:15:29 +0000912/* Write data to buffer. */
paul0dab9302005-05-03 09:07:56 +0000913size_t
Paul Jakma3d52bb82008-06-07 20:42:07 +0000914stream_write (struct stream *s, const void *ptr, size_t size)
paul718e3742002-12-13 20:15:29 +0000915{
916
917 CHECK_SIZE(s, size);
918
paul050c0132005-02-14 23:47:47 +0000919 STREAM_VERIFY_SANE(s);
920
921 if (STREAM_WRITEABLE (s) < size)
922 {
923 STREAM_BOUND_WARN (s, "put");
924 return 0;
925 }
926
paul9985f832005-02-09 15:51:56 +0000927 memcpy (s->data + s->endp, ptr, size);
928 s->endp += size;
929
paul718e3742002-12-13 20:15:29 +0000930 return size;
931}
932
paul050c0132005-02-14 23:47:47 +0000933/* Return current read pointer.
934 * DEPRECATED!
935 * Use stream_get_pnt_to if you must, but decoding streams properly
936 * is preferred
937 */
paul718e3742002-12-13 20:15:29 +0000938u_char *
939stream_pnt (struct stream *s)
940{
paul050c0132005-02-14 23:47:47 +0000941 STREAM_VERIFY_SANE(s);
paul718e3742002-12-13 20:15:29 +0000942 return s->data + s->getp;
943}
944
945/* Check does this stream empty? */
946int
947stream_empty (struct stream *s)
948{
paul050c0132005-02-14 23:47:47 +0000949 STREAM_VERIFY_SANE(s);
950
951 return (s->endp == 0);
paul718e3742002-12-13 20:15:29 +0000952}
953
954/* Reset stream. */
955void
956stream_reset (struct stream *s)
957{
paul050c0132005-02-14 23:47:47 +0000958 STREAM_VERIFY_SANE (s);
959
960 s->getp = s->endp = 0;
paul718e3742002-12-13 20:15:29 +0000961}
962
Paul Jakmadc633bd2016-12-26 17:25:26 +0000963/* Discard read data (prior to the getp), and move the unread data
964 * to the beginning of the stream.
965 *
966 * See also stream_fifo_* functions, for another approach to managing
967 * streams.
968 */
969void
970stream_discard (struct stream *s)
971{
972 STREAM_VERIFY_SANE (s);
973
974 if (s->getp == 0)
975 return;
976
977 if (s->getp == s->endp)
978 {
979 stream_reset (s);
980 return;
981 }
982
983 s->data = memmove (s->data, s->data + s->getp, s->endp - s->getp);
984 s->endp -= s->getp;
985 s->getp = 0;
986}
987
paul718e3742002-12-13 20:15:29 +0000988/* Write stream contens to the file discriptor. */
989int
990stream_flush (struct stream *s, int fd)
991{
992 int nbytes;
paul050c0132005-02-14 23:47:47 +0000993
994 STREAM_VERIFY_SANE(s);
995
paul718e3742002-12-13 20:15:29 +0000996 nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
paul050c0132005-02-14 23:47:47 +0000997
paul718e3742002-12-13 20:15:29 +0000998 return nbytes;
999}
David Lamparter6b0655a2014-06-04 06:53:35 +02001000
paul718e3742002-12-13 20:15:29 +00001001/* Stream first in first out queue. */
1002
1003struct stream_fifo *
ajs81fb3242005-02-24 16:02:53 +00001004stream_fifo_new (void)
paul718e3742002-12-13 20:15:29 +00001005{
1006 struct stream_fifo *new;
1007
1008 new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
1009 return new;
1010}
1011
1012/* Add new stream to fifo. */
1013void
1014stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
1015{
1016 if (fifo->tail)
1017 fifo->tail->next = s;
1018 else
1019 fifo->head = s;
1020
1021 fifo->tail = s;
1022
1023 fifo->count++;
1024}
1025
1026/* Delete first stream from fifo. */
1027struct stream *
1028stream_fifo_pop (struct stream_fifo *fifo)
1029{
1030 struct stream *s;
1031
1032 s = fifo->head;
1033
1034 if (s)
1035 {
1036 fifo->head = s->next;
1037
1038 if (fifo->head == NULL)
1039 fifo->tail = NULL;
paul718e3742002-12-13 20:15:29 +00001040
Subbaiah Venkatad5310502012-03-24 13:10:19 -07001041 fifo->count--;
1042 }
paul718e3742002-12-13 20:15:29 +00001043
1044 return s;
1045}
1046
1047/* Return first fifo entry. */
1048struct stream *
1049stream_fifo_head (struct stream_fifo *fifo)
1050{
1051 return fifo->head;
1052}
1053
1054void
1055stream_fifo_clean (struct stream_fifo *fifo)
1056{
1057 struct stream *s;
1058 struct stream *next;
1059
1060 for (s = fifo->head; s; s = next)
1061 {
1062 next = s->next;
1063 stream_free (s);
1064 }
1065 fifo->head = fifo->tail = NULL;
1066 fifo->count = 0;
1067}
1068
1069void
1070stream_fifo_free (struct stream_fifo *fifo)
1071{
1072 stream_fifo_clean (fifo);
1073 XFREE (MTYPE_STREAM_FIFO, fifo);
1074}