From ba48719946f2f1ea80db28b77dc23b27010e01e5 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Wed, 12 Dec 2007 04:39:42 +0000 Subject: [PATCH] support for 32-bit tag numbers in rpc structures svn:r583 --- ChangeLog | 1 + event.h | 24 +++++---- event_rpcgen.py | 18 +++---- event_tagging.c | 135 ++++++++++++++++++++++++++++++++++------------- test/regress.c | 59 ++++++++++++++++++++- test/regress.rpc | 2 +- 6 files changed, 180 insertions(+), 59 deletions(-) diff --git a/ChangeLog b/ChangeLog index 79756e16..b8d895d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ Changes in current version: o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions. o Rewrite win32.c backend to be O(n lg n) rather than O(n^2). o Removed obsoleted recalc code + o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly. Changes in 1.4.0: diff --git a/event.h b/event.h index d6fa3ee9..86474dfc 100644 --- a/event.h +++ b/event.h @@ -1095,7 +1095,7 @@ void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_ void evtag_init(void); -void evtag_marshal(struct evbuffer *evbuf, ev_uint8_t tag, const void *data, +void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, ev_uint32_t len); /** @@ -1110,32 +1110,34 @@ void evtag_marshal(struct evbuffer *evbuf, ev_uint8_t tag, const void *data, */ void encode_int(struct evbuffer *evbuf, ev_uint32_t number); -void evtag_marshal_int(struct evbuffer *evbuf, ev_uint8_t tag, ev_uint32_t integer); +void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint32_t integer); -void evtag_marshal_string(struct evbuffer *buf, ev_uint8_t tag, +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string); -void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint8_t tag, +void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv); void evtag_test(void); -int evtag_unmarshal(struct evbuffer *src, ev_uint8_t *ptag, struct evbuffer *dst); -int evtag_peek(struct evbuffer *evbuf, ev_uint8_t *ptag); +int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, + struct evbuffer *dst); +int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); int evtag_consume(struct evbuffer *evbuf); -int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint8_t need_tag, +int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint32_t *pinteger); -int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint8_t need_tag, void *data, - size_t len); +int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, + void *data, size_t len); -int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint8_t need_tag, +int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, char **pstring); -int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint8_t need_tag, +int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, struct timeval *ptv); /** diff --git a/event_rpcgen.py b/event_rpcgen.py index 4e767d65..3489dc7a 100755 --- a/event_rpcgen.py +++ b/event_rpcgen.py @@ -92,9 +92,9 @@ void %(name)s_clear(struct %(name)s *); void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); int %(name)s_complete(struct %(name)s *); -void evtag_marshal_%(name)s(struct evbuffer *, uint8_t, +void evtag_marshal_%(name)s(struct evbuffer *, uint32_t, const struct %(name)s *); -int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t, +int evtag_unmarshal_%(name)s(struct evbuffer *, uint32_t, struct %(name)s *);""" % { 'name' : self._name } @@ -196,7 +196,7 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t, '%(name)s_unmarshal(struct %(name)s *tmp, ' ' struct evbuffer *evbuf)\n' '{\n' - ' uint8_t tag;\n' + ' uint32_t tag;\n' ' while (EVBUFFER_LENGTH(evbuf) > 0) {\n' ' if (evtag_peek(evbuf, &tag) == -1)\n' ' return (-1);\n' @@ -247,9 +247,9 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t, print >>file, ( 'int\n' 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' - 'uint8_t need_tag, struct %(name)s *msg)\n' + 'uint32_t need_tag, struct %(name)s *msg)\n' '{\n' - ' uint8_t tag;\n' + ' uint32_t tag;\n' ' int res = -1;\n' '\n' ' struct evbuffer *tmp = evbuffer_new();\n' @@ -271,7 +271,7 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t, # Complete message marshaling print >>file, ( 'void\n' - 'evtag_marshal_%(name)s(struct evbuffer *evbuf, uint8_t tag, ' + 'evtag_marshal_%(name)s(struct evbuffer *evbuf, uint32_t tag, ' 'const struct %(name)s *msg)\n' '{\n' ' struct evbuffer *_buf = evbuffer_new();\n' @@ -436,7 +436,7 @@ class EntryBytes(Entry): Entry.__init__(self, type, name, tag) self._length = length - self._ctype = 'uint8_t' + self._ctype = 'uint32_t' def GetDeclaration(self, funcname): code = [ 'int %s(struct %s *, %s **);' % ( @@ -1099,10 +1099,10 @@ def ProcessOneEntry(newstruct, entry): if not tag_set: tag_set = 1 - if not re.match(r'^[0-9]+$', token): + if not re.match(r'^(0x)?[0-9]+$', token): print >>sys.stderr, 'Expected tag number: \"%s\"' % entry sys.exit(1) - tag = int(token) + tag = int(token, 0) continue print >>sys.stderr, 'Cannot parse \"%s\"' % entry diff --git a/event_tagging.c b/event_tagging.c index 027ff08a..788de0d4 100644 --- a/event_tagging.c +++ b/event_tagging.c @@ -111,6 +111,71 @@ encode_int(struct evbuffer *evbuf, uint32_t number) evbuffer_add(evbuf, data, (off + 1) / 2); } +/* + * Support variable length encoding of tags; we use the high bit in each + * octet as a continuation signal. + */ + +int +encode_tag(struct evbuffer *evbuf, uint32_t tag) +{ + int bytes = 0; + uint8_t data[5]; + + memset(data, 0, sizeof(data)); + do { + uint8_t lower = tag & 0x7f; + tag >>= 7; + + if (tag) + lower |= 0x80; + + data[bytes++] = lower; + } while (tag); + + if (evbuf != NULL) + evbuffer_add(evbuf, data, bytes); + + return (bytes); +} + +int +decode_tag_internal(uint32_t *ptag, struct evbuffer *evbuf, int dodrain) +{ + uint32_t number = 0; + uint8_t *data = EVBUFFER_DATA(evbuf); + int len = EVBUFFER_LENGTH(evbuf); + int count = 0, shift = 0, done = 0; + + while (count++ < len) { + uint8_t lower = *data++; + number |= (lower & 0x7f) << shift; + shift += 7; + + if (!(lower & 0x80)) { + done = 1; + break; + } + } + + if (!done) + return (-1); + + if (dodrain) + evbuffer_drain(evbuf, count); + + if (ptag != NULL) + *ptag = number; + + return (count); +} + +int +decode_tag(uint32_t *ptag, struct evbuffer *evbuf) +{ + return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */)); +} + /* * Marshal a data type, the general format is as follows: * @@ -118,34 +183,34 @@ encode_int(struct evbuffer *evbuf, uint32_t number) */ void -evtag_marshal(struct evbuffer *evbuf, uint8_t tag, +evtag_marshal(struct evbuffer *evbuf, uint32_t tag, const void *data, uint32_t len) { - evbuffer_add(evbuf, &tag, sizeof(tag)); + encode_tag(evbuf, tag); encode_int(evbuf, len); evbuffer_add(evbuf, (void *)data, len); } /* Marshaling for integers */ void -evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer) +evtag_marshal_int(struct evbuffer *evbuf, uint32_t tag, uint32_t integer) { evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); encode_int(_buf, integer); - evbuffer_add(evbuf, &tag, sizeof(tag)); + encode_tag(evbuf, tag); encode_int(evbuf, EVBUFFER_LENGTH(_buf)); evbuffer_add_buffer(evbuf, _buf); } void -evtag_marshal_string(struct evbuffer *buf, uint8_t tag, const char *string) +evtag_marshal_string(struct evbuffer *buf, uint32_t tag, const char *string) { evtag_marshal(buf, tag, string, strlen(string)); } void -evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag, struct timeval *tv) +evtag_marshal_timeval(struct evbuffer *evbuf, uint32_t tag, struct timeval *tv) { evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -196,33 +261,30 @@ decode_int(uint32_t *pnumber, struct evbuffer *evbuf) } int -evtag_peek(struct evbuffer *evbuf, uint8_t *ptag) +evtag_peek(struct evbuffer *evbuf, uint32_t *ptag) { - if (EVBUFFER_LENGTH(evbuf) < 2) - return (-1); - *ptag = EVBUFFER_DATA(evbuf)[0]; - - return (0); + return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */)); } int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength) { struct evbuffer tmp; - int res; + int res, len; - if (EVBUFFER_LENGTH(evbuf) < 2) + len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); + if (len == -1) return (-1); tmp = *evbuf; - tmp.buffer += 1; - tmp.off -= 1; + tmp.buffer += len; + tmp.off -= len; res = decode_int_internal(plength, &tmp, 0); if (res == -1) return (-1); - *plength += res + 1; + *plength += res + len; return (0); } @@ -231,14 +293,15 @@ int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength) { struct evbuffer tmp; - int res; + int res, len; - if (EVBUFFER_LENGTH(evbuf) < 2) + len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); + if (len == -1) return (-1); tmp = *evbuf; - tmp.buffer += 1; - tmp.off -= 1; + tmp.buffer += len; + tmp.off -= len; res = decode_int_internal(plength, &tmp, 0); if (res == -1) @@ -251,7 +314,8 @@ int evtag_consume(struct evbuffer *evbuf) { uint32_t len; - evbuffer_drain(evbuf, 1); + if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1) + return (-1); if (decode_int(&len, evbuf) == -1) return (-1); evbuffer_drain(evbuf, len); @@ -262,13 +326,12 @@ evtag_consume(struct evbuffer *evbuf) /* Reads the data type from an event buffer */ int -evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst) +evtag_unmarshal(struct evbuffer *src, uint32_t *ptag, struct evbuffer *dst) { - uint8_t tag; uint32_t len; uint32_t integer; - if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag)) + if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1) return (-1); if (decode_int(&integer, src) == -1) return (-1); @@ -282,22 +345,22 @@ evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst) evbuffer_drain(src, len); - *ptag = tag; return (len); } /* Marshaling for integers */ int -evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag, +evtag_unmarshal_int(struct evbuffer *evbuf, uint32_t need_tag, uint32_t *pinteger) { - uint8_t tag; + uint32_t tag; uint32_t len; uint32_t integer; - if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) || - tag != need_tag) + if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) + return (-1); + if (need_tag != tag) return (-1); if (decode_int(&integer, evbuf) == -1) return (-1); @@ -318,10 +381,10 @@ evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag, /* Unmarshal a fixed length tag */ int -evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data, +evtag_unmarshal_fixed(struct evbuffer *src, uint32_t need_tag, void *data, size_t len) { - uint8_t tag; + uint32_t tag; /* Initialize this event buffer so that we can read into it */ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -338,10 +401,10 @@ evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data, } int -evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, +evtag_unmarshal_string(struct evbuffer *evbuf, uint32_t need_tag, char **pstring) { - uint8_t tag; + uint32_t tag; evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); @@ -357,10 +420,10 @@ evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, } int -evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag, +evtag_unmarshal_timeval(struct evbuffer *evbuf, uint32_t need_tag, struct timeval *ptv) { - uint8_t tag; + uint32_t tag; uint32_t integer; evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); diff --git a/test/regress.c b/test/regress.c index 8cc3e995..e84fa36e 100644 --- a/test/regress.c +++ b/test/regress.c @@ -1206,6 +1206,8 @@ test_multiple_events_for_same_fd(void) } int decode_int(uint32_t *pnumber, struct evbuffer *evbuf); +int encode_tag(struct evbuffer *evbuf, uint32_t number); +int decode_tag(uint32_t *pnumber, struct evbuffer *evbuf); static void read_once_cb(int fd, short event, void *arg) @@ -1335,6 +1337,46 @@ evtag_fuzz(void) fprintf(stdout, "\t%s: OK\n", __func__); } +static void +evtag_tag_encoding(void) +{ + struct evbuffer *tmp = evbuffer_new(); + uint32_t integers[TEST_MAX_INT] = { + 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 + }; + uint32_t integer; + int i; + + for (i = 0; i < TEST_MAX_INT; i++) { + int oldlen, newlen; + oldlen = EVBUFFER_LENGTH(tmp); + encode_tag(tmp, integers[i]); + newlen = EVBUFFER_LENGTH(tmp); + fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n", + integers[i], newlen - oldlen); + } + + for (i = 0; i < TEST_MAX_INT; i++) { + if (decode_tag(&integer, tmp) == -1) { + fprintf(stderr, "decode %d failed", i); + exit(1); + } + if (integer != integers[i]) { + fprintf(stderr, "got %x, wanted %x", + integer, integers[i]); + exit(1); + } + } + + if (EVBUFFER_LENGTH(tmp) != 0) { + fprintf(stderr, "trailing data"); + exit(1); + } + evbuffer_free(tmp); + + fprintf(stdout, "\t%s: OK\n", __func__); +} + void evtag_test(void) { @@ -1344,6 +1386,8 @@ evtag_test(void) evtag_int_test(); evtag_fuzz(); + evtag_tag_encoding(); + fprintf(stdout, "OK\n"); } @@ -1355,6 +1399,7 @@ rpc_test(void) struct run *run; struct evbuffer *tmp = evbuffer_new(); struct timeval tv_start, tv_end; + uint32_t tag; int i; fprintf(stdout, "Testing RPC: "); @@ -1386,10 +1431,20 @@ rpc_test(void) exit(1); } - evtag_marshal_msg(tmp, 0, msg); + evtag_marshal_msg(tmp, 0xdeaf, msg); + + if (evtag_peek(tmp, &tag) == -1) { + fprintf(stderr, "Failed to peak tag.\n"); + exit (1); + } + + if (tag != 0xdeaf) { + fprintf(stderr, "Got incorrect tag: %0x.\n", tag); + exit (1); + } msg2 = msg_new(); - if (evtag_unmarshal_msg(tmp, 0, msg2) == -1) { + if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1) { fprintf(stderr, "Failed to unmarshal message.\n"); exit(1); } diff --git a/test/regress.rpc b/test/regress.rpc index 03537ccd..52a2104b 100644 --- a/test/regress.rpc +++ b/test/regress.rpc @@ -8,7 +8,7 @@ struct msg { } struct kill { - string weapon = 1; + string weapon = 0x10121; string action = 2; }