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