1: /*
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:
23: #include <zebra.h>
24: #include <stddef.h>
25:
26: #include "stream.h"
27: #include "memory.h"
28: #include "network.h"
29: #include "prefix.h"
30: #include "log.h"
31:
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)
38:
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, getp: %lu, endp: %lu\n", \
56: (void *)(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 */
77: #define CHECK_SIZE(S, Z) \
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);
87:
88: /* Make stream buffer. */
89: struct stream *
90: stream_new (size_t size)
91: {
92: struct stream *s;
93:
94: assert (size > 0);
95:
96: if (size == 0)
97: {
98: zlog_warn ("stream_new(): called with 0 size!");
99: return NULL;
100: }
101:
102: s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
103:
104: if (s == NULL)
105: return s;
106:
107: if ( (s->data = XMALLOC (MTYPE_STREAM_DATA, size)) == NULL)
108: {
109: XFREE (MTYPE_STREAM, s);
110: return NULL;
111: }
112:
113: s->size = size;
114: return s;
115: }
116:
117: /* Free it now. */
118: void
119: stream_free (struct stream *s)
120: {
121: if (!s)
122: return;
123:
124: XFREE (MTYPE_STREAM_DATA, s->data);
125: XFREE (MTYPE_STREAM, s);
126: }
127:
128: struct stream *
129: stream_copy (struct stream *new, struct stream *src)
130: {
131: STREAM_VERIFY_SANE (src);
132:
133: assert (new != NULL);
134: assert (STREAM_SIZE(new) >= src->endp);
135:
136: new->endp = src->endp;
137: new->getp = src->getp;
138:
139: memcpy (new->data, src->data, src->endp);
140:
141: return new;
142: }
143:
144: struct stream *
145: stream_dup (struct stream *s)
146: {
147: struct stream *new;
148:
149: STREAM_VERIFY_SANE (s);
150:
151: if ( (new = stream_new (s->endp)) == NULL)
152: return NULL;
153:
154: return (stream_copy (new, s));
155: }
156:
157: struct stream *
158: stream_dupcat (struct stream *s1, struct stream *s2, size_t offset)
159: {
160: struct stream *new;
161:
162: STREAM_VERIFY_SANE (s1);
163: STREAM_VERIFY_SANE (s2);
164:
165: if ( (new = stream_new (s1->endp + s2->endp)) == NULL)
166: return NULL;
167:
168: memcpy (new->data, s1->data, offset);
169: memcpy (new->data + offset, s2->data, s2->endp);
170: memcpy (new->data + offset + s2->endp, s1->data + offset,
171: (s1->endp - offset));
172: new->endp = s1->endp + s2->endp;
173: return new;
174: }
175:
176: size_t
177: stream_resize (struct stream *s, size_t newsize)
178: {
179: u_char *newdata;
180: STREAM_VERIFY_SANE (s);
181:
182: newdata = XREALLOC (MTYPE_STREAM_DATA, s->data, newsize);
183:
184: if (newdata == NULL)
185: return s->size;
186:
187: s->data = newdata;
188: s->size = newsize;
189:
190: if (s->endp > s->size)
191: s->endp = s->size;
192: if (s->getp > s->endp)
193: s->getp = s->endp;
194:
195: STREAM_VERIFY_SANE (s);
196:
197: return s->size;
198: }
199:
200: size_t
201: stream_get_getp (struct stream *s)
202: {
203: STREAM_VERIFY_SANE(s);
204: return s->getp;
205: }
206:
207: size_t
208: stream_get_endp (struct stream *s)
209: {
210: STREAM_VERIFY_SANE(s);
211: return s->endp;
212: }
213:
214: size_t
215: stream_get_size (struct stream *s)
216: {
217: STREAM_VERIFY_SANE(s);
218: return s->size;
219: }
220:
221: /* Stream structre' stream pointer related functions. */
222: void
223: stream_set_getp (struct stream *s, size_t pos)
224: {
225: STREAM_VERIFY_SANE(s);
226:
227: if (!GETP_VALID (s, pos))
228: {
229: STREAM_BOUND_WARN (s, "set getp");
230: pos = s->endp;
231: }
232:
233: s->getp = pos;
234: }
235:
236: void
237: stream_set_endp (struct stream *s, size_t pos)
238: {
239: STREAM_VERIFY_SANE(s);
240:
241: if (!ENDP_VALID(s, pos))
242: {
243: STREAM_BOUND_WARN (s, "set endp");
244: return;
245: }
246:
247: /*
248: * Make sure the current read pointer is not beyond the new endp.
249: */
250: if (s->getp > pos)
251: {
252: STREAM_BOUND_WARN(s, "set endp");
253: return;
254: }
255:
256: s->endp = pos;
257: STREAM_VERIFY_SANE(s);
258: }
259:
260: /* Forward pointer. */
261: void
262: stream_forward_getp (struct stream *s, size_t size)
263: {
264: STREAM_VERIFY_SANE(s);
265:
266: if (!GETP_VALID (s, s->getp + size))
267: {
268: STREAM_BOUND_WARN (s, "seek getp");
269: return;
270: }
271:
272: s->getp += size;
273: }
274:
275: void
276: stream_forward_endp (struct stream *s, size_t size)
277: {
278: STREAM_VERIFY_SANE(s);
279:
280: if (!ENDP_VALID (s, s->endp + size))
281: {
282: STREAM_BOUND_WARN (s, "seek endp");
283: return;
284: }
285:
286: s->endp += size;
287: }
288:
289: /* Copy from stream to destination. */
290: void
291: stream_get (void *dst, struct stream *s, size_t size)
292: {
293: STREAM_VERIFY_SANE(s);
294:
295: if (STREAM_READABLE(s) < size)
296: {
297: STREAM_BOUND_WARN (s, "get");
298: return;
299: }
300:
301: memcpy (dst, s->data + s->getp, size);
302: s->getp += size;
303: }
304:
305: /* Get next character from the stream. */
306: u_char
307: stream_getc (struct stream *s)
308: {
309: u_char c;
310:
311: STREAM_VERIFY_SANE (s);
312:
313: if (STREAM_READABLE(s) < sizeof (u_char))
314: {
315: STREAM_BOUND_WARN (s, "get char");
316: return 0;
317: }
318: c = s->data[s->getp++];
319:
320: return c;
321: }
322:
323: /* Get next character from the stream. */
324: u_char
325: stream_getc_from (struct stream *s, size_t from)
326: {
327: u_char c;
328:
329: STREAM_VERIFY_SANE(s);
330:
331: if (!GETP_VALID (s, from + sizeof (u_char)))
332: {
333: STREAM_BOUND_WARN (s, "get char");
334: return 0;
335: }
336:
337: c = s->data[from];
338:
339: return c;
340: }
341:
342: /* Get next word from the stream. */
343: u_int16_t
344: stream_getw (struct stream *s)
345: {
346: u_int16_t w;
347:
348: STREAM_VERIFY_SANE (s);
349:
350: if (STREAM_READABLE (s) < sizeof (u_int16_t))
351: {
352: STREAM_BOUND_WARN (s, "get ");
353: return 0;
354: }
355:
356: w = s->data[s->getp++] << 8;
357: w |= s->data[s->getp++];
358:
359: return w;
360: }
361:
362: /* Get next word from the stream. */
363: u_int16_t
364: stream_getw_from (struct stream *s, size_t from)
365: {
366: u_int16_t w;
367:
368: STREAM_VERIFY_SANE(s);
369:
370: if (!GETP_VALID (s, from + sizeof (u_int16_t)))
371: {
372: STREAM_BOUND_WARN (s, "get ");
373: return 0;
374: }
375:
376: w = s->data[from++] << 8;
377: w |= s->data[from];
378:
379: return w;
380: }
381:
382: /* Get next long word from the stream. */
383: u_int32_t
384: stream_getl_from (struct stream *s, size_t from)
385: {
386: u_int32_t l;
387:
388: STREAM_VERIFY_SANE(s);
389:
390: if (!GETP_VALID (s, from + sizeof (u_int32_t)))
391: {
392: STREAM_BOUND_WARN (s, "get long");
393: return 0;
394: }
395:
396: l = s->data[from++] << 24;
397: l |= s->data[from++] << 16;
398: l |= s->data[from++] << 8;
399: l |= s->data[from];
400:
401: return l;
402: }
403:
404: u_int32_t
405: stream_getl (struct stream *s)
406: {
407: u_int32_t l;
408:
409: STREAM_VERIFY_SANE(s);
410:
411: if (STREAM_READABLE (s) < sizeof (u_int32_t))
412: {
413: STREAM_BOUND_WARN (s, "get long");
414: return 0;
415: }
416:
417: l = s->data[s->getp++] << 24;
418: l |= s->data[s->getp++] << 16;
419: l |= s->data[s->getp++] << 8;
420: l |= s->data[s->getp++];
421:
422: return l;
423: }
424:
425: /* Get next quad word from the stream. */
426: uint64_t
427: stream_getq_from (struct stream *s, size_t from)
428: {
429: uint64_t q;
430:
431: STREAM_VERIFY_SANE(s);
432:
433: if (!GETP_VALID (s, from + sizeof (uint64_t)))
434: {
435: STREAM_BOUND_WARN (s, "get quad");
436: return 0;
437: }
438:
439: q = ((uint64_t) s->data[from++]) << 56;
440: q |= ((uint64_t) s->data[from++]) << 48;
441: q |= ((uint64_t) s->data[from++]) << 40;
442: q |= ((uint64_t) s->data[from++]) << 32;
443: q |= ((uint64_t) s->data[from++]) << 24;
444: q |= ((uint64_t) s->data[from++]) << 16;
445: q |= ((uint64_t) s->data[from++]) << 8;
446: q |= ((uint64_t) s->data[from++]);
447:
448: return q;
449: }
450:
451: uint64_t
452: stream_getq (struct stream *s)
453: {
454: uint64_t q;
455:
456: STREAM_VERIFY_SANE(s);
457:
458: if (STREAM_READABLE (s) < sizeof (uint64_t))
459: {
460: STREAM_BOUND_WARN (s, "get quad");
461: return 0;
462: }
463:
464: q = ((uint64_t) s->data[s->getp++]) << 56;
465: q |= ((uint64_t) s->data[s->getp++]) << 48;
466: q |= ((uint64_t) s->data[s->getp++]) << 40;
467: q |= ((uint64_t) s->data[s->getp++]) << 32;
468: q |= ((uint64_t) s->data[s->getp++]) << 24;
469: q |= ((uint64_t) s->data[s->getp++]) << 16;
470: q |= ((uint64_t) s->data[s->getp++]) << 8;
471: q |= ((uint64_t) s->data[s->getp++]);
472:
473: return q;
474: }
475:
476: /* Get next long word from the stream. */
477: u_int32_t
478: stream_get_ipv4 (struct stream *s)
479: {
480: u_int32_t l;
481:
482: STREAM_VERIFY_SANE(s);
483:
484: if (STREAM_READABLE (s) < sizeof(u_int32_t))
485: {
486: STREAM_BOUND_WARN (s, "get ipv4");
487: return 0;
488: }
489:
490: memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
491: s->getp += sizeof(u_int32_t);
492:
493: return l;
494: }
495:
496: /* Copy to source to stream.
497: *
498: * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
499: * around. This should be fixed once the stream updates are working.
500: *
501: * stream_write() is saner
502: */
503: void
504: stream_put (struct stream *s, const void *src, size_t size)
505: {
506:
507: /* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
508: CHECK_SIZE(s, size);
509:
510: STREAM_VERIFY_SANE(s);
511:
512: if (STREAM_WRITEABLE (s) < size)
513: {
514: STREAM_BOUND_WARN (s, "put");
515: return;
516: }
517:
518: if (src)
519: memcpy (s->data + s->endp, src, size);
520: else
521: memset (s->data + s->endp, 0, size);
522:
523: s->endp += size;
524: }
525:
526: /* Put character to the stream. */
527: int
528: stream_putc (struct stream *s, u_char c)
529: {
530: STREAM_VERIFY_SANE(s);
531:
532: if (STREAM_WRITEABLE (s) < sizeof(u_char))
533: {
534: STREAM_BOUND_WARN (s, "put");
535: return 0;
536: }
537:
538: s->data[s->endp++] = c;
539: return sizeof (u_char);
540: }
541:
542: /* Put word to the stream. */
543: int
544: stream_putw (struct stream *s, u_int16_t w)
545: {
546: STREAM_VERIFY_SANE (s);
547:
548: if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
549: {
550: STREAM_BOUND_WARN (s, "put");
551: return 0;
552: }
553:
554: s->data[s->endp++] = (u_char)(w >> 8);
555: s->data[s->endp++] = (u_char) w;
556:
557: return 2;
558: }
559:
560: /* Put long word to the stream. */
561: int
562: stream_putl (struct stream *s, u_int32_t l)
563: {
564: STREAM_VERIFY_SANE (s);
565:
566: if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
567: {
568: STREAM_BOUND_WARN (s, "put");
569: return 0;
570: }
571:
572: s->data[s->endp++] = (u_char)(l >> 24);
573: s->data[s->endp++] = (u_char)(l >> 16);
574: s->data[s->endp++] = (u_char)(l >> 8);
575: s->data[s->endp++] = (u_char)l;
576:
577: return 4;
578: }
579:
580: /* Put quad word to the stream. */
581: int
582: stream_putq (struct stream *s, uint64_t q)
583: {
584: STREAM_VERIFY_SANE (s);
585:
586: if (STREAM_WRITEABLE (s) < sizeof (uint64_t))
587: {
588: STREAM_BOUND_WARN (s, "put quad");
589: return 0;
590: }
591:
592: s->data[s->endp++] = (u_char)(q >> 56);
593: s->data[s->endp++] = (u_char)(q >> 48);
594: s->data[s->endp++] = (u_char)(q >> 40);
595: s->data[s->endp++] = (u_char)(q >> 32);
596: s->data[s->endp++] = (u_char)(q >> 24);
597: s->data[s->endp++] = (u_char)(q >> 16);
598: s->data[s->endp++] = (u_char)(q >> 8);
599: s->data[s->endp++] = (u_char)q;
600:
601: return 8;
602: }
603:
604: int
605: stream_putc_at (struct stream *s, size_t putp, u_char c)
606: {
607: STREAM_VERIFY_SANE(s);
608:
609: if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
610: {
611: STREAM_BOUND_WARN (s, "put");
612: return 0;
613: }
614:
615: s->data[putp] = c;
616:
617: return 1;
618: }
619:
620: int
621: stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
622: {
623: STREAM_VERIFY_SANE(s);
624:
625: if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
626: {
627: STREAM_BOUND_WARN (s, "put");
628: return 0;
629: }
630:
631: s->data[putp] = (u_char)(w >> 8);
632: s->data[putp + 1] = (u_char) w;
633:
634: return 2;
635: }
636:
637: int
638: stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
639: {
640: STREAM_VERIFY_SANE(s);
641:
642: if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
643: {
644: STREAM_BOUND_WARN (s, "put");
645: return 0;
646: }
647: s->data[putp] = (u_char)(l >> 24);
648: s->data[putp + 1] = (u_char)(l >> 16);
649: s->data[putp + 2] = (u_char)(l >> 8);
650: s->data[putp + 3] = (u_char)l;
651:
652: return 4;
653: }
654:
655: int
656: stream_putq_at (struct stream *s, size_t putp, uint64_t q)
657: {
658: STREAM_VERIFY_SANE(s);
659:
660: if (!PUT_AT_VALID (s, putp + sizeof (uint64_t)))
661: {
662: STREAM_BOUND_WARN (s, "put");
663: return 0;
664: }
665: s->data[putp] = (u_char)(q >> 56);
666: s->data[putp + 1] = (u_char)(q >> 48);
667: s->data[putp + 2] = (u_char)(q >> 40);
668: s->data[putp + 3] = (u_char)(q >> 32);
669: s->data[putp + 4] = (u_char)(q >> 24);
670: s->data[putp + 5] = (u_char)(q >> 16);
671: s->data[putp + 6] = (u_char)(q >> 8);
672: s->data[putp + 7] = (u_char)q;
673:
674: return 8;
675: }
676:
677: /* Put long word to the stream. */
678: int
679: stream_put_ipv4 (struct stream *s, u_int32_t l)
680: {
681: STREAM_VERIFY_SANE(s);
682:
683: if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
684: {
685: STREAM_BOUND_WARN (s, "put");
686: return 0;
687: }
688: memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
689: s->endp += sizeof (u_int32_t);
690:
691: return sizeof (u_int32_t);
692: }
693:
694: /* Put long word to the stream. */
695: int
696: stream_put_in_addr (struct stream *s, struct in_addr *addr)
697: {
698: STREAM_VERIFY_SANE(s);
699:
700: if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
701: {
702: STREAM_BOUND_WARN (s, "put");
703: return 0;
704: }
705:
706: memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
707: s->endp += sizeof (u_int32_t);
708:
709: return sizeof (u_int32_t);
710: }
711:
712: /* Put prefix by nlri type format. */
713: int
714: stream_put_prefix (struct stream *s, struct prefix *p)
715: {
716: size_t psize;
717:
718: STREAM_VERIFY_SANE(s);
719:
720: psize = PSIZE (p->prefixlen);
721:
722: if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char)))
723: {
724: STREAM_BOUND_WARN (s, "put");
725: return 0;
726: }
727:
728: s->data[s->endp++] = p->prefixlen;
729: memcpy (s->data + s->endp, &p->u.prefix, psize);
730: s->endp += psize;
731:
732: return psize;
733: }
734:
735: /* Read size from fd. */
736: int
737: stream_read (struct stream *s, int fd, size_t size)
738: {
739: int nbytes;
740:
741: STREAM_VERIFY_SANE(s);
742:
743: if (STREAM_WRITEABLE (s) < size)
744: {
745: STREAM_BOUND_WARN (s, "put");
746: return 0;
747: }
748:
749: nbytes = readn (fd, s->data + s->endp, size);
750:
751: if (nbytes > 0)
752: s->endp += nbytes;
753:
754: return nbytes;
755: }
756:
757: ssize_t
758: stream_read_try(struct stream *s, int fd, size_t size)
759: {
760: ssize_t nbytes;
761:
762: STREAM_VERIFY_SANE(s);
763:
764: if (STREAM_WRITEABLE(s) < size)
765: {
766: STREAM_BOUND_WARN (s, "put");
767: /* Fatal (not transient) error, since retrying will not help
768: (stream is too small to contain the desired data). */
769: return -1;
770: }
771:
772: if ((nbytes = read(fd, s->data + s->endp, size)) >= 0)
773: {
774: s->endp += nbytes;
775: return nbytes;
776: }
777: /* Error: was it transient (return -2) or fatal (return -1)? */
778: if (ERRNO_IO_RETRY(errno))
779: return -2;
780: zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
781: return -1;
782: }
783:
784: /* Read up to size bytes into the stream from the fd, using recvmsgfrom
785: * whose arguments match the remaining arguments to this function
786: */
787: ssize_t
788: stream_recvfrom (struct stream *s, int fd, size_t size, int flags,
789: struct sockaddr *from, socklen_t *fromlen)
790: {
791: ssize_t nbytes;
792:
793: STREAM_VERIFY_SANE(s);
794:
795: if (STREAM_WRITEABLE(s) < size)
796: {
797: STREAM_BOUND_WARN (s, "put");
798: /* Fatal (not transient) error, since retrying will not help
799: (stream is too small to contain the desired data). */
800: return -1;
801: }
802:
803: if ((nbytes = recvfrom (fd, s->data + s->endp, size,
804: flags, from, fromlen)) >= 0)
805: {
806: s->endp += nbytes;
807: return nbytes;
808: }
809: /* Error: was it transient (return -2) or fatal (return -1)? */
810: if (ERRNO_IO_RETRY(errno))
811: return -2;
812: zlog_warn("%s: read failed on fd %d: %s", __func__, fd, safe_strerror(errno));
813: return -1;
814: }
815:
816: /* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
817: * from endp.
818: * First iovec will be used to receive the data.
819: * Stream need not be empty.
820: */
821: ssize_t
822: stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags,
823: size_t size)
824: {
825: int nbytes;
826: struct iovec *iov;
827:
828: STREAM_VERIFY_SANE(s);
829: assert (msgh->msg_iovlen > 0);
830:
831: if (STREAM_WRITEABLE (s) < size)
832: {
833: STREAM_BOUND_WARN (s, "put");
834: /* This is a logic error in the calling code: the stream is too small
835: to hold the desired data! */
836: return -1;
837: }
838:
839: iov = &(msgh->msg_iov[0]);
840: iov->iov_base = (s->data + s->endp);
841: iov->iov_len = size;
842:
843: nbytes = recvmsg (fd, msgh, flags);
844:
845: if (nbytes > 0)
846: s->endp += nbytes;
847:
848: return nbytes;
849: }
850:
851: /* Write data to buffer. */
852: size_t
853: stream_write (struct stream *s, const void *ptr, size_t size)
854: {
855:
856: CHECK_SIZE(s, size);
857:
858: STREAM_VERIFY_SANE(s);
859:
860: if (STREAM_WRITEABLE (s) < size)
861: {
862: STREAM_BOUND_WARN (s, "put");
863: return 0;
864: }
865:
866: memcpy (s->data + s->endp, ptr, size);
867: s->endp += size;
868:
869: return size;
870: }
871:
872: /* Return current read pointer.
873: * DEPRECATED!
874: * Use stream_get_pnt_to if you must, but decoding streams properly
875: * is preferred
876: */
877: u_char *
878: stream_pnt (struct stream *s)
879: {
880: STREAM_VERIFY_SANE(s);
881: return s->data + s->getp;
882: }
883:
884: /* Check does this stream empty? */
885: int
886: stream_empty (struct stream *s)
887: {
888: STREAM_VERIFY_SANE(s);
889:
890: return (s->endp == 0);
891: }
892:
893: /* Reset stream. */
894: void
895: stream_reset (struct stream *s)
896: {
897: STREAM_VERIFY_SANE (s);
898:
899: s->getp = s->endp = 0;
900: }
901:
902: /* Write stream contens to the file discriptor. */
903: int
904: stream_flush (struct stream *s, int fd)
905: {
906: int nbytes;
907:
908: STREAM_VERIFY_SANE(s);
909:
910: nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
911:
912: return nbytes;
913: }
914:
915: /* Stream first in first out queue. */
916:
917: struct stream_fifo *
918: stream_fifo_new (void)
919: {
920: struct stream_fifo *new;
921:
922: new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
923: return new;
924: }
925:
926: /* Add new stream to fifo. */
927: void
928: stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
929: {
930: if (fifo->tail)
931: fifo->tail->next = s;
932: else
933: fifo->head = s;
934:
935: fifo->tail = s;
936:
937: fifo->count++;
938: }
939:
940: /* Delete first stream from fifo. */
941: struct stream *
942: stream_fifo_pop (struct stream_fifo *fifo)
943: {
944: struct stream *s;
945:
946: s = fifo->head;
947:
948: if (s)
949: {
950: fifo->head = s->next;
951:
952: if (fifo->head == NULL)
953: fifo->tail = NULL;
954:
955: fifo->count--;
956: }
957:
958: return s;
959: }
960:
961: /* Return first fifo entry. */
962: struct stream *
963: stream_fifo_head (struct stream_fifo *fifo)
964: {
965: return fifo->head;
966: }
967:
968: void
969: stream_fifo_clean (struct stream_fifo *fifo)
970: {
971: struct stream *s;
972: struct stream *next;
973:
974: for (s = fifo->head; s; s = next)
975: {
976: next = s->next;
977: stream_free (s);
978: }
979: fifo->head = fifo->tail = NULL;
980: fifo->count = 0;
981: }
982:
983: void
984: stream_fifo_free (struct stream_fifo *fifo)
985: {
986: stream_fifo_clean (fifo);
987: XFREE (MTYPE_STREAM_FIFO, fifo);
988: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>