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
75 static struct evhttp *
http_setup(ev_uint16_t * pport)76 http_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
97 EVRPC_HEADER(Message, msg, kill)
98 EVRPC_HEADER(NeverReply, msg, kill)
99
100 EVRPC_GENERATE(Message, msg, kill)
101 EVRPC_GENERATE(NeverReply, msg, kill)
102
103 static int need_input_hook = 0;
104 static int need_output_hook = 0;
105
106 static void
MessageCb(EVRPC_STRUCT (Message)* rpc,void * arg)107 MessageCb(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
EVRPC_STRUCT(NeverReply)127 static EVRPC_STRUCT(NeverReply) *saved_rpc;
128
129 static void
130 NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
131 {
132 test_ok += 1;
133 saved_rpc = rpc;
134 }
135
136 static void
rpc_setup(struct evhttp ** phttp,ev_uint16_t * pport,struct evrpc_base ** pbase)137 rpc_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
157 static void
rpc_teardown(struct evrpc_base * base)158 rpc_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
166 static void
rpc_postrequest_failure(struct evhttp_request * req,void * arg)167 rpc_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
183 static void
rpc_basic_test(void)184 rpc_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
225 end:
226 evhttp_free(http);
227 }
228
229 static void
rpc_postrequest_done(struct evhttp_request * req,void * arg)230 rpc_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
252 static void
rpc_basic_message(void)253 rpc_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
303 end:
304 evhttp_free(http);
305 }
306
307 static struct evrpc_pool *
rpc_pool_with_connection(ev_uint16_t port)308 rpc_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
324 static void
GotKillCb(struct evrpc_status * status,struct msg * msg,struct kill * kill,void * arg)325 GotKillCb(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
359 done:
360 event_loopexit(NULL);
361 }
362
363 static void
GotKillCbTwo(struct evrpc_status * status,struct msg * msg,struct kill * kill,void * arg)364 GotKillCbTwo(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
390 done:
391 if (test_ok == 2)
392 event_loopexit(NULL);
393 }
394
395 static int
rpc_hook_add_header(void * ctx,struct evhttp_request * req,struct evbuffer * evbuf,void * arg)396 rpc_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
410 static int
rpc_hook_add_meta(void * ctx,struct evhttp_request * req,struct evbuffer * evbuf,void * arg)411 rpc_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
421 static int
rpc_hook_remove_header(void * ctx,struct evhttp_request * req,struct evbuffer * evbuf,void * arg)422 rpc_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
444 static void
rpc_basic_client(void)445 rpc_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
511 end:
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 */
530 static void
rpc_basic_queued_client(void)531 rpc_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
565 end:
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
579 static void
GotErrorCb(struct evrpc_status * status,struct msg * msg,struct kill * kill,void * arg)580 GotErrorCb(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
592 done:
593 event_loopexit(NULL);
594 }
595
596 /* we just pause the rpc and continue it in the next callback */
597
598 struct rpc_hook_ctx_ {
599 void *vbase;
600 void *ctx;
601 };
602
603 static int hook_pause_cb_called=0;
604
605 static void
rpc_hook_pause_cb(evutil_socket_t fd,short what,void * arg)606 rpc_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
614 static int
rpc_hook_pause(void * ctx,struct evhttp_request * req,struct evbuffer * evbuf,void * arg)615 rpc_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
630 static void
rpc_basic_client_with_pause(void)631 rpc_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
667 end:
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
682 static void
rpc_client_timeout(void)683 rpc_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
721 end:
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
733 static void
rpc_test(void)734 rpc_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, ¬e_one) == -1 ||
835 EVTAG_ARRAY_GET(run, notes, 1, ¬e_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;
873 end:
874 if (msg)
875 msg_free(msg);
876 if (msg2)
877 msg_free(msg2);
878 if (tmp)
879 evbuffer_free(tmp);
880 }
881
882 static void
rpc_invalid_type(void)883 rpc_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
924 end:
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
941 struct 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