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