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