xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/test/regress_rpc.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: regress_rpc.c,v 1.4 2016/01/08 21:35:41 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
5  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* The old tests here need assertions to work. */
31 #undef NDEBUG
32 
33 #ifdef _WIN32
34 #include <winsock2.h>
35 #include <windows.h>
36 #endif
37 
38 #include "event2/event-config.h"
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef EVENT__HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 #include <sys/queue.h>
46 #ifndef _WIN32
47 #include <sys/socket.h>
48 #include <signal.h>
49 #include <unistd.h>
50 #include <netdb.h>
51 #endif
52 #include <fcntl.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <assert.h>
58 
59 #include "event2/buffer.h"
60 #include "event2/event.h"
61 #include "event2/event_compat.h"
62 #include "event2/http.h"
63 #include "event2/http_compat.h"
64 #include "event2/http_struct.h"
65 #include "event2/rpc.h"
66 #include "event2/rpc.h"
67 #include "event2/rpc_struct.h"
68 #include "event2/tag.h"
69 #include "log-internal.h"
70 
71 #include "regress.gen.h"
72 
73 #include "regress.h"
74 #include "regress_testutils.h"
75 
76 #ifndef NO_PYTHON_EXISTS
77 
78 static struct evhttp *
79 http_setup(ev_uint16_t *pport)
80 {
81 	struct evhttp *myhttp;
82 	ev_uint16_t port;
83 	struct evhttp_bound_socket *sock;
84 
85 	myhttp = evhttp_new(NULL);
86 	if (!myhttp)
87 		event_errx(1, "Could not start web server");
88 
89 	/* Try a few different ports */
90 	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", 0);
91 	if (!sock)
92 		event_errx(1, "Couldn't open web port");
93 
94 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
95 
96 	*pport = port;
97 	return (myhttp);
98 }
99 
100 EVRPC_HEADER(Message, msg, kill)
101 EVRPC_HEADER(NeverReply, msg, kill)
102 
103 EVRPC_GENERATE(Message, msg, kill)
104 EVRPC_GENERATE(NeverReply, msg, kill)
105 
106 static int need_input_hook = 0;
107 static int need_output_hook = 0;
108 
109 static void
110 MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
111 {
112 	struct kill* kill_reply = rpc->reply;
113 
114 	if (need_input_hook) {
115 		struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
116 		const char *header = evhttp_find_header(
117 			req->input_headers, "X-Hook");
118 		assert(header);
119 		assert(strcmp(header, "input") == 0);
120 	}
121 
122 	/* we just want to fill in some non-sense */
123 	EVTAG_ASSIGN(kill_reply, weapon, "dagger");
124 	EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
125 
126 	/* no reply to the RPC */
127 	EVRPC_REQUEST_DONE(rpc);
128 }
129 
130 static EVRPC_STRUCT(NeverReply) *saved_rpc;
131 
132 static void
133 NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
134 {
135 	test_ok += 1;
136 	saved_rpc = rpc;
137 }
138 
139 static void
140 rpc_setup(struct evhttp **phttp, ev_uint16_t *pport, struct evrpc_base **pbase)
141 {
142 	ev_uint16_t port;
143 	struct evhttp *http = NULL;
144 	struct evrpc_base *base = NULL;
145 
146 	http = http_setup(&port);
147 	base = evrpc_init(http);
148 
149 	EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
150 	EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
151 
152 	*phttp = http;
153 	*pport = port;
154 	*pbase = base;
155 
156 	need_input_hook = 0;
157 	need_output_hook = 0;
158 }
159 
160 static void
161 rpc_teardown(struct evrpc_base *base)
162 {
163 	assert(EVRPC_UNREGISTER(base, Message) == 0);
164 	assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
165 
166 	evrpc_free(base);
167 }
168 
169 static void
170 rpc_postrequest_failure(struct evhttp_request *req, void *arg)
171 {
172 	if (req->response_code != HTTP_SERVUNAVAIL) {
173 
174 		fprintf(stderr, "FAILED (response code)\n");
175 		exit(1);
176 	}
177 
178 	test_ok = 1;
179 	event_loopexit(NULL);
180 }
181 
182 /*
183  * Test a malformed payload submitted as an RPC
184  */
185 
186 static void
187 rpc_basic_test(void)
188 {
189 	ev_uint16_t port;
190 	struct evhttp *http = NULL;
191 	struct evrpc_base *base = NULL;
192 	struct evhttp_connection *evcon = NULL;
193 	struct evhttp_request *req = NULL;
194 
195 	rpc_setup(&http, &port, &base);
196 
197 	evcon = evhttp_connection_new("127.0.0.1", port);
198 	tt_assert(evcon);
199 
200 	/*
201 	 * At this point, we want to schedule an HTTP POST request
202 	 * server using our make request method.
203 	 */
204 
205 	req = evhttp_request_new(rpc_postrequest_failure, NULL);
206 	tt_assert(req);
207 
208 	/* Add the information that we care about */
209 	evhttp_add_header(req->output_headers, "Host", "somehost");
210 	evbuffer_add_printf(req->output_buffer, "Some Nonsense");
211 
212 	if (evhttp_make_request(evcon, req,
213 		EVHTTP_REQ_POST,
214 		"/.rpc.Message") == -1) {
215 		tt_abort();
216 	}
217 
218 	test_ok = 0;
219 
220 	event_dispatch();
221 
222 	evhttp_connection_free(evcon);
223 
224 	rpc_teardown(base);
225 
226 	tt_assert(test_ok == 1);
227 
228 end:
229 	evhttp_free(http);
230 }
231 
232 static void
233 rpc_postrequest_done(struct evhttp_request *req, void *arg)
234 {
235 	struct kill* kill_reply = NULL;
236 
237 	if (req->response_code != HTTP_OK) {
238 		fprintf(stderr, "FAILED (response code)\n");
239 		exit(1);
240 	}
241 
242 	kill_reply = kill_new();
243 
244 	if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
245 		fprintf(stderr, "FAILED (unmarshal)\n");
246 		exit(1);
247 	}
248 
249 	kill_free(kill_reply);
250 
251 	test_ok = 1;
252 	event_loopexit(NULL);
253 }
254 
255 static void
256 rpc_basic_message(void)
257 {
258 	ev_uint16_t port;
259 	struct evhttp *http = NULL;
260 	struct evrpc_base *base = NULL;
261 	struct evhttp_connection *evcon = NULL;
262 	struct evhttp_request *req = NULL;
263 	struct msg *msg;
264 
265 	rpc_setup(&http, &port, &base);
266 
267 	evcon = evhttp_connection_new("127.0.0.1", port);
268 	tt_assert(evcon);
269 
270 	/*
271 	 * At this point, we want to schedule an HTTP POST request
272 	 * server using our make request method.
273 	 */
274 
275 	req = evhttp_request_new(rpc_postrequest_done, NULL);
276 	if (req == NULL) {
277 		fprintf(stdout, "FAILED\n");
278 		exit(1);
279 	}
280 
281 	/* Add the information that we care about */
282 	evhttp_add_header(req->output_headers, "Host", "somehost");
283 
284 	/* set up the basic message */
285 	msg = msg_new();
286 	EVTAG_ASSIGN(msg, from_name, "niels");
287 	EVTAG_ASSIGN(msg, to_name, "tester");
288 	msg_marshal(req->output_buffer, msg);
289 	msg_free(msg);
290 
291 	if (evhttp_make_request(evcon, req,
292 		EVHTTP_REQ_POST,
293 		"/.rpc.Message") == -1) {
294 		fprintf(stdout, "FAILED\n");
295 		exit(1);
296 	}
297 
298 	test_ok = 0;
299 
300 	event_dispatch();
301 
302 	evhttp_connection_free(evcon);
303 
304 	rpc_teardown(base);
305 
306 end:
307 	evhttp_free(http);
308 }
309 
310 static struct evrpc_pool *
311 rpc_pool_with_connection(ev_uint16_t port)
312 {
313 	struct evhttp_connection *evcon;
314 	struct evrpc_pool *pool;
315 
316 	pool = evrpc_pool_new(NULL);
317 	assert(pool != NULL);
318 
319 	evcon = evhttp_connection_new("127.0.0.1", port);
320 	assert(evcon != NULL);
321 
322 	evrpc_pool_add_connection(pool, evcon);
323 
324 	return (pool);
325 }
326 
327 static void
328 GotKillCb(struct evrpc_status *status,
329     struct msg *msg, struct kill *kill, void *arg)
330 {
331 	char *weapon;
332 	char *action;
333 
334 	if (need_output_hook) {
335 		struct evhttp_request *req = status->http_req;
336 		const char *header = evhttp_find_header(
337 			req->input_headers, "X-Pool-Hook");
338 		assert(header);
339 		assert(strcmp(header, "ran") == 0);
340 	}
341 
342 	if (status->error != EVRPC_STATUS_ERR_NONE)
343 		goto done;
344 
345 	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
346 		fprintf(stderr, "get weapon\n");
347 		goto done;
348 	}
349 	if (EVTAG_GET(kill, action, &action) == -1) {
350 		fprintf(stderr, "get action\n");
351 		goto done;
352 	}
353 
354 	if (strcmp(weapon, "dagger"))
355 		goto done;
356 
357 	if (strcmp(action, "wave around like an idiot"))
358 		goto done;
359 
360 	test_ok += 1;
361 
362 done:
363 	event_loopexit(NULL);
364 }
365 
366 static void
367 GotKillCbTwo(struct evrpc_status *status,
368     struct msg *msg, struct kill *kill, void *arg)
369 {
370 	char *weapon;
371 	char *action;
372 
373 	if (status->error != EVRPC_STATUS_ERR_NONE)
374 		goto done;
375 
376 	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
377 		fprintf(stderr, "get weapon\n");
378 		goto done;
379 	}
380 	if (EVTAG_GET(kill, action, &action) == -1) {
381 		fprintf(stderr, "get action\n");
382 		goto done;
383 	}
384 
385 	if (strcmp(weapon, "dagger"))
386 		goto done;
387 
388 	if (strcmp(action, "wave around like an idiot"))
389 		goto done;
390 
391 	test_ok += 1;
392 
393 done:
394 	if (test_ok == 2)
395 		event_loopexit(NULL);
396 }
397 
398 static int
399 rpc_hook_add_header(void *ctx, struct evhttp_request *req,
400     struct evbuffer *evbuf, void *arg)
401 {
402 	const char *hook_type = arg;
403 	if (strcmp("input", hook_type) == 0)
404 		evhttp_add_header(req->input_headers, "X-Hook", hook_type);
405 	else
406 		evhttp_add_header(req->output_headers, "X-Hook", hook_type);
407 
408 	assert(evrpc_hook_get_connection(ctx) != NULL);
409 
410 	return (EVRPC_CONTINUE);
411 }
412 
413 static int
414 rpc_hook_add_meta(void *ctx, struct evhttp_request *req,
415     struct evbuffer *evbuf, void *arg)
416 {
417 	evrpc_hook_add_meta(ctx, "meta", "test", 5);
418 
419 	assert(evrpc_hook_get_connection(ctx) != NULL);
420 
421 	return (EVRPC_CONTINUE);
422 }
423 
424 static int
425 rpc_hook_remove_header(void *ctx, struct evhttp_request *req,
426     struct evbuffer *evbuf, void *arg)
427 {
428 	const char *header = evhttp_find_header(req->input_headers, "X-Hook");
429 	void *data = NULL;
430 	size_t data_len = 0;
431 
432 	assert(header != NULL);
433 	assert(strcmp(header, arg) == 0);
434 
435 	evhttp_remove_header(req->input_headers, "X-Hook");
436 	evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
437 
438 	assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0);
439 	assert(data != NULL);
440 	assert(data_len == 5);
441 
442 	assert(evrpc_hook_get_connection(ctx) != NULL);
443 
444 	return (EVRPC_CONTINUE);
445 }
446 
447 static void
448 rpc_basic_client(void)
449 {
450 	ev_uint16_t port;
451 	struct evhttp *http = NULL;
452 	struct evrpc_base *base = NULL;
453 	struct evrpc_pool *pool = NULL;
454 	struct msg *msg = NULL;
455 	struct kill *kill = NULL;
456 
457 	rpc_setup(&http, &port, &base);
458 
459 	need_input_hook = 1;
460 	need_output_hook = 1;
461 
462 	assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
463 	    != NULL);
464 	assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
465 	    != NULL);
466 
467 	pool = rpc_pool_with_connection(port);
468 	tt_assert(pool);
469 
470 	assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
471 	assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
472 
473 	/* set up the basic message */
474 	msg = msg_new();
475 	tt_assert(msg);
476 	EVTAG_ASSIGN(msg, from_name, "niels");
477 	EVTAG_ASSIGN(msg, to_name, "tester");
478 
479 	kill = kill_new();
480 
481 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
482 
483 	test_ok = 0;
484 
485 	event_dispatch();
486 
487 	tt_assert(test_ok == 1);
488 
489 	/* we do it twice to make sure that reuse works correctly */
490 	kill_clear(kill);
491 
492 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
493 
494 	event_dispatch();
495 
496 	tt_assert(test_ok == 2);
497 
498 	/* we do it trice to make sure other stuff works, too */
499 	kill_clear(kill);
500 
501 	{
502 		struct evrpc_request_wrapper *ctx =
503 		    EVRPC_MAKE_CTX(Message, msg, kill,
504 			pool, msg, kill, GotKillCb, NULL);
505 		evrpc_make_request(ctx);
506 	}
507 
508 	event_dispatch();
509 
510 	rpc_teardown(base);
511 
512 	tt_assert(test_ok == 3);
513 
514 end:
515 	if (msg)
516 		msg_free(msg);
517 	if (kill)
518 		kill_free(kill);
519 
520 	if (pool)
521 		evrpc_pool_free(pool);
522 	if (http)
523 		evhttp_free(http);
524 
525 	need_input_hook = 0;
526 	need_output_hook = 0;
527 }
528 
529 /*
530  * We are testing that the second requests gets send over the same
531  * connection after the first RPCs completes.
532  */
533 static void
534 rpc_basic_queued_client(void)
535 {
536 	ev_uint16_t port;
537 	struct evhttp *http = NULL;
538 	struct evrpc_base *base = NULL;
539 	struct evrpc_pool *pool = NULL;
540 	struct msg *msg=NULL;
541 	struct kill *kill_one=NULL, *kill_two=NULL;
542 
543 	rpc_setup(&http, &port, &base);
544 
545 	pool = rpc_pool_with_connection(port);
546 	tt_assert(pool);
547 
548 	/* set up the basic message */
549 	msg = msg_new();
550 	tt_assert(msg);
551 	EVTAG_ASSIGN(msg, from_name, "niels");
552 	EVTAG_ASSIGN(msg, to_name, "tester");
553 
554 	kill_one = kill_new();
555 	kill_two = kill_new();
556 
557 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one,  GotKillCbTwo, NULL);
558 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two,  GotKillCb, NULL);
559 
560 	test_ok = 0;
561 
562 	event_dispatch();
563 
564 	rpc_teardown(base);
565 
566 	tt_assert(test_ok == 2);
567 
568 end:
569 	if (msg)
570 		msg_free(msg);
571 	if (kill_one)
572 		kill_free(kill_one);
573 	if (kill_two)
574 		kill_free(kill_two);
575 
576 	if (pool)
577 		evrpc_pool_free(pool);
578 	if (http)
579 		evhttp_free(http);
580 }
581 
582 static void
583 GotErrorCb(struct evrpc_status *status,
584     struct msg *msg, struct kill *kill, void *arg)
585 {
586 	if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
587 		goto done;
588 
589 	/* should never be complete but just to check */
590 	if (kill_complete(kill) == 0)
591 		goto done;
592 
593 	test_ok += 1;
594 
595 done:
596 	event_loopexit(NULL);
597 }
598 
599 /* we just pause the rpc and continue it in the next callback */
600 
601 struct rpc_hook_ctx_ {
602 	void *vbase;
603 	void *ctx;
604 };
605 
606 static int hook_pause_cb_called=0;
607 
608 static void
609 rpc_hook_pause_cb(evutil_socket_t fd, short what, void *arg)
610 {
611 	struct rpc_hook_ctx_ *ctx = arg;
612 	++hook_pause_cb_called;
613 	evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
614 	free(arg);
615 }
616 
617 static int
618 rpc_hook_pause(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf,
619     void *arg)
620 {
621 	struct rpc_hook_ctx_ *tmp = malloc(sizeof(*tmp));
622 	struct timeval tv;
623 
624 	assert(tmp != NULL);
625 	tmp->vbase = arg;
626 	tmp->ctx = ctx;
627 
628 	memset(&tv, 0, sizeof(tv));
629 	event_once(-1, EV_TIMEOUT, rpc_hook_pause_cb, tmp, &tv);
630 	return EVRPC_PAUSE;
631 }
632 
633 static void
634 rpc_basic_client_with_pause(void)
635 {
636 	ev_uint16_t port;
637 	struct evhttp *http = NULL;
638 	struct evrpc_base *base = NULL;
639 	struct evrpc_pool *pool = NULL;
640 	struct msg *msg = NULL;
641 	struct kill *kill= NULL;
642 
643 	rpc_setup(&http, &port, &base);
644 
645 	assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_pause, base));
646 	assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
647 
648 	pool = rpc_pool_with_connection(port);
649 	tt_assert(pool);
650 	assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
651 	assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
652 
653 	/* set up the basic message */
654 	msg = msg_new();
655 	tt_assert(msg);
656 	EVTAG_ASSIGN(msg, from_name, "niels");
657 	EVTAG_ASSIGN(msg, to_name, "tester");
658 
659 	kill = kill_new();
660 
661 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
662 
663 	test_ok = 0;
664 
665 	event_dispatch();
666 
667 	tt_int_op(test_ok, ==, 1);
668 	tt_int_op(hook_pause_cb_called, ==, 4);
669 
670 end:
671 	if (base)
672 		rpc_teardown(base);
673 
674 	if (msg)
675 		msg_free(msg);
676 	if (kill)
677 		kill_free(kill);
678 
679 	if (pool)
680 		evrpc_pool_free(pool);
681 	if (http)
682 		evhttp_free(http);
683 }
684 
685 static void
686 rpc_client_timeout(void)
687 {
688 	ev_uint16_t port;
689 	struct evhttp *http = NULL;
690 	struct evrpc_base *base = NULL;
691 	struct evrpc_pool *pool = NULL;
692 	struct msg *msg = NULL;
693 	struct kill *kill = NULL;
694 
695 	rpc_setup(&http, &port, &base);
696 
697 	pool = rpc_pool_with_connection(port);
698 	tt_assert(pool);
699 
700 	/* set the timeout to 1 second. */
701 	evrpc_pool_set_timeout(pool, 1);
702 
703 	/* set up the basic message */
704 	msg = msg_new();
705 	tt_assert(msg);
706 	EVTAG_ASSIGN(msg, from_name, "niels");
707 	EVTAG_ASSIGN(msg, to_name, "tester");
708 
709 	kill = kill_new();
710 
711 	EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
712 
713 	test_ok = 0;
714 
715 	event_dispatch();
716 
717 	/* free the saved RPC structure up */
718 	EVRPC_REQUEST_DONE(saved_rpc);
719 
720 	rpc_teardown(base);
721 
722 	tt_assert(test_ok == 2);
723 
724 end:
725 	if (msg)
726 		msg_free(msg);
727 	if (kill)
728 		kill_free(kill);
729 
730 	if (pool)
731 		evrpc_pool_free(pool);
732 	if (http)
733 		evhttp_free(http);
734 }
735 
736 static void
737 rpc_test(void)
738 {
739 	struct msg *msg = NULL, *msg2 = NULL;
740 	struct kill *attack = NULL;
741 	struct run *run = NULL;
742 	struct evbuffer *tmp = evbuffer_new();
743 	struct timeval tv_start, tv_end;
744 	ev_uint32_t tag;
745 	int i;
746 
747 	msg = msg_new();
748 
749 	tt_assert(msg);
750 
751 	EVTAG_ASSIGN(msg, from_name, "niels");
752 	EVTAG_ASSIGN(msg, to_name, "phoenix");
753 
754 	if (EVTAG_GET(msg, attack, &attack) == -1) {
755 		tt_abort_msg("Failed to set kill message.");
756 	}
757 
758 	EVTAG_ASSIGN(attack, weapon, "feather");
759 	EVTAG_ASSIGN(attack, action, "tickle");
760 	for (i = 0; i < 3; ++i) {
761 		if (EVTAG_ARRAY_ADD_VALUE(attack, how_often, i) == NULL) {
762 			tt_abort_msg("Failed to add how_often.");
763 		}
764 	}
765 
766 	evutil_gettimeofday(&tv_start, NULL);
767 	for (i = 0; i < 1000; ++i) {
768 		run = EVTAG_ARRAY_ADD(msg, run);
769 		if (run == NULL) {
770 			tt_abort_msg("Failed to add run message.");
771 		}
772 		EVTAG_ASSIGN(run, how, "very fast but with some data in it");
773 		EVTAG_ASSIGN(run, fixed_bytes,
774 		    (ev_uint8_t*)"012345678901234567890123");
775 
776 		if (EVTAG_ARRAY_ADD_VALUE(
777 			    run, notes, "this is my note") == NULL) {
778 			tt_abort_msg("Failed to add note.");
779 		}
780 		if (EVTAG_ARRAY_ADD_VALUE(run, notes, "pps") == NULL) {
781 			tt_abort_msg("Failed to add note");
782 		}
783 
784 		EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL);
785 		EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xdead0a0b);
786 		EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xbeefcafe);
787 	}
788 
789 	if (msg_complete(msg) == -1)
790 		tt_abort_msg("Failed to make complete message.");
791 
792 	evtag_marshal_msg(tmp, 0xdeaf, msg);
793 
794 	if (evtag_peek(tmp, &tag) == -1)
795 		tt_abort_msg("Failed to peak tag.");
796 
797 	if (tag != 0xdeaf)
798 		TT_DIE(("Got incorrect tag: %0x.", (unsigned)tag));
799 
800 	msg2 = msg_new();
801 	if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1)
802 		tt_abort_msg("Failed to unmarshal message.");
803 
804 	evutil_gettimeofday(&tv_end, NULL);
805 	evutil_timersub(&tv_end, &tv_start, &tv_end);
806 	TT_BLATHER(("(%.1f us/add) ",
807 		(float)tv_end.tv_sec/(float)i * 1000000.0 +
808 		tv_end.tv_usec / (float)i));
809 
810 	if (!EVTAG_HAS(msg2, from_name) ||
811 	    !EVTAG_HAS(msg2, to_name) ||
812 	    !EVTAG_HAS(msg2, attack)) {
813 		tt_abort_msg("Missing data structures.");
814 	}
815 
816 	if (EVTAG_GET(msg2, attack, &attack) == -1) {
817 		tt_abort_msg("Could not get attack.");
818 	}
819 
820 	if (EVTAG_ARRAY_LEN(msg2, run) != i) {
821 		tt_abort_msg("Wrong number of run messages.");
822 	}
823 
824 	/* get the very first run message */
825 	if (EVTAG_ARRAY_GET(msg2, run, 0, &run) == -1) {
826 		tt_abort_msg("Failed to get run msg.");
827 	} else {
828 		/* verify the notes */
829 		char *note_one, *note_two;
830 		ev_uint64_t large_number;
831 		ev_uint32_t short_number;
832 
833 		if (EVTAG_ARRAY_LEN(run, notes) != 2) {
834 			tt_abort_msg("Wrong number of note strings.");
835 		}
836 
837 		if (EVTAG_ARRAY_GET(run, notes, 0, &note_one) == -1 ||
838 		    EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
839 			tt_abort_msg("Could not get note strings.");
840 		}
841 
842 		if (strcmp(note_one, "this is my note") ||
843 		    strcmp(note_two, "pps")) {
844 			tt_abort_msg("Incorrect note strings encoded.");
845 		}
846 
847 		if (EVTAG_GET(run, large_number, &large_number) == -1 ||
848 		    large_number != 0xdead0a0bcafebeefLL) {
849 			tt_abort_msg("Incorrrect large_number.");
850 		}
851 
852 		if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
853 			tt_abort_msg("Wrong number of other_numbers.");
854 		}
855 
856 		if (EVTAG_ARRAY_GET(
857 			    run, other_numbers, 0, &short_number) == -1) {
858 			tt_abort_msg("Could not get short number.");
859 		}
860 		tt_uint_op(short_number, ==, 0xdead0a0b);
861 
862 	}
863 	tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
864 
865 	for (i = 0; i < 3; ++i) {
866 		ev_uint32_t res;
867 		if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
868 			TT_DIE(("Cannot get %dth how_often msg.", i));
869 		}
870 		if ((int)res != i) {
871 			TT_DIE(("Wrong message encoded %d != %d", i, res));
872 		}
873 	}
874 
875 	test_ok = 1;
876 end:
877 	if (msg)
878 		msg_free(msg);
879 	if (msg2)
880 		msg_free(msg2);
881 	if (tmp)
882 		evbuffer_free(tmp);
883 }
884 
885 #define RPC_LEGACY(name)						\
886 	{ #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY,	\
887 		    &legacy_setup,					\
888 		    rpc_##name }
889 #else
890 /* NO_PYTHON_EXISTS */
891 
892 #define RPC_LEGACY(name) \
893 	{ #name, NULL, TT_SKIP, NULL, NULL }
894 
895 #endif
896 
897 struct testcase_t rpc_testcases[] = {
898 	RPC_LEGACY(basic_test),
899 	RPC_LEGACY(basic_message),
900 	RPC_LEGACY(basic_client),
901 	RPC_LEGACY(basic_queued_client),
902 	RPC_LEGACY(basic_client_with_pause),
903 	RPC_LEGACY(client_timeout),
904 	RPC_LEGACY(test),
905 
906 	END_OF_TESTCASES,
907 };
908