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