xref: /libevent-2.1.12/event_tagging.c (revision 9806b126)
1c4e60994SNiels Provos /*
2b85b710cSNick Mathewson  * Copyright (c) 2003-2009 Niels Provos <[email protected]>
3e49e2891SNick Mathewson  * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
4c4e60994SNiels Provos  *
5c4e60994SNiels Provos  * Redistribution and use in source and binary forms, with or without
6c4e60994SNiels Provos  * modification, are permitted provided that the following conditions
7c4e60994SNiels Provos  * are met:
8c4e60994SNiels Provos  * 1. Redistributions of source code must retain the above copyright
9c4e60994SNiels Provos  *    notice, this list of conditions and the following disclaimer.
10c4e60994SNiels Provos  * 2. Redistributions in binary form must reproduce the above copyright
11c4e60994SNiels Provos  *    notice, this list of conditions and the following disclaimer in the
12c4e60994SNiels Provos  *    documentation and/or other materials provided with the distribution.
13c4e60994SNiels Provos  * 3. The name of the author may not be used to endorse or promote products
14c4e60994SNiels Provos  *    derived from this software without specific prior written permission.
15c4e60994SNiels Provos  *
16c4e60994SNiels Provos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17c4e60994SNiels Provos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18c4e60994SNiels Provos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19c4e60994SNiels Provos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20c4e60994SNiels Provos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21c4e60994SNiels Provos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22c4e60994SNiels Provos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23c4e60994SNiels Provos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24c4e60994SNiels Provos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25c4e60994SNiels Provos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26c4e60994SNiels Provos  */
27c4e60994SNiels Provos 
28ec347b92SNick Mathewson #include "event2/event-config.h"
290915ca0aSKevin Bowling #include "evconfig-private.h"
30c4e60994SNiels Provos 
3168120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TYPES_H
324e1ec3e0SNick Mathewson #include <sys/types.h>
334e1ec3e0SNick Mathewson #endif
3468120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_PARAM_H
354e1ec3e0SNick Mathewson #include <sys/param.h>
364e1ec3e0SNick Mathewson #endif
374e1ec3e0SNick Mathewson 
389f560bfaSNick Mathewson #ifdef _WIN32
39868f10e7SNiels Provos #define WIN32_LEAN_AND_MEAN
404e1ec3e0SNick Mathewson #include <winsock2.h>
41868f10e7SNiels Provos #include <windows.h>
42868f10e7SNiels Provos #undef WIN32_LEAN_AND_MEAN
43868f10e7SNiels Provos #endif
44868f10e7SNiels Provos 
45c1404b56SEd Schouten #ifdef EVENT__HAVE_SYS_IOCTL_H
46c1404b56SEd Schouten #include <sys/ioctl.h>
47c1404b56SEd Schouten #endif
48c4e60994SNiels Provos #include <sys/queue.h>
4968120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
50c4e60994SNiels Provos #include <sys/time.h>
51c4e60994SNiels Provos #endif
52c4e60994SNiels Provos 
53c4e60994SNiels Provos #include <errno.h>
54c4e60994SNiels Provos #include <stdio.h>
55c4e60994SNiels Provos #include <stdlib.h>
56c4e60994SNiels Provos #include <string.h>
579f560bfaSNick Mathewson #ifndef _WIN32
58c4e60994SNiels Provos #include <syslog.h>
59868f10e7SNiels Provos #endif
6068120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
61c4e60994SNiels Provos #include <unistd.h>
624e1ec3e0SNick Mathewson #endif
63f2763fa8SNick Mathewson #include <limits.h>
64c4e60994SNiels Provos 
650ac73078SNick Mathewson #include "event2/event.h"
660ac73078SNick Mathewson #include "event2/tag.h"
670ac73078SNick Mathewson #include "event2/buffer.h"
68169321c9SNick Mathewson #include "log-internal.h"
697eb250e9SNick Mathewson #include "mm-internal.h"
70e865eb93SNick Mathewson #include "util-internal.h"
71c4e60994SNiels Provos 
725b3fb5bfSNick Mathewson /*
735b3fb5bfSNick Mathewson   Here's our wire format:
745b3fb5bfSNick Mathewson 
755b3fb5bfSNick Mathewson   Stream = TaggedData*
765b3fb5bfSNick Mathewson 
775b3fb5bfSNick Mathewson   TaggedData = Tag Length Data
785b3fb5bfSNick Mathewson        where the integer value of 'Length' is the length of 'data'.
795b3fb5bfSNick Mathewson 
805b3fb5bfSNick Mathewson   Tag = HByte* LByte
815b3fb5bfSNick Mathewson        where HByte is a byte with the high bit set, and LByte is a byte
825b3fb5bfSNick Mathewson        with the high bit clear. The integer value of the tag is taken
835b3fb5bfSNick Mathewson        by concatenating the lower 7 bits from all the tags.  So for example,
845b3fb5bfSNick Mathewson        the tag 0x66 is encoded as [66], whereas the tag 0x166 is encoded as
855b3fb5bfSNick Mathewson        [82 66]
865b3fb5bfSNick Mathewson 
875b3fb5bfSNick Mathewson   Length = Integer
885b3fb5bfSNick Mathewson 
895b3fb5bfSNick Mathewson   Integer = NNibbles Nibble* Padding?
905b3fb5bfSNick Mathewson        where NNibbles is a 4-bit value encoding the number of nibbles-1,
915b3fb5bfSNick Mathewson        and each Nibble is 4 bits worth of encoded integer, in big-endian
925b3fb5bfSNick Mathewson        order.  If the total encoded integer size is an odd number of nibbles,
935b3fb5bfSNick Mathewson        a final padding nibble with value 0 is appended.
945b3fb5bfSNick Mathewson */
955b3fb5bfSNick Mathewson 
96*9806b126SAzat Khuzhin EVENT2_EXPORT_SYMBOL
9711230f7eSNick Mathewson int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
98*9806b126SAzat Khuzhin EVENT2_EXPORT_SYMBOL
99e8400a43SNick Mathewson int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf);
100*9806b126SAzat Khuzhin EVENT2_EXPORT_SYMBOL
10111230f7eSNick Mathewson int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
102*9806b126SAzat Khuzhin EVENT2_EXPORT_SYMBOL
10311230f7eSNick Mathewson int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
104c4e60994SNiels Provos 
105c4e60994SNiels Provos void
evtag_init(void)10635983cd6SNick Mathewson evtag_init(void)
107c4e60994SNiels Provos {
108c4e60994SNiels Provos }
109c4e60994SNiels Provos 
110c4e60994SNiels Provos /*
1118d2a6160SNick Mathewson  * We encode integers by nibbles; the first nibble contains the number
112c4e60994SNiels Provos  * of significant nibbles - 1;  this allows us to encode up to 64-bit
113c4e60994SNiels Provos  * integers.  This function is byte-order independent.
1148d2a6160SNick Mathewson  *
1158d2a6160SNick Mathewson  * @param number a 32-bit unsigned integer to encode
1168d2a6160SNick Mathewson  * @param data a pointer to where the data should be written.  Must
1178d2a6160SNick Mathewson  *    have at least 5 bytes free.
1188d2a6160SNick Mathewson  * @return the number of bytes written into data.
119c4e60994SNiels Provos  */
120c4e60994SNiels Provos 
12199a1063eSNiels Provos #define ENCODE_INT_INTERNAL(data, number) do {				\
12299a1063eSNiels Provos 	int off = 1, nibbles = 0;					\
12399a1063eSNiels Provos 									\
12499a1063eSNiels Provos 	memset(data, 0, sizeof(number)+1);				\
12599a1063eSNiels Provos 	while (number) {						\
12699a1063eSNiels Provos 		if (off & 0x1)						\
12799a1063eSNiels Provos 			data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); \
12899a1063eSNiels Provos 		else							\
12999a1063eSNiels Provos 			data[off/2] = (data[off/2] & 0x0f) |		\
13099a1063eSNiels Provos 			    ((number & 0x0f) << 4);			\
13199a1063eSNiels Provos 		number >>= 4;						\
13299a1063eSNiels Provos 		off++;							\
13399a1063eSNiels Provos 	}								\
13499a1063eSNiels Provos 									\
13599a1063eSNiels Provos 	if (off > 2)							\
13699a1063eSNiels Provos 		nibbles = off - 2;					\
13799a1063eSNiels Provos 									\
13899a1063eSNiels Provos 	/* Off - 1 is the number of encoded nibbles */			\
13999a1063eSNiels Provos 	data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);		\
14099a1063eSNiels Provos 									\
14199a1063eSNiels Provos 	return ((off + 1) / 2);						\
14299a1063eSNiels Provos } while (0)
14399a1063eSNiels Provos 
1445c70ea4cSNiels Provos static inline int
encode_int_internal(ev_uint8_t * data,ev_uint32_t number)1455c70ea4cSNiels Provos encode_int_internal(ev_uint8_t *data, ev_uint32_t number)
146c4e60994SNiels Provos {
14799a1063eSNiels Provos 	ENCODE_INT_INTERNAL(data, number);
148c4e60994SNiels Provos }
149c4e60994SNiels Provos 
15099a1063eSNiels Provos static inline int
encode_int64_internal(ev_uint8_t * data,ev_uint64_t number)15199a1063eSNiels Provos encode_int64_internal(ev_uint8_t *data, ev_uint64_t number)
15299a1063eSNiels Provos {
15399a1063eSNiels Provos 	ENCODE_INT_INTERNAL(data, number);
1545c70ea4cSNiels Provos }
1555c70ea4cSNiels Provos 
1565c70ea4cSNiels Provos void
evtag_encode_int(struct evbuffer * evbuf,ev_uint32_t number)157e8400a43SNick Mathewson evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number)
1585c70ea4cSNiels Provos {
1595c70ea4cSNiels Provos 	ev_uint8_t data[5];
1605c70ea4cSNiels Provos 	int len = encode_int_internal(data, number);
1615c70ea4cSNiels Provos 	evbuffer_add(evbuf, data, len);
162c4e60994SNiels Provos }
163c4e60994SNiels Provos 
16499a1063eSNiels Provos void
evtag_encode_int64(struct evbuffer * evbuf,ev_uint64_t number)165e8400a43SNick Mathewson evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number)
16699a1063eSNiels Provos {
16799a1063eSNiels Provos 	ev_uint8_t data[9];
16899a1063eSNiels Provos 	int len = encode_int64_internal(data, number);
16999a1063eSNiels Provos 	evbuffer_add(evbuf, data, len);
17099a1063eSNiels Provos }
17199a1063eSNiels Provos 
172c4e60994SNiels Provos /*
173ba487199SNiels Provos  * Support variable length encoding of tags; we use the high bit in each
174ba487199SNiels Provos  * octet as a continuation signal.
175ba487199SNiels Provos  */
176ba487199SNiels Provos 
177ba487199SNiels Provos int
evtag_encode_tag(struct evbuffer * evbuf,ev_uint32_t tag)17811230f7eSNick Mathewson evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
179ba487199SNiels Provos {
180ba487199SNiels Provos 	int bytes = 0;
18111230f7eSNick Mathewson 	ev_uint8_t data[5];
182ba487199SNiels Provos 
183ba487199SNiels Provos 	memset(data, 0, sizeof(data));
184ba487199SNiels Provos 	do {
18511230f7eSNick Mathewson 		ev_uint8_t lower = tag & 0x7f;
186ba487199SNiels Provos 		tag >>= 7;
187ba487199SNiels Provos 
188ba487199SNiels Provos 		if (tag)
189ba487199SNiels Provos 			lower |= 0x80;
190ba487199SNiels Provos 
191ba487199SNiels Provos 		data[bytes++] = lower;
192ba487199SNiels Provos 	} while (tag);
193ba487199SNiels Provos 
194ba487199SNiels Provos 	if (evbuf != NULL)
195ba487199SNiels Provos 		evbuffer_add(evbuf, data, bytes);
196ba487199SNiels Provos 
197ba487199SNiels Provos 	return (bytes);
198ba487199SNiels Provos }
199ba487199SNiels Provos 
200ffd606cdSNiels Provos static int
decode_tag_internal(ev_uint32_t * ptag,struct evbuffer * evbuf,int dodrain)20111230f7eSNick Mathewson decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
202ba487199SNiels Provos {
20311230f7eSNick Mathewson 	ev_uint32_t number = 0;
2049c8db0f8SNick Mathewson 	size_t len = evbuffer_get_length(evbuf);
2055c70ea4cSNiels Provos 	ev_uint8_t *data;
2069c8db0f8SNick Mathewson 	size_t count = 0;
2079c8db0f8SNick Mathewson 	int  shift = 0, done = 0;
208ba487199SNiels Provos 
2095c70ea4cSNiels Provos 	/*
2105c70ea4cSNiels Provos 	 * the encoding of a number is at most one byte more than its
2115c70ea4cSNiels Provos 	 * storage size.  however, it may also be much smaller.
2125c70ea4cSNiels Provos 	 */
2135c70ea4cSNiels Provos 	data = evbuffer_pullup(
2145c70ea4cSNiels Provos 		evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1);
21560f8f729SNick Mathewson 	if (!data)
21660f8f729SNick Mathewson 		return (-1);
2175c70ea4cSNiels Provos 
218ba487199SNiels Provos 	while (count++ < len) {
21911230f7eSNick Mathewson 		ev_uint8_t lower = *data++;
22031c49150SNick Mathewson 		if (shift >= 28) {
22131c49150SNick Mathewson 			/* Make sure it fits into 32 bits */
22231c49150SNick Mathewson 			if (shift > 28)
22331c49150SNick Mathewson 				return (-1);
22431c49150SNick Mathewson 			if ((lower & 0x7f) > 15)
22531c49150SNick Mathewson 				return (-1);
22631c49150SNick Mathewson 		}
22731c49150SNick Mathewson 		number |= (lower & (unsigned)0x7f) << shift;
228ba487199SNiels Provos 		shift += 7;
229ba487199SNiels Provos 
230ba487199SNiels Provos 		if (!(lower & 0x80)) {
231ba487199SNiels Provos 			done = 1;
232ba487199SNiels Provos 			break;
233ba487199SNiels Provos 		}
234ba487199SNiels Provos 	}
235ba487199SNiels Provos 
236ba487199SNiels Provos 	if (!done)
237ba487199SNiels Provos 		return (-1);
238ba487199SNiels Provos 
239ba487199SNiels Provos 	if (dodrain)
240ba487199SNiels Provos 		evbuffer_drain(evbuf, count);
241ba487199SNiels Provos 
242ba487199SNiels Provos 	if (ptag != NULL)
243ba487199SNiels Provos 		*ptag = number;
244ba487199SNiels Provos 
2459c8db0f8SNick Mathewson 	return count > INT_MAX ? INT_MAX : (int)(count);
246ba487199SNiels Provos }
247ba487199SNiels Provos 
248ba487199SNiels Provos int
evtag_decode_tag(ev_uint32_t * ptag,struct evbuffer * evbuf)24911230f7eSNick Mathewson evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
250ba487199SNiels Provos {
251ba487199SNiels Provos 	return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
252ba487199SNiels Provos }
253ba487199SNiels Provos 
254ba487199SNiels Provos /*
255c4e60994SNiels Provos  * Marshal a data type, the general format is as follows:
256c4e60994SNiels Provos  *
257c4e60994SNiels Provos  * tag number: one byte; length: var bytes; payload: var bytes
258c4e60994SNiels Provos  */
259c4e60994SNiels Provos 
260c4e60994SNiels Provos void
evtag_marshal(struct evbuffer * evbuf,ev_uint32_t tag,const void * data,ev_uint32_t len)26111230f7eSNick Mathewson evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
26211230f7eSNick Mathewson     const void *data, ev_uint32_t len)
263c4e60994SNiels Provos {
264ffd606cdSNiels Provos 	evtag_encode_tag(evbuf, tag);
265e8400a43SNick Mathewson 	evtag_encode_int(evbuf, len);
266c4e60994SNiels Provos 	evbuffer_add(evbuf, (void *)data, len);
267c4e60994SNiels Provos }
268c4e60994SNiels Provos 
2695c70ea4cSNiels Provos void
evtag_marshal_buffer(struct evbuffer * evbuf,ev_uint32_t tag,struct evbuffer * data)2705c70ea4cSNiels Provos evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
2715c70ea4cSNiels Provos     struct evbuffer *data)
2725c70ea4cSNiels Provos {
2735c70ea4cSNiels Provos 	evtag_encode_tag(evbuf, tag);
274545a6114SNick Mathewson 	/* XXX support more than UINT32_MAX data */
275545a6114SNick Mathewson 	evtag_encode_int(evbuf, (ev_uint32_t)evbuffer_get_length(data));
2765c70ea4cSNiels Provos 	evbuffer_add_buffer(evbuf, data);
2775c70ea4cSNiels Provos }
2785c70ea4cSNiels Provos 
279c4e60994SNiels Provos /* Marshaling for integers */
280c4e60994SNiels Provos void
evtag_marshal_int(struct evbuffer * evbuf,ev_uint32_t tag,ev_uint32_t integer)28111230f7eSNick Mathewson evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
282c4e60994SNiels Provos {
2835c70ea4cSNiels Provos 	ev_uint8_t data[5];
2845c70ea4cSNiels Provos 	int len = encode_int_internal(data, integer);
285c4e60994SNiels Provos 
286ffd606cdSNiels Provos 	evtag_encode_tag(evbuf, tag);
287e8400a43SNick Mathewson 	evtag_encode_int(evbuf, len);
2885c70ea4cSNiels Provos 	evbuffer_add(evbuf, data, len);
289c4e60994SNiels Provos }
290c4e60994SNiels Provos 
291c4e60994SNiels Provos void
evtag_marshal_int64(struct evbuffer * evbuf,ev_uint32_t tag,ev_uint64_t integer)29299a1063eSNiels Provos evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
29399a1063eSNiels Provos     ev_uint64_t integer)
29499a1063eSNiels Provos {
29599a1063eSNiels Provos 	ev_uint8_t data[9];
29699a1063eSNiels Provos 	int len = encode_int64_internal(data, integer);
29799a1063eSNiels Provos 
29899a1063eSNiels Provos 	evtag_encode_tag(evbuf, tag);
299e8400a43SNick Mathewson 	evtag_encode_int(evbuf, len);
30099a1063eSNiels Provos 	evbuffer_add(evbuf, data, len);
30199a1063eSNiels Provos }
30299a1063eSNiels Provos 
30399a1063eSNiels Provos void
evtag_marshal_string(struct evbuffer * buf,ev_uint32_t tag,const char * string)30411230f7eSNick Mathewson evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
305c4e60994SNiels Provos {
306545a6114SNick Mathewson 	/* TODO support strings longer than UINT32_MAX ? */
307545a6114SNick Mathewson 	evtag_marshal(buf, tag, string, (ev_uint32_t)strlen(string));
308c4e60994SNiels Provos }
309c4e60994SNiels Provos 
310c4e60994SNiels Provos void
evtag_marshal_timeval(struct evbuffer * evbuf,ev_uint32_t tag,struct timeval * tv)31111230f7eSNick Mathewson evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
312c4e60994SNiels Provos {
3135c70ea4cSNiels Provos 	ev_uint8_t data[10];
3145c70ea4cSNiels Provos 	int len = encode_int_internal(data, tv->tv_sec);
3155c70ea4cSNiels Provos 	len += encode_int_internal(data + len, tv->tv_usec);
3165c70ea4cSNiels Provos 	evtag_marshal(evbuf, tag, data, len);
317c4e60994SNiels Provos }
318c4e60994SNiels Provos 
31999a1063eSNiels Provos #define DECODE_INT_INTERNAL(number, maxnibbles, pnumber, evbuf, offset) \
32099a1063eSNiels Provos do {									\
32199a1063eSNiels Provos 	ev_uint8_t *data;						\
322545a6114SNick Mathewson 	ev_ssize_t len = evbuffer_get_length(evbuf) - offset;		\
32399a1063eSNiels Provos 	int nibbles = 0;						\
32499a1063eSNiels Provos 									\
32599a1063eSNiels Provos 	if (len <= 0)							\
32699a1063eSNiels Provos 		return (-1);						\
32799a1063eSNiels Provos 									\
32899a1063eSNiels Provos 	/* XXX(niels): faster? */					\
32999a1063eSNiels Provos 	data = evbuffer_pullup(evbuf, offset + 1) + offset;		\
33060f8f729SNick Mathewson 	if (!data)							\
33160f8f729SNick Mathewson 		return (-1);						\
33299a1063eSNiels Provos 									\
33399a1063eSNiels Provos 	nibbles = ((data[0] & 0xf0) >> 4) + 1;				\
33499a1063eSNiels Provos 	if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len)		\
33599a1063eSNiels Provos 		return (-1);						\
33699a1063eSNiels Provos 	len = (nibbles >> 1) + 1;					\
33799a1063eSNiels Provos 									\
33899a1063eSNiels Provos 	data = evbuffer_pullup(evbuf, offset + len) + offset;		\
33960f8f729SNick Mathewson 	if (!data)							\
34060f8f729SNick Mathewson 		return (-1);						\
34199a1063eSNiels Provos 									\
34299a1063eSNiels Provos 	while (nibbles > 0) {						\
34399a1063eSNiels Provos 		number <<= 4;						\
34499a1063eSNiels Provos 		if (nibbles & 0x1)					\
34599a1063eSNiels Provos 			number |= data[nibbles >> 1] & 0x0f;		\
34699a1063eSNiels Provos 		else							\
34799a1063eSNiels Provos 			number |= (data[nibbles >> 1] & 0xf0) >> 4;	\
34899a1063eSNiels Provos 		nibbles--;						\
34999a1063eSNiels Provos 	}								\
35099a1063eSNiels Provos 									\
35199a1063eSNiels Provos 	*pnumber = number;						\
35299a1063eSNiels Provos 									\
353545a6114SNick Mathewson 	return (int)(len);						\
35499a1063eSNiels Provos } while (0)
35599a1063eSNiels Provos 
3568d2a6160SNick Mathewson /* Internal: decode an integer from an evbuffer, without draining it.
3578d2a6160SNick Mathewson  *  Only integers up to 32-bits are supported.
3588d2a6160SNick Mathewson  *
3598d2a6160SNick Mathewson  * @param evbuf the buffer to read from
3608d2a6160SNick Mathewson  * @param offset an index into the buffer at which we should start reading.
3618d2a6160SNick Mathewson  * @param pnumber a pointer to receive the integer.
3628d2a6160SNick Mathewson  * @return The length of the number as encoded, or -1 on error.
3638d2a6160SNick Mathewson  */
36499a1063eSNiels Provos 
365f0ff792aSNiels Provos static int
decode_int_internal(ev_uint32_t * pnumber,struct evbuffer * evbuf,int offset)3665c70ea4cSNiels Provos decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset)
367c4e60994SNiels Provos {
36811230f7eSNick Mathewson 	ev_uint32_t number = 0;
36999a1063eSNiels Provos 	DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset);
370c4e60994SNiels Provos }
371c4e60994SNiels Provos 
37299a1063eSNiels Provos static int
decode_int64_internal(ev_uint64_t * pnumber,struct evbuffer * evbuf,int offset)37399a1063eSNiels Provos decode_int64_internal(ev_uint64_t *pnumber, struct evbuffer *evbuf, int offset)
37499a1063eSNiels Provos {
37599a1063eSNiels Provos 	ev_uint64_t number = 0;
37699a1063eSNiels Provos 	DECODE_INT_INTERNAL(number, 16, pnumber, evbuf, offset);
377c4e60994SNiels Provos }
378c4e60994SNiels Provos 
379c4e60994SNiels Provos int
evtag_decode_int(ev_uint32_t * pnumber,struct evbuffer * evbuf)38011230f7eSNick Mathewson evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
381c4e60994SNiels Provos {
3825c70ea4cSNiels Provos 	int res = decode_int_internal(pnumber, evbuf, 0);
3835c70ea4cSNiels Provos 	if (res != -1)
3845c70ea4cSNiels Provos 		evbuffer_drain(evbuf, res);
3855c70ea4cSNiels Provos 
3865c70ea4cSNiels Provos 	return (res == -1 ? -1 : 0);
387c4e60994SNiels Provos }
388c4e60994SNiels Provos 
389c4e60994SNiels Provos int
evtag_decode_int64(ev_uint64_t * pnumber,struct evbuffer * evbuf)390e8400a43SNick Mathewson evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf)
391e8400a43SNick Mathewson {
392e8400a43SNick Mathewson 	int res = decode_int64_internal(pnumber, evbuf, 0);
393e8400a43SNick Mathewson 	if (res != -1)
394e8400a43SNick Mathewson 		evbuffer_drain(evbuf, res);
395e8400a43SNick Mathewson 
396e8400a43SNick Mathewson 	return (res == -1 ? -1 : 0);
397e8400a43SNick Mathewson }
398e8400a43SNick Mathewson 
399e8400a43SNick Mathewson int
evtag_peek(struct evbuffer * evbuf,ev_uint32_t * ptag)40011230f7eSNick Mathewson evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
401c4e60994SNiels Provos {
402ba487199SNiels Provos 	return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
403c4e60994SNiels Provos }
404c4e60994SNiels Provos 
405c4e60994SNiels Provos int
evtag_peek_length(struct evbuffer * evbuf,ev_uint32_t * plength)40611230f7eSNick Mathewson evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
407c4e60994SNiels Provos {
408ba487199SNiels Provos 	int res, len;
409c4e60994SNiels Provos 
410ba487199SNiels Provos 	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
411ba487199SNiels Provos 	if (len == -1)
412c4e60994SNiels Provos 		return (-1);
413c4e60994SNiels Provos 
4145c70ea4cSNiels Provos 	res = decode_int_internal(plength, evbuf, len);
415c4e60994SNiels Provos 	if (res == -1)
416c4e60994SNiels Provos 		return (-1);
417c4e60994SNiels Provos 
418ba487199SNiels Provos 	*plength += res + len;
419c4e60994SNiels Provos 
420c4e60994SNiels Provos 	return (0);
421c4e60994SNiels Provos }
422c4e60994SNiels Provos 
423c4e60994SNiels Provos int
evtag_payload_length(struct evbuffer * evbuf,ev_uint32_t * plength)42411230f7eSNick Mathewson evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
42532acc283SNiels Provos {
426ba487199SNiels Provos 	int res, len;
42732acc283SNiels Provos 
428ba487199SNiels Provos 	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
429ba487199SNiels Provos 	if (len == -1)
43032acc283SNiels Provos 		return (-1);
43132acc283SNiels Provos 
4325c70ea4cSNiels Provos 	res = decode_int_internal(plength, evbuf, len);
43332acc283SNiels Provos 	if (res == -1)
43432acc283SNiels Provos 		return (-1);
43532acc283SNiels Provos 
43632acc283SNiels Provos 	return (0);
43732acc283SNiels Provos }
43832acc283SNiels Provos 
4395c70ea4cSNiels Provos /* just unmarshals the header and returns the length of the remaining data */
4405c70ea4cSNiels Provos 
4415c70ea4cSNiels Provos int
evtag_unmarshal_header(struct evbuffer * evbuf,ev_uint32_t * ptag)4425c70ea4cSNiels Provos evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag)
4435c70ea4cSNiels Provos {
4445c70ea4cSNiels Provos 	ev_uint32_t len;
4455c70ea4cSNiels Provos 
4465c70ea4cSNiels Provos 	if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1)
4475c70ea4cSNiels Provos 		return (-1);
4485c70ea4cSNiels Provos 	if (evtag_decode_int(&len, evbuf) == -1)
4495c70ea4cSNiels Provos 		return (-1);
4505c70ea4cSNiels Provos 
451a8f6d961SNick Mathewson 	if (evbuffer_get_length(evbuf) < len)
4525c70ea4cSNiels Provos 		return (-1);
4535c70ea4cSNiels Provos 
4545c70ea4cSNiels Provos 	return (len);
4555c70ea4cSNiels Provos }
4565c70ea4cSNiels Provos 
45732acc283SNiels Provos int
evtag_consume(struct evbuffer * evbuf)458c4e60994SNiels Provos evtag_consume(struct evbuffer *evbuf)
459c4e60994SNiels Provos {
4605c70ea4cSNiels Provos 	int len;
4615c70ea4cSNiels Provos 	if ((len = evtag_unmarshal_header(evbuf, NULL)) == -1)
462c4e60994SNiels Provos 		return (-1);
463c4e60994SNiels Provos 	evbuffer_drain(evbuf, len);
464c4e60994SNiels Provos 
465c4e60994SNiels Provos 	return (0);
466c4e60994SNiels Provos }
467c4e60994SNiels Provos 
468c4e60994SNiels Provos /* Reads the data type from an event buffer */
469c4e60994SNiels Provos 
470c4e60994SNiels Provos int
evtag_unmarshal(struct evbuffer * src,ev_uint32_t * ptag,struct evbuffer * dst)47111230f7eSNick Mathewson evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
472c4e60994SNiels Provos {
4735c70ea4cSNiels Provos 	int len;
474c4e60994SNiels Provos 
4755c70ea4cSNiels Provos 	if ((len = evtag_unmarshal_header(src, ptag)) == -1)
476c4e60994SNiels Provos 		return (-1);
477c4e60994SNiels Provos 
4785c70ea4cSNiels Provos 	if (evbuffer_add(dst, evbuffer_pullup(src, len), len) == -1)
479c4e60994SNiels Provos 		return (-1);
480c4e60994SNiels Provos 
481c4e60994SNiels Provos 	evbuffer_drain(src, len);
482c4e60994SNiels Provos 
483c4e60994SNiels Provos 	return (len);
484c4e60994SNiels Provos }
485c4e60994SNiels Provos 
486c4e60994SNiels Provos /* Marshaling for integers */
487c4e60994SNiels Provos 
488c4e60994SNiels Provos int
evtag_unmarshal_int(struct evbuffer * evbuf,ev_uint32_t need_tag,ev_uint32_t * pinteger)48911230f7eSNick Mathewson evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
49011230f7eSNick Mathewson     ev_uint32_t *pinteger)
491c4e60994SNiels Provos {
49211230f7eSNick Mathewson 	ev_uint32_t tag;
49311230f7eSNick Mathewson 	ev_uint32_t len;
4948d2a6160SNick Mathewson 	int result;
495c4e60994SNiels Provos 
496ba487199SNiels Provos 	if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
497ba487199SNiels Provos 		return (-1);
498ba487199SNiels Provos 	if (need_tag != tag)
499c4e60994SNiels Provos 		return (-1);
50099a1063eSNiels Provos 	if (evtag_decode_int(&len, evbuf) == -1)
501c4e60994SNiels Provos 		return (-1);
502c4e60994SNiels Provos 
503a8f6d961SNick Mathewson 	if (evbuffer_get_length(evbuf) < len)
504c4e60994SNiels Provos 		return (-1);
505c4e60994SNiels Provos 
5068d2a6160SNick Mathewson 	result = decode_int_internal(pinteger, evbuf, 0);
507c4e60994SNiels Provos 	evbuffer_drain(evbuf, len);
508e865eb93SNick Mathewson 	if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
5098d2a6160SNick Mathewson 		return (-1);
5108d2a6160SNick Mathewson 	else
5118d2a6160SNick Mathewson 		return result;
512c4e60994SNiels Provos }
513c4e60994SNiels Provos 
51499a1063eSNiels Provos int
evtag_unmarshal_int64(struct evbuffer * evbuf,ev_uint32_t need_tag,ev_uint64_t * pinteger)51599a1063eSNiels Provos evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
51699a1063eSNiels Provos     ev_uint64_t *pinteger)
51799a1063eSNiels Provos {
51899a1063eSNiels Provos 	ev_uint32_t tag;
51999a1063eSNiels Provos 	ev_uint32_t len;
52099a1063eSNiels Provos 	int result;
52199a1063eSNiels Provos 
52299a1063eSNiels Provos 	if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
52399a1063eSNiels Provos 		return (-1);
52499a1063eSNiels Provos 	if (need_tag != tag)
52599a1063eSNiels Provos 		return (-1);
52699a1063eSNiels Provos 	if (evtag_decode_int(&len, evbuf) == -1)
52799a1063eSNiels Provos 		return (-1);
52899a1063eSNiels Provos 
529a8f6d961SNick Mathewson 	if (evbuffer_get_length(evbuf) < len)
53099a1063eSNiels Provos 		return (-1);
53199a1063eSNiels Provos 
53299a1063eSNiels Provos 	result = decode_int64_internal(pinteger, evbuf, 0);
53399a1063eSNiels Provos 	evbuffer_drain(evbuf, len);
534e865eb93SNick Mathewson 	if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
53599a1063eSNiels Provos 		return (-1);
53699a1063eSNiels Provos 	else
53799a1063eSNiels Provos 		return result;
53899a1063eSNiels Provos }
53999a1063eSNiels Provos 
540c4e60994SNiels Provos /* Unmarshal a fixed length tag */
541c4e60994SNiels Provos 
542c4e60994SNiels Provos int
evtag_unmarshal_fixed(struct evbuffer * src,ev_uint32_t need_tag,void * data,size_t len)54311230f7eSNick Mathewson evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
544c4e60994SNiels Provos     size_t len)
545c4e60994SNiels Provos {
54611230f7eSNick Mathewson 	ev_uint32_t tag;
5475c70ea4cSNiels Provos 	int tag_len;
548c4e60994SNiels Provos 
549c4e60994SNiels Provos 	/* Now unmarshal a tag and check that it matches the tag we want */
5509c8db0f8SNick Mathewson 	if ((tag_len = evtag_unmarshal_header(src, &tag)) < 0 ||
5515c70ea4cSNiels Provos 	    tag != need_tag)
552c4e60994SNiels Provos 		return (-1);
553c4e60994SNiels Provos 
5549c8db0f8SNick Mathewson 	if ((size_t)tag_len != len)
555c4e60994SNiels Provos 		return (-1);
556c4e60994SNiels Provos 
5575c70ea4cSNiels Provos 	evbuffer_remove(src, data, len);
558c4e60994SNiels Provos 	return (0);
559c4e60994SNiels Provos }
560c4e60994SNiels Provos 
561c4e60994SNiels Provos int
evtag_unmarshal_string(struct evbuffer * evbuf,ev_uint32_t need_tag,char ** pstring)56211230f7eSNick Mathewson evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
56350f7aaefSNiels Provos     char **pstring)
564c4e60994SNiels Provos {
56511230f7eSNick Mathewson 	ev_uint32_t tag;
5665c70ea4cSNiels Provos 	int tag_len;
567c4e60994SNiels Provos 
5685c70ea4cSNiels Provos 	if ((tag_len = evtag_unmarshal_header(evbuf, &tag)) == -1 ||
5695c70ea4cSNiels Provos 	    tag != need_tag)
570c4e60994SNiels Provos 		return (-1);
571c4e60994SNiels Provos 
57249868b61SNick Mathewson 	*pstring = mm_malloc(tag_len + 1);
573cdf58009SNick Mathewson 	if (*pstring == NULL) {
574cdf58009SNick Mathewson 		event_warn("%s: malloc", __func__);
575cdf58009SNick Mathewson 		return -1;
576cdf58009SNick Mathewson 	}
5775c70ea4cSNiels Provos 	evbuffer_remove(evbuf, *pstring, tag_len);
5785c70ea4cSNiels Provos 	(*pstring)[tag_len] = '\0';
579c4e60994SNiels Provos 
580c4e60994SNiels Provos 	return (0);
581c4e60994SNiels Provos }
582c4e60994SNiels Provos 
583c4e60994SNiels Provos int
evtag_unmarshal_timeval(struct evbuffer * evbuf,ev_uint32_t need_tag,struct timeval * ptv)58411230f7eSNick Mathewson evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
585c4e60994SNiels Provos     struct timeval *ptv)
586c4e60994SNiels Provos {
58711230f7eSNick Mathewson 	ev_uint32_t tag;
58811230f7eSNick Mathewson 	ev_uint32_t integer;
5898d2a6160SNick Mathewson 	int len, offset, offset2;
5908d2a6160SNick Mathewson 	int result = -1;
591c4e60994SNiels Provos 
5928d2a6160SNick Mathewson 	if ((len = evtag_unmarshal_header(evbuf, &tag)) == -1)
593c4e60994SNiels Provos 		return (-1);
5948d2a6160SNick Mathewson 	if (tag != need_tag)
5958d2a6160SNick Mathewson 		goto done;
5968d2a6160SNick Mathewson 	if ((offset = decode_int_internal(&integer, evbuf, 0)) == -1)
5978d2a6160SNick Mathewson 		goto done;
598c4e60994SNiels Provos 	ptv->tv_sec = integer;
5998d2a6160SNick Mathewson 	if ((offset2 = decode_int_internal(&integer, evbuf, offset)) == -1)
6008d2a6160SNick Mathewson 		goto done;
601c4e60994SNiels Provos 	ptv->tv_usec = integer;
6028d2a6160SNick Mathewson 	if (offset + offset2 > len) /* XXX Should this be != instead of > ? */
6038d2a6160SNick Mathewson 		goto done;
604c4e60994SNiels Provos 
6058d2a6160SNick Mathewson 	result = 0;
6068d2a6160SNick Mathewson  done:
6078d2a6160SNick Mathewson 	evbuffer_drain(evbuf, len);
6088d2a6160SNick Mathewson 	return result;
609c4e60994SNiels Provos }
610