3 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/types.h>
40 #ifdef HAVE_SYS_TIME_H
43 #include <sys/queue.h>
45 #include <sys/socket.h>
62 #include "regress.gen.h"
68 static struct evhttp
*
69 http_setup(short *pport
)
72 struct evhttp
*myhttp
;
75 /* Try a few different ports */
76 for (i
= 0; i
< 50; ++i
) {
77 myhttp
= evhttp_start("127.0.0.1", 8080 + i
);
85 event_errx(1, "Could not start web server");
91 EVRPC_HEADER(Message
, msg
, kill
);
92 EVRPC_HEADER(NeverReply
, msg
, kill
);
94 EVRPC_GENERATE(Message
, msg
, kill
);
95 EVRPC_GENERATE(NeverReply
, msg
, kill
);
97 static int need_input_hook
= 0;
98 static int need_output_hook
= 0;
101 MessageCb(EVRPC_STRUCT(Message
)* rpc
, void *arg
)
103 struct kill
* kill_reply
= rpc
->reply
;
105 if (need_input_hook
) {
106 struct evhttp_request
* req
= EVRPC_REQUEST_HTTP(rpc
);
107 const char *header
= evhttp_find_header(
108 req
->input_headers
, "X-Hook");
109 assert(strcmp(header
, "input") == 0);
112 /* we just want to fill in some non-sense */
113 EVTAG_ASSIGN(kill_reply
, weapon
, "dagger");
114 EVTAG_ASSIGN(kill_reply
, action
, "wave around like an idiot");
116 /* no reply to the RPC */
117 EVRPC_REQUEST_DONE(rpc
);
120 static EVRPC_STRUCT(NeverReply
) *saved_rpc
;
123 NeverReplyCb(EVRPC_STRUCT(NeverReply
)* rpc
, void *arg
)
130 rpc_setup(struct evhttp
**phttp
, short *pport
, struct evrpc_base
**pbase
)
133 struct evhttp
*http
= NULL
;
134 struct evrpc_base
*base
= NULL
;
136 http
= http_setup(&port
);
137 base
= evrpc_init(http
);
139 EVRPC_REGISTER(base
, Message
, msg
, kill
, MessageCb
, NULL
);
140 EVRPC_REGISTER(base
, NeverReply
, msg
, kill
, NeverReplyCb
, NULL
);
147 need_output_hook
= 0;
151 rpc_teardown(struct evrpc_base
*base
)
153 assert(EVRPC_UNREGISTER(base
, Message
) == 0);
154 assert(EVRPC_UNREGISTER(base
, NeverReply
) == 0);
160 rpc_postrequest_failure(struct evhttp_request
*req
, void *arg
)
162 if (req
->response_code
!= HTTP_SERVUNAVAIL
) {
164 fprintf(stderr
, "FAILED (response code)\n");
169 event_loopexit(NULL
);
173 * Test a malformed payload submitted as an RPC
180 struct evhttp
*http
= NULL
;
181 struct evrpc_base
*base
= NULL
;
182 struct evhttp_connection
*evcon
= NULL
;
183 struct evhttp_request
*req
= NULL
;
185 fprintf(stdout
, "Testing Basic RPC Support: ");
187 rpc_setup(&http
, &port
, &base
);
189 evcon
= evhttp_connection_new("127.0.0.1", port
);
191 fprintf(stdout
, "FAILED\n");
196 * At this point, we want to schedule an HTTP POST request
197 * server using our make request method.
200 req
= evhttp_request_new(rpc_postrequest_failure
, NULL
);
202 fprintf(stdout
, "FAILED\n");
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");
210 if (evhttp_make_request(evcon
, req
,
212 "/.rpc.Message") == -1) {
213 fprintf(stdout
, "FAILED\n");
221 evhttp_connection_free(evcon
);
226 fprintf(stdout
, "FAILED\n");
230 fprintf(stdout
, "OK\n");
236 rpc_postrequest_done(struct evhttp_request
*req
, void *arg
)
238 struct kill
* kill_reply
= NULL
;
240 if (req
->response_code
!= HTTP_OK
) {
242 fprintf(stderr
, "FAILED (response code)\n");
246 kill_reply
= kill_new();
248 if ((kill_unmarshal(kill_reply
, req
->input_buffer
)) == -1) {
249 fprintf(stderr
, "FAILED (unmarshal)\n");
253 kill_free(kill_reply
);
256 event_loopexit(NULL
);
260 rpc_basic_message(void)
263 struct evhttp
*http
= NULL
;
264 struct evrpc_base
*base
= NULL
;
265 struct evhttp_connection
*evcon
= NULL
;
266 struct evhttp_request
*req
= NULL
;
269 fprintf(stdout
, "Testing Good RPC Post: ");
271 rpc_setup(&http
, &port
, &base
);
273 evcon
= evhttp_connection_new("127.0.0.1", port
);
275 fprintf(stdout
, "FAILED\n");
280 * At this point, we want to schedule an HTTP POST request
281 * server using our make request method.
284 req
= evhttp_request_new(rpc_postrequest_done
, NULL
);
286 fprintf(stdout
, "FAILED\n");
290 /* Add the information that we care about */
291 evhttp_add_header(req
->output_headers
, "Host", "somehost");
293 /* set up the basic message */
295 EVTAG_ASSIGN(msg
, from_name
, "niels");
296 EVTAG_ASSIGN(msg
, to_name
, "tester");
297 msg_marshal(req
->output_buffer
, msg
);
300 if (evhttp_make_request(evcon
, req
,
302 "/.rpc.Message") == -1) {
303 fprintf(stdout
, "FAILED\n");
311 evhttp_connection_free(evcon
);
316 fprintf(stdout
, "FAILED\n");
320 fprintf(stdout
, "OK\n");
325 static struct evrpc_pool
*
326 rpc_pool_with_connection(short port
)
328 struct evhttp_connection
*evcon
;
329 struct evrpc_pool
*pool
;
331 pool
= evrpc_pool_new(NULL
);
332 assert(pool
!= NULL
);
334 evcon
= evhttp_connection_new("127.0.0.1", port
);
335 assert(evcon
!= NULL
);
337 evrpc_pool_add_connection(pool
, evcon
);
343 GotKillCb(struct evrpc_status
*status
,
344 struct msg
*msg
, struct kill
*kill
, void *arg
)
349 if (need_output_hook
) {
350 struct evhttp_request
*req
= status
->http_req
;
351 const char *header
= evhttp_find_header(
352 req
->input_headers
, "X-Pool-Hook");
353 assert(strcmp(header
, "ran") == 0);
356 if (status
->error
!= EVRPC_STATUS_ERR_NONE
)
359 if (EVTAG_GET(kill
, weapon
, &weapon
) == -1) {
360 fprintf(stderr
, "get weapon\n");
363 if (EVTAG_GET(kill
, action
, &action
) == -1) {
364 fprintf(stderr
, "get action\n");
368 if (strcmp(weapon
, "dagger"))
371 if (strcmp(action
, "wave around like an idiot"))
377 event_loopexit(NULL
);
381 GotKillCbTwo(struct evrpc_status
*status
,
382 struct msg
*msg
, struct kill
*kill
, void *arg
)
387 if (status
->error
!= EVRPC_STATUS_ERR_NONE
)
390 if (EVTAG_GET(kill
, weapon
, &weapon
) == -1) {
391 fprintf(stderr
, "get weapon\n");
394 if (EVTAG_GET(kill
, action
, &action
) == -1) {
395 fprintf(stderr
, "get action\n");
399 if (strcmp(weapon
, "dagger"))
402 if (strcmp(action
, "wave around like an idiot"))
409 event_loopexit(NULL
);
413 rpc_hook_add_header(struct evhttp_request
*req
,
414 struct evbuffer
*evbuf
, void *arg
)
416 const char *hook_type
= arg
;
417 if (strcmp("input", hook_type
) == 0)
418 evhttp_add_header(req
->input_headers
, "X-Hook", hook_type
);
420 evhttp_add_header(req
->output_headers
, "X-Hook", hook_type
);
425 rpc_hook_remove_header(struct evhttp_request
*req
,
426 struct evbuffer
*evbuf
, void *arg
)
428 const char *header
= evhttp_find_header(req
->input_headers
, "X-Hook");
429 assert(header
!= NULL
);
430 assert(strcmp(header
, arg
) == 0);
431 evhttp_remove_header(req
->input_headers
, "X-Hook");
432 evhttp_add_header(req
->input_headers
, "X-Pool-Hook", "ran");
438 rpc_basic_client(void)
441 struct evhttp
*http
= NULL
;
442 struct evrpc_base
*base
= NULL
;
443 struct evrpc_pool
*pool
= NULL
;
447 fprintf(stdout
, "Testing RPC Client: ");
449 rpc_setup(&http
, &port
, &base
);
452 need_output_hook
= 1;
454 assert(evrpc_add_hook(base
, EVRPC_INPUT
, rpc_hook_add_header
, (void*)"input")
456 assert(evrpc_add_hook(base
, EVRPC_OUTPUT
, rpc_hook_add_header
, (void*)"output")
459 pool
= rpc_pool_with_connection(port
);
461 assert(evrpc_add_hook(pool
, EVRPC_INPUT
, rpc_hook_remove_header
, (void*)"output"));
463 /* set up the basic message */
465 EVTAG_ASSIGN(msg
, from_name
, "niels");
466 EVTAG_ASSIGN(msg
, to_name
, "tester");
470 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill
, GotKillCb
, NULL
);
477 fprintf(stdout
, "FAILED (1)\n");
481 /* we do it twice to make sure that reuse works correctly */
484 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill
, GotKillCb
, NULL
);
491 fprintf(stdout
, "FAILED (2)\n");
495 fprintf(stdout
, "OK\n");
500 evrpc_pool_free(pool
);
505 * We are testing that the second requests gets send over the same
506 * connection after the first RPCs completes.
509 rpc_basic_queued_client(void)
512 struct evhttp
*http
= NULL
;
513 struct evrpc_base
*base
= NULL
;
514 struct evrpc_pool
*pool
= NULL
;
516 struct kill
*kill_one
, *kill_two
;
518 fprintf(stdout
, "Testing RPC (Queued) Client: ");
520 rpc_setup(&http
, &port
, &base
);
522 pool
= rpc_pool_with_connection(port
);
524 /* set up the basic message */
526 EVTAG_ASSIGN(msg
, from_name
, "niels");
527 EVTAG_ASSIGN(msg
, to_name
, "tester");
529 kill_one
= kill_new();
530 kill_two
= kill_new();
532 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill_one
, GotKillCbTwo
, NULL
);
533 EVRPC_MAKE_REQUEST(Message
, pool
, msg
, kill_two
, GotKillCb
, NULL
);
542 fprintf(stdout
, "FAILED (1)\n");
546 fprintf(stdout
, "OK\n");
552 evrpc_pool_free(pool
);
557 GotErrorCb(struct evrpc_status
*status
,
558 struct msg
*msg
, struct kill
*kill
, void *arg
)
560 if (status
->error
!= EVRPC_STATUS_ERR_TIMEOUT
)
563 /* should never be complete but just to check */
564 if (kill_complete(kill
) == 0)
570 event_loopexit(NULL
);
574 rpc_client_timeout(void)
577 struct evhttp
*http
= NULL
;
578 struct evrpc_base
*base
= NULL
;
579 struct evrpc_pool
*pool
= NULL
;
583 fprintf(stdout
, "Testing RPC Client Timeout: ");
585 rpc_setup(&http
, &port
, &base
);
587 pool
= rpc_pool_with_connection(port
);
589 /* set the timeout to 5 seconds */
590 evrpc_pool_set_timeout(pool
, 5);
592 /* set up the basic message */
594 EVTAG_ASSIGN(msg
, from_name
, "niels");
595 EVTAG_ASSIGN(msg
, to_name
, "tester");
599 EVRPC_MAKE_REQUEST(NeverReply
, pool
, msg
, kill
, GotErrorCb
, NULL
);
605 /* free the saved RPC structure up */
606 EVRPC_REQUEST_DONE(saved_rpc
);
611 fprintf(stdout
, "FAILED (1)\n");
615 fprintf(stdout
, "OK\n");
620 evrpc_pool_free(pool
);
630 rpc_basic_queued_client();
631 rpc_client_timeout();