mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 14:05:31 +00:00
2005-02-14 Paul Jakma <paul.jakma@sun.com>
* stream.h: Unsigned long updated to size_t * stream.c: ditto * stream.h: Add stream_copy, stream_dup, stream_recvmsg. Add comment describing struct stream abstraction, and various other comments. Deprecate several unsafe/ambigious macros. Add STREAM_WRITEABLE and STREAM_READABLE. Add (stream_getl_from) for symmetry. Update stream_forward_{endp,getp} to use size_t offset. Make stream data a 0 length array, rather than a seperate malloc. * stream.c: Add consistency checks. Update to follow stream.h changes. (stream_new) Alloc stream+data in one go. (stream_copy) new function, copy a stream. (stream_dup) new function, dup a stream. (stream_recvmsg) new function, recvmsg data into a stream. (stream_empty) no need to check getp == 0.
This commit is contained in:
parent
f2e6c42937
commit
050c013ac3
@ -2,6 +2,21 @@
|
|||||||
|
|
||||||
* stream.h: Unsigned long updated to size_t
|
* stream.h: Unsigned long updated to size_t
|
||||||
* stream.c: ditto
|
* stream.c: ditto
|
||||||
|
* stream.h: Add stream_copy, stream_dup, stream_recvmsg.
|
||||||
|
Add comment describing struct stream abstraction, and various
|
||||||
|
other comments.
|
||||||
|
Deprecate several unsafe/ambigious macros.
|
||||||
|
Add STREAM_WRITEABLE and STREAM_READABLE.
|
||||||
|
Add (stream_getl_from) for symmetry.
|
||||||
|
Update stream_forward_{endp,getp} to use size_t offset.
|
||||||
|
Make stream data a 0 length array, rather than a seperate malloc.
|
||||||
|
* stream.c: Add consistency checks. Update to follow stream.h
|
||||||
|
changes.
|
||||||
|
(stream_new) Alloc stream+data in one go.
|
||||||
|
(stream_copy) new function, copy a stream.
|
||||||
|
(stream_dup) new function, dup a stream.
|
||||||
|
(stream_recvmsg) new function, recvmsg data into a stream.
|
||||||
|
(stream_empty) no need to check getp == 0.
|
||||||
|
|
||||||
2005-02-09 Paul Jakma <paul.jakma@sun.com>
|
2005-02-09 Paul Jakma <paul.jakma@sun.com>
|
||||||
|
|
||||||
|
402
lib/stream.c
402
lib/stream.c
@ -20,25 +20,70 @@
|
|||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/* Tests whether a position is valid */
|
||||||
|
#define GETP_VALID(S,G) \
|
||||||
|
((G) <= (S)->endp)
|
||||||
|
#define PUT_AT_VALID(S,G) GETP_VALID(S,G)
|
||||||
|
#define ENDP_VALID(S,E) \
|
||||||
|
((E) <= (S)->size)
|
||||||
|
|
||||||
/*A macro to check pointers in order to not
|
/* asserting sanity checks. Following must be true before
|
||||||
go behind the allocated mem block
|
* stream functions are called:
|
||||||
S -- stream reference
|
*
|
||||||
Z -- size of data to be written
|
* Following must always be true of stream elements
|
||||||
|
* before and after calls to stream functions:
|
||||||
|
*
|
||||||
|
* getp <= endp <= size
|
||||||
|
*
|
||||||
|
* Note that after a stream function is called following may be true:
|
||||||
|
* if (getp == endp) then stream is no longer readable
|
||||||
|
* if (endp == size) then stream is no longer writeable
|
||||||
|
*
|
||||||
|
* It is valid to put to anywhere within the size of the stream, but only
|
||||||
|
* using stream_put..._at() functions.
|
||||||
*/
|
*/
|
||||||
|
#define STREAM_WARN_OFFSETS(S) \
|
||||||
|
zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \
|
||||||
|
(S), \
|
||||||
|
(unsigned long) (S)->size, \
|
||||||
|
(unsigned long) (S)->getp, \
|
||||||
|
(unsigned long) (S)->endp)\
|
||||||
|
|
||||||
|
#define STREAM_VERIFY_SANE(S) \
|
||||||
|
do { \
|
||||||
|
if ( !(GETP_VALID(S, (S)->getp)) && ENDP_VALID(S, (S)->endp) ) \
|
||||||
|
STREAM_WARN_OFFSETS(S); \
|
||||||
|
assert ( GETP_VALID(S, (S)->getp) ); \
|
||||||
|
assert ( ENDP_VALID(S, (S)->endp) ); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define STREAM_BOUND_WARN(S, WHAT) \
|
||||||
|
do { \
|
||||||
|
zlog_warn ("%s: Attempt to %s out of bounds", __func__, (WHAT)); \
|
||||||
|
STREAM_WARN_OFFSETS(S); \
|
||||||
|
assert (0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* XXX: Deprecated macro: do not use */
|
||||||
#define CHECK_SIZE(S, Z) \
|
#define CHECK_SIZE(S, Z) \
|
||||||
|
do { \
|
||||||
if (((S)->endp + (Z)) > (S)->size) \
|
if (((S)->endp + (Z)) > (S)->size) \
|
||||||
(Z) = (S)->size - (S)->endp;
|
{ \
|
||||||
|
zlog_warn ("CHECK_SIZE: truncating requested size %lu\n", \
|
||||||
/* Stream is fixed length buffer for network output/input. */
|
(unsigned long) (Z)); \
|
||||||
|
STREAM_WARN_OFFSETS(S); \
|
||||||
|
(Z) = (S)->size - (S)->endp; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
/* Make stream buffer. */
|
/* Make stream buffer. */
|
||||||
struct stream *
|
struct stream *
|
||||||
@ -49,11 +94,16 @@ stream_new (size_t size)
|
|||||||
assert (size > 0);
|
assert (size > 0);
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
|
{
|
||||||
|
zlog_warn ("stream_new(): called with 0 size!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
|
s = XCALLOC (MTYPE_STREAM, offsetof(struct stream, size));
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
return s;
|
||||||
|
|
||||||
s->data = XCALLOC (MTYPE_STREAM_DATA, size);
|
|
||||||
s->size = size;
|
s->size = size;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -62,25 +112,56 @@ stream_new (size_t size)
|
|||||||
void
|
void
|
||||||
stream_free (struct stream *s)
|
stream_free (struct stream *s)
|
||||||
{
|
{
|
||||||
XFREE (MTYPE_STREAM_DATA, s->data);
|
|
||||||
XFREE (MTYPE_STREAM, s);
|
XFREE (MTYPE_STREAM, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct stream *
|
||||||
|
stream_copy (struct stream *new, struct stream *src)
|
||||||
|
{
|
||||||
|
STREAM_VERIFY_SANE (src);
|
||||||
|
|
||||||
|
assert (new != NULL);
|
||||||
|
assert (STREAM_SIZE(new) >= src->endp);
|
||||||
|
|
||||||
|
new->endp = src->endp;
|
||||||
|
new->getp = src->getp;
|
||||||
|
|
||||||
|
memcpy (new->data, src->data, src->endp);
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stream *
|
||||||
|
stream_dup (struct stream *s)
|
||||||
|
{
|
||||||
|
struct stream *new;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE (s);
|
||||||
|
|
||||||
|
if ( (new = stream_new (s->endp)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (stream_copy (new, s));
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
stream_get_getp (struct stream *s)
|
stream_get_getp (struct stream *s)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
return s->getp;
|
return s->getp;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
stream_get_endp (struct stream *s)
|
stream_get_endp (struct stream *s)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
return s->endp;
|
return s->endp;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
stream_get_size (struct stream *s)
|
stream_get_size (struct stream *s)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
return s->size;
|
return s->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,19 +169,43 @@ stream_get_size (struct stream *s)
|
|||||||
void
|
void
|
||||||
stream_set_getp (struct stream *s, size_t pos)
|
stream_set_getp (struct stream *s, size_t pos)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!GETP_VALID (s, pos))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "set getp");
|
||||||
|
pos = s->endp;
|
||||||
|
}
|
||||||
|
|
||||||
s->getp = pos;
|
s->getp = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward pointer. */
|
/* Forward pointer. */
|
||||||
void
|
void
|
||||||
stream_forward_getp (struct stream *s, int size)
|
stream_forward_getp (struct stream *s, size_t size)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!GETP_VALID (s, s->getp + size))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "seek getp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
s->getp += size;
|
s->getp += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
stream_forward_endp (struct stream *s, int size)
|
stream_forward_endp (struct stream *s, size_t size)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!ENDP_VALID (s, s->endp + size))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "seek endp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
s->endp += size;
|
s->endp += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +213,14 @@ stream_forward_endp (struct stream *s, int size)
|
|||||||
void
|
void
|
||||||
stream_get (void *dst, struct stream *s, size_t size)
|
stream_get (void *dst, struct stream *s, size_t size)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_READABLE(s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy (dst, s->data + s->getp, size);
|
memcpy (dst, s->data + s->getp, size);
|
||||||
s->getp += size;
|
s->getp += size;
|
||||||
}
|
}
|
||||||
@ -118,8 +231,15 @@ stream_getc (struct stream *s)
|
|||||||
{
|
{
|
||||||
u_char c;
|
u_char c;
|
||||||
|
|
||||||
c = s->data[s->getp];
|
STREAM_VERIFY_SANE (s);
|
||||||
s->getp++;
|
|
||||||
|
if (STREAM_READABLE(s) < sizeof (u_char))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get char");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
c = s->data[s->getp++];
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +249,16 @@ stream_getc_from (struct stream *s, size_t from)
|
|||||||
{
|
{
|
||||||
u_char c;
|
u_char c;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!GETP_VALID (s, from + sizeof (u_char)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get char");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
c = s->data[from];
|
c = s->data[from];
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,8 +268,17 @@ stream_getw (struct stream *s)
|
|||||||
{
|
{
|
||||||
u_int16_t w;
|
u_int16_t w;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE (s);
|
||||||
|
|
||||||
|
if (STREAM_READABLE (s) < sizeof (u_int16_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
w = s->data[s->getp++] << 8;
|
w = s->data[s->getp++] << 8;
|
||||||
w |= s->data[s->getp++];
|
w |= s->data[s->getp++];
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,43 +288,102 @@ stream_getw_from (struct stream *s, size_t from)
|
|||||||
{
|
{
|
||||||
u_int16_t w;
|
u_int16_t w;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!GETP_VALID (s, from + sizeof (u_int16_t)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
w = s->data[from++] << 8;
|
w = s->data[from++] << 8;
|
||||||
w |= s->data[from];
|
w |= s->data[from];
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get next long word from the stream. */
|
/* Get next long word from the stream. */
|
||||||
|
u_int32_t
|
||||||
|
stream_getl_from (struct stream *s, size_t from)
|
||||||
|
{
|
||||||
|
u_int32_t l;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!GETP_VALID (s, from + sizeof (u_int32_t)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get long");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = s->data[from++] << 24;
|
||||||
|
l |= s->data[from++] << 16;
|
||||||
|
l |= s->data[from++] << 8;
|
||||||
|
l |= s->data[from];
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
u_int32_t
|
u_int32_t
|
||||||
stream_getl (struct stream *s)
|
stream_getl (struct stream *s)
|
||||||
{
|
{
|
||||||
u_int32_t l;
|
u_int32_t l;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_READABLE (s) < sizeof (u_int32_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get long");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
l = s->data[s->getp++] << 24;
|
l = s->data[s->getp++] << 24;
|
||||||
l |= s->data[s->getp++] << 16;
|
l |= s->data[s->getp++] << 16;
|
||||||
l |= s->data[s->getp++] << 8;
|
l |= s->data[s->getp++] << 8;
|
||||||
l |= s->data[s->getp++];
|
l |= s->data[s->getp++];
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get next long word from the stream. */
|
/* Get next long word from the stream. */
|
||||||
u_int32_t
|
u_int32_t
|
||||||
stream_get_ipv4 (struct stream *s)
|
stream_get_ipv4 (struct stream *s)
|
||||||
{
|
{
|
||||||
u_int32_t l;
|
u_int32_t l;
|
||||||
|
|
||||||
memcpy (&l, s->data + s->getp, 4);
|
STREAM_VERIFY_SANE(s);
|
||||||
s->getp += 4;
|
|
||||||
|
if (STREAM_READABLE (s) < sizeof(u_int32_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "get ipv4");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&l, s->data + s->getp, sizeof(u_int32_t));
|
||||||
|
s->getp += sizeof(u_int32_t);
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy to source to stream. */
|
/* Copy to source to stream.
|
||||||
|
*
|
||||||
|
* XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
|
||||||
|
* around. This should be fixed once the stream updates are working.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
stream_put (struct stream *s, void *src, size_t size)
|
stream_put (struct stream *s, void *src, size_t size)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/* XXX: CHECK_SIZE has strange semantics. It should be deprecated */
|
||||||
CHECK_SIZE(s, size);
|
CHECK_SIZE(s, size);
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
memcpy (s->data + s->endp, src, size);
|
memcpy (s->data + s->endp, src, size);
|
||||||
else
|
else
|
||||||
@ -199,19 +396,29 @@ stream_put (struct stream *s, void *src, size_t size)
|
|||||||
int
|
int
|
||||||
stream_putc (struct stream *s, u_char c)
|
stream_putc (struct stream *s, u_char c)
|
||||||
{
|
{
|
||||||
if (s->endp >= s->size) return 0;
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
s->data[s->endp] = c;
|
if (STREAM_WRITEABLE (s) < sizeof(u_char))
|
||||||
s->endp++;
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
s->data[s->endp++] = c;
|
||||||
|
return sizeof (u_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put word to the stream. */
|
/* Put word to the stream. */
|
||||||
int
|
int
|
||||||
stream_putw (struct stream *s, u_int16_t w)
|
stream_putw (struct stream *s, u_int16_t w)
|
||||||
{
|
{
|
||||||
if ((s->size - s->endp) < 2) return 0;
|
STREAM_VERIFY_SANE (s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < sizeof (u_int16_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
s->data[s->endp++] = (u_char)(w >> 8);
|
s->data[s->endp++] = (u_char)(w >> 8);
|
||||||
s->data[s->endp++] = (u_char) w;
|
s->data[s->endp++] = (u_char) w;
|
||||||
@ -223,7 +430,13 @@ stream_putw (struct stream *s, u_int16_t w)
|
|||||||
int
|
int
|
||||||
stream_putl (struct stream *s, u_int32_t l)
|
stream_putl (struct stream *s, u_int32_t l)
|
||||||
{
|
{
|
||||||
if ((s->size - s->endp) < 4) return 0;
|
STREAM_VERIFY_SANE (s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
s->data[s->endp++] = (u_char)(l >> 24);
|
s->data[s->endp++] = (u_char)(l >> 24);
|
||||||
s->data[s->endp++] = (u_char)(l >> 16);
|
s->data[s->endp++] = (u_char)(l >> 16);
|
||||||
@ -236,25 +449,51 @@ stream_putl (struct stream *s, u_int32_t l)
|
|||||||
int
|
int
|
||||||
stream_putc_at (struct stream *s, size_t putp, u_char c)
|
stream_putc_at (struct stream *s, size_t putp, u_char c)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!PUT_AT_VALID (s, putp + sizeof (u_char)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
s->data[putp] = c;
|
s->data[putp] = c;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
|
stream_putw_at (struct stream *s, size_t putp, u_int16_t w)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!PUT_AT_VALID (s, putp + sizeof (u_int16_t)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
s->data[putp] = (u_char)(w >> 8);
|
s->data[putp] = (u_char)(w >> 8);
|
||||||
s->data[putp + 1] = (u_char) w;
|
s->data[putp + 1] = (u_char) w;
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
|
stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (!PUT_AT_VALID (s, putp + sizeof (u_int32_t)))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
s->data[putp] = (u_char)(l >> 24);
|
s->data[putp] = (u_char)(l >> 24);
|
||||||
s->data[putp + 1] = (u_char)(l >> 16);
|
s->data[putp + 1] = (u_char)(l >> 16);
|
||||||
s->data[putp + 2] = (u_char)(l >> 8);
|
s->data[putp + 2] = (u_char)(l >> 8);
|
||||||
s->data[putp + 3] = (u_char)l;
|
s->data[putp + 3] = (u_char)l;
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,37 +501,52 @@ stream_putl_at (struct stream *s, size_t putp, u_int32_t l)
|
|||||||
int
|
int
|
||||||
stream_put_ipv4 (struct stream *s, u_int32_t l)
|
stream_put_ipv4 (struct stream *s, u_int32_t l)
|
||||||
{
|
{
|
||||||
if ((s->size - s->endp) < 4)
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy (s->data + s->endp, &l, sizeof (u_int32_t));
|
||||||
|
s->endp += sizeof (u_int32_t);
|
||||||
|
|
||||||
memcpy (s->data + s->endp, &l, 4);
|
return sizeof (u_int32_t);
|
||||||
s->endp += 4;
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put long word to the stream. */
|
/* Put long word to the stream. */
|
||||||
int
|
int
|
||||||
stream_put_in_addr (struct stream *s, struct in_addr *addr)
|
stream_put_in_addr (struct stream *s, struct in_addr *addr)
|
||||||
{
|
{
|
||||||
if ((s->size - s->endp) < 4)
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < sizeof (u_int32_t))
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy (s->data + s->endp, addr, 4);
|
memcpy (s->data + s->endp, addr, sizeof (u_int32_t));
|
||||||
s->endp += 4;
|
s->endp += sizeof (u_int32_t);
|
||||||
|
|
||||||
return 4;
|
return sizeof (u_int32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put prefix by nlri type format. */
|
/* Put prefix by nlri type format. */
|
||||||
int
|
int
|
||||||
stream_put_prefix (struct stream *s, struct prefix *p)
|
stream_put_prefix (struct stream *s, struct prefix *p)
|
||||||
{
|
{
|
||||||
u_char psize;
|
size_t psize;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
psize = PSIZE (p->prefixlen);
|
psize = PSIZE (p->prefixlen);
|
||||||
|
|
||||||
if ((s->size - s->endp) < psize) return 0;
|
if (STREAM_WRITEABLE (s) < psize)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
stream_putc (s, p->prefixlen);
|
stream_putc (s, p->prefixlen);
|
||||||
memcpy (s->data + s->endp, &p->u.prefix, psize);
|
memcpy (s->data + s->endp, &p->u.prefix, psize);
|
||||||
@ -307,6 +561,14 @@ stream_read (struct stream *s, int fd, size_t size)
|
|||||||
{
|
{
|
||||||
int nbytes;
|
int nbytes;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
nbytes = readn (fd, s->data + s->endp, size);
|
nbytes = readn (fd, s->data + s->endp, size);
|
||||||
|
|
||||||
if (nbytes > 0)
|
if (nbytes > 0)
|
||||||
@ -322,6 +584,14 @@ stream_read_unblock (struct stream *s, int fd, size_t size)
|
|||||||
int nbytes;
|
int nbytes;
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
val = fcntl (fd, F_GETFL, 0);
|
val = fcntl (fd, F_GETFL, 0);
|
||||||
fcntl (fd, F_SETFL, val|O_NONBLOCK);
|
fcntl (fd, F_SETFL, val|O_NONBLOCK);
|
||||||
nbytes = read (fd, s->data + s->endp, size);
|
nbytes = read (fd, s->data + s->endp, size);
|
||||||
@ -333,6 +603,39 @@ stream_read_unblock (struct stream *s, int fd, size_t size)
|
|||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read up to smaller of size or SIZE_REMAIN() bytes to the stream, starting
|
||||||
|
* from endp.
|
||||||
|
* First iovec will be used to receive the data.
|
||||||
|
* Stream need not be empty.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
stream_recvmsg (struct stream *s, int fd, struct msghdr *msgh, int flags,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
int nbytes;
|
||||||
|
struct iovec *iov;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
assert (msgh->msg_iovlen > 0);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov = &(msgh->msg_iov[0]);
|
||||||
|
iov->iov_base = (s->data + s->endp);
|
||||||
|
iov->iov_len = size;
|
||||||
|
|
||||||
|
nbytes = recvmsg (fd, msgh, flags);
|
||||||
|
|
||||||
|
if (nbytes > 0)
|
||||||
|
s->endp += nbytes;
|
||||||
|
|
||||||
|
return nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write data to buffer. */
|
/* Write data to buffer. */
|
||||||
int
|
int
|
||||||
stream_write (struct stream *s, u_char *ptr, size_t size)
|
stream_write (struct stream *s, u_char *ptr, size_t size)
|
||||||
@ -340,16 +643,29 @@ stream_write (struct stream *s, u_char *ptr, size_t size)
|
|||||||
|
|
||||||
CHECK_SIZE(s, size);
|
CHECK_SIZE(s, size);
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
|
if (STREAM_WRITEABLE (s) < size)
|
||||||
|
{
|
||||||
|
STREAM_BOUND_WARN (s, "put");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy (s->data + s->endp, ptr, size);
|
memcpy (s->data + s->endp, ptr, size);
|
||||||
s->endp += size;
|
s->endp += size;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return current read pointer. */
|
/* Return current read pointer.
|
||||||
|
* DEPRECATED!
|
||||||
|
* Use stream_get_pnt_to if you must, but decoding streams properly
|
||||||
|
* is preferred
|
||||||
|
*/
|
||||||
u_char *
|
u_char *
|
||||||
stream_pnt (struct stream *s)
|
stream_pnt (struct stream *s)
|
||||||
{
|
{
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
return s->data + s->getp;
|
return s->data + s->getp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,18 +673,18 @@ stream_pnt (struct stream *s)
|
|||||||
int
|
int
|
||||||
stream_empty (struct stream *s)
|
stream_empty (struct stream *s)
|
||||||
{
|
{
|
||||||
if (s->endp == 0 && s->getp == 0)
|
STREAM_VERIFY_SANE(s);
|
||||||
return 1;
|
|
||||||
else
|
return (s->endp == 0);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset stream. */
|
/* Reset stream. */
|
||||||
void
|
void
|
||||||
stream_reset (struct stream *s)
|
stream_reset (struct stream *s)
|
||||||
{
|
{
|
||||||
s->endp = 0;
|
STREAM_VERIFY_SANE (s);
|
||||||
s->getp = 0;
|
|
||||||
|
s->getp = s->endp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write stream contens to the file discriptor. */
|
/* Write stream contens to the file discriptor. */
|
||||||
@ -377,6 +693,8 @@ stream_flush (struct stream *s, int fd)
|
|||||||
{
|
{
|
||||||
int nbytes;
|
int nbytes;
|
||||||
|
|
||||||
|
STREAM_VERIFY_SANE(s);
|
||||||
|
|
||||||
nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
|
nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
112
lib/stream.h
112
lib/stream.h
@ -25,21 +25,86 @@
|
|||||||
|
|
||||||
#include "prefix.h"
|
#include "prefix.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A stream is an arbitrary buffer, whose contents generally are assumed to
|
||||||
|
* be in network order.
|
||||||
|
*
|
||||||
|
* A stream has the following attributes associated with it:
|
||||||
|
*
|
||||||
|
* - size: the allocated, invariant size of the buffer.
|
||||||
|
*
|
||||||
|
* - getp: the get position marker, denoting the offset in the stream where
|
||||||
|
* the next read (or 'get') will be from. This getp marker is
|
||||||
|
* automatically adjusted when data is read from the stream, the
|
||||||
|
* user may also manipulate this offset as they wish, within limits
|
||||||
|
* (see below)
|
||||||
|
*
|
||||||
|
* - endp: the end position marker, denoting the offset in the stream where
|
||||||
|
* valid data ends, and if the user attempted to write (or
|
||||||
|
* 'put') data where that data would be written (or 'put') to.
|
||||||
|
*
|
||||||
|
* These attributes are all size_t values.
|
||||||
|
*
|
||||||
|
* Constraints:
|
||||||
|
*
|
||||||
|
* 1. getp can never exceed endp
|
||||||
|
*
|
||||||
|
* - hence if getp is equal to endp, there is no more valid data that can be
|
||||||
|
* gotten from the stream (though, the user may reposition getp to earlier in
|
||||||
|
* the stream, if they wish).
|
||||||
|
*
|
||||||
|
* 2. endp can never exceed size
|
||||||
|
*
|
||||||
|
* - hence, if endp is equal to size, then the stream is full, and no more
|
||||||
|
* data can be written to the stream.
|
||||||
|
*
|
||||||
|
* In other words the following must always be true, and the stream
|
||||||
|
* abstraction is allowed internally to assert that the following property
|
||||||
|
* holds true for a stream, as and when it wishes:
|
||||||
|
*
|
||||||
|
* getp <= endp <= size
|
||||||
|
*
|
||||||
|
* It is the users responsibility to ensure this property is never violated.
|
||||||
|
*
|
||||||
|
* A stream therefore can be thought of like this:
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------
|
||||||
|
* |XXXXXXXXXXXXXXXXXXXXXXXX |
|
||||||
|
* ---------------------------------------------------
|
||||||
|
* ^ ^ ^
|
||||||
|
* getp endp size
|
||||||
|
*
|
||||||
|
* This shows a stream containing data (shown as 'X') up to the endp offset.
|
||||||
|
* The stream is empty from endp to size. Without adjusting getp, there are
|
||||||
|
* still endp-getp bytes of valid data to be read from the stream.
|
||||||
|
*
|
||||||
|
* Methods are provided to get and put to/from the stream, as well as
|
||||||
|
* retrieve the values of the 3 markers and manipulate the getp marker.
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* At the moment, newly allocated streams are zero filled. Hence, one can
|
||||||
|
* use stream_forward_endp() to effectively create arbitrary zero-fill
|
||||||
|
* padding. However, note that stream_reset() does *not* zero-out the
|
||||||
|
* stream. This property should **not** be relied upon.
|
||||||
|
*
|
||||||
|
* A Good stream user should ensure it writes all bytes. (the zero-fill
|
||||||
|
* guarantee may be removed in future, however, the zero-filling may
|
||||||
|
* possibly be moved to stream_forward_endp() instead, maybe..)
|
||||||
|
*/
|
||||||
|
|
||||||
/* Stream buffer. */
|
/* Stream buffer. */
|
||||||
struct stream
|
struct stream
|
||||||
{
|
{
|
||||||
struct stream *next;
|
struct stream *next;
|
||||||
|
|
||||||
unsigned char *data;
|
/* Remainder is ***private*** to stream
|
||||||
|
* direct access is frowned upon!
|
||||||
/* Get pointer. */
|
* Use the appropriate functions/macros
|
||||||
size_t getp;
|
*/
|
||||||
|
size_t getp; /* next get position */
|
||||||
/* End of pointer. */
|
size_t endp; /* last valid data position */
|
||||||
size_t endp;
|
size_t size; /* size of data segment */
|
||||||
|
unsigned char data[0]; /* data pointer */
|
||||||
/* Data size. */
|
|
||||||
size_t size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* First in first out queue structure. */
|
/* First in first out queue structure. */
|
||||||
@ -52,14 +117,22 @@ struct stream_fifo
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Utility macros. */
|
/* Utility macros. */
|
||||||
#define STREAM_PNT(S) ((S)->data + (S)->getp)
|
|
||||||
#define STREAM_SIZE(S) ((S)->size)
|
#define STREAM_SIZE(S) ((S)->size)
|
||||||
#define STREAM_REMAIN(S) ((S)->size - (S)->endp)
|
/* number of bytes which can still be written */
|
||||||
|
#define STREAM_WRITEABLE(S) ((S)->size - (S)->endp)
|
||||||
|
/* number of bytes still to be read */
|
||||||
|
#define STREAM_READABLE(S) ((S)->endp - (S)->getp)
|
||||||
|
|
||||||
|
/* deprecated macros - do not use in new code */
|
||||||
|
#define STREAM_PNT(S) stream_pnt((S))
|
||||||
#define STREAM_DATA(S) ((S)->data)
|
#define STREAM_DATA(S) ((S)->data)
|
||||||
|
#define STREAM_REMAIN(S) STREAM_WRITEABLE((S))
|
||||||
|
|
||||||
/* Stream prototypes. */
|
/* Stream prototypes. */
|
||||||
struct stream *stream_new (size_t);
|
struct stream *stream_new (size_t);
|
||||||
void stream_free (struct stream *);
|
void stream_free (struct stream *);
|
||||||
|
struct stream * stream_copy (struct stream *new, struct stream *src);
|
||||||
|
struct stream *stream_dup (struct stream *);
|
||||||
|
|
||||||
size_t stream_get_getp (struct stream *);
|
size_t stream_get_getp (struct stream *);
|
||||||
size_t stream_get_endp (struct stream *);
|
size_t stream_get_endp (struct stream *);
|
||||||
@ -67,8 +140,8 @@ size_t stream_get_size (struct stream *);
|
|||||||
u_char *stream_get_data (struct stream *);
|
u_char *stream_get_data (struct stream *);
|
||||||
|
|
||||||
void stream_set_getp (struct stream *, size_t);
|
void stream_set_getp (struct stream *, size_t);
|
||||||
void stream_forward_getp (struct stream *, int);
|
void stream_forward_getp (struct stream *, size_t);
|
||||||
void stream_forward_endp (struct stream *, int);
|
void stream_forward_endp (struct stream *, size_t);
|
||||||
|
|
||||||
void stream_put (struct stream *, void *, size_t);
|
void stream_put (struct stream *, void *, size_t);
|
||||||
int stream_putc (struct stream *, u_char);
|
int stream_putc (struct stream *, u_char);
|
||||||
@ -87,18 +160,23 @@ u_char stream_getc_from (struct stream *, size_t);
|
|||||||
u_int16_t stream_getw (struct stream *);
|
u_int16_t stream_getw (struct stream *);
|
||||||
u_int16_t stream_getw_from (struct stream *, size_t);
|
u_int16_t stream_getw_from (struct stream *, size_t);
|
||||||
u_int32_t stream_getl (struct stream *);
|
u_int32_t stream_getl (struct stream *);
|
||||||
|
u_int32_t stream_getl_from (struct stream *, size_t);
|
||||||
u_int32_t stream_get_ipv4 (struct stream *);
|
u_int32_t stream_get_ipv4 (struct stream *);
|
||||||
|
|
||||||
#undef stream_read
|
#undef stream_read
|
||||||
#undef stream_write
|
#undef stream_write
|
||||||
int stream_read (struct stream *, int, size_t);
|
int stream_read (struct stream *, int, size_t);
|
||||||
int stream_read_unblock (struct stream *, int, size_t);
|
int stream_read_unblock (struct stream *, int, size_t);
|
||||||
|
int stream_recvmsg (struct stream *s, int fd, struct msghdr *,
|
||||||
|
int flags, size_t size);
|
||||||
int stream_write (struct stream *, u_char *, size_t);
|
int stream_write (struct stream *, u_char *, size_t);
|
||||||
|
|
||||||
u_char *stream_pnt (struct stream *);
|
void stream_reset (struct stream *); /* reset the stream. See Note above */
|
||||||
void stream_reset (struct stream *);
|
|
||||||
int stream_flush (struct stream *, int);
|
int stream_flush (struct stream *, int);
|
||||||
int stream_empty (struct stream *);
|
int stream_empty (struct stream *); /* is the stream empty? */
|
||||||
|
|
||||||
|
/* deprecated */
|
||||||
|
u_char *stream_pnt (struct stream *);
|
||||||
|
|
||||||
/* Stream fifo. */
|
/* Stream fifo. */
|
||||||
struct stream_fifo *stream_fifo_new ();
|
struct stream_fifo *stream_fifo_new ();
|
||||||
|
Loading…
Reference in New Issue
Block a user