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