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