root/opal/mca/event/libevent2022/libevent/test/regress_rpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. http_setup
  2. MessageCb
  3. EVRPC_STRUCT
  4. rpc_setup
  5. rpc_teardown
  6. rpc_postrequest_failure
  7. rpc_basic_test
  8. rpc_postrequest_done
  9. rpc_basic_message
  10. rpc_pool_with_connection
  11. GotKillCb
  12. GotKillCbTwo
  13. rpc_hook_add_header
  14. rpc_hook_add_meta
  15. rpc_hook_remove_header
  16. rpc_basic_client
  17. rpc_basic_queued_client
  18. GotErrorCb
  19. rpc_hook_pause_cb
  20. rpc_hook_pause
  21. rpc_basic_client_with_pause
  22. rpc_client_timeout
  23. rpc_test

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

/* [<][>][^][v][top][bottom][index][help] */