tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

regress_rpc.c (20957B)


      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 *
     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
    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 
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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, &note_one) == -1 ||
    835 	    EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
    836 		tt_abort_msg("Could not get note strings.");
    837 	}
    838 
    839 	if (strcmp(note_one, "this is my note") ||
    840 	    strcmp(note_two, "pps")) {
    841 		tt_abort_msg("Incorrect note strings encoded.");
    842 	}
    843 
    844 	if (EVTAG_GET(run, large_number, &large_number) == -1 ||
    845 	    large_number != 0xdead0a0bcafebeefLL) {
    846 		tt_abort_msg("Incorrrect large_number.");
    847 	}
    848 
    849 	if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
    850 		tt_abort_msg("Wrong number of other_numbers.");
    851 	}
    852 
    853 	if (EVTAG_ARRAY_GET(
    854 		    run, other_numbers, 0, &short_number) == -1) {
    855 		tt_abort_msg("Could not get short number.");
    856 	}
    857 	tt_uint_op(short_number, ==, 0xdead0a0b);
    858 
    859 }
    860 tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
    861 
    862 for (i = 0; i < 3; ++i) {
    863 	ev_uint32_t res;
    864 	if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
    865 		TT_DIE(("Cannot get %dth how_often msg.", i));
    866 	}
    867 	if ((int)res != i) {
    868 		TT_DIE(("Wrong message encoded %d != %d", i, res));
    869 	}
    870 }
    871 
    872 test_ok = 1;
    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
    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 };