1*663afb9bSAndroid Build Coastguard Worker /*
2*663afb9bSAndroid Build Coastguard Worker * Copyright (c) 2000-2007 Niels Provos <[email protected]>
3*663afb9bSAndroid Build Coastguard Worker * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
4*663afb9bSAndroid Build Coastguard Worker *
5*663afb9bSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*663afb9bSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*663afb9bSAndroid Build Coastguard Worker * are met:
8*663afb9bSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
9*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*663afb9bSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
11*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
12*663afb9bSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
13*663afb9bSAndroid Build Coastguard Worker * 3. The name of the author may not be used to endorse or promote products
14*663afb9bSAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*663afb9bSAndroid Build Coastguard Worker *
16*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*663afb9bSAndroid Build Coastguard Worker * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*663afb9bSAndroid Build Coastguard Worker * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*663afb9bSAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*663afb9bSAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*663afb9bSAndroid Build Coastguard Worker * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*663afb9bSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*663afb9bSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*663afb9bSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*663afb9bSAndroid Build Coastguard Worker */
27*663afb9bSAndroid Build Coastguard Worker #include "event2/event-config.h"
28*663afb9bSAndroid Build Coastguard Worker #include "evconfig-private.h"
29*663afb9bSAndroid Build Coastguard Worker
30*663afb9bSAndroid Build Coastguard Worker #ifdef _WIN32
31*663afb9bSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
32*663afb9bSAndroid Build Coastguard Worker #include <winsock2.h>
33*663afb9bSAndroid Build Coastguard Worker #include <windows.h>
34*663afb9bSAndroid Build Coastguard Worker #undef WIN32_LEAN_AND_MEAN
35*663afb9bSAndroid Build Coastguard Worker #endif
36*663afb9bSAndroid Build Coastguard Worker
37*663afb9bSAndroid Build Coastguard Worker #include <sys/types.h>
38*663afb9bSAndroid Build Coastguard Worker #ifndef _WIN32
39*663afb9bSAndroid Build Coastguard Worker #include <sys/socket.h>
40*663afb9bSAndroid Build Coastguard Worker #endif
41*663afb9bSAndroid Build Coastguard Worker #ifdef EVENT__HAVE_SYS_TIME_H
42*663afb9bSAndroid Build Coastguard Worker #include <sys/time.h>
43*663afb9bSAndroid Build Coastguard Worker #endif
44*663afb9bSAndroid Build Coastguard Worker #include <sys/queue.h>
45*663afb9bSAndroid Build Coastguard Worker #include <stdio.h>
46*663afb9bSAndroid Build Coastguard Worker #include <stdlib.h>
47*663afb9bSAndroid Build Coastguard Worker #ifndef _WIN32
48*663afb9bSAndroid Build Coastguard Worker #include <unistd.h>
49*663afb9bSAndroid Build Coastguard Worker #endif
50*663afb9bSAndroid Build Coastguard Worker #include <errno.h>
51*663afb9bSAndroid Build Coastguard Worker #include <signal.h>
52*663afb9bSAndroid Build Coastguard Worker #include <string.h>
53*663afb9bSAndroid Build Coastguard Worker
54*663afb9bSAndroid Build Coastguard Worker #include <sys/queue.h>
55*663afb9bSAndroid Build Coastguard Worker
56*663afb9bSAndroid Build Coastguard Worker #include "event2/event.h"
57*663afb9bSAndroid Build Coastguard Worker #include "event2/event_struct.h"
58*663afb9bSAndroid Build Coastguard Worker #include "event2/rpc.h"
59*663afb9bSAndroid Build Coastguard Worker #include "event2/rpc_struct.h"
60*663afb9bSAndroid Build Coastguard Worker #include "evrpc-internal.h"
61*663afb9bSAndroid Build Coastguard Worker #include "event2/http.h"
62*663afb9bSAndroid Build Coastguard Worker #include "event2/buffer.h"
63*663afb9bSAndroid Build Coastguard Worker #include "event2/tag.h"
64*663afb9bSAndroid Build Coastguard Worker #include "event2/http_struct.h"
65*663afb9bSAndroid Build Coastguard Worker #include "event2/http_compat.h"
66*663afb9bSAndroid Build Coastguard Worker #include "event2/util.h"
67*663afb9bSAndroid Build Coastguard Worker #include "util-internal.h"
68*663afb9bSAndroid Build Coastguard Worker #include "log-internal.h"
69*663afb9bSAndroid Build Coastguard Worker #include "mm-internal.h"
70*663afb9bSAndroid Build Coastguard Worker
71*663afb9bSAndroid Build Coastguard Worker struct evrpc_base *
evrpc_init(struct evhttp * http_server)72*663afb9bSAndroid Build Coastguard Worker evrpc_init(struct evhttp *http_server)
73*663afb9bSAndroid Build Coastguard Worker {
74*663afb9bSAndroid Build Coastguard Worker struct evrpc_base* base = mm_calloc(1, sizeof(struct evrpc_base));
75*663afb9bSAndroid Build Coastguard Worker if (base == NULL)
76*663afb9bSAndroid Build Coastguard Worker return (NULL);
77*663afb9bSAndroid Build Coastguard Worker
78*663afb9bSAndroid Build Coastguard Worker /* we rely on the tagging sub system */
79*663afb9bSAndroid Build Coastguard Worker evtag_init();
80*663afb9bSAndroid Build Coastguard Worker
81*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&base->registered_rpcs);
82*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&base->input_hooks);
83*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&base->output_hooks);
84*663afb9bSAndroid Build Coastguard Worker
85*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&base->paused_requests);
86*663afb9bSAndroid Build Coastguard Worker
87*663afb9bSAndroid Build Coastguard Worker base->http_server = http_server;
88*663afb9bSAndroid Build Coastguard Worker
89*663afb9bSAndroid Build Coastguard Worker return (base);
90*663afb9bSAndroid Build Coastguard Worker }
91*663afb9bSAndroid Build Coastguard Worker
92*663afb9bSAndroid Build Coastguard Worker void
evrpc_free(struct evrpc_base * base)93*663afb9bSAndroid Build Coastguard Worker evrpc_free(struct evrpc_base *base)
94*663afb9bSAndroid Build Coastguard Worker {
95*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc;
96*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook *hook;
97*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_ctx *pause;
98*663afb9bSAndroid Build Coastguard Worker int r;
99*663afb9bSAndroid Build Coastguard Worker
100*663afb9bSAndroid Build Coastguard Worker while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
101*663afb9bSAndroid Build Coastguard Worker r = evrpc_unregister_rpc(base, rpc->uri);
102*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r == 0);
103*663afb9bSAndroid Build Coastguard Worker }
104*663afb9bSAndroid Build Coastguard Worker while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) {
105*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&base->paused_requests, pause, next);
106*663afb9bSAndroid Build Coastguard Worker mm_free(pause);
107*663afb9bSAndroid Build Coastguard Worker }
108*663afb9bSAndroid Build Coastguard Worker while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
109*663afb9bSAndroid Build Coastguard Worker r = evrpc_remove_hook(base, EVRPC_INPUT, hook);
110*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r);
111*663afb9bSAndroid Build Coastguard Worker }
112*663afb9bSAndroid Build Coastguard Worker while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
113*663afb9bSAndroid Build Coastguard Worker r = evrpc_remove_hook(base, EVRPC_OUTPUT, hook);
114*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r);
115*663afb9bSAndroid Build Coastguard Worker }
116*663afb9bSAndroid Build Coastguard Worker mm_free(base);
117*663afb9bSAndroid Build Coastguard Worker }
118*663afb9bSAndroid Build Coastguard Worker
119*663afb9bSAndroid Build Coastguard Worker void *
evrpc_add_hook(void * vbase,enum EVRPC_HOOK_TYPE hook_type,int (* cb)(void *,struct evhttp_request *,struct evbuffer *,void *),void * cb_arg)120*663afb9bSAndroid Build Coastguard Worker evrpc_add_hook(void *vbase,
121*663afb9bSAndroid Build Coastguard Worker enum EVRPC_HOOK_TYPE hook_type,
122*663afb9bSAndroid Build Coastguard Worker int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
123*663afb9bSAndroid Build Coastguard Worker void *cb_arg)
124*663afb9bSAndroid Build Coastguard Worker {
125*663afb9bSAndroid Build Coastguard Worker struct evrpc_hooks_ *base = vbase;
126*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_list *head = NULL;
127*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook *hook = NULL;
128*663afb9bSAndroid Build Coastguard Worker switch (hook_type) {
129*663afb9bSAndroid Build Coastguard Worker case EVRPC_INPUT:
130*663afb9bSAndroid Build Coastguard Worker head = &base->in_hooks;
131*663afb9bSAndroid Build Coastguard Worker break;
132*663afb9bSAndroid Build Coastguard Worker case EVRPC_OUTPUT:
133*663afb9bSAndroid Build Coastguard Worker head = &base->out_hooks;
134*663afb9bSAndroid Build Coastguard Worker break;
135*663afb9bSAndroid Build Coastguard Worker default:
136*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
137*663afb9bSAndroid Build Coastguard Worker }
138*663afb9bSAndroid Build Coastguard Worker
139*663afb9bSAndroid Build Coastguard Worker hook = mm_calloc(1, sizeof(struct evrpc_hook));
140*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook != NULL);
141*663afb9bSAndroid Build Coastguard Worker
142*663afb9bSAndroid Build Coastguard Worker hook->process = cb;
143*663afb9bSAndroid Build Coastguard Worker hook->process_arg = cb_arg;
144*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(head, hook, next);
145*663afb9bSAndroid Build Coastguard Worker
146*663afb9bSAndroid Build Coastguard Worker return (hook);
147*663afb9bSAndroid Build Coastguard Worker }
148*663afb9bSAndroid Build Coastguard Worker
149*663afb9bSAndroid Build Coastguard Worker static int
evrpc_remove_hook_internal(struct evrpc_hook_list * head,void * handle)150*663afb9bSAndroid Build Coastguard Worker evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
151*663afb9bSAndroid Build Coastguard Worker {
152*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook *hook = NULL;
153*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(hook, head, next) {
154*663afb9bSAndroid Build Coastguard Worker if (hook == handle) {
155*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(head, hook, next);
156*663afb9bSAndroid Build Coastguard Worker mm_free(hook);
157*663afb9bSAndroid Build Coastguard Worker return (1);
158*663afb9bSAndroid Build Coastguard Worker }
159*663afb9bSAndroid Build Coastguard Worker }
160*663afb9bSAndroid Build Coastguard Worker
161*663afb9bSAndroid Build Coastguard Worker return (0);
162*663afb9bSAndroid Build Coastguard Worker }
163*663afb9bSAndroid Build Coastguard Worker
164*663afb9bSAndroid Build Coastguard Worker /*
165*663afb9bSAndroid Build Coastguard Worker * remove the hook specified by the handle
166*663afb9bSAndroid Build Coastguard Worker */
167*663afb9bSAndroid Build Coastguard Worker
168*663afb9bSAndroid Build Coastguard Worker int
evrpc_remove_hook(void * vbase,enum EVRPC_HOOK_TYPE hook_type,void * handle)169*663afb9bSAndroid Build Coastguard Worker evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
170*663afb9bSAndroid Build Coastguard Worker {
171*663afb9bSAndroid Build Coastguard Worker struct evrpc_hooks_ *base = vbase;
172*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_list *head = NULL;
173*663afb9bSAndroid Build Coastguard Worker switch (hook_type) {
174*663afb9bSAndroid Build Coastguard Worker case EVRPC_INPUT:
175*663afb9bSAndroid Build Coastguard Worker head = &base->in_hooks;
176*663afb9bSAndroid Build Coastguard Worker break;
177*663afb9bSAndroid Build Coastguard Worker case EVRPC_OUTPUT:
178*663afb9bSAndroid Build Coastguard Worker head = &base->out_hooks;
179*663afb9bSAndroid Build Coastguard Worker break;
180*663afb9bSAndroid Build Coastguard Worker default:
181*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
182*663afb9bSAndroid Build Coastguard Worker }
183*663afb9bSAndroid Build Coastguard Worker
184*663afb9bSAndroid Build Coastguard Worker return (evrpc_remove_hook_internal(head, handle));
185*663afb9bSAndroid Build Coastguard Worker }
186*663afb9bSAndroid Build Coastguard Worker
187*663afb9bSAndroid Build Coastguard Worker static int
evrpc_process_hooks(struct evrpc_hook_list * head,void * ctx,struct evhttp_request * req,struct evbuffer * evbuf)188*663afb9bSAndroid Build Coastguard Worker evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx,
189*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req, struct evbuffer *evbuf)
190*663afb9bSAndroid Build Coastguard Worker {
191*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook *hook;
192*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(hook, head, next) {
193*663afb9bSAndroid Build Coastguard Worker int res = hook->process(ctx, req, evbuf, hook->process_arg);
194*663afb9bSAndroid Build Coastguard Worker if (res != EVRPC_CONTINUE)
195*663afb9bSAndroid Build Coastguard Worker return (res);
196*663afb9bSAndroid Build Coastguard Worker }
197*663afb9bSAndroid Build Coastguard Worker
198*663afb9bSAndroid Build Coastguard Worker return (EVRPC_CONTINUE);
199*663afb9bSAndroid Build Coastguard Worker }
200*663afb9bSAndroid Build Coastguard Worker
201*663afb9bSAndroid Build Coastguard Worker static void evrpc_pool_schedule(struct evrpc_pool *pool);
202*663afb9bSAndroid Build Coastguard Worker static void evrpc_request_cb(struct evhttp_request *, void *);
203*663afb9bSAndroid Build Coastguard Worker
204*663afb9bSAndroid Build Coastguard Worker /*
205*663afb9bSAndroid Build Coastguard Worker * Registers a new RPC with the HTTP server. The evrpc object is expected
206*663afb9bSAndroid Build Coastguard Worker * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
207*663afb9bSAndroid Build Coastguard Worker * calls this function.
208*663afb9bSAndroid Build Coastguard Worker */
209*663afb9bSAndroid Build Coastguard Worker
210*663afb9bSAndroid Build Coastguard Worker static char *
evrpc_construct_uri(const char * uri)211*663afb9bSAndroid Build Coastguard Worker evrpc_construct_uri(const char *uri)
212*663afb9bSAndroid Build Coastguard Worker {
213*663afb9bSAndroid Build Coastguard Worker char *constructed_uri;
214*663afb9bSAndroid Build Coastguard Worker size_t constructed_uri_len;
215*663afb9bSAndroid Build Coastguard Worker
216*663afb9bSAndroid Build Coastguard Worker constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
217*663afb9bSAndroid Build Coastguard Worker if ((constructed_uri = mm_malloc(constructed_uri_len)) == NULL)
218*663afb9bSAndroid Build Coastguard Worker event_err(1, "%s: failed to register rpc at %s",
219*663afb9bSAndroid Build Coastguard Worker __func__, uri);
220*663afb9bSAndroid Build Coastguard Worker memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
221*663afb9bSAndroid Build Coastguard Worker memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
222*663afb9bSAndroid Build Coastguard Worker constructed_uri[constructed_uri_len - 1] = '\0';
223*663afb9bSAndroid Build Coastguard Worker
224*663afb9bSAndroid Build Coastguard Worker return (constructed_uri);
225*663afb9bSAndroid Build Coastguard Worker }
226*663afb9bSAndroid Build Coastguard Worker
227*663afb9bSAndroid Build Coastguard Worker int
evrpc_register_rpc(struct evrpc_base * base,struct evrpc * rpc,void (* cb)(struct evrpc_req_generic *,void *),void * cb_arg)228*663afb9bSAndroid Build Coastguard Worker evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
229*663afb9bSAndroid Build Coastguard Worker void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
230*663afb9bSAndroid Build Coastguard Worker {
231*663afb9bSAndroid Build Coastguard Worker char *constructed_uri = evrpc_construct_uri(rpc->uri);
232*663afb9bSAndroid Build Coastguard Worker
233*663afb9bSAndroid Build Coastguard Worker rpc->base = base;
234*663afb9bSAndroid Build Coastguard Worker rpc->cb = cb;
235*663afb9bSAndroid Build Coastguard Worker rpc->cb_arg = cb_arg;
236*663afb9bSAndroid Build Coastguard Worker
237*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
238*663afb9bSAndroid Build Coastguard Worker
239*663afb9bSAndroid Build Coastguard Worker evhttp_set_cb(base->http_server,
240*663afb9bSAndroid Build Coastguard Worker constructed_uri,
241*663afb9bSAndroid Build Coastguard Worker evrpc_request_cb,
242*663afb9bSAndroid Build Coastguard Worker rpc);
243*663afb9bSAndroid Build Coastguard Worker
244*663afb9bSAndroid Build Coastguard Worker mm_free(constructed_uri);
245*663afb9bSAndroid Build Coastguard Worker
246*663afb9bSAndroid Build Coastguard Worker return (0);
247*663afb9bSAndroid Build Coastguard Worker }
248*663afb9bSAndroid Build Coastguard Worker
249*663afb9bSAndroid Build Coastguard Worker int
evrpc_unregister_rpc(struct evrpc_base * base,const char * name)250*663afb9bSAndroid Build Coastguard Worker evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
251*663afb9bSAndroid Build Coastguard Worker {
252*663afb9bSAndroid Build Coastguard Worker char *registered_uri = NULL;
253*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc;
254*663afb9bSAndroid Build Coastguard Worker int r;
255*663afb9bSAndroid Build Coastguard Worker
256*663afb9bSAndroid Build Coastguard Worker /* find the right rpc; linear search might be slow */
257*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
258*663afb9bSAndroid Build Coastguard Worker if (strcmp(rpc->uri, name) == 0)
259*663afb9bSAndroid Build Coastguard Worker break;
260*663afb9bSAndroid Build Coastguard Worker }
261*663afb9bSAndroid Build Coastguard Worker if (rpc == NULL) {
262*663afb9bSAndroid Build Coastguard Worker /* We did not find an RPC with this name */
263*663afb9bSAndroid Build Coastguard Worker return (-1);
264*663afb9bSAndroid Build Coastguard Worker }
265*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
266*663afb9bSAndroid Build Coastguard Worker
267*663afb9bSAndroid Build Coastguard Worker registered_uri = evrpc_construct_uri(name);
268*663afb9bSAndroid Build Coastguard Worker
269*663afb9bSAndroid Build Coastguard Worker /* remove the http server callback */
270*663afb9bSAndroid Build Coastguard Worker r = evhttp_del_cb(base->http_server, registered_uri);
271*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r == 0);
272*663afb9bSAndroid Build Coastguard Worker
273*663afb9bSAndroid Build Coastguard Worker mm_free(registered_uri);
274*663afb9bSAndroid Build Coastguard Worker
275*663afb9bSAndroid Build Coastguard Worker mm_free((char *)rpc->uri);
276*663afb9bSAndroid Build Coastguard Worker mm_free(rpc);
277*663afb9bSAndroid Build Coastguard Worker return (0);
278*663afb9bSAndroid Build Coastguard Worker }
279*663afb9bSAndroid Build Coastguard Worker
280*663afb9bSAndroid Build Coastguard Worker static int evrpc_pause_request(void *vbase, void *ctx,
281*663afb9bSAndroid Build Coastguard Worker void (*cb)(void *, enum EVRPC_HOOK_RESULT));
282*663afb9bSAndroid Build Coastguard Worker static void evrpc_request_cb_closure(void *, enum EVRPC_HOOK_RESULT);
283*663afb9bSAndroid Build Coastguard Worker
284*663afb9bSAndroid Build Coastguard Worker static void
evrpc_request_cb(struct evhttp_request * req,void * arg)285*663afb9bSAndroid Build Coastguard Worker evrpc_request_cb(struct evhttp_request *req, void *arg)
286*663afb9bSAndroid Build Coastguard Worker {
287*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc = arg;
288*663afb9bSAndroid Build Coastguard Worker struct evrpc_req_generic *rpc_state = NULL;
289*663afb9bSAndroid Build Coastguard Worker
290*663afb9bSAndroid Build Coastguard Worker /* let's verify the outside parameters */
291*663afb9bSAndroid Build Coastguard Worker if (req->type != EVHTTP_REQ_POST ||
292*663afb9bSAndroid Build Coastguard Worker evbuffer_get_length(req->input_buffer) <= 0)
293*663afb9bSAndroid Build Coastguard Worker goto error;
294*663afb9bSAndroid Build Coastguard Worker
295*663afb9bSAndroid Build Coastguard Worker rpc_state = mm_calloc(1, sizeof(struct evrpc_req_generic));
296*663afb9bSAndroid Build Coastguard Worker if (rpc_state == NULL)
297*663afb9bSAndroid Build Coastguard Worker goto error;
298*663afb9bSAndroid Build Coastguard Worker rpc_state->rpc = rpc;
299*663afb9bSAndroid Build Coastguard Worker rpc_state->http_req = req;
300*663afb9bSAndroid Build Coastguard Worker rpc_state->rpc_data = NULL;
301*663afb9bSAndroid Build Coastguard Worker
302*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&rpc->base->input_hooks) != NULL) {
303*663afb9bSAndroid Build Coastguard Worker int hook_res;
304*663afb9bSAndroid Build Coastguard Worker
305*663afb9bSAndroid Build Coastguard Worker evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
306*663afb9bSAndroid Build Coastguard Worker
307*663afb9bSAndroid Build Coastguard Worker /*
308*663afb9bSAndroid Build Coastguard Worker * allow hooks to modify the outgoing request
309*663afb9bSAndroid Build Coastguard Worker */
310*663afb9bSAndroid Build Coastguard Worker hook_res = evrpc_process_hooks(&rpc->base->input_hooks,
311*663afb9bSAndroid Build Coastguard Worker rpc_state, req, req->input_buffer);
312*663afb9bSAndroid Build Coastguard Worker switch (hook_res) {
313*663afb9bSAndroid Build Coastguard Worker case EVRPC_TERMINATE:
314*663afb9bSAndroid Build Coastguard Worker goto error;
315*663afb9bSAndroid Build Coastguard Worker case EVRPC_PAUSE:
316*663afb9bSAndroid Build Coastguard Worker evrpc_pause_request(rpc->base, rpc_state,
317*663afb9bSAndroid Build Coastguard Worker evrpc_request_cb_closure);
318*663afb9bSAndroid Build Coastguard Worker return;
319*663afb9bSAndroid Build Coastguard Worker case EVRPC_CONTINUE:
320*663afb9bSAndroid Build Coastguard Worker break;
321*663afb9bSAndroid Build Coastguard Worker default:
322*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
323*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_CONTINUE ||
324*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_PAUSE);
325*663afb9bSAndroid Build Coastguard Worker }
326*663afb9bSAndroid Build Coastguard Worker }
327*663afb9bSAndroid Build Coastguard Worker
328*663afb9bSAndroid Build Coastguard Worker evrpc_request_cb_closure(rpc_state, EVRPC_CONTINUE);
329*663afb9bSAndroid Build Coastguard Worker return;
330*663afb9bSAndroid Build Coastguard Worker
331*663afb9bSAndroid Build Coastguard Worker error:
332*663afb9bSAndroid Build Coastguard Worker if (rpc_state)
333*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(rpc_state);
334*663afb9bSAndroid Build Coastguard Worker evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
335*663afb9bSAndroid Build Coastguard Worker return;
336*663afb9bSAndroid Build Coastguard Worker }
337*663afb9bSAndroid Build Coastguard Worker
338*663afb9bSAndroid Build Coastguard Worker static void
evrpc_request_cb_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)339*663afb9bSAndroid Build Coastguard Worker evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
340*663afb9bSAndroid Build Coastguard Worker {
341*663afb9bSAndroid Build Coastguard Worker struct evrpc_req_generic *rpc_state = arg;
342*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc;
343*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req;
344*663afb9bSAndroid Build Coastguard Worker
345*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(rpc_state);
346*663afb9bSAndroid Build Coastguard Worker rpc = rpc_state->rpc;
347*663afb9bSAndroid Build Coastguard Worker req = rpc_state->http_req;
348*663afb9bSAndroid Build Coastguard Worker
349*663afb9bSAndroid Build Coastguard Worker if (hook_res == EVRPC_TERMINATE)
350*663afb9bSAndroid Build Coastguard Worker goto error;
351*663afb9bSAndroid Build Coastguard Worker
352*663afb9bSAndroid Build Coastguard Worker /* let's check that we can parse the request */
353*663afb9bSAndroid Build Coastguard Worker rpc_state->request = rpc->request_new(rpc->request_new_arg);
354*663afb9bSAndroid Build Coastguard Worker if (rpc_state->request == NULL)
355*663afb9bSAndroid Build Coastguard Worker goto error;
356*663afb9bSAndroid Build Coastguard Worker
357*663afb9bSAndroid Build Coastguard Worker if (rpc->request_unmarshal(
358*663afb9bSAndroid Build Coastguard Worker rpc_state->request, req->input_buffer) == -1) {
359*663afb9bSAndroid Build Coastguard Worker /* we failed to parse the request; that's a bummer */
360*663afb9bSAndroid Build Coastguard Worker goto error;
361*663afb9bSAndroid Build Coastguard Worker }
362*663afb9bSAndroid Build Coastguard Worker
363*663afb9bSAndroid Build Coastguard Worker /* at this point, we have a well formed request, prepare the reply */
364*663afb9bSAndroid Build Coastguard Worker
365*663afb9bSAndroid Build Coastguard Worker rpc_state->reply = rpc->reply_new(rpc->reply_new_arg);
366*663afb9bSAndroid Build Coastguard Worker if (rpc_state->reply == NULL)
367*663afb9bSAndroid Build Coastguard Worker goto error;
368*663afb9bSAndroid Build Coastguard Worker
369*663afb9bSAndroid Build Coastguard Worker /* give the rpc to the user; they can deal with it */
370*663afb9bSAndroid Build Coastguard Worker rpc->cb(rpc_state, rpc->cb_arg);
371*663afb9bSAndroid Build Coastguard Worker
372*663afb9bSAndroid Build Coastguard Worker return;
373*663afb9bSAndroid Build Coastguard Worker
374*663afb9bSAndroid Build Coastguard Worker error:
375*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(rpc_state);
376*663afb9bSAndroid Build Coastguard Worker evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
377*663afb9bSAndroid Build Coastguard Worker return;
378*663afb9bSAndroid Build Coastguard Worker }
379*663afb9bSAndroid Build Coastguard Worker
380*663afb9bSAndroid Build Coastguard Worker
381*663afb9bSAndroid Build Coastguard Worker void
evrpc_reqstate_free_(struct evrpc_req_generic * rpc_state)382*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state)
383*663afb9bSAndroid Build Coastguard Worker {
384*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc;
385*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(rpc_state != NULL);
386*663afb9bSAndroid Build Coastguard Worker rpc = rpc_state->rpc;
387*663afb9bSAndroid Build Coastguard Worker
388*663afb9bSAndroid Build Coastguard Worker /* clean up all memory */
389*663afb9bSAndroid Build Coastguard Worker if (rpc_state->hook_meta != NULL)
390*663afb9bSAndroid Build Coastguard Worker evrpc_hook_context_free_(rpc_state->hook_meta);
391*663afb9bSAndroid Build Coastguard Worker if (rpc_state->request != NULL)
392*663afb9bSAndroid Build Coastguard Worker rpc->request_free(rpc_state->request);
393*663afb9bSAndroid Build Coastguard Worker if (rpc_state->reply != NULL)
394*663afb9bSAndroid Build Coastguard Worker rpc->reply_free(rpc_state->reply);
395*663afb9bSAndroid Build Coastguard Worker if (rpc_state->rpc_data != NULL)
396*663afb9bSAndroid Build Coastguard Worker evbuffer_free(rpc_state->rpc_data);
397*663afb9bSAndroid Build Coastguard Worker mm_free(rpc_state);
398*663afb9bSAndroid Build Coastguard Worker }
399*663afb9bSAndroid Build Coastguard Worker
400*663afb9bSAndroid Build Coastguard Worker static void
401*663afb9bSAndroid Build Coastguard Worker evrpc_request_done_closure(void *, enum EVRPC_HOOK_RESULT);
402*663afb9bSAndroid Build Coastguard Worker
403*663afb9bSAndroid Build Coastguard Worker void
evrpc_request_done(struct evrpc_req_generic * rpc_state)404*663afb9bSAndroid Build Coastguard Worker evrpc_request_done(struct evrpc_req_generic *rpc_state)
405*663afb9bSAndroid Build Coastguard Worker {
406*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req;
407*663afb9bSAndroid Build Coastguard Worker struct evrpc *rpc;
408*663afb9bSAndroid Build Coastguard Worker
409*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(rpc_state);
410*663afb9bSAndroid Build Coastguard Worker
411*663afb9bSAndroid Build Coastguard Worker req = rpc_state->http_req;
412*663afb9bSAndroid Build Coastguard Worker rpc = rpc_state->rpc;
413*663afb9bSAndroid Build Coastguard Worker
414*663afb9bSAndroid Build Coastguard Worker if (rpc->reply_complete(rpc_state->reply) == -1) {
415*663afb9bSAndroid Build Coastguard Worker /* the reply was not completely filled in. error out */
416*663afb9bSAndroid Build Coastguard Worker goto error;
417*663afb9bSAndroid Build Coastguard Worker }
418*663afb9bSAndroid Build Coastguard Worker
419*663afb9bSAndroid Build Coastguard Worker if ((rpc_state->rpc_data = evbuffer_new()) == NULL) {
420*663afb9bSAndroid Build Coastguard Worker /* out of memory */
421*663afb9bSAndroid Build Coastguard Worker goto error;
422*663afb9bSAndroid Build Coastguard Worker }
423*663afb9bSAndroid Build Coastguard Worker
424*663afb9bSAndroid Build Coastguard Worker /* serialize the reply */
425*663afb9bSAndroid Build Coastguard Worker rpc->reply_marshal(rpc_state->rpc_data, rpc_state->reply);
426*663afb9bSAndroid Build Coastguard Worker
427*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&rpc->base->output_hooks) != NULL) {
428*663afb9bSAndroid Build Coastguard Worker int hook_res;
429*663afb9bSAndroid Build Coastguard Worker
430*663afb9bSAndroid Build Coastguard Worker evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
431*663afb9bSAndroid Build Coastguard Worker
432*663afb9bSAndroid Build Coastguard Worker /* do hook based tweaks to the request */
433*663afb9bSAndroid Build Coastguard Worker hook_res = evrpc_process_hooks(&rpc->base->output_hooks,
434*663afb9bSAndroid Build Coastguard Worker rpc_state, req, rpc_state->rpc_data);
435*663afb9bSAndroid Build Coastguard Worker switch (hook_res) {
436*663afb9bSAndroid Build Coastguard Worker case EVRPC_TERMINATE:
437*663afb9bSAndroid Build Coastguard Worker goto error;
438*663afb9bSAndroid Build Coastguard Worker case EVRPC_PAUSE:
439*663afb9bSAndroid Build Coastguard Worker if (evrpc_pause_request(rpc->base, rpc_state,
440*663afb9bSAndroid Build Coastguard Worker evrpc_request_done_closure) == -1)
441*663afb9bSAndroid Build Coastguard Worker goto error;
442*663afb9bSAndroid Build Coastguard Worker return;
443*663afb9bSAndroid Build Coastguard Worker case EVRPC_CONTINUE:
444*663afb9bSAndroid Build Coastguard Worker break;
445*663afb9bSAndroid Build Coastguard Worker default:
446*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
447*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_CONTINUE ||
448*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_PAUSE);
449*663afb9bSAndroid Build Coastguard Worker }
450*663afb9bSAndroid Build Coastguard Worker }
451*663afb9bSAndroid Build Coastguard Worker
452*663afb9bSAndroid Build Coastguard Worker evrpc_request_done_closure(rpc_state, EVRPC_CONTINUE);
453*663afb9bSAndroid Build Coastguard Worker return;
454*663afb9bSAndroid Build Coastguard Worker
455*663afb9bSAndroid Build Coastguard Worker error:
456*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(rpc_state);
457*663afb9bSAndroid Build Coastguard Worker evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
458*663afb9bSAndroid Build Coastguard Worker return;
459*663afb9bSAndroid Build Coastguard Worker }
460*663afb9bSAndroid Build Coastguard Worker
461*663afb9bSAndroid Build Coastguard Worker void *
evrpc_get_request(struct evrpc_req_generic * req)462*663afb9bSAndroid Build Coastguard Worker evrpc_get_request(struct evrpc_req_generic *req)
463*663afb9bSAndroid Build Coastguard Worker {
464*663afb9bSAndroid Build Coastguard Worker return req->request;
465*663afb9bSAndroid Build Coastguard Worker }
466*663afb9bSAndroid Build Coastguard Worker
467*663afb9bSAndroid Build Coastguard Worker void *
evrpc_get_reply(struct evrpc_req_generic * req)468*663afb9bSAndroid Build Coastguard Worker evrpc_get_reply(struct evrpc_req_generic *req)
469*663afb9bSAndroid Build Coastguard Worker {
470*663afb9bSAndroid Build Coastguard Worker return req->reply;
471*663afb9bSAndroid Build Coastguard Worker }
472*663afb9bSAndroid Build Coastguard Worker
473*663afb9bSAndroid Build Coastguard Worker static void
evrpc_request_done_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)474*663afb9bSAndroid Build Coastguard Worker evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
475*663afb9bSAndroid Build Coastguard Worker {
476*663afb9bSAndroid Build Coastguard Worker struct evrpc_req_generic *rpc_state = arg;
477*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req;
478*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(rpc_state);
479*663afb9bSAndroid Build Coastguard Worker req = rpc_state->http_req;
480*663afb9bSAndroid Build Coastguard Worker
481*663afb9bSAndroid Build Coastguard Worker if (hook_res == EVRPC_TERMINATE)
482*663afb9bSAndroid Build Coastguard Worker goto error;
483*663afb9bSAndroid Build Coastguard Worker
484*663afb9bSAndroid Build Coastguard Worker /* on success, we are going to transmit marshaled binary data */
485*663afb9bSAndroid Build Coastguard Worker if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
486*663afb9bSAndroid Build Coastguard Worker evhttp_add_header(req->output_headers,
487*663afb9bSAndroid Build Coastguard Worker "Content-Type", "application/octet-stream");
488*663afb9bSAndroid Build Coastguard Worker }
489*663afb9bSAndroid Build Coastguard Worker evhttp_send_reply(req, HTTP_OK, "OK", rpc_state->rpc_data);
490*663afb9bSAndroid Build Coastguard Worker
491*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(rpc_state);
492*663afb9bSAndroid Build Coastguard Worker
493*663afb9bSAndroid Build Coastguard Worker return;
494*663afb9bSAndroid Build Coastguard Worker
495*663afb9bSAndroid Build Coastguard Worker error:
496*663afb9bSAndroid Build Coastguard Worker evrpc_reqstate_free_(rpc_state);
497*663afb9bSAndroid Build Coastguard Worker evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
498*663afb9bSAndroid Build Coastguard Worker return;
499*663afb9bSAndroid Build Coastguard Worker }
500*663afb9bSAndroid Build Coastguard Worker
501*663afb9bSAndroid Build Coastguard Worker
502*663afb9bSAndroid Build Coastguard Worker /* Client implementation of RPC site */
503*663afb9bSAndroid Build Coastguard Worker
504*663afb9bSAndroid Build Coastguard Worker static int evrpc_schedule_request(struct evhttp_connection *connection,
505*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx);
506*663afb9bSAndroid Build Coastguard Worker
507*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *
evrpc_pool_new(struct event_base * base)508*663afb9bSAndroid Build Coastguard Worker evrpc_pool_new(struct event_base *base)
509*663afb9bSAndroid Build Coastguard Worker {
510*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = mm_calloc(1, sizeof(struct evrpc_pool));
511*663afb9bSAndroid Build Coastguard Worker if (pool == NULL)
512*663afb9bSAndroid Build Coastguard Worker return (NULL);
513*663afb9bSAndroid Build Coastguard Worker
514*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&pool->connections);
515*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&pool->requests);
516*663afb9bSAndroid Build Coastguard Worker
517*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&pool->paused_requests);
518*663afb9bSAndroid Build Coastguard Worker
519*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&pool->input_hooks);
520*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&pool->output_hooks);
521*663afb9bSAndroid Build Coastguard Worker
522*663afb9bSAndroid Build Coastguard Worker pool->base = base;
523*663afb9bSAndroid Build Coastguard Worker pool->timeout = -1;
524*663afb9bSAndroid Build Coastguard Worker
525*663afb9bSAndroid Build Coastguard Worker return (pool);
526*663afb9bSAndroid Build Coastguard Worker }
527*663afb9bSAndroid Build Coastguard Worker
528*663afb9bSAndroid Build Coastguard Worker static void
evrpc_request_wrapper_free(struct evrpc_request_wrapper * request)529*663afb9bSAndroid Build Coastguard Worker evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
530*663afb9bSAndroid Build Coastguard Worker {
531*663afb9bSAndroid Build Coastguard Worker if (request->hook_meta != NULL)
532*663afb9bSAndroid Build Coastguard Worker evrpc_hook_context_free_(request->hook_meta);
533*663afb9bSAndroid Build Coastguard Worker mm_free(request->name);
534*663afb9bSAndroid Build Coastguard Worker mm_free(request);
535*663afb9bSAndroid Build Coastguard Worker }
536*663afb9bSAndroid Build Coastguard Worker
537*663afb9bSAndroid Build Coastguard Worker void
evrpc_pool_free(struct evrpc_pool * pool)538*663afb9bSAndroid Build Coastguard Worker evrpc_pool_free(struct evrpc_pool *pool)
539*663afb9bSAndroid Build Coastguard Worker {
540*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *connection;
541*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *request;
542*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_ctx *pause;
543*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook *hook;
544*663afb9bSAndroid Build Coastguard Worker int r;
545*663afb9bSAndroid Build Coastguard Worker
546*663afb9bSAndroid Build Coastguard Worker while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
547*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->requests, request, next);
548*663afb9bSAndroid Build Coastguard Worker evrpc_request_wrapper_free(request);
549*663afb9bSAndroid Build Coastguard Worker }
550*663afb9bSAndroid Build Coastguard Worker
551*663afb9bSAndroid Build Coastguard Worker while ((pause = TAILQ_FIRST(&pool->paused_requests)) != NULL) {
552*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->paused_requests, pause, next);
553*663afb9bSAndroid Build Coastguard Worker mm_free(pause);
554*663afb9bSAndroid Build Coastguard Worker }
555*663afb9bSAndroid Build Coastguard Worker
556*663afb9bSAndroid Build Coastguard Worker while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
557*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->connections, connection, next);
558*663afb9bSAndroid Build Coastguard Worker evhttp_connection_free(connection);
559*663afb9bSAndroid Build Coastguard Worker }
560*663afb9bSAndroid Build Coastguard Worker
561*663afb9bSAndroid Build Coastguard Worker while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
562*663afb9bSAndroid Build Coastguard Worker r = evrpc_remove_hook(pool, EVRPC_INPUT, hook);
563*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r);
564*663afb9bSAndroid Build Coastguard Worker }
565*663afb9bSAndroid Build Coastguard Worker
566*663afb9bSAndroid Build Coastguard Worker while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
567*663afb9bSAndroid Build Coastguard Worker r = evrpc_remove_hook(pool, EVRPC_OUTPUT, hook);
568*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(r);
569*663afb9bSAndroid Build Coastguard Worker }
570*663afb9bSAndroid Build Coastguard Worker
571*663afb9bSAndroid Build Coastguard Worker mm_free(pool);
572*663afb9bSAndroid Build Coastguard Worker }
573*663afb9bSAndroid Build Coastguard Worker
574*663afb9bSAndroid Build Coastguard Worker /*
575*663afb9bSAndroid Build Coastguard Worker * Add a connection to the RPC pool. A request scheduled on the pool
576*663afb9bSAndroid Build Coastguard Worker * may use any available connection.
577*663afb9bSAndroid Build Coastguard Worker */
578*663afb9bSAndroid Build Coastguard Worker
579*663afb9bSAndroid Build Coastguard Worker void
evrpc_pool_add_connection(struct evrpc_pool * pool,struct evhttp_connection * connection)580*663afb9bSAndroid Build Coastguard Worker evrpc_pool_add_connection(struct evrpc_pool *pool,
581*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *connection)
582*663afb9bSAndroid Build Coastguard Worker {
583*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(connection->http_server == NULL);
584*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(&pool->connections, connection, next);
585*663afb9bSAndroid Build Coastguard Worker
586*663afb9bSAndroid Build Coastguard Worker /*
587*663afb9bSAndroid Build Coastguard Worker * associate an event base with this connection
588*663afb9bSAndroid Build Coastguard Worker */
589*663afb9bSAndroid Build Coastguard Worker if (pool->base != NULL)
590*663afb9bSAndroid Build Coastguard Worker evhttp_connection_set_base(connection, pool->base);
591*663afb9bSAndroid Build Coastguard Worker
592*663afb9bSAndroid Build Coastguard Worker /*
593*663afb9bSAndroid Build Coastguard Worker * unless a timeout was specifically set for a connection,
594*663afb9bSAndroid Build Coastguard Worker * the connection inherits the timeout from the pool.
595*663afb9bSAndroid Build Coastguard Worker */
596*663afb9bSAndroid Build Coastguard Worker if (!evutil_timerisset(&connection->timeout))
597*663afb9bSAndroid Build Coastguard Worker evhttp_connection_set_timeout(connection, pool->timeout);
598*663afb9bSAndroid Build Coastguard Worker
599*663afb9bSAndroid Build Coastguard Worker /*
600*663afb9bSAndroid Build Coastguard Worker * if we have any requests pending, schedule them with the new
601*663afb9bSAndroid Build Coastguard Worker * connections.
602*663afb9bSAndroid Build Coastguard Worker */
603*663afb9bSAndroid Build Coastguard Worker
604*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&pool->requests) != NULL) {
605*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *request =
606*663afb9bSAndroid Build Coastguard Worker TAILQ_FIRST(&pool->requests);
607*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->requests, request, next);
608*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request(connection, request);
609*663afb9bSAndroid Build Coastguard Worker }
610*663afb9bSAndroid Build Coastguard Worker }
611*663afb9bSAndroid Build Coastguard Worker
612*663afb9bSAndroid Build Coastguard Worker void
evrpc_pool_remove_connection(struct evrpc_pool * pool,struct evhttp_connection * connection)613*663afb9bSAndroid Build Coastguard Worker evrpc_pool_remove_connection(struct evrpc_pool *pool,
614*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *connection)
615*663afb9bSAndroid Build Coastguard Worker {
616*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->connections, connection, next);
617*663afb9bSAndroid Build Coastguard Worker }
618*663afb9bSAndroid Build Coastguard Worker
619*663afb9bSAndroid Build Coastguard Worker void
evrpc_pool_set_timeout(struct evrpc_pool * pool,int timeout_in_secs)620*663afb9bSAndroid Build Coastguard Worker evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
621*663afb9bSAndroid Build Coastguard Worker {
622*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *evcon;
623*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(evcon, &pool->connections, next) {
624*663afb9bSAndroid Build Coastguard Worker evhttp_connection_set_timeout(evcon, timeout_in_secs);
625*663afb9bSAndroid Build Coastguard Worker }
626*663afb9bSAndroid Build Coastguard Worker pool->timeout = timeout_in_secs;
627*663afb9bSAndroid Build Coastguard Worker }
628*663afb9bSAndroid Build Coastguard Worker
629*663afb9bSAndroid Build Coastguard Worker
630*663afb9bSAndroid Build Coastguard Worker static void evrpc_reply_done(struct evhttp_request *, void *);
631*663afb9bSAndroid Build Coastguard Worker static void evrpc_request_timeout(evutil_socket_t, short, void *);
632*663afb9bSAndroid Build Coastguard Worker
633*663afb9bSAndroid Build Coastguard Worker /*
634*663afb9bSAndroid Build Coastguard Worker * Finds a connection object associated with the pool that is currently
635*663afb9bSAndroid Build Coastguard Worker * idle and can be used to make a request.
636*663afb9bSAndroid Build Coastguard Worker */
637*663afb9bSAndroid Build Coastguard Worker static struct evhttp_connection *
evrpc_pool_find_connection(struct evrpc_pool * pool)638*663afb9bSAndroid Build Coastguard Worker evrpc_pool_find_connection(struct evrpc_pool *pool)
639*663afb9bSAndroid Build Coastguard Worker {
640*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *connection;
641*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(connection, &pool->connections, next) {
642*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&connection->requests) == NULL)
643*663afb9bSAndroid Build Coastguard Worker return (connection);
644*663afb9bSAndroid Build Coastguard Worker }
645*663afb9bSAndroid Build Coastguard Worker
646*663afb9bSAndroid Build Coastguard Worker return (NULL);
647*663afb9bSAndroid Build Coastguard Worker }
648*663afb9bSAndroid Build Coastguard Worker
649*663afb9bSAndroid Build Coastguard Worker /*
650*663afb9bSAndroid Build Coastguard Worker * Prototypes responsible for evrpc scheduling and hooking
651*663afb9bSAndroid Build Coastguard Worker */
652*663afb9bSAndroid Build Coastguard Worker
653*663afb9bSAndroid Build Coastguard Worker static void evrpc_schedule_request_closure(void *ctx, enum EVRPC_HOOK_RESULT);
654*663afb9bSAndroid Build Coastguard Worker
655*663afb9bSAndroid Build Coastguard Worker /*
656*663afb9bSAndroid Build Coastguard Worker * We assume that the ctx is no longer queued on the pool.
657*663afb9bSAndroid Build Coastguard Worker */
658*663afb9bSAndroid Build Coastguard Worker static int
evrpc_schedule_request(struct evhttp_connection * connection,struct evrpc_request_wrapper * ctx)659*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request(struct evhttp_connection *connection,
660*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx)
661*663afb9bSAndroid Build Coastguard Worker {
662*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req = NULL;
663*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = ctx->pool;
664*663afb9bSAndroid Build Coastguard Worker struct evrpc_status status;
665*663afb9bSAndroid Build Coastguard Worker
666*663afb9bSAndroid Build Coastguard Worker if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
667*663afb9bSAndroid Build Coastguard Worker goto error;
668*663afb9bSAndroid Build Coastguard Worker
669*663afb9bSAndroid Build Coastguard Worker /* serialize the request data into the output buffer */
670*663afb9bSAndroid Build Coastguard Worker ctx->request_marshal(req->output_buffer, ctx->request);
671*663afb9bSAndroid Build Coastguard Worker
672*663afb9bSAndroid Build Coastguard Worker /* we need to know the connection that we might have to abort */
673*663afb9bSAndroid Build Coastguard Worker ctx->evcon = connection;
674*663afb9bSAndroid Build Coastguard Worker
675*663afb9bSAndroid Build Coastguard Worker /* if we get paused we also need to know the request */
676*663afb9bSAndroid Build Coastguard Worker ctx->req = req;
677*663afb9bSAndroid Build Coastguard Worker
678*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&pool->output_hooks) != NULL) {
679*663afb9bSAndroid Build Coastguard Worker int hook_res;
680*663afb9bSAndroid Build Coastguard Worker
681*663afb9bSAndroid Build Coastguard Worker evrpc_hook_associate_meta_(&ctx->hook_meta, connection);
682*663afb9bSAndroid Build Coastguard Worker
683*663afb9bSAndroid Build Coastguard Worker /* apply hooks to the outgoing request */
684*663afb9bSAndroid Build Coastguard Worker hook_res = evrpc_process_hooks(&pool->output_hooks,
685*663afb9bSAndroid Build Coastguard Worker ctx, req, req->output_buffer);
686*663afb9bSAndroid Build Coastguard Worker
687*663afb9bSAndroid Build Coastguard Worker switch (hook_res) {
688*663afb9bSAndroid Build Coastguard Worker case EVRPC_TERMINATE:
689*663afb9bSAndroid Build Coastguard Worker goto error;
690*663afb9bSAndroid Build Coastguard Worker case EVRPC_PAUSE:
691*663afb9bSAndroid Build Coastguard Worker /* we need to be explicitly resumed */
692*663afb9bSAndroid Build Coastguard Worker if (evrpc_pause_request(pool, ctx,
693*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request_closure) == -1)
694*663afb9bSAndroid Build Coastguard Worker goto error;
695*663afb9bSAndroid Build Coastguard Worker return (0);
696*663afb9bSAndroid Build Coastguard Worker case EVRPC_CONTINUE:
697*663afb9bSAndroid Build Coastguard Worker /* we can just continue */
698*663afb9bSAndroid Build Coastguard Worker break;
699*663afb9bSAndroid Build Coastguard Worker default:
700*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
701*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_CONTINUE ||
702*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_PAUSE);
703*663afb9bSAndroid Build Coastguard Worker }
704*663afb9bSAndroid Build Coastguard Worker }
705*663afb9bSAndroid Build Coastguard Worker
706*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request_closure(ctx, EVRPC_CONTINUE);
707*663afb9bSAndroid Build Coastguard Worker return (0);
708*663afb9bSAndroid Build Coastguard Worker
709*663afb9bSAndroid Build Coastguard Worker error:
710*663afb9bSAndroid Build Coastguard Worker memset(&status, 0, sizeof(status));
711*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_UNSTARTED;
712*663afb9bSAndroid Build Coastguard Worker (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
713*663afb9bSAndroid Build Coastguard Worker evrpc_request_wrapper_free(ctx);
714*663afb9bSAndroid Build Coastguard Worker return (-1);
715*663afb9bSAndroid Build Coastguard Worker }
716*663afb9bSAndroid Build Coastguard Worker
717*663afb9bSAndroid Build Coastguard Worker static void
evrpc_schedule_request_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)718*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
719*663afb9bSAndroid Build Coastguard Worker {
720*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = arg;
721*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *connection = ctx->evcon;
722*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req = ctx->req;
723*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = ctx->pool;
724*663afb9bSAndroid Build Coastguard Worker struct evrpc_status status;
725*663afb9bSAndroid Build Coastguard Worker char *uri = NULL;
726*663afb9bSAndroid Build Coastguard Worker int res = 0;
727*663afb9bSAndroid Build Coastguard Worker
728*663afb9bSAndroid Build Coastguard Worker if (hook_res == EVRPC_TERMINATE)
729*663afb9bSAndroid Build Coastguard Worker goto error;
730*663afb9bSAndroid Build Coastguard Worker
731*663afb9bSAndroid Build Coastguard Worker uri = evrpc_construct_uri(ctx->name);
732*663afb9bSAndroid Build Coastguard Worker if (uri == NULL)
733*663afb9bSAndroid Build Coastguard Worker goto error;
734*663afb9bSAndroid Build Coastguard Worker
735*663afb9bSAndroid Build Coastguard Worker if (pool->timeout > 0) {
736*663afb9bSAndroid Build Coastguard Worker /*
737*663afb9bSAndroid Build Coastguard Worker * a timeout after which the whole rpc is going to be aborted.
738*663afb9bSAndroid Build Coastguard Worker */
739*663afb9bSAndroid Build Coastguard Worker struct timeval tv;
740*663afb9bSAndroid Build Coastguard Worker evutil_timerclear(&tv);
741*663afb9bSAndroid Build Coastguard Worker tv.tv_sec = pool->timeout;
742*663afb9bSAndroid Build Coastguard Worker evtimer_add(&ctx->ev_timeout, &tv);
743*663afb9bSAndroid Build Coastguard Worker }
744*663afb9bSAndroid Build Coastguard Worker
745*663afb9bSAndroid Build Coastguard Worker /* start the request over the connection */
746*663afb9bSAndroid Build Coastguard Worker res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
747*663afb9bSAndroid Build Coastguard Worker mm_free(uri);
748*663afb9bSAndroid Build Coastguard Worker
749*663afb9bSAndroid Build Coastguard Worker if (res == -1)
750*663afb9bSAndroid Build Coastguard Worker goto error;
751*663afb9bSAndroid Build Coastguard Worker
752*663afb9bSAndroid Build Coastguard Worker return;
753*663afb9bSAndroid Build Coastguard Worker
754*663afb9bSAndroid Build Coastguard Worker error:
755*663afb9bSAndroid Build Coastguard Worker memset(&status, 0, sizeof(status));
756*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_UNSTARTED;
757*663afb9bSAndroid Build Coastguard Worker (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
758*663afb9bSAndroid Build Coastguard Worker evrpc_request_wrapper_free(ctx);
759*663afb9bSAndroid Build Coastguard Worker }
760*663afb9bSAndroid Build Coastguard Worker
761*663afb9bSAndroid Build Coastguard Worker /* we just queue the paused request on the pool under the req object */
762*663afb9bSAndroid Build Coastguard Worker static int
evrpc_pause_request(void * vbase,void * ctx,void (* cb)(void *,enum EVRPC_HOOK_RESULT))763*663afb9bSAndroid Build Coastguard Worker evrpc_pause_request(void *vbase, void *ctx,
764*663afb9bSAndroid Build Coastguard Worker void (*cb)(void *, enum EVRPC_HOOK_RESULT))
765*663afb9bSAndroid Build Coastguard Worker {
766*663afb9bSAndroid Build Coastguard Worker struct evrpc_hooks_ *base = vbase;
767*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_ctx *pause = mm_malloc(sizeof(*pause));
768*663afb9bSAndroid Build Coastguard Worker if (pause == NULL)
769*663afb9bSAndroid Build Coastguard Worker return (-1);
770*663afb9bSAndroid Build Coastguard Worker
771*663afb9bSAndroid Build Coastguard Worker pause->ctx = ctx;
772*663afb9bSAndroid Build Coastguard Worker pause->cb = cb;
773*663afb9bSAndroid Build Coastguard Worker
774*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(&base->pause_requests, pause, next);
775*663afb9bSAndroid Build Coastguard Worker return (0);
776*663afb9bSAndroid Build Coastguard Worker }
777*663afb9bSAndroid Build Coastguard Worker
778*663afb9bSAndroid Build Coastguard Worker int
evrpc_resume_request(void * vbase,void * ctx,enum EVRPC_HOOK_RESULT res)779*663afb9bSAndroid Build Coastguard Worker evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res)
780*663afb9bSAndroid Build Coastguard Worker {
781*663afb9bSAndroid Build Coastguard Worker struct evrpc_hooks_ *base = vbase;
782*663afb9bSAndroid Build Coastguard Worker struct evrpc_pause_list *head = &base->pause_requests;
783*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_ctx *pause;
784*663afb9bSAndroid Build Coastguard Worker
785*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(pause, head, next) {
786*663afb9bSAndroid Build Coastguard Worker if (pause->ctx == ctx)
787*663afb9bSAndroid Build Coastguard Worker break;
788*663afb9bSAndroid Build Coastguard Worker }
789*663afb9bSAndroid Build Coastguard Worker
790*663afb9bSAndroid Build Coastguard Worker if (pause == NULL)
791*663afb9bSAndroid Build Coastguard Worker return (-1);
792*663afb9bSAndroid Build Coastguard Worker
793*663afb9bSAndroid Build Coastguard Worker (*pause->cb)(pause->ctx, res);
794*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(head, pause, next);
795*663afb9bSAndroid Build Coastguard Worker mm_free(pause);
796*663afb9bSAndroid Build Coastguard Worker return (0);
797*663afb9bSAndroid Build Coastguard Worker }
798*663afb9bSAndroid Build Coastguard Worker
799*663afb9bSAndroid Build Coastguard Worker int
evrpc_make_request(struct evrpc_request_wrapper * ctx)800*663afb9bSAndroid Build Coastguard Worker evrpc_make_request(struct evrpc_request_wrapper *ctx)
801*663afb9bSAndroid Build Coastguard Worker {
802*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = ctx->pool;
803*663afb9bSAndroid Build Coastguard Worker
804*663afb9bSAndroid Build Coastguard Worker /* initialize the event structure for this rpc */
805*663afb9bSAndroid Build Coastguard Worker evtimer_assign(&ctx->ev_timeout, pool->base, evrpc_request_timeout, ctx);
806*663afb9bSAndroid Build Coastguard Worker
807*663afb9bSAndroid Build Coastguard Worker /* we better have some available connections on the pool */
808*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(TAILQ_FIRST(&pool->connections) != NULL);
809*663afb9bSAndroid Build Coastguard Worker
810*663afb9bSAndroid Build Coastguard Worker /*
811*663afb9bSAndroid Build Coastguard Worker * if no connection is available, we queue the request on the pool,
812*663afb9bSAndroid Build Coastguard Worker * the next time a connection is empty, the rpc will be send on that.
813*663afb9bSAndroid Build Coastguard Worker */
814*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
815*663afb9bSAndroid Build Coastguard Worker
816*663afb9bSAndroid Build Coastguard Worker evrpc_pool_schedule(pool);
817*663afb9bSAndroid Build Coastguard Worker
818*663afb9bSAndroid Build Coastguard Worker return (0);
819*663afb9bSAndroid Build Coastguard Worker }
820*663afb9bSAndroid Build Coastguard Worker
821*663afb9bSAndroid Build Coastguard Worker
822*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *
evrpc_make_request_ctx(struct evrpc_pool * pool,void * request,void * reply,const char * rpcname,void (* req_marshal)(struct evbuffer *,void *),void (* rpl_clear)(void *),int (* rpl_unmarshal)(void *,struct evbuffer *),void (* cb)(struct evrpc_status *,void *,void *,void *),void * cbarg)823*663afb9bSAndroid Build Coastguard Worker evrpc_make_request_ctx(
824*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool, void *request, void *reply,
825*663afb9bSAndroid Build Coastguard Worker const char *rpcname,
826*663afb9bSAndroid Build Coastguard Worker void (*req_marshal)(struct evbuffer*, void *),
827*663afb9bSAndroid Build Coastguard Worker void (*rpl_clear)(void *),
828*663afb9bSAndroid Build Coastguard Worker int (*rpl_unmarshal)(void *, struct evbuffer *),
829*663afb9bSAndroid Build Coastguard Worker void (*cb)(struct evrpc_status *, void *, void *, void *),
830*663afb9bSAndroid Build Coastguard Worker void *cbarg)
831*663afb9bSAndroid Build Coastguard Worker {
832*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *)
833*663afb9bSAndroid Build Coastguard Worker mm_malloc(sizeof(struct evrpc_request_wrapper));
834*663afb9bSAndroid Build Coastguard Worker if (ctx == NULL)
835*663afb9bSAndroid Build Coastguard Worker return (NULL);
836*663afb9bSAndroid Build Coastguard Worker
837*663afb9bSAndroid Build Coastguard Worker ctx->pool = pool;
838*663afb9bSAndroid Build Coastguard Worker ctx->hook_meta = NULL;
839*663afb9bSAndroid Build Coastguard Worker ctx->evcon = NULL;
840*663afb9bSAndroid Build Coastguard Worker ctx->name = mm_strdup(rpcname);
841*663afb9bSAndroid Build Coastguard Worker if (ctx->name == NULL) {
842*663afb9bSAndroid Build Coastguard Worker mm_free(ctx);
843*663afb9bSAndroid Build Coastguard Worker return (NULL);
844*663afb9bSAndroid Build Coastguard Worker }
845*663afb9bSAndroid Build Coastguard Worker ctx->cb = cb;
846*663afb9bSAndroid Build Coastguard Worker ctx->cb_arg = cbarg;
847*663afb9bSAndroid Build Coastguard Worker ctx->request = request;
848*663afb9bSAndroid Build Coastguard Worker ctx->reply = reply;
849*663afb9bSAndroid Build Coastguard Worker ctx->request_marshal = req_marshal;
850*663afb9bSAndroid Build Coastguard Worker ctx->reply_clear = rpl_clear;
851*663afb9bSAndroid Build Coastguard Worker ctx->reply_unmarshal = rpl_unmarshal;
852*663afb9bSAndroid Build Coastguard Worker
853*663afb9bSAndroid Build Coastguard Worker return (ctx);
854*663afb9bSAndroid Build Coastguard Worker }
855*663afb9bSAndroid Build Coastguard Worker
856*663afb9bSAndroid Build Coastguard Worker static void
857*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT);
858*663afb9bSAndroid Build Coastguard Worker
859*663afb9bSAndroid Build Coastguard Worker static void
evrpc_reply_done(struct evhttp_request * req,void * arg)860*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done(struct evhttp_request *req, void *arg)
861*663afb9bSAndroid Build Coastguard Worker {
862*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = arg;
863*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = ctx->pool;
864*663afb9bSAndroid Build Coastguard Worker int hook_res = EVRPC_CONTINUE;
865*663afb9bSAndroid Build Coastguard Worker
866*663afb9bSAndroid Build Coastguard Worker /* cancel any timeout we might have scheduled */
867*663afb9bSAndroid Build Coastguard Worker event_del(&ctx->ev_timeout);
868*663afb9bSAndroid Build Coastguard Worker
869*663afb9bSAndroid Build Coastguard Worker ctx->req = req;
870*663afb9bSAndroid Build Coastguard Worker
871*663afb9bSAndroid Build Coastguard Worker /* we need to get the reply now */
872*663afb9bSAndroid Build Coastguard Worker if (req == NULL) {
873*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done_closure(ctx, EVRPC_CONTINUE);
874*663afb9bSAndroid Build Coastguard Worker return;
875*663afb9bSAndroid Build Coastguard Worker }
876*663afb9bSAndroid Build Coastguard Worker
877*663afb9bSAndroid Build Coastguard Worker if (TAILQ_FIRST(&pool->input_hooks) != NULL) {
878*663afb9bSAndroid Build Coastguard Worker evrpc_hook_associate_meta_(&ctx->hook_meta, ctx->evcon);
879*663afb9bSAndroid Build Coastguard Worker
880*663afb9bSAndroid Build Coastguard Worker /* apply hooks to the incoming request */
881*663afb9bSAndroid Build Coastguard Worker hook_res = evrpc_process_hooks(&pool->input_hooks,
882*663afb9bSAndroid Build Coastguard Worker ctx, req, req->input_buffer);
883*663afb9bSAndroid Build Coastguard Worker
884*663afb9bSAndroid Build Coastguard Worker switch (hook_res) {
885*663afb9bSAndroid Build Coastguard Worker case EVRPC_TERMINATE:
886*663afb9bSAndroid Build Coastguard Worker case EVRPC_CONTINUE:
887*663afb9bSAndroid Build Coastguard Worker break;
888*663afb9bSAndroid Build Coastguard Worker case EVRPC_PAUSE:
889*663afb9bSAndroid Build Coastguard Worker /*
890*663afb9bSAndroid Build Coastguard Worker * if we get paused we also need to know the
891*663afb9bSAndroid Build Coastguard Worker * request. unfortunately, the underlying
892*663afb9bSAndroid Build Coastguard Worker * layer is going to free it. we need to
893*663afb9bSAndroid Build Coastguard Worker * request ownership explicitly
894*663afb9bSAndroid Build Coastguard Worker */
895*663afb9bSAndroid Build Coastguard Worker evhttp_request_own(req);
896*663afb9bSAndroid Build Coastguard Worker
897*663afb9bSAndroid Build Coastguard Worker evrpc_pause_request(pool, ctx,
898*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done_closure);
899*663afb9bSAndroid Build Coastguard Worker return;
900*663afb9bSAndroid Build Coastguard Worker default:
901*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
902*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_CONTINUE ||
903*663afb9bSAndroid Build Coastguard Worker hook_res == EVRPC_PAUSE);
904*663afb9bSAndroid Build Coastguard Worker }
905*663afb9bSAndroid Build Coastguard Worker }
906*663afb9bSAndroid Build Coastguard Worker
907*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done_closure(ctx, hook_res);
908*663afb9bSAndroid Build Coastguard Worker
909*663afb9bSAndroid Build Coastguard Worker /* http request is being freed by underlying layer */
910*663afb9bSAndroid Build Coastguard Worker }
911*663afb9bSAndroid Build Coastguard Worker
912*663afb9bSAndroid Build Coastguard Worker static void
evrpc_reply_done_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)913*663afb9bSAndroid Build Coastguard Worker evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
914*663afb9bSAndroid Build Coastguard Worker {
915*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = arg;
916*663afb9bSAndroid Build Coastguard Worker struct evhttp_request *req = ctx->req;
917*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool = ctx->pool;
918*663afb9bSAndroid Build Coastguard Worker struct evrpc_status status;
919*663afb9bSAndroid Build Coastguard Worker int res = -1;
920*663afb9bSAndroid Build Coastguard Worker
921*663afb9bSAndroid Build Coastguard Worker memset(&status, 0, sizeof(status));
922*663afb9bSAndroid Build Coastguard Worker status.http_req = req;
923*663afb9bSAndroid Build Coastguard Worker
924*663afb9bSAndroid Build Coastguard Worker /* we need to get the reply now */
925*663afb9bSAndroid Build Coastguard Worker if (req == NULL) {
926*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_TIMEOUT;
927*663afb9bSAndroid Build Coastguard Worker } else if (hook_res == EVRPC_TERMINATE) {
928*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_HOOKABORTED;
929*663afb9bSAndroid Build Coastguard Worker } else {
930*663afb9bSAndroid Build Coastguard Worker res = ctx->reply_unmarshal(ctx->reply, req->input_buffer);
931*663afb9bSAndroid Build Coastguard Worker if (res == -1)
932*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
933*663afb9bSAndroid Build Coastguard Worker }
934*663afb9bSAndroid Build Coastguard Worker
935*663afb9bSAndroid Build Coastguard Worker if (res == -1) {
936*663afb9bSAndroid Build Coastguard Worker /* clear everything that we might have written previously */
937*663afb9bSAndroid Build Coastguard Worker ctx->reply_clear(ctx->reply);
938*663afb9bSAndroid Build Coastguard Worker }
939*663afb9bSAndroid Build Coastguard Worker
940*663afb9bSAndroid Build Coastguard Worker (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
941*663afb9bSAndroid Build Coastguard Worker
942*663afb9bSAndroid Build Coastguard Worker evrpc_request_wrapper_free(ctx);
943*663afb9bSAndroid Build Coastguard Worker
944*663afb9bSAndroid Build Coastguard Worker /* the http layer owned the original request structure, but if we
945*663afb9bSAndroid Build Coastguard Worker * got paused, we asked for ownership and need to free it here. */
946*663afb9bSAndroid Build Coastguard Worker if (req != NULL && evhttp_request_is_owned(req))
947*663afb9bSAndroid Build Coastguard Worker evhttp_request_free(req);
948*663afb9bSAndroid Build Coastguard Worker
949*663afb9bSAndroid Build Coastguard Worker /* see if we can schedule another request */
950*663afb9bSAndroid Build Coastguard Worker evrpc_pool_schedule(pool);
951*663afb9bSAndroid Build Coastguard Worker }
952*663afb9bSAndroid Build Coastguard Worker
953*663afb9bSAndroid Build Coastguard Worker static void
evrpc_pool_schedule(struct evrpc_pool * pool)954*663afb9bSAndroid Build Coastguard Worker evrpc_pool_schedule(struct evrpc_pool *pool)
955*663afb9bSAndroid Build Coastguard Worker {
956*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
957*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *evcon;
958*663afb9bSAndroid Build Coastguard Worker
959*663afb9bSAndroid Build Coastguard Worker /* if no requests are pending, we have no work */
960*663afb9bSAndroid Build Coastguard Worker if (ctx == NULL)
961*663afb9bSAndroid Build Coastguard Worker return;
962*663afb9bSAndroid Build Coastguard Worker
963*663afb9bSAndroid Build Coastguard Worker if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
964*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(&pool->requests, ctx, next);
965*663afb9bSAndroid Build Coastguard Worker evrpc_schedule_request(evcon, ctx);
966*663afb9bSAndroid Build Coastguard Worker }
967*663afb9bSAndroid Build Coastguard Worker }
968*663afb9bSAndroid Build Coastguard Worker
969*663afb9bSAndroid Build Coastguard Worker static void
evrpc_request_timeout(evutil_socket_t fd,short what,void * arg)970*663afb9bSAndroid Build Coastguard Worker evrpc_request_timeout(evutil_socket_t fd, short what, void *arg)
971*663afb9bSAndroid Build Coastguard Worker {
972*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx = arg;
973*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *evcon = ctx->evcon;
974*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(evcon != NULL);
975*663afb9bSAndroid Build Coastguard Worker
976*663afb9bSAndroid Build Coastguard Worker evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
977*663afb9bSAndroid Build Coastguard Worker }
978*663afb9bSAndroid Build Coastguard Worker
979*663afb9bSAndroid Build Coastguard Worker /*
980*663afb9bSAndroid Build Coastguard Worker * frees potential meta data associated with a request.
981*663afb9bSAndroid Build Coastguard Worker */
982*663afb9bSAndroid Build Coastguard Worker
983*663afb9bSAndroid Build Coastguard Worker static void
evrpc_meta_data_free(struct evrpc_meta_list * meta_data)984*663afb9bSAndroid Build Coastguard Worker evrpc_meta_data_free(struct evrpc_meta_list *meta_data)
985*663afb9bSAndroid Build Coastguard Worker {
986*663afb9bSAndroid Build Coastguard Worker struct evrpc_meta *entry;
987*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(meta_data != NULL);
988*663afb9bSAndroid Build Coastguard Worker
989*663afb9bSAndroid Build Coastguard Worker while ((entry = TAILQ_FIRST(meta_data)) != NULL) {
990*663afb9bSAndroid Build Coastguard Worker TAILQ_REMOVE(meta_data, entry, next);
991*663afb9bSAndroid Build Coastguard Worker mm_free(entry->key);
992*663afb9bSAndroid Build Coastguard Worker mm_free(entry->data);
993*663afb9bSAndroid Build Coastguard Worker mm_free(entry);
994*663afb9bSAndroid Build Coastguard Worker }
995*663afb9bSAndroid Build Coastguard Worker }
996*663afb9bSAndroid Build Coastguard Worker
997*663afb9bSAndroid Build Coastguard Worker static struct evrpc_hook_meta *
evrpc_hook_meta_new_(void)998*663afb9bSAndroid Build Coastguard Worker evrpc_hook_meta_new_(void)
999*663afb9bSAndroid Build Coastguard Worker {
1000*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_meta *ctx;
1001*663afb9bSAndroid Build Coastguard Worker ctx = mm_malloc(sizeof(struct evrpc_hook_meta));
1002*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(ctx != NULL);
1003*663afb9bSAndroid Build Coastguard Worker
1004*663afb9bSAndroid Build Coastguard Worker TAILQ_INIT(&ctx->meta_data);
1005*663afb9bSAndroid Build Coastguard Worker ctx->evcon = NULL;
1006*663afb9bSAndroid Build Coastguard Worker
1007*663afb9bSAndroid Build Coastguard Worker return (ctx);
1008*663afb9bSAndroid Build Coastguard Worker }
1009*663afb9bSAndroid Build Coastguard Worker
1010*663afb9bSAndroid Build Coastguard Worker static void
evrpc_hook_associate_meta_(struct evrpc_hook_meta ** pctx,struct evhttp_connection * evcon)1011*663afb9bSAndroid Build Coastguard Worker evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
1012*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *evcon)
1013*663afb9bSAndroid Build Coastguard Worker {
1014*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_meta *ctx = *pctx;
1015*663afb9bSAndroid Build Coastguard Worker if (ctx == NULL)
1016*663afb9bSAndroid Build Coastguard Worker *pctx = ctx = evrpc_hook_meta_new_();
1017*663afb9bSAndroid Build Coastguard Worker ctx->evcon = evcon;
1018*663afb9bSAndroid Build Coastguard Worker }
1019*663afb9bSAndroid Build Coastguard Worker
1020*663afb9bSAndroid Build Coastguard Worker static void
evrpc_hook_context_free_(struct evrpc_hook_meta * ctx)1021*663afb9bSAndroid Build Coastguard Worker evrpc_hook_context_free_(struct evrpc_hook_meta *ctx)
1022*663afb9bSAndroid Build Coastguard Worker {
1023*663afb9bSAndroid Build Coastguard Worker evrpc_meta_data_free(&ctx->meta_data);
1024*663afb9bSAndroid Build Coastguard Worker mm_free(ctx);
1025*663afb9bSAndroid Build Coastguard Worker }
1026*663afb9bSAndroid Build Coastguard Worker
1027*663afb9bSAndroid Build Coastguard Worker /* Adds meta data */
1028*663afb9bSAndroid Build Coastguard Worker void
evrpc_hook_add_meta(void * ctx,const char * key,const void * data,size_t data_size)1029*663afb9bSAndroid Build Coastguard Worker evrpc_hook_add_meta(void *ctx, const char *key,
1030*663afb9bSAndroid Build Coastguard Worker const void *data, size_t data_size)
1031*663afb9bSAndroid Build Coastguard Worker {
1032*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *req = ctx;
1033*663afb9bSAndroid Build Coastguard Worker struct evrpc_hook_meta *store = NULL;
1034*663afb9bSAndroid Build Coastguard Worker struct evrpc_meta *meta = NULL;
1035*663afb9bSAndroid Build Coastguard Worker
1036*663afb9bSAndroid Build Coastguard Worker if ((store = req->hook_meta) == NULL)
1037*663afb9bSAndroid Build Coastguard Worker store = req->hook_meta = evrpc_hook_meta_new_();
1038*663afb9bSAndroid Build Coastguard Worker
1039*663afb9bSAndroid Build Coastguard Worker meta = mm_malloc(sizeof(struct evrpc_meta));
1040*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(meta != NULL);
1041*663afb9bSAndroid Build Coastguard Worker meta->key = mm_strdup(key);
1042*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(meta->key != NULL);
1043*663afb9bSAndroid Build Coastguard Worker meta->data_size = data_size;
1044*663afb9bSAndroid Build Coastguard Worker meta->data = mm_malloc(data_size);
1045*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(meta->data != NULL);
1046*663afb9bSAndroid Build Coastguard Worker memcpy(meta->data, data, data_size);
1047*663afb9bSAndroid Build Coastguard Worker
1048*663afb9bSAndroid Build Coastguard Worker TAILQ_INSERT_TAIL(&store->meta_data, meta, next);
1049*663afb9bSAndroid Build Coastguard Worker }
1050*663afb9bSAndroid Build Coastguard Worker
1051*663afb9bSAndroid Build Coastguard Worker int
evrpc_hook_find_meta(void * ctx,const char * key,void ** data,size_t * data_size)1052*663afb9bSAndroid Build Coastguard Worker evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size)
1053*663afb9bSAndroid Build Coastguard Worker {
1054*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *req = ctx;
1055*663afb9bSAndroid Build Coastguard Worker struct evrpc_meta *meta = NULL;
1056*663afb9bSAndroid Build Coastguard Worker
1057*663afb9bSAndroid Build Coastguard Worker if (req->hook_meta == NULL)
1058*663afb9bSAndroid Build Coastguard Worker return (-1);
1059*663afb9bSAndroid Build Coastguard Worker
1060*663afb9bSAndroid Build Coastguard Worker TAILQ_FOREACH(meta, &req->hook_meta->meta_data, next) {
1061*663afb9bSAndroid Build Coastguard Worker if (strcmp(meta->key, key) == 0) {
1062*663afb9bSAndroid Build Coastguard Worker *data = meta->data;
1063*663afb9bSAndroid Build Coastguard Worker *data_size = meta->data_size;
1064*663afb9bSAndroid Build Coastguard Worker return (0);
1065*663afb9bSAndroid Build Coastguard Worker }
1066*663afb9bSAndroid Build Coastguard Worker }
1067*663afb9bSAndroid Build Coastguard Worker
1068*663afb9bSAndroid Build Coastguard Worker return (-1);
1069*663afb9bSAndroid Build Coastguard Worker }
1070*663afb9bSAndroid Build Coastguard Worker
1071*663afb9bSAndroid Build Coastguard Worker struct evhttp_connection *
evrpc_hook_get_connection(void * ctx)1072*663afb9bSAndroid Build Coastguard Worker evrpc_hook_get_connection(void *ctx)
1073*663afb9bSAndroid Build Coastguard Worker {
1074*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *req = ctx;
1075*663afb9bSAndroid Build Coastguard Worker return (req->hook_meta != NULL ? req->hook_meta->evcon : NULL);
1076*663afb9bSAndroid Build Coastguard Worker }
1077*663afb9bSAndroid Build Coastguard Worker
1078*663afb9bSAndroid Build Coastguard Worker int
evrpc_send_request_generic(struct evrpc_pool * pool,void * request,void * reply,void (* cb)(struct evrpc_status *,void *,void *,void *),void * cb_arg,const char * rpcname,void (* req_marshal)(struct evbuffer *,void *),void (* rpl_clear)(void *),int (* rpl_unmarshal)(void *,struct evbuffer *))1079*663afb9bSAndroid Build Coastguard Worker evrpc_send_request_generic(struct evrpc_pool *pool,
1080*663afb9bSAndroid Build Coastguard Worker void *request, void *reply,
1081*663afb9bSAndroid Build Coastguard Worker void (*cb)(struct evrpc_status *, void *, void *, void *),
1082*663afb9bSAndroid Build Coastguard Worker void *cb_arg,
1083*663afb9bSAndroid Build Coastguard Worker const char *rpcname,
1084*663afb9bSAndroid Build Coastguard Worker void (*req_marshal)(struct evbuffer *, void *),
1085*663afb9bSAndroid Build Coastguard Worker void (*rpl_clear)(void *),
1086*663afb9bSAndroid Build Coastguard Worker int (*rpl_unmarshal)(void *, struct evbuffer *))
1087*663afb9bSAndroid Build Coastguard Worker {
1088*663afb9bSAndroid Build Coastguard Worker struct evrpc_status status;
1089*663afb9bSAndroid Build Coastguard Worker struct evrpc_request_wrapper *ctx;
1090*663afb9bSAndroid Build Coastguard Worker ctx = evrpc_make_request_ctx(pool, request, reply,
1091*663afb9bSAndroid Build Coastguard Worker rpcname, req_marshal, rpl_clear, rpl_unmarshal, cb, cb_arg);
1092*663afb9bSAndroid Build Coastguard Worker if (ctx == NULL)
1093*663afb9bSAndroid Build Coastguard Worker goto error;
1094*663afb9bSAndroid Build Coastguard Worker return (evrpc_make_request(ctx));
1095*663afb9bSAndroid Build Coastguard Worker error:
1096*663afb9bSAndroid Build Coastguard Worker memset(&status, 0, sizeof(status));
1097*663afb9bSAndroid Build Coastguard Worker status.error = EVRPC_STATUS_ERR_UNSTARTED;
1098*663afb9bSAndroid Build Coastguard Worker (*(cb))(&status, request, reply, cb_arg);
1099*663afb9bSAndroid Build Coastguard Worker return (-1);
1100*663afb9bSAndroid Build Coastguard Worker }
1101*663afb9bSAndroid Build Coastguard Worker
1102*663afb9bSAndroid Build Coastguard Worker /** Takes a request object and fills it in with the right magic */
1103*663afb9bSAndroid Build Coastguard Worker static struct evrpc *
evrpc_register_object(const char * name,void * (* req_new)(void *),void * req_new_arg,void (* req_free)(void *),int (* req_unmarshal)(void *,struct evbuffer *),void * (* rpl_new)(void *),void * rpl_new_arg,void (* rpl_free)(void *),int (* rpl_complete)(void *),void (* rpl_marshal)(struct evbuffer *,void *))1104*663afb9bSAndroid Build Coastguard Worker evrpc_register_object(const char *name,
1105*663afb9bSAndroid Build Coastguard Worker void *(*req_new)(void*), void *req_new_arg, void (*req_free)(void *),
1106*663afb9bSAndroid Build Coastguard Worker int (*req_unmarshal)(void *, struct evbuffer *),
1107*663afb9bSAndroid Build Coastguard Worker void *(*rpl_new)(void*), void *rpl_new_arg, void (*rpl_free)(void *),
1108*663afb9bSAndroid Build Coastguard Worker int (*rpl_complete)(void *),
1109*663afb9bSAndroid Build Coastguard Worker void (*rpl_marshal)(struct evbuffer *, void *))
1110*663afb9bSAndroid Build Coastguard Worker {
1111*663afb9bSAndroid Build Coastguard Worker struct evrpc* rpc = (struct evrpc *)mm_calloc(1, sizeof(struct evrpc));
1112*663afb9bSAndroid Build Coastguard Worker if (rpc == NULL)
1113*663afb9bSAndroid Build Coastguard Worker return (NULL);
1114*663afb9bSAndroid Build Coastguard Worker rpc->uri = mm_strdup(name);
1115*663afb9bSAndroid Build Coastguard Worker if (rpc->uri == NULL) {
1116*663afb9bSAndroid Build Coastguard Worker mm_free(rpc);
1117*663afb9bSAndroid Build Coastguard Worker return (NULL);
1118*663afb9bSAndroid Build Coastguard Worker }
1119*663afb9bSAndroid Build Coastguard Worker rpc->request_new = req_new;
1120*663afb9bSAndroid Build Coastguard Worker rpc->request_new_arg = req_new_arg;
1121*663afb9bSAndroid Build Coastguard Worker rpc->request_free = req_free;
1122*663afb9bSAndroid Build Coastguard Worker rpc->request_unmarshal = req_unmarshal;
1123*663afb9bSAndroid Build Coastguard Worker rpc->reply_new = rpl_new;
1124*663afb9bSAndroid Build Coastguard Worker rpc->reply_new_arg = rpl_new_arg;
1125*663afb9bSAndroid Build Coastguard Worker rpc->reply_free = rpl_free;
1126*663afb9bSAndroid Build Coastguard Worker rpc->reply_complete = rpl_complete;
1127*663afb9bSAndroid Build Coastguard Worker rpc->reply_marshal = rpl_marshal;
1128*663afb9bSAndroid Build Coastguard Worker return (rpc);
1129*663afb9bSAndroid Build Coastguard Worker }
1130*663afb9bSAndroid Build Coastguard Worker
1131*663afb9bSAndroid Build Coastguard Worker int
evrpc_register_generic(struct evrpc_base * base,const char * name,void (* callback)(struct evrpc_req_generic *,void *),void * cbarg,void * (* req_new)(void *),void * req_new_arg,void (* req_free)(void *),int (* req_unmarshal)(void *,struct evbuffer *),void * (* rpl_new)(void *),void * rpl_new_arg,void (* rpl_free)(void *),int (* rpl_complete)(void *),void (* rpl_marshal)(struct evbuffer *,void *))1132*663afb9bSAndroid Build Coastguard Worker evrpc_register_generic(struct evrpc_base *base, const char *name,
1133*663afb9bSAndroid Build Coastguard Worker void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
1134*663afb9bSAndroid Build Coastguard Worker void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
1135*663afb9bSAndroid Build Coastguard Worker int (*req_unmarshal)(void *, struct evbuffer *),
1136*663afb9bSAndroid Build Coastguard Worker void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *),
1137*663afb9bSAndroid Build Coastguard Worker int (*rpl_complete)(void *),
1138*663afb9bSAndroid Build Coastguard Worker void (*rpl_marshal)(struct evbuffer *, void *))
1139*663afb9bSAndroid Build Coastguard Worker {
1140*663afb9bSAndroid Build Coastguard Worker struct evrpc* rpc =
1141*663afb9bSAndroid Build Coastguard Worker evrpc_register_object(name, req_new, req_new_arg, req_free, req_unmarshal,
1142*663afb9bSAndroid Build Coastguard Worker rpl_new, rpl_new_arg, rpl_free, rpl_complete, rpl_marshal);
1143*663afb9bSAndroid Build Coastguard Worker if (rpc == NULL)
1144*663afb9bSAndroid Build Coastguard Worker return (-1);
1145*663afb9bSAndroid Build Coastguard Worker evrpc_register_rpc(base, rpc,
1146*663afb9bSAndroid Build Coastguard Worker (void (*)(struct evrpc_req_generic*, void *))callback, cbarg);
1147*663afb9bSAndroid Build Coastguard Worker return (0);
1148*663afb9bSAndroid Build Coastguard Worker }
1149*663afb9bSAndroid Build Coastguard Worker
1150*663afb9bSAndroid Build Coastguard Worker /** accessors for obscure and undocumented functionality */
1151*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *
evrpc_request_get_pool(struct evrpc_request_wrapper * ctx)1152*663afb9bSAndroid Build Coastguard Worker evrpc_request_get_pool(struct evrpc_request_wrapper *ctx)
1153*663afb9bSAndroid Build Coastguard Worker {
1154*663afb9bSAndroid Build Coastguard Worker return (ctx->pool);
1155*663afb9bSAndroid Build Coastguard Worker }
1156*663afb9bSAndroid Build Coastguard Worker
1157*663afb9bSAndroid Build Coastguard Worker void
evrpc_request_set_pool(struct evrpc_request_wrapper * ctx,struct evrpc_pool * pool)1158*663afb9bSAndroid Build Coastguard Worker evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
1159*663afb9bSAndroid Build Coastguard Worker struct evrpc_pool *pool)
1160*663afb9bSAndroid Build Coastguard Worker {
1161*663afb9bSAndroid Build Coastguard Worker ctx->pool = pool;
1162*663afb9bSAndroid Build Coastguard Worker }
1163*663afb9bSAndroid Build Coastguard Worker
1164*663afb9bSAndroid Build Coastguard Worker void
evrpc_request_set_cb(struct evrpc_request_wrapper * ctx,void (* cb)(struct evrpc_status *,void * request,void * reply,void * arg),void * cb_arg)1165*663afb9bSAndroid Build Coastguard Worker evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
1166*663afb9bSAndroid Build Coastguard Worker void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
1167*663afb9bSAndroid Build Coastguard Worker void *cb_arg)
1168*663afb9bSAndroid Build Coastguard Worker {
1169*663afb9bSAndroid Build Coastguard Worker ctx->cb = cb;
1170*663afb9bSAndroid Build Coastguard Worker ctx->cb_arg = cb_arg;
1171*663afb9bSAndroid Build Coastguard Worker }
1172