diff options
author | Niels Provos <provos@gmail.com> | 2008-06-21 02:21:25 +0000 |
---|---|---|
committer | Niels Provos <provos@gmail.com> | 2008-06-21 02:21:25 +0000 |
commit | 99a1063e735f70443268b50d14f042c87cb9b99a (patch) | |
tree | 2789eb33ecbbb259c280e9c290f183b31ba40d72 | |
parent | 4c56ba1cede32ba30624208e8e84672531e644e3 (diff) | |
download | libevent-99a1063e735f70443268b50d14f042c87cb9b99a.tar.gz |
support 64-bit integers in rpc structs
svn:r856
-rw-r--r-- | ChangeLog | 2 | ||||
-rwxr-xr-x | event_rpcgen.py | 32 | ||||
-rw-r--r-- | event_tagging.c | 167 | ||||
-rw-r--r-- | include/event2/tag.h | 5 | ||||
-rw-r--r-- | test/regress.c | 25 | ||||
-rw-r--r-- | test/regress.rpc | 3 |
6 files changed, 171 insertions, 63 deletions
@@ -110,7 +110,7 @@ Changes in current version: o allow min_heap_erase to be called on removed members; from liusifan. o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT. Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility. o Do not use SO_REUSEADDR when connecting - + o Support 64-bit integers in RPC structs Changes in 1.4.0: o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr. diff --git a/event_rpcgen.py b/event_rpcgen.py index ea480a25..b3770830 100755 --- a/event_rpcgen.py +++ b/event_rpcgen.py @@ -575,12 +575,17 @@ class EntryBytes(Entry): Entry.Verify(self) class EntryInt(Entry): - def __init__(self, type, name, tag): + def __init__(self, type, name, tag, bits=32): # Init base class Entry.__init__(self, type, name, tag) self._can_be_array = 1 - self._ctype = 'ev_uint32_t' + if bits == 32: + self._ctype = 'ev_uint32_t' + self._marshal_type = 'int' + if bits == 64: + self._ctype = 'ev_uint64_t' + self._marshal_type = 'int64' def GetInitializer(self): return "0" @@ -598,23 +603,26 @@ class EntryInt(Entry): 'value' : value } ] def CodeUnmarshal(self, buf, tag_name, var_name, var_len): - code = ['if (evtag_unmarshal_int(%(buf)s, %(tag)s, &%(var)s) == -1) {', - ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', - ' return (-1);', - '}' ] + code = [ + 'if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {', + ' event_warnx("%%s: failed to unmarshal %(name)s", __func__);', + ' return (-1);', + '}' ] code = '\n'.join(code) % self.GetTranslation({ + 'ma' : self._marshal_type, 'buf' : buf, 'tag' : tag_name, 'var' : var_name }) return code.split('\n') def CodeMarshal(self, buf, tag_name, var_name, var_len): - code = ['evtag_marshal_int(%s, %s, %s);' % ( - buf, tag_name, var_name)] + code = [ + 'evtag_marshal_%s(%s, %s, %s);' % ( + self._marshal_type, buf, tag_name, var_name)] return code def Declaration(self): - dcl = ['ev_uint32_t %s_data;' % self._name] + dcl = ['%s %s_data;' % (self._ctype, self._name)] return dcl @@ -1338,6 +1346,8 @@ def ProcessOneEntry(factory, newstruct, entry): newentry = factory.EntryVarBytes(entry_type, name, tag) elif entry_type == 'int' and not fixed_length: newentry = factory.EntryInt(entry_type, name, tag) + elif entry_type == 'int64' and not fixed_length: + newentry = factory.EntryInt(entry_type, name, tag, bits=64) elif entry_type == 'string' and not fixed_length: newentry = factory.EntryString(entry_type, name, tag) else: @@ -1593,8 +1603,8 @@ class CCodeGenerator: def EntryVarBytes(self, entry_type, name, tag): return EntryVarBytes(entry_type, name, tag) - def EntryInt(self, entry_type, name, tag): - return EntryInt(entry_type, name, tag) + def EntryInt(self, entry_type, name, tag, bits=32): + return EntryInt(entry_type, name, tag, bits) def EntryString(self, entry_type, name, tag): return EntryString(entry_type, name, tag) diff --git a/event_tagging.c b/event_tagging.c index 62fc4b22..4a39ea2c 100644 --- a/event_tagging.c +++ b/event_tagging.c @@ -87,29 +87,39 @@ evtag_init(void) * @return the number of bytes written into data. */ +#define ENCODE_INT_INTERNAL(data, number) do { \ + int off = 1, nibbles = 0; \ + \ + memset(data, 0, sizeof(number)+1); \ + while (number) { \ + if (off & 0x1) \ + data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); \ + else \ + data[off/2] = (data[off/2] & 0x0f) | \ + ((number & 0x0f) << 4); \ + number >>= 4; \ + off++; \ + } \ + \ + if (off > 2) \ + nibbles = off - 2; \ + \ + /* Off - 1 is the number of encoded nibbles */ \ + data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); \ + \ + return ((off + 1) / 2); \ +} while (0) + static inline int encode_int_internal(ev_uint8_t *data, ev_uint32_t number) { - int off = 1, nibbles = 0; - - memset(data, 0, sizeof(ev_uint32_t)+1); - while (number) { - if (off & 0x1) - data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); - else - data[off/2] = (data[off/2] & 0x0f) | - ((number & 0x0f) << 4); - number >>= 4; - off++; - } - - if (off > 2) - nibbles = off - 2; - - /* Off - 1 is the number of encoded nibbles */ - data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); + ENCODE_INT_INTERNAL(data, number); +} - return ((off + 1) / 2); +static inline int +encode_int64_internal(ev_uint8_t *data, ev_uint64_t number) +{ + ENCODE_INT_INTERNAL(data, number); } void @@ -120,6 +130,14 @@ encode_int(struct evbuffer *evbuf, ev_uint32_t number) evbuffer_add(evbuf, data, len); } +void +encode_int64(struct evbuffer *evbuf, ev_uint64_t number) +{ + ev_uint8_t data[9]; + int len = encode_int64_internal(data, number); + evbuffer_add(evbuf, data, len); +} + /* * Support variable length encoding of tags; we use the high bit in each * octet as a continuation signal. @@ -229,6 +247,18 @@ evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer) } void +evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint64_t integer) +{ + ev_uint8_t data[9]; + int len = encode_int64_internal(data, integer); + + evtag_encode_tag(evbuf, tag); + encode_int(evbuf, len); + evbuffer_add(evbuf, data, len); +} + +void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string) { evtag_marshal(buf, tag, string, strlen(string)); @@ -243,6 +273,39 @@ evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *t evtag_marshal(evbuf, tag, data, len); } +#define DECODE_INT_INTERNAL(number, maxnibbles, pnumber, evbuf, offset) \ +do { \ + ev_uint8_t *data; \ + int len = EVBUFFER_LENGTH(evbuf) - offset; \ + int nibbles = 0; \ + \ + if (len <= 0) \ + return (-1); \ + \ + /* XXX(niels): faster? */ \ + data = evbuffer_pullup(evbuf, offset + 1) + offset; \ + \ + nibbles = ((data[0] & 0xf0) >> 4) + 1; \ + if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len) \ + return (-1); \ + len = (nibbles >> 1) + 1; \ + \ + data = evbuffer_pullup(evbuf, offset + len) + offset; \ + \ + while (nibbles > 0) { \ + number <<= 4; \ + if (nibbles & 0x1) \ + number |= data[nibbles >> 1] & 0x0f; \ + else \ + number |= (data[nibbles >> 1] & 0xf0) >> 4; \ + nibbles--; \ + } \ + \ + *pnumber = number; \ + \ + return (len); \ +} while (0) + /* Internal: decode an integer from an evbuffer, without draining it. * Only integers up to 32-bits are supported. * @@ -251,39 +314,19 @@ evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *t * @param pnumber a pointer to receive the integer. * @return The length of the number as encoded, or -1 on error. */ + static int decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset) { ev_uint32_t number = 0; - ev_uint8_t *data; - int len = EVBUFFER_LENGTH(evbuf) - offset; - int nibbles = 0; - - if (len <= 0) - return (-1); - - /* XXX(niels): faster? */ - data = evbuffer_pullup(evbuf, offset + 1) + offset; - - nibbles = ((data[0] & 0xf0) >> 4) + 1; - if (nibbles > 8 || (nibbles >> 1) + 1 > len) - return (-1); - len = (nibbles >> 1) + 1; - - data = evbuffer_pullup(evbuf, offset + len) + offset; - - while (nibbles > 0) { - number <<= 4; - if (nibbles & 0x1) - number |= data[nibbles >> 1] & 0x0f; - else - number |= (data[nibbles >> 1] & 0xf0) >> 4; - nibbles--; - } - - *pnumber = number; + DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset); +} - return (len); +static int +decode_int64_internal(ev_uint64_t *pnumber, struct evbuffer *evbuf, int offset) +{ + ev_uint64_t number = 0; + DECODE_INT_INTERNAL(number, 16, pnumber, evbuf, offset); } int @@ -391,16 +434,14 @@ evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, { ev_uint32_t tag; ev_uint32_t len; - ev_uint32_t integer; int result; if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) return (-1); if (need_tag != tag) return (-1); - if (evtag_decode_int(&integer, evbuf) == -1) + if (evtag_decode_int(&len, evbuf) == -1) return (-1); - len = integer; if (EVBUFFER_LENGTH(evbuf) < len) return (-1); @@ -413,6 +454,32 @@ evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, return result; } +int +evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint64_t *pinteger) +{ + ev_uint32_t tag; + ev_uint32_t len; + int result; + + if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) + return (-1); + if (need_tag != tag) + return (-1); + if (evtag_decode_int(&len, evbuf) == -1) + return (-1); + + if (EVBUFFER_LENGTH(evbuf) < len) + return (-1); + + result = decode_int64_internal(pinteger, evbuf, 0); + evbuffer_drain(evbuf, len); + if (result < 0 || result > len) /* XXX Should this be != rather than > ?*/ + return (-1); + else + return result; +} + /* Unmarshal a fixed length tag */ int diff --git a/include/event2/tag.h b/include/event2/tag.h index 0d0d8ca1..3f166e79 100644 --- a/include/event2/tag.h +++ b/include/event2/tag.h @@ -89,9 +89,12 @@ void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag, @param number a 32-bit integer */ void encode_int(struct evbuffer *evbuf, ev_uint32_t number); +void encode_int64(struct evbuffer *evbuf, ev_uint64_t number); void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer); +void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag, + ev_uint64_t integer); void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string); @@ -108,6 +111,8 @@ int evtag_consume(struct evbuffer *evbuf); int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, ev_uint32_t *pinteger); +int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag, + ev_uint64_t *pinteger); int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, size_t len); diff --git a/test/regress.c b/test/regress.c index 063fb1b9..d267a7ac 100644 --- a/test/regress.c +++ b/test/regress.c @@ -1947,6 +1947,10 @@ rpc_test(void) fprintf(stderr, "Failed to add note.\n"); exit(1); } + + EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL); + EVTAG_ADD(run, other_numbers, 0xdead0a0b); + EVTAG_ADD(run, other_numbers, 0xbeefcafe); } if (msg_complete(msg) == -1) { @@ -2002,6 +2006,8 @@ rpc_test(void) } else { /* verify the notes */ char *note_one, *note_two; + ev_uint64_t large_number; + ev_uint32_t short_number; if (EVTAG_LEN(run, notes) != 2) { fprintf(stderr, "Wrong number of note strings.\n"); @@ -2019,7 +2025,24 @@ rpc_test(void) fprintf(stderr, "Incorrect note strings encoded.\n"); exit(1); } - + + if (EVTAG_GET(run, large_number, &large_number) == -1 || + large_number != 0xdead0a0bcafebeefLL) { + fprintf(stderr, "Incorrrect large_number.\n"); + exit(1); + } + + if (EVTAG_LEN(run, other_numbers) != 2) { + fprintf(stderr, "Wrong number of other_numbers.\n"); + exit(1); + } + + if (EVTAG_GET(run, other_numbers, 0, &short_number) == -1) { + fprintf(stderr, "Could not get short number.\n"); + exit(1); + } + assert(short_number == 0xdead0a0b); + } if (EVTAG_LEN(attack, how_often) != 3) { fprintf(stderr, "Wrong number of how_often ints.\n"); diff --git a/test/regress.rpc b/test/regress.rpc index f8a4b1c1..c0170a78 100644 --- a/test/regress.rpc +++ b/test/regress.rpc @@ -19,4 +19,7 @@ struct run { bytes fixed_bytes[24] = 3; array string notes = 4; + + optional int64 large_number = 5; + array int other_numbers = 6; } |