support 64-bit integers in rpc structs

svn:r856
This commit is contained in:
Niels Provos 2008-06-21 02:21:25 +00:00
parent 4c56ba1ced
commit 99a1063e73
6 changed files with 171 additions and 63 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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;
ENCODE_INT_INTERNAL(data, number);
}
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);
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.
@ -228,6 +246,18 @@ evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
evbuffer_add(evbuf, data, len);
}
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)
{
@ -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;
DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset);
}
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;
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

View File

@ -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);

View File

@ -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");

View File

@ -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;
}