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