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