2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
37 #include <sys/types.h>
39 #ifdef HAVE_SYS_TIME_H
42 #include <sys/queue.h>
44 #include <sys/socket.h>
61 #include "regress.gen.h"
67 static struct evhttp
*
68 http_setup(short *pport
)
71 struct evhttp
*myhttp
;
74 /* Try a few different ports */
75 for (i
= 0; i
< 50; ++i
) {
76 myhttp
= evhttp_start("127.0.0.1", 8080 + i
);
84 event_errx(1, "Could not start web server");
90 EVRPC_HEADER(Message
, msg
, kill
);
91 EVRPC_HEADER(NeverReply
, msg
, kill
);
93 EVRPC_GENERATE(Message
, msg
, kill
);
94 EVRPC_GENERATE(NeverReply
, msg
, kill
);
96 static int need_input_hook
= 0;
97 static int need_output_hook
= 0;
100 MessageCb(EVRPC_STRUCT(Message
)* rpc
, void *arg
)
102 struct kill
* kill_reply
= rpc
->reply
;
104 if (need_input_hook
) {
105 struct evhttp_request
* req
= EVRPC_REQUEST_HTTP(rpc
);
106 const char *header
= evhttp_find_header(
107 req
->input_headers
, "X-Hook");
108 assert(strcmp(header
, "input") == 0);
111 /* we just want to fill in some non-sense */
112 EVTAG_ASSIGN(kill_reply
, weapon
, "dagger");
113 EVTAG_ASSIGN(kill_reply
, action
, "wave around like an idiot");
115 /* no reply to the RPC */
116 EVRPC_REQUEST_DONE(rpc
);
119 static EVRPC_STRUCT(NeverReply
) *saved_rpc
;
122 NeverReplyCb(EVRPC_STRUCT(NeverReply
)* rpc
, void *arg
)
129 rpc_setup(struct evhttp
**phttp
, short *pport
, struct evrpc_base
**pbase
)
132 struct evhttp
*http
= NULL
;
133 struct evrpc_base
*base
= NULL
;
135 http
= http_setup(&port
);
136 base
= evrpc_init(http
);
138 EVRPC_REGISTER(base
, Message
, msg
, kill
, MessageCb
, NULL
);
139 EVRPC_REGISTER(base
, NeverReply
, msg
, kill
, NeverReplyCb
, NULL
);
146 need_output_hook
= 0;
150 rpc_teardown(struct evrpc_base
*base
)
152 assert(EVRPC_UNREGISTER(base
, Message
) == 0);
153 assert(EVRPC_UNREGISTER(base
, NeverReply
) == 0);
159 rpc_postrequest_failure(struct evhttp_request
*req
, void *arg
)
161 if (req
->response_code
!= HTTP_SERVUNAVAIL
) {
163 fprintf(stderr
, "FAILED (response code)\n");
168 event_loopexit(NULL
);
172 * Test a malformed payload submitted as an RPC
179 struct evhttp
*http
= NULL
;
180 struct evrpc_base
*base
= NULL
;
181 struct evhttp_connection
*evcon
= NULL
;
182 struct evhttp_request
*req
= NULL
;
184 fprintf(stdout
, "Testing Basic RPC Support: ");
186 rpc_setup(&http
, &port
, &base
);
188 evcon
= evhttp_connection_new("127.0.0.1", port
);
190 fprintf(stdout
, "FAILED\n");
195 * At this point, we want to schedule an HTTP POST request
196 * server using our make request method.
199 req
= evhttp_request_new(rpc_postrequest_failure
, NULL
);
201 fprintf(stdout
, "FAILED\n");
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");
209 if (evhttp_make_request(evcon
, req
,
211 "/.rpc.Message") == -1) {
212 fprintf(stdout
, "FAILED\n");
220 evhttp_connection_free(evcon
);
225 fprintf(stdout
, "FAILED\n");
229 fprintf(stdout
, "OK\n");
235 rpc_postrequest_done(struct evhttp_request
*req
, void *arg
)
237 struct kill
* kill_reply
= NULL
;
239 if (req
->response_code
!= HTTP_OK
) {
241 fprintf(stderr
, "FAILED (response code)\n");
245 kill_reply
= kill_new();
247 if ((kill_unmarshal(kill_reply
, req
->input_buffer
)) == -1) {
248 fprintf(stderr
, "FAILED (unmarshal)\n");
252 kill_free(kill_reply
);
255 event_loopexit(NULL
);
259 rpc_basic_message(void)
262 struct evhttp
*http
= NULL
;
263 struct evrpc_base
*base
= NULL
;
264 struct evhttp_connection
*evcon
= NULL
;
265 struct evhttp_request
*req
= NULL
;
268 fprintf(stdout
, "Testing Good RPC Post: ");
270 rpc_setup(&http
, &port
, &base
);
272 evcon
= evhttp_connection_new("127.0.0.1", port
);
274 fprintf(stdout
, "FAILED\n");
279 * At this point, we want to schedule an HTTP POST request
280 * server using our make request method.
283 req
= evhttp_request_new(rpc_postrequest_done
, NULL
);
285 fprintf(stdout
, "FAILED\n");
289 /* Add the information that we care about */
290 evhttp_add_header(req
->output_headers
, "Host", "somehost");
292 /* set up the basic message */
294 EVTAG_ASSIGN(msg
, from_name
, "niels");
295 EVTAG_ASSIGN(msg
, to_name
, "tester");
296 msg_marshal(req
->output_buffer
, msg
);
299 if (evhttp_make_request(evcon
, req
,
301 "/.rpc.Message") == -1) {
302 fprintf(stdout
, "FAILED\n");
310 evhttp_connection_free(evcon
);
315 fprintf(stdout
, "FAILED\n");
319 fprintf(stdout
, "OK\n");
324 static struct evrpc_pool
*
325 rpc_pool_with_connection(short port
)
327 struct evhttp_connection
*evcon
;
328 struct evrpc_pool
*pool
;
330 pool
= evrpc_pool_new(NULL
);
331 assert(pool
!= NULL
);
333 evcon
= evhttp_connection_new("127.0.0.1", port
);
334 assert(evcon
!= NULL
);
336 evrpc_pool_add_connection(pool
, evcon
);
342 GotKillCb(struct evrpc_status
*status
,
343 struct msg
*msg
, struct kill
*kill
, void *arg
)
348 if (need_output_hook
) {
349 struct evhttp_request
*req
= status
->http_req
;
350 const char *header
= evhttp_find_header(
351 req
->input_headers
, "X-Pool-Hook");
352 assert(strcmp(header
, "ran") == 0);
355 if (status
->error
!= EVRPC_STATUS_ERR_NONE
)
358 if (EVTAG_GET(kill
, weapon
, &weapon
) == -1) {
359 fprintf(stderr
, "get weapon\n");
362 if (EVTAG_GET(kill
, action
, &action
) == -1) {
363 fprintf(stderr
, "get action\n");
367 if (strcmp(weapon
, "dagger"))
370 if (strcmp(action
, "wave around like an idiot"))
376 event_loopexit(NULL
);
380 GotKillCbTwo(struct evrpc_status
*status
,
381 struct msg
*msg
, struct kill
*kill
, void *arg
)
386 if (status
->error
!= EVRPC_STATUS_ERR_NONE
)
389 if (EVTAG_GET(kill
, weapon
, &weapon
) == -1) {
390 fprintf(stderr
, "get weapon\n");
393 if (EVTAG_GET(kill
, action
, &action
) == -1) {
394 fprintf(stderr
, "get action\n");
398 if (strcmp(weapon
, "dagger"))
401 if (strcmp(action
, "wave around like an idiot"))
408 event_loopexit(NULL
);
412 rpc_hook_add_header(struct evhttp_request
*req
,
413 struct evbuffer
*evbuf
, void *arg
)
415 const char *hook_type
= arg
;
416 if (strcmp("input", hook_type
) == 0)
417 evhttp_add_header(req
->input_headers
, "X-Hook", hook_type
);
419 evhttp_add_header(req
->output_headers
, "X-Hook", hook_type
);
424 rpc_hook_remove_header(struct evhttp_request
*req
,
425 struct evbuffer
*evbuf
, void *arg
)
427 const char *header
= evhttp_find_header(req
->input_headers
, "X-Hook");
428 assert(header
!= NULL
);
429 assert(strcmp(header
, arg
) == 0);
430 evhttp_remove_header(req
->input_headers
, "X-Hook");
431 evhttp_add_header(req
->input_headers
, "X-Pool-Hook", "ran");
437 rpc_basic_client(void)
440 struct evhttp
*http
= NULL
;
441 struct evrpc_base
*base
= NULL
;
442 struct evrpc_pool
*pool
= NULL
;
446 fprintf(stdout
, "Testing RPC Client: ");
448 rpc_setup(&http
, &port
, &base
);
451 need_output_hook
= 1;
453 assert(evrpc_add_hook(base
, EVRPC_INPUT
, rpc_hook_add_header
, (void*)"input")
455 assert(evrpc_add_hook(base
, EVRPC_OUTPUT
, rpc_hook_add_header
, (void*)"output")
458 pool
= rpc_pool_with_connection(port
);
460 assert(evrpc_add_hook(pool
, EVRPC_INPUT
, rpc_hook_remove_header
, (void*)"output"));
462 /* set up the basic message */
464 EVTAG_ASSIGN(msg
, from_name
, "niels");
465 EVTAG_ASSIGN(msg
, to_name
, "tester");
469 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill
, GotKillCb
, NULL
);
476 fprintf(stdout
, "FAILED (1)\n");
480 /* we do it twice to make sure that reuse works correctly */
483 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill
, GotKillCb
, NULL
);
490 fprintf(stdout
, "FAILED (2)\n");
494 fprintf(stdout
, "OK\n");
499 evrpc_pool_free(pool
);
504 * We are testing that the second requests gets send over the same
505 * connection after the first RPCs completes.
508 rpc_basic_queued_client(void)
511 struct evhttp
*http
= NULL
;
512 struct evrpc_base
*base
= NULL
;
513 struct evrpc_pool
*pool
= NULL
;
515 struct kill
*kill_one
, *kill_two
;
517 fprintf(stdout
, "Testing RPC (Queued) Client: ");
519 rpc_setup(&http
, &port
, &base
);
521 pool
= rpc_pool_with_connection(port
);
523 /* set up the basic message */
525 EVTAG_ASSIGN(msg
, from_name
, "niels");
526 EVTAG_ASSIGN(msg
, to_name
, "tester");
528 kill_one
= kill_new();
529 kill_two
= kill_new();
531 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill_one
, GotKillCbTwo
, NULL
);
532 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill_two
, GotKillCb
, NULL
);
541 fprintf(stdout
, "FAILED (1)\n");
545 fprintf(stdout
, "OK\n");
551 evrpc_pool_free(pool
);
556 GotErrorCb(struct evrpc_status
*status
,
557 struct msg
*msg
, struct kill
*kill
, void *arg
)
559 if (status
->error
!= EVRPC_STATUS_ERR_TIMEOUT
)
562 /* should never be complete but just to check */
563 if (kill_complete(kill
) == 0)
569 event_loopexit(NULL
);
573 rpc_client_timeout(void)
576 struct evhttp
*http
= NULL
;
577 struct evrpc_base
*base
= NULL
;
578 struct evrpc_pool
*pool
= NULL
;
582 fprintf(stdout
, "Testing RPC Client Timeout: ");
584 rpc_setup(&http
, &port
, &base
);
586 pool
= rpc_pool_with_connection(port
);
588 /* set the timeout to 5 seconds */
589 evrpc_pool_set_timeout(pool
, 5);
591 /* set up the basic message */
593 EVTAG_ASSIGN(msg
, from_name
, "niels");
594 EVTAG_ASSIGN(msg
, to_name
, "tester");
598 EVRPC_MAKE_REQUEST(NeverReply
, pool
, msg
, kill
, GotErrorCb
, NULL
);
604 /* free the saved RPC structure up */
605 EVRPC_REQUEST_DONE(saved_rpc
);
610 fprintf(stdout
, "FAILED (1)\n");
614 fprintf(stdout
, "OK\n");
619 evrpc_pool_free(pool
);
629 rpc_basic_queued_client();
630 rpc_client_timeout();