]>
Commit | Line | Data |
---|---|---|
050c013a | 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 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
22 | ||
050c013a | 23 | #include <stddef.h> |
718e3744 | 24 | #include <zebra.h> |
25 | ||
26 | #include "stream.h" | |
27 | #include "memory.h" | |
28 | #include "network.h" | |
29 | #include "prefix.h" | |
050c013a | 30 | #include "log.h" |
718e3744 | 31 | |
050c013a | 32 | /* Tests whether a position is valid */ |
33 | #define GETP_VALID(S,G) \ | |
34 | ((G) <= (S)->endp) | |
35 | #define PUT_AT_VALID(S,G) GETP_VALID(S,G) | |
36 | #define ENDP_VALID(S,E) \ | |
37 | ((E) <= (S)->size) | |
718e3744 | 38 | |
050c013a | 39 | /* asserting sanity checks. Following must be true before |
40 | * stream functions are called: | |
41 | * | |
42 | * Following must always be true of stream elements | |
43 | * before and after calls to stream functions: | |
44 | * | |
45 | * getp <= endp <= size | |
46 | * | |
47 | * Note that after a stream function is called following may be true: | |
48 | * if (getp == endp) then stream is no longer readable | |
49 | * if (endp == size) then stream is no longer writeable | |
50 | * | |
51 | * It is valid to put to anywhere within the size of the stream, but only | |
52 | * using stream_put..._at() functions. | |
53 | */ | |
54 | #define STREAM_WARN_OFFSETS(S) \ | |
55 | zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \ | |
56 | (S), \ | |
57 | (unsigned long) (S)->size, \ | |
58 | (unsigned long) (S)->getp, \ | |
59 | (unsigned long) (S)->endp)\ | |
60 | ||
61 | #define STREAM_VERIFY_SANE(S) \ | |
62 | do { \ | |
63 | if ( !(GETP_VALID(S, (S)->getp)) && ENDP_VALID(S, (S)->endp) ) \ | |
64 | STREAM_WARN_OFFSETS(S); \ | |
65 | assert ( GETP_VALID(S, (S)->getp) ); \ | |
66 | assert ( ENDP_VALID(S, (S)->endp) ); \ | |
67 | } while (0) | |
68 | ||
69 | #define STREAM_BOUND_WARN(S, WHAT) \ | |
70 | do { \ | |
71 | zlog_warn ("%s: Attempt to %s out of bounds", __func__, (WHAT)); \ | |
72 | STREAM_WARN_OFFSETS(S); \ | |
73 | assert (0); \ | |
74 | } while (0) | |
75 | ||
76 | /* XXX: Deprecated macro: do not use */ | |
718e3744 | 77 | #define CHECK_SIZE(S, Z) \ |
050c013a | 78 | do { \ |
79 | if (((S)->endp + (Z)) > (S)->size) \ | |
80 | { \ | |
81 | zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \ | |
82 | (unsigned long) (Z)); \ | |
83 | STREAM_WARN_OFFSETS(S); \ | |
84 | (Z) = (S)->size - (S)->endp; \ | |
85 | } \ | |
86 | } while (0); | |
718e3744 | 87 | |
88 | /* Make stream buffer. */ | |
89 | struct stream * | |
90 | stream_new (size_t size) | |
91 | { | |
92 | struct stream *s; | |
93 | ||
0e43a2bc | 94 | assert (size > 0); |
95 | ||
96 | if (size == 0) | |
050c013a | 97 | { |
98 | zlog_warn ("stream_new(): called with 0 size!"); | |
99 | return NULL; | |
100 | } | |
0e43a2bc | 101 | |
109ac96f | 102 | s = XCALLOC (MTYPE_STREAM, offsetof(struct stream, data[size])); |
718e3744 | 103 | |
050c013a | 104 | if (s == NULL) |
105 | return s; | |
106 | ||
718e3744 | 107 | s->size = size; |
108 | return s; | |
109 | } | |
110 | ||
111 | /* Free it now. */ | |
112 | void | |
113 | stream_free (struct stream *s) | |
114 | { | |
718e3744 | 115 | XFREE (MTYPE_STREAM, s); |
116 | } | |
050c013a | 117 | |
118 | struct stream * | |
119 | stream_copy (struct stream *new, struct stream *src) | |
120 | { | |
121 | STREAM_VERIFY_SANE (src); | |
122 | ||
123 | assert (new != NULL); | |
124 | assert (STREAM_SIZE(new) >= src->endp); | |
125 | ||
126 | new->endp = src->endp; | |
127 | new->getp = src->getp; | |
128 | ||
129 | memcpy (new->data, src->data, src->endp); | |
130 | ||
131 | return new; | |
132 | } | |
133 | ||
134 | struct stream * | |
135 | stream_dup (struct stream *s) | |
136 | { | |
137 | struct stream *new; | |
138 | ||
139 | STREAM_VERIFY_SANE (s); | |
140 | ||
141 | if ( (new = stream_new (s->endp)) == NULL) | |
142 | return NULL; | |
143 | ||
144 | return (stream_copy (new, s)); | |
145 | } | |
718e3744 | 146 | \f |
f2e6c429 | 147 | size_t |
718e3744 | 148 | stream_get_getp (struct stream *s) |
149 | { | |
050c013a | 150 | STREAM_VERIFY_SANE(s); |
718e3744 | 151 | return s->getp; |
152 | } | |
153 | ||
f2e6c429 | 154 | size_t |
718e3744 | 155 | stream_get_endp (struct stream *s) |
156 | { | |
050c013a | 157 | STREAM_VERIFY_SANE(s); |
718e3744 | 158 | return s->endp; |
159 | } | |
160 | ||
f2e6c429 | 161 | size_t |
718e3744 | 162 | stream_get_size (struct stream *s) |
163 | { | |
050c013a | 164 | STREAM_VERIFY_SANE(s); |
718e3744 | 165 | return s->size; |
166 | } | |
167 | ||
168 | /* Stream structre' stream pointer related functions. */ | |
169 | void | |
f2e6c429 | 170 | stream_set_getp (struct stream *s, size_t pos) |
718e3744 | 171 | { |
050c013a | 172 | STREAM_VERIFY_SANE(s); |
173 | ||
174 | if (!GETP_VALID (s, pos)) | |
175 | { | |
176 | STREAM_BOUND_WARN (s, "set getp"); | |
177 | pos = s->endp; | |
178 | } | |
179 | ||
718e3744 | 180 | s->getp = pos; |
181 | } | |
182 | ||
9985f83c | 183 | /* Forward pointer. */ |
718e3744 | 184 | void |
050c013a | 185 | stream_forward_getp (struct stream *s, size_t size) |
718e3744 | 186 | { |
050c013a | 187 | STREAM_VERIFY_SANE(s); |
188 | ||
189 | if (!GETP_VALID (s, s->getp + size)) | |
190 | { | |
191 | STREAM_BOUND_WARN (s, "seek getp"); | |
192 | return; | |
193 | } | |
194 | ||
9985f83c | 195 | s->getp += size; |
718e3744 | 196 | } |
197 | ||
718e3744 | 198 | void |
050c013a | 199 | stream_forward_endp (struct stream *s, size_t size) |
718e3744 | 200 | { |
050c013a | 201 | STREAM_VERIFY_SANE(s); |
202 | ||
203 | if (!ENDP_VALID (s, s->endp + size)) | |
204 | { | |
205 | STREAM_BOUND_WARN (s, "seek endp"); | |
206 | return; | |
207 | } | |
208 | ||
9985f83c | 209 | s->endp += size; |
718e3744 | 210 | } |
211 | \f | |
212 | /* Copy from stream to destination. */ | |
213 | void | |
214 | stream_get (void *dst, struct stream *s, size_t size) | |
215 | { | |
050c013a | 216 | STREAM_VERIFY_SANE(s); |
217 | ||
218 | if (STREAM_READABLE(s) < size) | |
219 | { | |
220 | STREAM_BOUND_WARN (s, "get"); | |
221 | return; | |
222 | } | |
223 | ||
718e3744 | 224 | memcpy (dst, s->data + s->getp, size); |
225 | s->getp += size; | |
226 | } | |
227 | ||
228 | /* Get next character from the stream. */ | |
229 | u_char | |
230 | stream_getc (struct stream *s) | |
231 | { | |
232 | u_char c; | |
050c013a | 233 | |
234 | STREAM_VERIFY_SANE (s); | |
235 | ||
236 | if (STREAM_READABLE(s) < sizeof (u_char)) | |
237 | { | |
238 | STREAM_BOUND_WARN (s, "get char"); | |
239 | return 0; | |
240 | } | |
241 | c = s->data[s->getp++]; | |
242 | ||
718e3744 | 243 | return c; |
244 | } | |
245 | ||
246 | /* Get next character from the stream. */ | |
247 | u_char | |
f2e6c429 | 248 | stream_getc_from (struct stream *s, size_t from) |
718e3744 | 249 | { |
250 | u_char c; | |
251 | ||
050c013a | 252 | STREAM_VERIFY_SANE(s); |
253 | ||
254 | if (!GETP_VALID (s, from + sizeof (u_char))) | |
255 | { | |
256 | STREAM_BOUND_WARN (s, "get char"); | |
257 | return 0; | |
258 | } | |
259 | ||
718e3744 | 260 | c = s->data[from]; |
050c013a | 261 | |
718e3744 | 262 | return c; |
263 | } | |
264 | ||
265 | /* Get next word from the stream. */ | |
266 | u_int16_t | |
267 | stream_getw (struct stream *s) | |
268 | { | |
269 | u_int16_t w; | |
270 | ||
050c013a | 271 | STREAM_VERIFY_SANE (s); |
272 | ||
273 | if (STREAM_READABLE (s) < sizeof (u_int16_t)) | |
274 | { | |
275 | STREAM_BOUND_WARN (s, "get "); | |
276 | return 0; | |
277 | } | |
278 | ||
718e3744 | 279 | w = s->data[s->getp++] << 8; |
280 | w |= s->data[s->getp++]; | |
050c013a | 281 | |
718e3744 | 282 | return w; |
283 | } | |
284 | ||
285 | /* Get next word from the stream. */ | |
286 | u_int16_t | |
f2e6c429 | 287 | stream_getw_from (struct stream *s, size_t from) |
718e3744 | 288 | { |
289 | u_int16_t w; | |
290 | ||
050c013a | 291 | STREAM_VERIFY_SANE(s); |
292 | ||
293 | if (!GETP_VALID (s, from + sizeof (u_int16_t))) | |
294 | { | |
295 | STREAM_BOUND_WARN (s, "get "); | |
296 | return 0; | |
297 | } | |
298 | ||
718e3744 | 299 | w = s->data[from++] << 8; |
300 | w |= s->data[from]; | |
050c013a | 301 | |
718e3744 | 302 | return w; |
303 | } | |
304 | ||
305 | /* Get next long word from the stream. */ | |
050c013a | 306 | u_int32_t |
307 | stream_getl_from (struct stream *s, size_t from) | |
308 | { | |
309 | u_int32_t l; | |
310 | ||
311 | STREAM_VERIFY_SANE(s); | |
312 | ||
313 | if (!GETP_VALID (s, from + sizeof (u_int32_t))) | |
314 | { | |
315 | STREAM_BOUND_WARN (s, "get long"); | |
316 | return 0; | |
317 | } | |
318 | ||
319 | l = s->data[from++] << 24; | |
320 | l |= s->data[from++] << 16; | |
321 | l |= s->data[from++] << 8; | |
322 | l |= s->data[from]; | |
323 | ||
324 | return l; | |
325 | } | |
326 | ||
718e3744 | 327 | u_int32_t |
328 | stream_getl (struct stream *s) | |
329 | { | |
330 | u_int32_t l; | |
331 | ||
050c013a | 332 | STREAM_VERIFY_SANE(s); |
333 | ||
334 | if (STREAM_READABLE (s) < sizeof (u_int32_t)) | |
335 | { | |
336 | STREAM_BOUND_WARN (s, "get long"); | |
337 | return 0; | |
338 | } | |
339 | ||
718e3744 | 340 | l = s->data[s->getp++] << 24; |
341 | l |= s->data[s->getp++] << 16; | |
342 | l |= s->data[s->getp++] << 8; | |
343 | l |= s->data[s->getp++]; | |
050c013a | 344 | |
718e3744 | 345 | return l; |
346 | } | |
718e3744 | 347 | /* Get next long word from the stream. */ |
348 | u_int32_t | |
349 | stream_get_ipv4 (struct stream *s) | |
350 | { | |
351 | u_int32_t l; | |
352 | ||
050c013a | 353 | STREAM_VERIFY_SANE(s); |
354 | ||
355 | if (STREAM_READABLE (s) < sizeof(u_int32_t)) | |
356 | { | |
357 | STREAM_BOUND_WARN (s, "get ipv4"); | |
358 | return 0; | |
359 | } | |
360 | ||
361 | memcpy (&l, s->data + s->getp, sizeof(u_int32_t)); | |
362 | s->getp += sizeof(u_int32_t); | |
718e3744 | 363 | |
364 | return l; | |
365 | } | |
366 | \f | |
050c013a | 367 | /* Copy to source to stream. |
368 | * | |
369 | * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap | |
370 | * around. This should be fixed once the stream updates are working. | |
371 | */ | |
718e3744 | 372 | void |
373 | stream_put (struct stream *s, void *src, size_t size) | |
374 | { | |
375 | ||
050c013a | 376 | /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */ |
718e3744 | 377 | CHECK_SIZE(s, size); |
050c013a | 378 | |
379 | STREAM_VERIFY_SANE(s); | |
380 | ||
381 | if (STREAM_WRITEABLE (s) < size) | |
382 | { | |
383 | STREAM_BOUND_WARN (s, "put"); | |
384 | return; | |
385 | } | |
386 | ||
718e3744 | 387 | if (src) |
9985f83c | 388 | memcpy (s->data + s->endp, src, size); |
718e3744 | 389 | else |
9985f83c | 390 | memset (s->data + s->endp, 0, size); |
718e3744 | 391 | |
9985f83c | 392 | s->endp += size; |
718e3744 | 393 | } |
394 | ||
395 | /* Put character to the stream. */ | |
396 | int | |
397 | stream_putc (struct stream *s, u_char c) | |
398 | { | |
050c013a | 399 | STREAM_VERIFY_SANE(s); |
400 | ||
401 | if (STREAM_WRITEABLE (s) < sizeof(u_char)) | |
402 | { | |
403 | STREAM_BOUND_WARN (s, "put"); | |
404 | return 0; | |
405 | } | |
406 | ||
407 | s->data[s->endp++] = c; | |
408 | return sizeof (u_char); | |
718e3744 | 409 | } |
410 | ||
411 | /* Put word to the stream. */ | |
412 | int | |
413 | stream_putw (struct stream *s, u_int16_t w) | |
414 | { | |
050c013a | 415 | STREAM_VERIFY_SANE (s); |
718e3744 | 416 | |
050c013a | 417 | if (STREAM_WRITEABLE (s) < sizeof (u_int16_t)) |
418 | { | |
419 | STREAM_BOUND_WARN (s, "put"); | |
420 | return 0; | |
421 | } | |
422 | ||
9985f83c | 423 | s->data[s->endp++] = (u_char)(w >> 8); |
424 | s->data[s->endp++] = (u_char) w; | |
718e3744 | 425 | |
718e3744 | 426 | return 2; |
427 | } | |
428 | ||
429 | /* Put long word to the stream. */ | |
430 | int | |
431 | stream_putl (struct stream *s, u_int32_t l) | |
432 | { | |
050c013a | 433 | STREAM_VERIFY_SANE (s); |
718e3744 | 434 | |
050c013a | 435 | if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) |
436 | { | |
437 | STREAM_BOUND_WARN (s, "put"); | |
438 | return 0; | |
439 | } | |
440 | ||
9985f83c | 441 | s->data[s->endp++] = (u_char)(l >> 24); |
442 | s->data[s->endp++] = (u_char)(l >> 16); | |
443 | s->data[s->endp++] = (u_char)(l >> 8); | |
444 | s->data[s->endp++] = (u_char)l; | |
718e3744 | 445 | |
718e3744 | 446 | return 4; |
447 | } | |
448 | ||
449 | int | |
f2e6c429 | 450 | stream_putc_at (struct stream *s, size_t putp, u_char c) |
718e3744 | 451 | { |
050c013a | 452 | STREAM_VERIFY_SANE(s); |
453 | ||
454 | if (!PUT_AT_VALID (s, putp + sizeof (u_char))) | |
455 | { | |
456 | STREAM_BOUND_WARN (s, "put"); | |
457 | return 0; | |
458 | } | |
459 | ||
718e3744 | 460 | s->data[putp] = c; |
050c013a | 461 | |
718e3744 | 462 | return 1; |
463 | } | |
464 | ||
465 | int | |
f2e6c429 | 466 | stream_putw_at (struct stream *s, size_t putp, u_int16_t w) |
718e3744 | 467 | { |
050c013a | 468 | STREAM_VERIFY_SANE(s); |
469 | ||
470 | if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t))) | |
471 | { | |
472 | STREAM_BOUND_WARN (s, "put"); | |
473 | return 0; | |
474 | } | |
475 | ||
718e3744 | 476 | s->data[putp] = (u_char)(w >> 8); |
477 | s->data[putp + 1] = (u_char) w; | |
050c013a | 478 | |
718e3744 | 479 | return 2; |
480 | } | |
481 | ||
482 | int | |
f2e6c429 | 483 | stream_putl_at (struct stream *s, size_t putp, u_int32_t l) |
718e3744 | 484 | { |
050c013a | 485 | STREAM_VERIFY_SANE(s); |
486 | ||
487 | if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t))) | |
488 | { | |
489 | STREAM_BOUND_WARN (s, "put"); | |
490 | return 0; | |
491 | } | |
718e3744 | 492 | s->data[putp] = (u_char)(l >> 24); |
493 | s->data[putp + 1] = (u_char)(l >> 16); | |
494 | s->data[putp + 2] = (u_char)(l >> 8); | |
495 | s->data[putp + 3] = (u_char)l; | |
050c013a | 496 | |
718e3744 | 497 | return 4; |
498 | } | |
499 | ||
500 | /* Put long word to the stream. */ | |
501 | int | |
502 | stream_put_ipv4 (struct stream *s, u_int32_t l) | |
503 | { | |
050c013a | 504 | STREAM_VERIFY_SANE(s); |
505 | ||
506 | if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) | |
507 | { | |
508 | STREAM_BOUND_WARN (s, "put"); | |
509 | return 0; | |
510 | } | |
511 | memcpy (s->data + s->endp, &l, sizeof (u_int32_t)); | |
512 | s->endp += sizeof (u_int32_t); | |
718e3744 | 513 | |
050c013a | 514 | return sizeof (u_int32_t); |
718e3744 | 515 | } |
516 | ||
517 | /* Put long word to the stream. */ | |
518 | int | |
519 | stream_put_in_addr (struct stream *s, struct in_addr *addr) | |
520 | { | |
050c013a | 521 | STREAM_VERIFY_SANE(s); |
522 | ||
523 | if (STREAM_WRITEABLE (s) < sizeof (u_int32_t)) | |
524 | { | |
525 | STREAM_BOUND_WARN (s, "put"); | |
526 | return 0; | |
527 | } | |
718e3744 | 528 | |
050c013a | 529 | memcpy (s->data + s->endp, addr, sizeof (u_int32_t)); |
530 | s->endp += sizeof (u_int32_t); | |
718e3744 | 531 | |
050c013a | 532 | return sizeof (u_int32_t); |
718e3744 | 533 | } |
534 | ||
535 | /* Put prefix by nlri type format. */ | |
536 | int | |
537 | stream_put_prefix (struct stream *s, struct prefix *p) | |
538 | { | |
050c013a | 539 | size_t psize; |
540 | ||
541 | STREAM_VERIFY_SANE(s); | |
542 | ||
718e3744 | 543 | psize = PSIZE (p->prefixlen); |
050c013a | 544 | |
545 | if (STREAM_WRITEABLE (s) < psize) | |
546 | { | |
547 | STREAM_BOUND_WARN (s, "put"); | |
548 | return 0; | |
549 | } | |
550 | ||
718e3744 | 551 | stream_putc (s, p->prefixlen); |
9985f83c | 552 | memcpy (s->data + s->endp, &p->u.prefix, psize); |
553 | s->endp += psize; | |
718e3744 | 554 | |
718e3744 | 555 | return psize; |
556 | } | |
557 | \f | |
558 | /* Read size from fd. */ | |
559 | int | |
560 | stream_read (struct stream *s, int fd, size_t size) | |
561 | { | |
562 | int nbytes; | |
563 | ||
050c013a | 564 | STREAM_VERIFY_SANE(s); |
565 | ||
566 | if (STREAM_WRITEABLE (s) < size) | |
567 | { | |
568 | STREAM_BOUND_WARN (s, "put"); | |
569 | return 0; | |
570 | } | |
571 | ||
9985f83c | 572 | nbytes = readn (fd, s->data + s->endp, size); |
718e3744 | 573 | |
574 | if (nbytes > 0) | |
9985f83c | 575 | s->endp += nbytes; |
576 | ||
718e3744 | 577 | return nbytes; |
578 | } | |
579 | ||
580 | /* Read size from fd. */ | |
581 | int | |
582 | stream_read_unblock (struct stream *s, int fd, size_t size) | |
583 | { | |
584 | int nbytes; | |
585 | int val; | |
050c013a | 586 | |
587 | STREAM_VERIFY_SANE(s); | |
588 | ||
589 | if (STREAM_WRITEABLE (s) < size) | |
590 | { | |
591 | STREAM_BOUND_WARN (s, "put"); | |
592 | return 0; | |
593 | } | |
594 | ||
718e3744 | 595 | val = fcntl (fd, F_GETFL, 0); |
596 | fcntl (fd, F_SETFL, val|O_NONBLOCK); | |
9985f83c | 597 | nbytes = read (fd, s->data + s->endp, size); |
718e3744 | 598 | fcntl (fd, F_SETFL, val); |
599 | ||
600 | if (nbytes > 0) | |
9985f83c | 601 | s->endp += nbytes; |
602 | ||
718e3744 | 603 | return nbytes; |
604 | } | |
605 | ||
262feb1a | 606 | ssize_t |
607 | stream_read_try(struct stream *s, int fd, size_t size) | |
608 | { | |
609 | ssize_t nbytes; | |
610 | ||
611 | STREAM_VERIFY_SANE(s); | |
612 | ||
613 | if (STREAM_WRITEABLE(s) < size) | |
614 | { | |
615 | STREAM_BOUND_WARN (s, "put"); | |
616 | /* Fatal (not transient) error, since retrying will not help | |
617 | (stream is too small to contain the desired data). */ | |
618 | return -1; | |
619 | } | |
620 | ||
621 | if ((nbytes = read(fd, s->data + s->endp, size)) >= 0) | |
622 | { | |
623 | s->endp += nbytes; | |
624 | return nbytes; | |
625 | } | |
626 | /* Error: was it transient (return -2) or fatal (return -1)? */ | |
81fb3240 | 627 | if (ERRNO_IO_RETRY(errno)) |
628 | return -2; | |
629 | zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno)); | |
630 | return -1; | |
262feb1a | 631 | } |
632 | ||
050c013a | 633 | /* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting |
634 | * from endp. | |
635 | * First iovec will be used to receive the data. | |
636 | * Stream need not be empty. | |
637 | */ | |
638 | int | |
639 | stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags, | |
640 | size_t size) | |
641 | { | |
642 | int nbytes; | |
643 | struct iovec *iov; | |
644 | ||
645 | STREAM_VERIFY_SANE(s); | |
646 | assert (msgh->msg_iovlen > 0); | |
647 | ||
648 | if (STREAM_WRITEABLE (s) < size) | |
649 | { | |
650 | STREAM_BOUND_WARN (s, "put"); | |
262feb1a | 651 | /* This is a logic error in the calling code: the stream is too small |
652 | to hold the desired data! */ | |
653 | return -1; | |
050c013a | 654 | } |
655 | ||
656 | iov = &(msgh->msg_iov[0]); | |
657 | iov->iov_base = (s->data + s->endp); | |
658 | iov->iov_len = size; | |
659 | ||
660 | nbytes = recvmsg (fd, msgh, flags); | |
661 | ||
662 | if (nbytes > 0) | |
663 | s->endp += nbytes; | |
664 | ||
665 | return nbytes; | |
666 | } | |
667 | ||
718e3744 | 668 | /* Write data to buffer. */ |
669 | int | |
670 | stream_write (struct stream *s, u_char *ptr, size_t size) | |
671 | { | |
672 | ||
673 | CHECK_SIZE(s, size); | |
674 | ||
050c013a | 675 | STREAM_VERIFY_SANE(s); |
676 | ||
677 | if (STREAM_WRITEABLE (s) < size) | |
678 | { | |
679 | STREAM_BOUND_WARN (s, "put"); | |
680 | return 0; | |
681 | } | |
682 | ||
9985f83c | 683 | memcpy (s->data + s->endp, ptr, size); |
684 | s->endp += size; | |
685 | ||
718e3744 | 686 | return size; |
687 | } | |
688 | ||
050c013a | 689 | /* Return current read pointer. |
690 | * DEPRECATED! | |
691 | * Use stream_get_pnt_to if you must, but decoding streams properly | |
692 | * is preferred | |
693 | */ | |
718e3744 | 694 | u_char * |
695 | stream_pnt (struct stream *s) | |
696 | { | |
050c013a | 697 | STREAM_VERIFY_SANE(s); |
718e3744 | 698 | return s->data + s->getp; |
699 | } | |
700 | ||
701 | /* Check does this stream empty? */ | |
702 | int | |
703 | stream_empty (struct stream *s) | |
704 | { | |
050c013a | 705 | STREAM_VERIFY_SANE(s); |
706 | ||
707 | return (s->endp == 0); | |
718e3744 | 708 | } |
709 | ||
710 | /* Reset stream. */ | |
711 | void | |
712 | stream_reset (struct stream *s) | |
713 | { | |
050c013a | 714 | STREAM_VERIFY_SANE (s); |
715 | ||
716 | s->getp = s->endp = 0; | |
718e3744 | 717 | } |
718 | ||
719 | /* Write stream contens to the file discriptor. */ | |
720 | int | |
721 | stream_flush (struct stream *s, int fd) | |
722 | { | |
723 | int nbytes; | |
050c013a | 724 | |
725 | STREAM_VERIFY_SANE(s); | |
726 | ||
718e3744 | 727 | nbytes = write (fd, s->data + s->getp, s->endp - s->getp); |
050c013a | 728 | |
718e3744 | 729 | return nbytes; |
730 | } | |
731 | \f | |
732 | /* Stream first in first out queue. */ | |
733 | ||
734 | struct stream_fifo * | |
81fb3240 | 735 | stream_fifo_new (void) |
718e3744 | 736 | { |
737 | struct stream_fifo *new; | |
738 | ||
739 | new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo)); | |
740 | return new; | |
741 | } | |
742 | ||
743 | /* Add new stream to fifo. */ | |
744 | void | |
745 | stream_fifo_push (struct stream_fifo *fifo, struct stream *s) | |
746 | { | |
747 | if (fifo->tail) | |
748 | fifo->tail->next = s; | |
749 | else | |
750 | fifo->head = s; | |
751 | ||
752 | fifo->tail = s; | |
753 | ||
754 | fifo->count++; | |
755 | } | |
756 | ||
757 | /* Delete first stream from fifo. */ | |
758 | struct stream * | |
759 | stream_fifo_pop (struct stream_fifo *fifo) | |
760 | { | |
761 | struct stream *s; | |
762 | ||
763 | s = fifo->head; | |
764 | ||
765 | if (s) | |
766 | { | |
767 | fifo->head = s->next; | |
768 | ||
769 | if (fifo->head == NULL) | |
770 | fifo->tail = NULL; | |
771 | } | |
772 | ||
773 | fifo->count--; | |
774 | ||
775 | return s; | |
776 | } | |
777 | ||
778 | /* Return first fifo entry. */ | |
779 | struct stream * | |
780 | stream_fifo_head (struct stream_fifo *fifo) | |
781 | { | |
782 | return fifo->head; | |
783 | } | |
784 | ||
785 | void | |
786 | stream_fifo_clean (struct stream_fifo *fifo) | |
787 | { | |
788 | struct stream *s; | |
789 | struct stream *next; | |
790 | ||
791 | for (s = fifo->head; s; s = next) | |
792 | { | |
793 | next = s->next; | |
794 | stream_free (s); | |
795 | } | |
796 | fifo->head = fifo->tail = NULL; | |
797 | fifo->count = 0; | |
798 | } | |
799 | ||
800 | void | |
801 | stream_fifo_free (struct stream_fifo *fifo) | |
802 | { | |
803 | stream_fifo_clean (fifo); | |
804 | XFREE (MTYPE_STREAM_FIFO, fifo); | |
805 | } |