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