Index: stream.c =================================================================== RCS file: /var/cvsroot/quagga/lib/stream.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 stream.c --- stream.c 13 Dec 2002 20:15:29 -0000 1.1.1.1 +++ stream.c 17 Nov 2004 16:08:26 -0000 @@ -21,12 +21,13 @@ */ #include +#include #include "stream.h" #include "memory.h" #include "network.h" #include "prefix.h" - +#include "log.h" /*A macro to check pointers in order to not go behind the allocated mem block @@ -35,8 +36,43 @@ */ #define CHECK_SIZE(S, Z) \ - if (((S)->putp + (Z)) > (S)->size) \ - (Z) = (S)->size - (S)->putp; + if (((S)->putp + (Z)) > (S)->size) \ + (Z) = (S)->size - (S)->putp; + +#define UPDATE_ENDP(S) \ + do { \ + if ((S)->putp > (S)->endp) \ + (S)->endp = (S)->putp; \ + } while (0) + +/* check if a position is within the size of the stream */ +#define POS_IS_VALID(S,P) \ + ((P) < (S)->size) + +/* check if a get/put position is valid */ +#define GETP_IS_VALID(S,P) \ + ( POS_IS_VALID ((S), (P)) && ((P) <= (S)->endp)) +#define PUTP_IS_VALID(S,P) \ + POS_IS_VALID ((S), (P)) + +/* Check if get/put position is valid to the added length */ +#define GETP_IS_VALID_TO(S,P,L) \ + GETP_IS_VALID((S), ((P) + (L))) +#define PUTP_IS_VALID_TO(S,P,L) \ + POS_IS_VALID((S), ((P) + (L))) + +/* various asserting sanity checks */ +#define STREAM_IS_SANE(S) \ + do { \ + assert (POS_IS_VALID ((S), (S)->endp)); \ + assert (PUTP_IS_VALID ((S), (S)->putp)); \ + assert (GETP_IS_VALID ((S), (S)->getp)); \ + } while (0) + +#define STR_END_STREAM " past end of stream" +#define STR_END_MID ": Attempt to " +#define STR_END_WARN2 "%s" STR_END_MID "%s %s" STR_END_STREAM +#define STR_END_WARN1 "%s" STR_END_MID "%s" STR_END_STREAM /* Stream is fixed length buffer for network output/input. */ @@ -45,10 +81,26 @@ stream_new (size_t size) { struct stream *s; - + + if (size == 0) + { + zlog_warn ("stream_new(): called with 0 size!"); + return NULL; + } + s = XCALLOC (MTYPE_STREAM, sizeof (struct stream)); - + + if (s == NULL) + return s; + s->data = XCALLOC (MTYPE_STREAM_DATA, size); + + if (s->data == NULL) + { + XFREE (MTYPE_STREAM, s); + return NULL; + } + s->size = size; return s; } @@ -60,154 +112,355 @@ XFREE (MTYPE_STREAM_DATA, s->data); XFREE (MTYPE_STREAM, s); } + +struct stream * +stream_copy (struct stream *new, struct stream *src) +{ + STREAM_IS_SANE (src); + + assert (new != NULL); + assert (STREAM_SIZE(new) >= stream_get_endp (src)); + + new->endp = src->endp; + new->putp = src->putp; + new->getp = src->getp; + + memcpy (new->data, src->data, stream_get_endp (src)); + + return new; +} + +struct stream * +stream_dup (struct stream *s) +{ + struct stream *new; + + if ( (new = stream_new (stream_get_endp(s))) == NULL) + return NULL; + + return (stream_copy (new, s)); +} -unsigned long +size_t stream_get_getp (struct stream *s) { + STREAM_IS_SANE(s); + return s->getp; } -unsigned long +size_t stream_get_putp (struct stream *s) { + STREAM_IS_SANE(s); return s->putp; } -unsigned long +size_t stream_get_endp (struct stream *s) { + STREAM_IS_SANE(s); return s->endp; } -unsigned long +size_t stream_get_size (struct stream *s) { + STREAM_IS_SANE(s); return s->size; } /* Stream structre' stream pointer related functions. */ void -stream_set_getp (struct stream *s, unsigned long pos) +stream_set_getp (struct stream *s, size_t pos) { + STREAM_IS_SANE(s); + + if (!GETP_IS_VALID(s,pos)) + { + zlog_warn (STR_END_WARN2, "stream_set_getp", "set", "getp"); + pos = s->endp; + } + s->getp = pos; + + UPDATE_ENDP(s); } void -stream_set_putp (struct stream *s, unsigned long pos) +stream_set_putp (struct stream *s, size_t pos) { + STREAM_IS_SANE(s); + + if (!PUTP_IS_VALID(s,pos)) + { + zlog_warn (STR_END_WARN2, "stream_set_putp", "set", "putp"); + pos = s->endp; + } + s->putp = pos; + + UPDATE_ENDP(s); } -/* Forward pointer. */ +/* Forward getp pointer. */ void -stream_forward (struct stream *s, int size) +stream_forward_getp (struct stream *s, size_t size) { + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, s->getp, size) ) + { + zlog_warn (STR_END_WARN2, "stream_forward_getp", "seek", "getp"); + return; + } + s->getp += size; + + UPDATE_ENDP(s); +} + +/* Forward putp pointer. */ +void +stream_forward_putp (struct stream *s, size_t size) +{ + STREAM_IS_SANE(s); + + if ( !PUTP_IS_VALID_TO(s, s->putp, size) ) + { + zlog_warn (STR_END_WARN2, "stream_forward_putp", "seek" "putp"); + return; + } + + s->putp += size; + + UPDATE_ENDP(s); } /* Copy from stream to destination. */ void stream_get (void *dst, struct stream *s, size_t size) { + STREAM_IS_SANE(s); + + if (!GETP_IS_VALID_TO (s, s->getp, size)) + { + zlog_warn (STR_END_WARN1, "stream_get", "get"); + return; + } + memcpy (dst, s->data + s->getp, size); s->getp += size; + + UPDATE_ENDP(s); } /* Get next character from the stream. */ -u_char +int stream_getc (struct stream *s) { u_char c; + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, s->getp, sizeof (u_char)) ) + { + zlog_warn (STR_END_WARN1, "stream_getc", "get"); + return '0'; + } + c = s->data[s->getp]; s->getp++; - return c; + + UPDATE_ENDP(s); + + return 1; } /* Get next character from the stream. */ -u_char -stream_getc_from (struct stream *s, unsigned long from) +int +stream_getc_from (struct stream *s, size_t from) { u_char c; + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, from, sizeof (u_char)) ) + { + zlog_warn (STR_END_WARN1, "stream_getc_from", "get"); + return 0; + } + c = s->data[from]; - return c; + return 1; } /* Get next word from the stream. */ -u_int16_t +int stream_getw (struct stream *s) { u_int16_t w; + + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, s->getp, sizeof (u_int16_t)) ) + { + zlog_warn (STR_END_WARN1, "stream_getw", "get"); + return 0; + } w = s->data[s->getp++] << 8; w |= s->data[s->getp++]; - return w; + + UPDATE_ENDP(s); + + return 2; } /* Get next word from the stream. */ -u_int16_t -stream_getw_from (struct stream *s, unsigned long from) +int +stream_getw_from (struct stream *s, size_t from) { u_int16_t w; + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, from, sizeof (u_int16_t)) ) + { + zlog_warn ("stream_getw_from", "get"); + return 0; + } + w = s->data[from++] << 8; w |= s->data[from]; - return w; + + return sizeof (u_int16_t); } +/* internal helper to get size bytes, corresponding to an integral + * type from the stream. Must only be called by API visible functions + * which get a definite type (ie char, int16_t, int32_t, int64_t)! + * return number of bytes gotten. + */ +static int +stream_get_typed_size (struct stream *s, void *dst, size_t size) +{ + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID_TO (s, s->getp, size)) + { + zlog_warn (STR_END_WARN1, "stream_get_typed_size", "get"); + return 0; + } + + switch (size) + { + case 8: + ((u_int64_t) *dst) = s->data[getp++] << 8*7; + ((u_int64_t) *dst) = s->data[getp++] << 8*6; + ((u_int64_t) *dst) = s->data[getp++] << 8*5; + ((u_int64_t) *dst) = s->data[getp++] << 8*4; + case 4: + ((u_int32_t) *dst) = s->data[getp++] << 8*3; + ((u_int32_t) *dst) = s->data[getp++] << 8*2; + case 2: + ((u_int16_t) *dst) = s->data[getp++] << 8*1; + case 1: + ((u_char) *dst) = s->data[getp++] << 8; + break; + default: + zlog_err ("stream_get_typed_size: called with non-integral size" + " %d! should never happen!"); + return 0; + } + + return size; +} + /* Get next long word from the stream. */ u_int32_t stream_getl (struct stream *s) { u_int32_t l; - + + STREAM_IS_SANE(s); + + if ( !GETP_IS_VALID (s, s->getp, sizeof (u_int32_t)) ) + { + zlog_warn ("stream_getl", "get"); + return 0; + } + l = s->data[s->getp++] << 24; l |= s->data[s->getp++] << 16; l |= s->data[s->getp++] << 8; l |= s->data[s->getp++]; - return l; + + UPDATE_ENDP(s); + + return sizeof (u_int32_t); } /* Get next long word from the stream. */ -u_int32_t +int stream_get_ipv4 (struct stream *s) { u_int32_t l; - memcpy (&l, s->data + s->getp, 4); - s->getp += 4; + STREAM_IS_SANE(s); - return l; + if ( !GETP_IS_VALID (s, s->getp, sizeof (u_int32_t)) ) + { + zlog_warn ("stream_get_ipv4", "get"); + return 0; + } + + memcpy (&l, s->data + s->getp, sizeof (u_int32_t)); + s->getp += sizeof (u_int32_t); + + UPDATE_ENDP(s); + return sizeof (u_int32_t); } /* Copy to source to stream. */ -void +int stream_put (struct stream *s, void *src, size_t size) { - + STREAM_IS_SANE(s); CHECK_SIZE(s, size); - + + if ( !PUTP_IS_VALID (s, s->putp, size) ) + { + zlog_warn ("stream_put", "put"); + return 0; + } + if (src) memcpy (s->data + s->putp, src, size); else memset (s->data + s->putp, 0, size); s->putp += size; - if (s->putp > s->endp) - s->endp = s->putp; + + UPDATE_ENDP(s); + + return size; } /* Put character to the stream. */ int stream_putc (struct stream *s, u_char c) { - if (s->putp >= s->size) return 0; - + STREAM_IS_SANE(s); + + if (!STREAM_FITS (s, sizeof (u_char))) + { + zlog_warn ("stream_putc(): size exceeds free stream space!"); + return 0; + } s->data[s->putp] = c; s->putp++; - if (s->putp > s->endp) - s->endp = s->putp; + UPDATE_ENDP(s); return 1; } @@ -215,13 +468,16 @@ int stream_putw (struct stream *s, u_int16_t w) { - if ((s->size - s->putp) < 2) return 0; + STREAM_IS_SANE(s); + + if (!STREAM_FITS (s, sizeof(u_int16_t))) + return 0; s->data[s->putp++] = (u_char)(w >> 8); s->data[s->putp++] = (u_char) w; - - if (s->putp > s->endp) - s->endp = s->putp; + + UPDATE_ENDP (s); + return 2; } @@ -229,36 +485,54 @@ int stream_putl (struct stream *s, u_int32_t l) { - if ((s->size - s->putp) < 4) return 0; + STREAM_IS_SANE(s); + if (!STREAM_FITS_T (s, u_int32_t)) + return 0; + s->data[s->putp++] = (u_char)(l >> 24); s->data[s->putp++] = (u_char)(l >> 16); s->data[s->putp++] = (u_char)(l >> 8); s->data[s->putp++] = (u_char)l; - - if (s->putp > s->endp) - s->endp = s->putp; + + UPDATE_ENDP (s); + return 4; } int -stream_putc_at (struct stream *s, unsigned long putp, u_char c) +stream_putc_at (struct stream *s, size_t putp, u_char c) { + STREAM_IS_SANE(s); + + if ( (putp + sizeof (u_char)) >= STREAM_SIZE(s)) + return 0; + s->data[putp] = c; return 1; } int -stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w) +stream_putw_at (struct stream *s, size_t putp, u_int16_t w) { + STREAM_IS_SANE(s); + + if ( (putp+sizeof (u_int16_t)) >= STREAM_SIZE(s)) + return 0; + s->data[putp] = (u_char)(w >> 8); s->data[putp + 1] = (u_char) w; return 2; } int -stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l) +stream_putl_at (struct stream *s, size_t putp, u_int32_t l) { + STREAM_IS_SANE(s); + + if ( (putp + sizeof (u_int32_t)) >= STREAM_SIZE(s)) + return 0; + s->data[putp] = (u_char)(l >> 24); s->data[putp + 1] = (u_char)(l >> 16); s->data[putp + 2] = (u_char)(l >> 8); @@ -270,30 +544,32 @@ int stream_put_ipv4 (struct stream *s, u_int32_t l) { - if ((s->size - s->putp) < 4) + STREAM_IS_SANE(s); + + if (!STREAM_FITS_T (s, u_int32_t)) return 0; - memcpy (s->data + s->putp, &l, 4); - s->putp += 4; + memcpy (s->data + s->putp, &l, sizeof (u_int32_t)); + s->putp += sizeof (u_int32_t); - if (s->putp > s->endp) - s->endp = s->putp; - return 4; + UPDATE_ENDP(s); + return sizeof (u_int32_t); } /* Put long word to the stream. */ int stream_put_in_addr (struct stream *s, struct in_addr *addr) { - if ((s->size - s->putp) < 4) - return 0; + STREAM_IS_SANE(s); - memcpy (s->data + s->putp, addr, 4); - s->putp += 4; + if (!STREAM_FITS_T(s, struct in_addr)) + return 0; - if (s->putp > s->endp) - s->endp = s->putp; - return 4; + memcpy (s->data + s->putp, addr, sizeof (struct in_addr)); + s->putp += sizeof (struct in_addr); + + UPDATE_ENDP(s); + return sizeof (struct in_addr); } /* Put prefix by nlri type format. */ @@ -302,17 +578,18 @@ { u_char psize; + STREAM_IS_SANE(s); + psize = PSIZE (p->prefixlen); - if ((s->size - s->putp) < psize) return 0; + if (!STREAM_FITS (s, psize)) + return 0; stream_putc (s, p->prefixlen); memcpy (s->data + s->putp, &p->u.prefix, psize); s->putp += psize; - if (s->putp > s->endp) - s->endp = s->putp; - + UPDATE_ENDP(s); return psize; } @@ -321,7 +598,9 @@ stream_read (struct stream *s, int fd, size_t size) { int nbytes; - + + STREAM_IS_SANE(s); + nbytes = readn (fd, s->data + s->putp, size); if (nbytes > 0) @@ -329,6 +608,8 @@ s->putp += nbytes; s->endp += nbytes; } + + UPDATE_ENDP(s); return nbytes; } @@ -338,7 +619,9 @@ { int nbytes; int val; - + + STREAM_IS_SANE(s); + val = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, val|O_NONBLOCK); nbytes = read (fd, s->data + s->putp, size); @@ -349,6 +632,8 @@ s->putp += nbytes; s->endp += nbytes; } + + UPDATE_ENDP(s); return nbytes; } @@ -356,13 +641,13 @@ int stream_write (struct stream *s, u_char *ptr, size_t size) { + STREAM_IS_SANE(s); CHECK_SIZE(s, size); memcpy (s->data + s->putp, ptr, size); s->putp += size; - if (s->putp > s->endp) - s->endp = s->putp; + UPDATE_ENDP(s); return size; } @@ -396,6 +681,7 @@ int stream_flush (struct stream *s, int fd) { + STREAM_IS_SANE(s); int nbytes; nbytes = write (fd, s->data + s->getp, s->endp - s->getp); @@ -418,6 +704,7 @@ void stream_fifo_push (struct stream_fifo *fifo, struct stream *s) { + STREAM_IS_SANE(s); if (fifo->tail) fifo->tail->next = s; else