support for 32-bit tag numbers in rpc structures

svn:r583
This commit is contained in:
Niels Provos 2007-12-12 04:39:42 +00:00
parent e8b916c36e
commit ba48719946
6 changed files with 180 additions and 59 deletions

View File

@ -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 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 Rewrite win32.c backend to be O(n lg n) rather than O(n^2).
o Removed obsoleted recalc code 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: Changes in 1.4.0:

24
event.h
View File

@ -1095,7 +1095,7 @@ void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_
void evtag_init(void); 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); 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 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); 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); struct timeval *tv);
void evtag_test(void); void evtag_test(void);
int evtag_unmarshal(struct evbuffer *src, ev_uint8_t *ptag, struct evbuffer *dst); int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
int evtag_peek(struct evbuffer *evbuf, ev_uint8_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_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
int evtag_payload_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_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); ev_uint32_t *pinteger);
int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint8_t need_tag, void *data, int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
size_t len); 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); 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); struct timeval *ptv);
/** /**

View File

@ -92,9 +92,9 @@ void %(name)s_clear(struct %(name)s *);
void %(name)s_marshal(struct evbuffer *, const 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_unmarshal(struct %(name)s *, struct evbuffer *);
int %(name)s_complete(struct %(name)s *); 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 *); 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 } 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, ' '%(name)s_unmarshal(struct %(name)s *tmp, '
' struct evbuffer *evbuf)\n' ' struct evbuffer *evbuf)\n'
'{\n' '{\n'
' uint8_t tag;\n' ' uint32_t tag;\n'
' while (EVBUFFER_LENGTH(evbuf) > 0) {\n' ' while (EVBUFFER_LENGTH(evbuf) > 0) {\n'
' if (evtag_peek(evbuf, &tag) == -1)\n' ' if (evtag_peek(evbuf, &tag) == -1)\n'
' return (-1);\n' ' return (-1);\n'
@ -247,9 +247,9 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t,
print >>file, ( print >>file, (
'int\n' 'int\n'
'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' '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' '{\n'
' uint8_t tag;\n' ' uint32_t tag;\n'
' int res = -1;\n' ' int res = -1;\n'
'\n' '\n'
' struct evbuffer *tmp = evbuffer_new();\n' ' struct evbuffer *tmp = evbuffer_new();\n'
@ -271,7 +271,7 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, uint8_t,
# Complete message marshaling # Complete message marshaling
print >>file, ( print >>file, (
'void\n' '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' 'const struct %(name)s *msg)\n'
'{\n' '{\n'
' struct evbuffer *_buf = evbuffer_new();\n' ' struct evbuffer *_buf = evbuffer_new();\n'
@ -436,7 +436,7 @@ class EntryBytes(Entry):
Entry.__init__(self, type, name, tag) Entry.__init__(self, type, name, tag)
self._length = length self._length = length
self._ctype = 'uint8_t' self._ctype = 'uint32_t'
def GetDeclaration(self, funcname): def GetDeclaration(self, funcname):
code = [ 'int %s(struct %s *, %s **);' % ( code = [ 'int %s(struct %s *, %s **);' % (
@ -1099,10 +1099,10 @@ def ProcessOneEntry(newstruct, entry):
if not tag_set: if not tag_set:
tag_set = 1 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 print >>sys.stderr, 'Expected tag number: \"%s\"' % entry
sys.exit(1) sys.exit(1)
tag = int(token) tag = int(token, 0)
continue continue
print >>sys.stderr, 'Cannot parse \"%s\"' % entry print >>sys.stderr, 'Cannot parse \"%s\"' % entry

View File

@ -111,6 +111,71 @@ encode_int(struct evbuffer *evbuf, uint32_t number)
evbuffer_add(evbuf, data, (off + 1) / 2); 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: * Marshal a data type, the general format is as follows:
* *
@ -118,34 +183,34 @@ encode_int(struct evbuffer *evbuf, uint32_t number)
*/ */
void void
evtag_marshal(struct evbuffer *evbuf, uint8_t tag, evtag_marshal(struct evbuffer *evbuf, uint32_t tag,
const void *data, uint32_t len) const void *data, uint32_t len)
{ {
evbuffer_add(evbuf, &tag, sizeof(tag)); encode_tag(evbuf, tag);
encode_int(evbuf, len); encode_int(evbuf, len);
evbuffer_add(evbuf, (void *)data, len); evbuffer_add(evbuf, (void *)data, len);
} }
/* Marshaling for integers */ /* Marshaling for integers */
void 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)); evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
encode_int(_buf, integer); encode_int(_buf, integer);
evbuffer_add(evbuf, &tag, sizeof(tag)); encode_tag(evbuf, tag);
encode_int(evbuf, EVBUFFER_LENGTH(_buf)); encode_int(evbuf, EVBUFFER_LENGTH(_buf));
evbuffer_add_buffer(evbuf, _buf); evbuffer_add_buffer(evbuf, _buf);
} }
void 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)); evtag_marshal(buf, tag, string, strlen(string));
} }
void 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)); evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@ -196,33 +261,30 @@ decode_int(uint32_t *pnumber, struct evbuffer *evbuf)
} }
int int
evtag_peek(struct evbuffer *evbuf, uint8_t *ptag) evtag_peek(struct evbuffer *evbuf, uint32_t *ptag)
{ {
if (EVBUFFER_LENGTH(evbuf) < 2) return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
return (-1);
*ptag = EVBUFFER_DATA(evbuf)[0];
return (0);
} }
int int
evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength) evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength)
{ {
struct evbuffer tmp; 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); return (-1);
tmp = *evbuf; tmp = *evbuf;
tmp.buffer += 1; tmp.buffer += len;
tmp.off -= 1; tmp.off -= len;
res = decode_int_internal(plength, &tmp, 0); res = decode_int_internal(plength, &tmp, 0);
if (res == -1) if (res == -1)
return (-1); return (-1);
*plength += res + 1; *plength += res + len;
return (0); return (0);
} }
@ -231,14 +293,15 @@ int
evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength) evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength)
{ {
struct evbuffer tmp; 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); return (-1);
tmp = *evbuf; tmp = *evbuf;
tmp.buffer += 1; tmp.buffer += len;
tmp.off -= 1; tmp.off -= len;
res = decode_int_internal(plength, &tmp, 0); res = decode_int_internal(plength, &tmp, 0);
if (res == -1) if (res == -1)
@ -251,7 +314,8 @@ int
evtag_consume(struct evbuffer *evbuf) evtag_consume(struct evbuffer *evbuf)
{ {
uint32_t len; uint32_t len;
evbuffer_drain(evbuf, 1); if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
return (-1);
if (decode_int(&len, evbuf) == -1) if (decode_int(&len, evbuf) == -1)
return (-1); return (-1);
evbuffer_drain(evbuf, len); evbuffer_drain(evbuf, len);
@ -262,13 +326,12 @@ evtag_consume(struct evbuffer *evbuf)
/* Reads the data type from an event buffer */ /* Reads the data type from an event buffer */
int 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 len;
uint32_t integer; uint32_t integer;
if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag)) if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
return (-1); return (-1);
if (decode_int(&integer, src) == -1) if (decode_int(&integer, src) == -1)
return (-1); return (-1);
@ -282,22 +345,22 @@ evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst)
evbuffer_drain(src, len); evbuffer_drain(src, len);
*ptag = tag;
return (len); return (len);
} }
/* Marshaling for integers */ /* Marshaling for integers */
int int
evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag, evtag_unmarshal_int(struct evbuffer *evbuf, uint32_t need_tag,
uint32_t *pinteger) uint32_t *pinteger)
{ {
uint8_t tag; uint32_t tag;
uint32_t len; uint32_t len;
uint32_t integer; uint32_t integer;
if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) || if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
tag != need_tag) return (-1);
if (need_tag != tag)
return (-1); return (-1);
if (decode_int(&integer, evbuf) == -1) if (decode_int(&integer, evbuf) == -1)
return (-1); return (-1);
@ -318,10 +381,10 @@ evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag,
/* Unmarshal a fixed length tag */ /* Unmarshal a fixed length tag */
int 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) size_t len)
{ {
uint8_t tag; uint32_t tag;
/* Initialize this event buffer so that we can read into it */ /* Initialize this event buffer so that we can read into it */
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@ -338,10 +401,10 @@ evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data,
} }
int int
evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, evtag_unmarshal_string(struct evbuffer *evbuf, uint32_t need_tag,
char **pstring) char **pstring)
{ {
uint8_t tag; uint32_t tag;
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@ -357,10 +420,10 @@ evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag,
} }
int int
evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag, evtag_unmarshal_timeval(struct evbuffer *evbuf, uint32_t need_tag,
struct timeval *ptv) struct timeval *ptv)
{ {
uint8_t tag; uint32_t tag;
uint32_t integer; uint32_t integer;
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));

View File

@ -1206,6 +1206,8 @@ test_multiple_events_for_same_fd(void)
} }
int decode_int(uint32_t *pnumber, struct evbuffer *evbuf); 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 static void
read_once_cb(int fd, short event, void *arg) read_once_cb(int fd, short event, void *arg)
@ -1335,6 +1337,46 @@ evtag_fuzz(void)
fprintf(stdout, "\t%s: OK\n", __func__); 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 void
evtag_test(void) evtag_test(void)
{ {
@ -1344,6 +1386,8 @@ evtag_test(void)
evtag_int_test(); evtag_int_test();
evtag_fuzz(); evtag_fuzz();
evtag_tag_encoding();
fprintf(stdout, "OK\n"); fprintf(stdout, "OK\n");
} }
@ -1355,6 +1399,7 @@ rpc_test(void)
struct run *run; struct run *run;
struct evbuffer *tmp = evbuffer_new(); struct evbuffer *tmp = evbuffer_new();
struct timeval tv_start, tv_end; struct timeval tv_start, tv_end;
uint32_t tag;
int i; int i;
fprintf(stdout, "Testing RPC: "); fprintf(stdout, "Testing RPC: ");
@ -1386,10 +1431,20 @@ rpc_test(void)
exit(1); 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(); 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"); fprintf(stderr, "Failed to unmarshal message.\n");
exit(1); exit(1);
} }

View File

@ -8,7 +8,7 @@ struct msg {
} }
struct kill { struct kill {
string weapon = 1; string weapon = 0x10121;
string action = 2; string action = 2;
} }