1f554234fSNiels Provos /*
2b85b710cSNick Mathewson * Copyright (c) 2000-2007 Niels Provos <[email protected]>
3e49e2891SNick Mathewson * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
4f554234fSNiels Provos *
5f554234fSNiels Provos * Redistribution and use in source and binary forms, with or without
6f554234fSNiels Provos * modification, are permitted provided that the following conditions
7f554234fSNiels Provos * are met:
8f554234fSNiels Provos * 1. Redistributions of source code must retain the above copyright
9f554234fSNiels Provos * notice, this list of conditions and the following disclaimer.
10f554234fSNiels Provos * 2. Redistributions in binary form must reproduce the above copyright
11f554234fSNiels Provos * notice, this list of conditions and the following disclaimer in the
12f554234fSNiels Provos * documentation and/or other materials provided with the distribution.
13f554234fSNiels Provos * 3. The name of the author may not be used to endorse or promote products
14f554234fSNiels Provos * derived from this software without specific prior written permission.
15f554234fSNiels Provos *
16f554234fSNiels Provos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f554234fSNiels Provos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f554234fSNiels Provos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f554234fSNiels Provos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f554234fSNiels Provos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21f554234fSNiels Provos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22f554234fSNiels Provos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23f554234fSNiels Provos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24f554234fSNiels Provos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25f554234fSNiels Provos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f554234fSNiels Provos */
27ec347b92SNick Mathewson #include "event2/event-config.h"
280915ca0aSKevin Bowling #include "evconfig-private.h"
29f554234fSNiels Provos
309f560bfaSNick Mathewson #ifdef _WIN32
31f554234fSNiels Provos #define WIN32_LEAN_AND_MEAN
32868f10e7SNiels Provos #include <winsock2.h>
337868ab5aSNick Mathewson #include <windows.h>
34f554234fSNiels Provos #undef WIN32_LEAN_AND_MEAN
35f554234fSNiels Provos #endif
36868f10e7SNiels Provos
37f554234fSNiels Provos #include <sys/types.h>
389f560bfaSNick Mathewson #ifndef _WIN32
39fda1216bSNiels Provos #include <sys/socket.h>
40868f10e7SNiels Provos #endif
4168120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TIME_H
42f554234fSNiels Provos #include <sys/time.h>
43f554234fSNiels Provos #endif
44f554234fSNiels Provos #include <sys/queue.h>
45f554234fSNiels Provos #include <stdio.h>
46f554234fSNiels Provos #include <stdlib.h>
479f560bfaSNick Mathewson #ifndef _WIN32
48f554234fSNiels Provos #include <unistd.h>
49f554234fSNiels Provos #endif
50f554234fSNiels Provos #include <errno.h>
51f554234fSNiels Provos #include <signal.h>
52f554234fSNiels Provos #include <string.h>
53f554234fSNiels Provos
5400ecd1d8SNick Mathewson #include <sys/queue.h>
5500ecd1d8SNick Mathewson
56ae09ac4aSNick Mathewson #include "event2/event.h"
57ae09ac4aSNick Mathewson #include "event2/event_struct.h"
5800ecd1d8SNick Mathewson #include "event2/rpc.h"
5900ecd1d8SNick Mathewson #include "event2/rpc_struct.h"
60f554234fSNiels Provos #include "evrpc-internal.h"
61de1c4392SNiels Provos #include "event2/http.h"
627defe4cbSNick Mathewson #include "event2/buffer.h"
637defe4cbSNick Mathewson #include "event2/tag.h"
64de1c4392SNiels Provos #include "event2/http_struct.h"
65de1c4392SNiels Provos #include "event2/http_compat.h"
66cd731b77SNick Mathewson #include "event2/util.h"
67cd731b77SNick Mathewson #include "util-internal.h"
68169321c9SNick Mathewson #include "log-internal.h"
697eb250e9SNick Mathewson #include "mm-internal.h"
70f554234fSNiels Provos
71f554234fSNiels Provos struct evrpc_base *
evrpc_init(struct evhttp * http_server)72f554234fSNiels Provos evrpc_init(struct evhttp *http_server)
73f554234fSNiels Provos {
7449868b61SNick Mathewson struct evrpc_base* base = mm_calloc(1, sizeof(struct evrpc_base));
75f554234fSNiels Provos if (base == NULL)
76f554234fSNiels Provos return (NULL);
77f554234fSNiels Provos
78c4836d10SNiels Provos /* we rely on the tagging sub system */
79c4836d10SNiels Provos evtag_init();
80c4836d10SNiels Provos
81f554234fSNiels Provos TAILQ_INIT(&base->registered_rpcs);
8265236aa8SNiels Provos TAILQ_INIT(&base->input_hooks);
8365236aa8SNiels Provos TAILQ_INIT(&base->output_hooks);
84819d4a33SNiels Provos
85819d4a33SNiels Provos TAILQ_INIT(&base->paused_requests);
86819d4a33SNiels Provos
87f554234fSNiels Provos base->http_server = http_server;
88f554234fSNiels Provos
89f554234fSNiels Provos return (base);
90f554234fSNiels Provos }
91f554234fSNiels Provos
92c4836d10SNiels Provos void
evrpc_free(struct evrpc_base * base)93c4836d10SNiels Provos evrpc_free(struct evrpc_base *base)
94c4836d10SNiels Provos {
95621a1b29SNiels Provos struct evrpc *rpc;
9665236aa8SNiels Provos struct evrpc_hook *hook;
978c594168SNiels Provos struct evrpc_hook_ctx *pause;
98743f8665SNick Mathewson int r;
99c4836d10SNiels Provos
100621a1b29SNiels Provos while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
101743f8665SNick Mathewson r = evrpc_unregister_rpc(base, rpc->uri);
1024b8f02f1SChristophe Fillot EVUTIL_ASSERT(r == 0);
103621a1b29SNiels Provos }
1048c594168SNiels Provos while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) {
1058c594168SNiels Provos TAILQ_REMOVE(&base->paused_requests, pause, next);
1068c594168SNiels Provos mm_free(pause);
1078c594168SNiels Provos }
10865236aa8SNiels Provos while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
109743f8665SNick Mathewson r = evrpc_remove_hook(base, EVRPC_INPUT, hook);
110743f8665SNick Mathewson EVUTIL_ASSERT(r);
11165236aa8SNiels Provos }
11265236aa8SNiels Provos while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
113743f8665SNick Mathewson r = evrpc_remove_hook(base, EVRPC_OUTPUT, hook);
114743f8665SNick Mathewson EVUTIL_ASSERT(r);
11565236aa8SNiels Provos }
11649868b61SNick Mathewson mm_free(base);
117c4836d10SNiels Provos }
118c4836d10SNiels Provos
11965236aa8SNiels Provos void *
evrpc_add_hook(void * vbase,enum EVRPC_HOOK_TYPE hook_type,int (* cb)(void *,struct evhttp_request *,struct evbuffer *,void *),void * cb_arg)1201d3a008aSNiels Provos evrpc_add_hook(void *vbase,
12165236aa8SNiels Provos enum EVRPC_HOOK_TYPE hook_type,
122819d4a33SNiels Provos int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
12365236aa8SNiels Provos void *cb_arg)
12465236aa8SNiels Provos {
125cb9da0bfSNick Mathewson struct evrpc_hooks_ *base = vbase;
12665236aa8SNiels Provos struct evrpc_hook_list *head = NULL;
12765236aa8SNiels Provos struct evrpc_hook *hook = NULL;
12865236aa8SNiels Provos switch (hook_type) {
1292baaac7fSNick Mathewson case EVRPC_INPUT:
1301d3a008aSNiels Provos head = &base->in_hooks;
13165236aa8SNiels Provos break;
1322baaac7fSNick Mathewson case EVRPC_OUTPUT:
1331d3a008aSNiels Provos head = &base->out_hooks;
13465236aa8SNiels Provos break;
13565236aa8SNiels Provos default:
1362e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
13765236aa8SNiels Provos }
13865236aa8SNiels Provos
13949868b61SNick Mathewson hook = mm_calloc(1, sizeof(struct evrpc_hook));
1402e36dbe1SNick Mathewson EVUTIL_ASSERT(hook != NULL);
14165236aa8SNiels Provos
14265236aa8SNiels Provos hook->process = cb;
14365236aa8SNiels Provos hook->process_arg = cb_arg;
14465236aa8SNiels Provos TAILQ_INSERT_TAIL(head, hook, next);
14565236aa8SNiels Provos
14665236aa8SNiels Provos return (hook);
14765236aa8SNiels Provos }
14865236aa8SNiels Provos
1491d3a008aSNiels Provos static int
evrpc_remove_hook_internal(struct evrpc_hook_list * head,void * handle)1501d3a008aSNiels Provos evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
15165236aa8SNiels Provos {
15265236aa8SNiels Provos struct evrpc_hook *hook = NULL;
15365236aa8SNiels Provos TAILQ_FOREACH(hook, head, next) {
15465236aa8SNiels Provos if (hook == handle) {
15565236aa8SNiels Provos TAILQ_REMOVE(head, hook, next);
15649868b61SNick Mathewson mm_free(hook);
15765236aa8SNiels Provos return (1);
15865236aa8SNiels Provos }
15965236aa8SNiels Provos }
16065236aa8SNiels Provos
16165236aa8SNiels Provos return (0);
16265236aa8SNiels Provos }
16365236aa8SNiels Provos
1641d3a008aSNiels Provos /*
1651d3a008aSNiels Provos * remove the hook specified by the handle
1661d3a008aSNiels Provos */
1671d3a008aSNiels Provos
1681d3a008aSNiels Provos int
evrpc_remove_hook(void * vbase,enum EVRPC_HOOK_TYPE hook_type,void * handle)1691d3a008aSNiels Provos evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
1701d3a008aSNiels Provos {
171cb9da0bfSNick Mathewson struct evrpc_hooks_ *base = vbase;
1721d3a008aSNiels Provos struct evrpc_hook_list *head = NULL;
1731d3a008aSNiels Provos switch (hook_type) {
1742baaac7fSNick Mathewson case EVRPC_INPUT:
1751d3a008aSNiels Provos head = &base->in_hooks;
1761d3a008aSNiels Provos break;
1772baaac7fSNick Mathewson case EVRPC_OUTPUT:
1781d3a008aSNiels Provos head = &base->out_hooks;
1791d3a008aSNiels Provos break;
1801d3a008aSNiels Provos default:
1812e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
1821d3a008aSNiels Provos }
1831d3a008aSNiels Provos
1841d3a008aSNiels Provos return (evrpc_remove_hook_internal(head, handle));
1851d3a008aSNiels Provos }
1861d3a008aSNiels Provos
18765236aa8SNiels Provos static int
evrpc_process_hooks(struct evrpc_hook_list * head,void * ctx,struct evhttp_request * req,struct evbuffer * evbuf)188819d4a33SNiels Provos evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx,
18965236aa8SNiels Provos struct evhttp_request *req, struct evbuffer *evbuf)
19065236aa8SNiels Provos {
19165236aa8SNiels Provos struct evrpc_hook *hook;
19265236aa8SNiels Provos TAILQ_FOREACH(hook, head, next) {
193955c6abfSNiels Provos int res = hook->process(ctx, req, evbuf, hook->process_arg);
194955c6abfSNiels Provos if (res != EVRPC_CONTINUE)
195955c6abfSNiels Provos return (res);
19665236aa8SNiels Provos }
19765236aa8SNiels Provos
198955c6abfSNiels Provos return (EVRPC_CONTINUE);
19965236aa8SNiels Provos }
20065236aa8SNiels Provos
2012d028ef6SNiels Provos static void evrpc_pool_schedule(struct evrpc_pool *pool);
2022d028ef6SNiels Provos static void evrpc_request_cb(struct evhttp_request *, void *);
203f554234fSNiels Provos
204f554234fSNiels Provos /*
205f554234fSNiels Provos * Registers a new RPC with the HTTP server. The evrpc object is expected
206f554234fSNiels Provos * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
207f554234fSNiels Provos * calls this function.
208f554234fSNiels Provos */
209f554234fSNiels Provos
210a3f122d6SNick Mathewson static char *
evrpc_construct_uri(const char * uri)211fda1216bSNiels Provos evrpc_construct_uri(const char *uri)
212f554234fSNiels Provos {
213f554234fSNiels Provos char *constructed_uri;
214545a6114SNick Mathewson size_t constructed_uri_len;
215f554234fSNiels Provos
216fda1216bSNiels Provos constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
21749868b61SNick Mathewson if ((constructed_uri = mm_malloc(constructed_uri_len)) == NULL)
218f554234fSNiels Provos event_err(1, "%s: failed to register rpc at %s",
219fda1216bSNiels Provos __func__, uri);
220f554234fSNiels Provos memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
221fda1216bSNiels Provos memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
222f554234fSNiels Provos constructed_uri[constructed_uri_len - 1] = '\0';
223f554234fSNiels Provos
224fda1216bSNiels Provos return (constructed_uri);
225fda1216bSNiels Provos }
226fda1216bSNiels Provos
227fda1216bSNiels Provos int
evrpc_register_rpc(struct evrpc_base * base,struct evrpc * rpc,void (* cb)(struct evrpc_req_generic *,void *),void * cb_arg)228fda1216bSNiels Provos evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
229fda1216bSNiels Provos void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
230fda1216bSNiels Provos {
231fda1216bSNiels Provos char *constructed_uri = evrpc_construct_uri(rpc->uri);
232fda1216bSNiels Provos
23365236aa8SNiels Provos rpc->base = base;
234fda1216bSNiels Provos rpc->cb = cb;
235fda1216bSNiels Provos rpc->cb_arg = cb_arg;
236fda1216bSNiels Provos
237f554234fSNiels Provos TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
238f554234fSNiels Provos
239f554234fSNiels Provos evhttp_set_cb(base->http_server,
240f554234fSNiels Provos constructed_uri,
241f554234fSNiels Provos evrpc_request_cb,
242f554234fSNiels Provos rpc);
243f554234fSNiels Provos
24449868b61SNick Mathewson mm_free(constructed_uri);
245c4836d10SNiels Provos
246f554234fSNiels Provos return (0);
247f554234fSNiels Provos }
248f554234fSNiels Provos
2490c280824SNiels Provos int
evrpc_unregister_rpc(struct evrpc_base * base,const char * name)2500c280824SNiels Provos evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
2510c280824SNiels Provos {
2520c280824SNiels Provos char *registered_uri = NULL;
2530c280824SNiels Provos struct evrpc *rpc;
254743f8665SNick Mathewson int r;
2550c280824SNiels Provos
2560c280824SNiels Provos /* find the right rpc; linear search might be slow */
2570c280824SNiels Provos TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
2580c280824SNiels Provos if (strcmp(rpc->uri, name) == 0)
2590c280824SNiels Provos break;
2600c280824SNiels Provos }
2610c280824SNiels Provos if (rpc == NULL) {
2620c280824SNiels Provos /* We did not find an RPC with this name */
2630c280824SNiels Provos return (-1);
2640c280824SNiels Provos }
2650c280824SNiels Provos TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
2660c280824SNiels Provos
2670c280824SNiels Provos registered_uri = evrpc_construct_uri(name);
2680c280824SNiels Provos
2690c280824SNiels Provos /* remove the http server callback */
270743f8665SNick Mathewson r = evhttp_del_cb(base->http_server, registered_uri);
271743f8665SNick Mathewson EVUTIL_ASSERT(r == 0);
2720c280824SNiels Provos
27349868b61SNick Mathewson mm_free(registered_uri);
2744b8f02f1SChristophe Fillot
2754b8f02f1SChristophe Fillot mm_free((char *)rpc->uri);
2764b8f02f1SChristophe Fillot mm_free(rpc);
2770c280824SNiels Provos return (0);
2780c280824SNiels Provos }
2790c280824SNiels Provos
280819d4a33SNiels Provos static int evrpc_pause_request(void *vbase, void *ctx,
281819d4a33SNiels Provos void (*cb)(void *, enum EVRPC_HOOK_RESULT));
282819d4a33SNiels Provos static void evrpc_request_cb_closure(void *, enum EVRPC_HOOK_RESULT);
283819d4a33SNiels Provos
2842d028ef6SNiels Provos static void
evrpc_request_cb(struct evhttp_request * req,void * arg)285f554234fSNiels Provos evrpc_request_cb(struct evhttp_request *req, void *arg)
286f554234fSNiels Provos {
287f554234fSNiels Provos struct evrpc *rpc = arg;
288f554234fSNiels Provos struct evrpc_req_generic *rpc_state = NULL;
289f554234fSNiels Provos
290f554234fSNiels Provos /* let's verify the outside parameters */
291f554234fSNiels Provos if (req->type != EVHTTP_REQ_POST ||
292a8f6d961SNick Mathewson evbuffer_get_length(req->input_buffer) <= 0)
293f554234fSNiels Provos goto error;
294f554234fSNiels Provos
29549868b61SNick Mathewson rpc_state = mm_calloc(1, sizeof(struct evrpc_req_generic));
296819d4a33SNiels Provos if (rpc_state == NULL)
297819d4a33SNiels Provos goto error;
298819d4a33SNiels Provos rpc_state->rpc = rpc;
299819d4a33SNiels Provos rpc_state->http_req = req;
300819d4a33SNiels Provos rpc_state->rpc_data = NULL;
301819d4a33SNiels Provos
3022460aa59SNiels Provos if (TAILQ_FIRST(&rpc->base->input_hooks) != NULL) {
3032460aa59SNiels Provos int hook_res;
3042460aa59SNiels Provos
3058ac3c4c2SNick Mathewson evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
306819d4a33SNiels Provos
30765236aa8SNiels Provos /*
3082460aa59SNiels Provos * allow hooks to modify the outgoing request
30965236aa8SNiels Provos */
310819d4a33SNiels Provos hook_res = evrpc_process_hooks(&rpc->base->input_hooks,
311819d4a33SNiels Provos rpc_state, req, req->input_buffer);
312819d4a33SNiels Provos switch (hook_res) {
313819d4a33SNiels Provos case EVRPC_TERMINATE:
31465236aa8SNiels Provos goto error;
315819d4a33SNiels Provos case EVRPC_PAUSE:
316819d4a33SNiels Provos evrpc_pause_request(rpc->base, rpc_state,
317819d4a33SNiels Provos evrpc_request_cb_closure);
318819d4a33SNiels Provos return;
319819d4a33SNiels Provos case EVRPC_CONTINUE:
320819d4a33SNiels Provos break;
321819d4a33SNiels Provos default:
3222e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
3232460aa59SNiels Provos hook_res == EVRPC_CONTINUE ||
3242460aa59SNiels Provos hook_res == EVRPC_PAUSE);
3252460aa59SNiels Provos }
326819d4a33SNiels Provos }
32765236aa8SNiels Provos
328819d4a33SNiels Provos evrpc_request_cb_closure(rpc_state, EVRPC_CONTINUE);
329819d4a33SNiels Provos return;
330819d4a33SNiels Provos
331819d4a33SNiels Provos error:
332*e05136c7SAzat Khuzhin if (rpc_state)
3338ac3c4c2SNick Mathewson evrpc_reqstate_free_(rpc_state);
33439906698SNick Mathewson evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
335819d4a33SNiels Provos return;
336819d4a33SNiels Provos }
337819d4a33SNiels Provos
338819d4a33SNiels Provos static void
evrpc_request_cb_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)339819d4a33SNiels Provos evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
340819d4a33SNiels Provos {
341819d4a33SNiels Provos struct evrpc_req_generic *rpc_state = arg;
3426056d6e0SNick Mathewson struct evrpc *rpc;
3436056d6e0SNick Mathewson struct evhttp_request *req;
3446056d6e0SNick Mathewson
3457c11e51eSHarlan Stenn EVUTIL_ASSERT(rpc_state);
3466056d6e0SNick Mathewson rpc = rpc_state->rpc;
3476056d6e0SNick Mathewson req = rpc_state->http_req;
348819d4a33SNiels Provos
349819d4a33SNiels Provos if (hook_res == EVRPC_TERMINATE)
350f554234fSNiels Provos goto error;
351f554234fSNiels Provos
352f554234fSNiels Provos /* let's check that we can parse the request */
353755fbf16SShuo Chen rpc_state->request = rpc->request_new(rpc->request_new_arg);
354f554234fSNiels Provos if (rpc_state->request == NULL)
355f554234fSNiels Provos goto error;
356c4836d10SNiels Provos
357f554234fSNiels Provos if (rpc->request_unmarshal(
358f554234fSNiels Provos rpc_state->request, req->input_buffer) == -1) {
359f554234fSNiels Provos /* we failed to parse the request; that's a bummer */
360f554234fSNiels Provos goto error;
361f554234fSNiels Provos }
362f554234fSNiels Provos
363f554234fSNiels Provos /* at this point, we have a well formed request, prepare the reply */
364f554234fSNiels Provos
365755fbf16SShuo Chen rpc_state->reply = rpc->reply_new(rpc->reply_new_arg);
366f554234fSNiels Provos if (rpc_state->reply == NULL)
367f554234fSNiels Provos goto error;
368f554234fSNiels Provos
369f554234fSNiels Provos /* give the rpc to the user; they can deal with it */
370f554234fSNiels Provos rpc->cb(rpc_state, rpc->cb_arg);
371f554234fSNiels Provos
372f554234fSNiels Provos return;
373f554234fSNiels Provos
374f554234fSNiels Provos error:
3758ac3c4c2SNick Mathewson evrpc_reqstate_free_(rpc_state);
37639906698SNick Mathewson evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
377f554234fSNiels Provos return;
378f554234fSNiels Provos }
379f554234fSNiels Provos
380819d4a33SNiels Provos
381f554234fSNiels Provos void
evrpc_reqstate_free_(struct evrpc_req_generic * rpc_state)3828ac3c4c2SNick Mathewson evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state)
383f554234fSNiels Provos {
384819d4a33SNiels Provos struct evrpc *rpc;
3852e36dbe1SNick Mathewson EVUTIL_ASSERT(rpc_state != NULL);
386819d4a33SNiels Provos rpc = rpc_state->rpc;
38744bd5ab4SNiels Provos
388819d4a33SNiels Provos /* clean up all memory */
3892460aa59SNiels Provos if (rpc_state->hook_meta != NULL)
3908ac3c4c2SNick Mathewson evrpc_hook_context_free_(rpc_state->hook_meta);
391f554234fSNiels Provos if (rpc_state->request != NULL)
392c4836d10SNiels Provos rpc->request_free(rpc_state->request);
393f554234fSNiels Provos if (rpc_state->reply != NULL)
394f554234fSNiels Provos rpc->reply_free(rpc_state->reply);
395819d4a33SNiels Provos if (rpc_state->rpc_data != NULL)
396819d4a33SNiels Provos evbuffer_free(rpc_state->rpc_data);
39749868b61SNick Mathewson mm_free(rpc_state);
398f554234fSNiels Provos }
399819d4a33SNiels Provos
400819d4a33SNiels Provos static void
401819d4a33SNiels Provos evrpc_request_done_closure(void *, enum EVRPC_HOOK_RESULT);
402f554234fSNiels Provos
403f554234fSNiels Provos void
evrpc_request_done(struct evrpc_req_generic * rpc_state)404f554234fSNiels Provos evrpc_request_done(struct evrpc_req_generic *rpc_state)
405f554234fSNiels Provos {
4067c11e51eSHarlan Stenn struct evhttp_request *req;
4077c11e51eSHarlan Stenn struct evrpc *rpc;
4087c11e51eSHarlan Stenn
4097c11e51eSHarlan Stenn EVUTIL_ASSERT(rpc_state);
4107c11e51eSHarlan Stenn
4117c11e51eSHarlan Stenn req = rpc_state->http_req;
4127c11e51eSHarlan Stenn rpc = rpc_state->rpc;
413f554234fSNiels Provos
414c4836d10SNiels Provos if (rpc->reply_complete(rpc_state->reply) == -1) {
415f554234fSNiels Provos /* the reply was not completely filled in. error out */
416f554234fSNiels Provos goto error;
417f554234fSNiels Provos }
418f554234fSNiels Provos
419819d4a33SNiels Provos if ((rpc_state->rpc_data = evbuffer_new()) == NULL) {
420f554234fSNiels Provos /* out of memory */
421f554234fSNiels Provos goto error;
422f554234fSNiels Provos }
423f554234fSNiels Provos
424f554234fSNiels Provos /* serialize the reply */
425819d4a33SNiels Provos rpc->reply_marshal(rpc_state->rpc_data, rpc_state->reply);
426f554234fSNiels Provos
4272460aa59SNiels Provos if (TAILQ_FIRST(&rpc->base->output_hooks) != NULL) {
4282460aa59SNiels Provos int hook_res;
4292460aa59SNiels Provos
4308ac3c4c2SNick Mathewson evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
4312460aa59SNiels Provos
43265236aa8SNiels Provos /* do hook based tweaks to the request */
433819d4a33SNiels Provos hook_res = evrpc_process_hooks(&rpc->base->output_hooks,
434819d4a33SNiels Provos rpc_state, req, rpc_state->rpc_data);
435819d4a33SNiels Provos switch (hook_res) {
436819d4a33SNiels Provos case EVRPC_TERMINATE:
437819d4a33SNiels Provos goto error;
438819d4a33SNiels Provos case EVRPC_PAUSE:
439819d4a33SNiels Provos if (evrpc_pause_request(rpc->base, rpc_state,
440819d4a33SNiels Provos evrpc_request_done_closure) == -1)
441819d4a33SNiels Provos goto error;
442819d4a33SNiels Provos return;
443819d4a33SNiels Provos case EVRPC_CONTINUE:
444819d4a33SNiels Provos break;
445819d4a33SNiels Provos default:
4462e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
4472460aa59SNiels Provos hook_res == EVRPC_CONTINUE ||
4482460aa59SNiels Provos hook_res == EVRPC_PAUSE);
4492460aa59SNiels Provos }
450819d4a33SNiels Provos }
451819d4a33SNiels Provos
452819d4a33SNiels Provos evrpc_request_done_closure(rpc_state, EVRPC_CONTINUE);
453819d4a33SNiels Provos return;
454819d4a33SNiels Provos
455819d4a33SNiels Provos error:
4568ac3c4c2SNick Mathewson evrpc_reqstate_free_(rpc_state);
45739906698SNick Mathewson evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
458819d4a33SNiels Provos return;
459819d4a33SNiels Provos }
460819d4a33SNiels Provos
46107edf784SShuo Chen void *
evrpc_get_request(struct evrpc_req_generic * req)46207edf784SShuo Chen evrpc_get_request(struct evrpc_req_generic *req)
46307edf784SShuo Chen {
46407edf784SShuo Chen return req->request;
46507edf784SShuo Chen }
46607edf784SShuo Chen
46707edf784SShuo Chen void *
evrpc_get_reply(struct evrpc_req_generic * req)46807edf784SShuo Chen evrpc_get_reply(struct evrpc_req_generic *req)
46907edf784SShuo Chen {
47007edf784SShuo Chen return req->reply;
47107edf784SShuo Chen }
47207edf784SShuo Chen
473819d4a33SNiels Provos static void
evrpc_request_done_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)474819d4a33SNiels Provos evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
475819d4a33SNiels Provos {
476819d4a33SNiels Provos struct evrpc_req_generic *rpc_state = arg;
4776056d6e0SNick Mathewson struct evhttp_request *req;
4787c11e51eSHarlan Stenn EVUTIL_ASSERT(rpc_state);
4796056d6e0SNick Mathewson req = rpc_state->http_req;
480819d4a33SNiels Provos
481819d4a33SNiels Provos if (hook_res == EVRPC_TERMINATE)
48265236aa8SNiels Provos goto error;
48365236aa8SNiels Provos
4848920ac4dSNiels Provos /* on success, we are going to transmit marshaled binary data */
4858920ac4dSNiels Provos if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
4868920ac4dSNiels Provos evhttp_add_header(req->output_headers,
4878920ac4dSNiels Provos "Content-Type", "application/octet-stream");
4888920ac4dSNiels Provos }
489819d4a33SNiels Provos evhttp_send_reply(req, HTTP_OK, "OK", rpc_state->rpc_data);
490f554234fSNiels Provos
4918ac3c4c2SNick Mathewson evrpc_reqstate_free_(rpc_state);
492f554234fSNiels Provos
493f554234fSNiels Provos return;
494f554234fSNiels Provos
495f554234fSNiels Provos error:
4968ac3c4c2SNick Mathewson evrpc_reqstate_free_(rpc_state);
49739906698SNick Mathewson evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
498f554234fSNiels Provos return;
499f554234fSNiels Provos }
500fda1216bSNiels Provos
501819d4a33SNiels Provos
502fda1216bSNiels Provos /* Client implementation of RPC site */
503fda1216bSNiels Provos
504fda1216bSNiels Provos static int evrpc_schedule_request(struct evhttp_connection *connection,
505fda1216bSNiels Provos struct evrpc_request_wrapper *ctx);
506fda1216bSNiels Provos
507fda1216bSNiels Provos struct evrpc_pool *
evrpc_pool_new(struct event_base * base)5081d3a008aSNiels Provos evrpc_pool_new(struct event_base *base)
509fda1216bSNiels Provos {
51049868b61SNick Mathewson struct evrpc_pool *pool = mm_calloc(1, sizeof(struct evrpc_pool));
511fda1216bSNiels Provos if (pool == NULL)
512fda1216bSNiels Provos return (NULL);
513fda1216bSNiels Provos
514fda1216bSNiels Provos TAILQ_INIT(&pool->connections);
515fda1216bSNiels Provos TAILQ_INIT(&pool->requests);
516fda1216bSNiels Provos
517819d4a33SNiels Provos TAILQ_INIT(&pool->paused_requests);
518819d4a33SNiels Provos
5191d3a008aSNiels Provos TAILQ_INIT(&pool->input_hooks);
5201d3a008aSNiels Provos TAILQ_INIT(&pool->output_hooks);
5211d3a008aSNiels Provos
5221d3a008aSNiels Provos pool->base = base;
5232d028ef6SNiels Provos pool->timeout = -1;
5242d028ef6SNiels Provos
525fda1216bSNiels Provos return (pool);
526fda1216bSNiels Provos }
527fda1216bSNiels Provos
528ff43ed5bSNiels Provos static void
evrpc_request_wrapper_free(struct evrpc_request_wrapper * request)529ff43ed5bSNiels Provos evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
530ff43ed5bSNiels Provos {
5312460aa59SNiels Provos if (request->hook_meta != NULL)
5328ac3c4c2SNick Mathewson evrpc_hook_context_free_(request->hook_meta);
53349868b61SNick Mathewson mm_free(request->name);
53449868b61SNick Mathewson mm_free(request);
535ff43ed5bSNiels Provos }
536ff43ed5bSNiels Provos
537fda1216bSNiels Provos void
evrpc_pool_free(struct evrpc_pool * pool)538fda1216bSNiels Provos evrpc_pool_free(struct evrpc_pool *pool)
539fda1216bSNiels Provos {
540fda1216bSNiels Provos struct evhttp_connection *connection;
541fda1216bSNiels Provos struct evrpc_request_wrapper *request;
542819d4a33SNiels Provos struct evrpc_hook_ctx *pause;
5431d3a008aSNiels Provos struct evrpc_hook *hook;
544743f8665SNick Mathewson int r;
545fda1216bSNiels Provos
546fda1216bSNiels Provos while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
547fda1216bSNiels Provos TAILQ_REMOVE(&pool->requests, request, next);
548ff43ed5bSNiels Provos evrpc_request_wrapper_free(request);
549fda1216bSNiels Provos }
550fda1216bSNiels Provos
551819d4a33SNiels Provos while ((pause = TAILQ_FIRST(&pool->paused_requests)) != NULL) {
552819d4a33SNiels Provos TAILQ_REMOVE(&pool->paused_requests, pause, next);
55349868b61SNick Mathewson mm_free(pause);
554819d4a33SNiels Provos }
555819d4a33SNiels Provos
556fda1216bSNiels Provos while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
557fda1216bSNiels Provos TAILQ_REMOVE(&pool->connections, connection, next);
558fda1216bSNiels Provos evhttp_connection_free(connection);
559fda1216bSNiels Provos }
560fda1216bSNiels Provos
5611d3a008aSNiels Provos while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
562743f8665SNick Mathewson r = evrpc_remove_hook(pool, EVRPC_INPUT, hook);
563743f8665SNick Mathewson EVUTIL_ASSERT(r);
5641d3a008aSNiels Provos }
5651d3a008aSNiels Provos
5661d3a008aSNiels Provos while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
567743f8665SNick Mathewson r = evrpc_remove_hook(pool, EVRPC_OUTPUT, hook);
568743f8665SNick Mathewson EVUTIL_ASSERT(r);
5691d3a008aSNiels Provos }
5701d3a008aSNiels Provos
57149868b61SNick Mathewson mm_free(pool);
572fda1216bSNiels Provos }
573fda1216bSNiels Provos
574ff43ed5bSNiels Provos /*
575ff43ed5bSNiels Provos * Add a connection to the RPC pool. A request scheduled on the pool
576ff43ed5bSNiels Provos * may use any available connection.
577ff43ed5bSNiels Provos */
578ff43ed5bSNiels Provos
579fda1216bSNiels Provos void
evrpc_pool_add_connection(struct evrpc_pool * pool,struct evhttp_connection * connection)580fda1216bSNiels Provos evrpc_pool_add_connection(struct evrpc_pool *pool,
58185c4904bSNiels Provos struct evhttp_connection *connection)
58285c4904bSNiels Provos {
5832e36dbe1SNick Mathewson EVUTIL_ASSERT(connection->http_server == NULL);
584fda1216bSNiels Provos TAILQ_INSERT_TAIL(&pool->connections, connection, next);
585fda1216bSNiels Provos
586fda1216bSNiels Provos /*
5871d3a008aSNiels Provos * associate an event base with this connection
5881d3a008aSNiels Provos */
5891d3a008aSNiels Provos if (pool->base != NULL)
5901d3a008aSNiels Provos evhttp_connection_set_base(connection, pool->base);
5911d3a008aSNiels Provos
5921d3a008aSNiels Provos /*
5932d028ef6SNiels Provos * unless a timeout was specifically set for a connection,
5942d028ef6SNiels Provos * the connection inherits the timeout from the pool.
5952d028ef6SNiels Provos */
5966350e6c4SConstantine Verutin if (!evutil_timerisset(&connection->timeout))
5976350e6c4SConstantine Verutin evhttp_connection_set_timeout(connection, pool->timeout);
5982d028ef6SNiels Provos
5992d028ef6SNiels Provos /*
600ff43ed5bSNiels Provos * if we have any requests pending, schedule them with the new
601fda1216bSNiels Provos * connections.
602fda1216bSNiels Provos */
603fda1216bSNiels Provos
604fda1216bSNiels Provos if (TAILQ_FIRST(&pool->requests) != NULL) {
605fda1216bSNiels Provos struct evrpc_request_wrapper *request =
606fda1216bSNiels Provos TAILQ_FIRST(&pool->requests);
607fda1216bSNiels Provos TAILQ_REMOVE(&pool->requests, request, next);
608fda1216bSNiels Provos evrpc_schedule_request(connection, request);
609fda1216bSNiels Provos }
610fda1216bSNiels Provos }
611fda1216bSNiels Provos
6122d028ef6SNiels Provos void
evrpc_pool_remove_connection(struct evrpc_pool * pool,struct evhttp_connection * connection)61385c4904bSNiels Provos evrpc_pool_remove_connection(struct evrpc_pool *pool,
61485c4904bSNiels Provos struct evhttp_connection *connection)
61585c4904bSNiels Provos {
61685c4904bSNiels Provos TAILQ_REMOVE(&pool->connections, connection, next);
61785c4904bSNiels Provos }
61885c4904bSNiels Provos
61985c4904bSNiels Provos void
evrpc_pool_set_timeout(struct evrpc_pool * pool,int timeout_in_secs)6202d028ef6SNiels Provos evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
6212d028ef6SNiels Provos {
6222d028ef6SNiels Provos struct evhttp_connection *evcon;
6232d028ef6SNiels Provos TAILQ_FOREACH(evcon, &pool->connections, next) {
6246350e6c4SConstantine Verutin evhttp_connection_set_timeout(evcon, timeout_in_secs);
6252d028ef6SNiels Provos }
6262d028ef6SNiels Provos pool->timeout = timeout_in_secs;
6272d028ef6SNiels Provos }
6282d028ef6SNiels Provos
629fda1216bSNiels Provos
630fda1216bSNiels Provos static void evrpc_reply_done(struct evhttp_request *, void *);
6311120f04fSNick Mathewson static void evrpc_request_timeout(evutil_socket_t, short, void *);
632fda1216bSNiels Provos
633fda1216bSNiels Provos /*
634fda1216bSNiels Provos * Finds a connection object associated with the pool that is currently
635fda1216bSNiels Provos * idle and can be used to make a request.
636fda1216bSNiels Provos */
637fda1216bSNiels Provos static struct evhttp_connection *
evrpc_pool_find_connection(struct evrpc_pool * pool)638fda1216bSNiels Provos evrpc_pool_find_connection(struct evrpc_pool *pool)
639fda1216bSNiels Provos {
640fda1216bSNiels Provos struct evhttp_connection *connection;
641fda1216bSNiels Provos TAILQ_FOREACH(connection, &pool->connections, next) {
642fda1216bSNiels Provos if (TAILQ_FIRST(&connection->requests) == NULL)
643fda1216bSNiels Provos return (connection);
644fda1216bSNiels Provos }
645fda1216bSNiels Provos
646fda1216bSNiels Provos return (NULL);
647fda1216bSNiels Provos }
648fda1216bSNiels Provos
649fda1216bSNiels Provos /*
650819d4a33SNiels Provos * Prototypes responsible for evrpc scheduling and hooking
651819d4a33SNiels Provos */
652819d4a33SNiels Provos
653819d4a33SNiels Provos static void evrpc_schedule_request_closure(void *ctx, enum EVRPC_HOOK_RESULT);
654819d4a33SNiels Provos
655819d4a33SNiels Provos /*
656fda1216bSNiels Provos * We assume that the ctx is no longer queued on the pool.
657fda1216bSNiels Provos */
658fda1216bSNiels Provos static int
evrpc_schedule_request(struct evhttp_connection * connection,struct evrpc_request_wrapper * ctx)659fda1216bSNiels Provos evrpc_schedule_request(struct evhttp_connection *connection,
660fda1216bSNiels Provos struct evrpc_request_wrapper *ctx)
661fda1216bSNiels Provos {
662ff43ed5bSNiels Provos struct evhttp_request *req = NULL;
6632d028ef6SNiels Provos struct evrpc_pool *pool = ctx->pool;
6643794534fSNiels Provos struct evrpc_status status;
665fda1216bSNiels Provos
666fda1216bSNiels Provos if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
667fda1216bSNiels Provos goto error;
668fda1216bSNiels Provos
669ff43ed5bSNiels Provos /* serialize the request data into the output buffer */
670ff43ed5bSNiels Provos ctx->request_marshal(req->output_buffer, ctx->request);
671ff43ed5bSNiels Provos
6722d028ef6SNiels Provos /* we need to know the connection that we might have to abort */
6732d028ef6SNiels Provos ctx->evcon = connection;
6742d028ef6SNiels Provos
675819d4a33SNiels Provos /* if we get paused we also need to know the request */
676819d4a33SNiels Provos ctx->req = req;
677819d4a33SNiels Provos
6782460aa59SNiels Provos if (TAILQ_FIRST(&pool->output_hooks) != NULL) {
6792460aa59SNiels Provos int hook_res;
6802460aa59SNiels Provos
6818ac3c4c2SNick Mathewson evrpc_hook_associate_meta_(&ctx->hook_meta, connection);
6822460aa59SNiels Provos
6831d3a008aSNiels Provos /* apply hooks to the outgoing request */
684819d4a33SNiels Provos hook_res = evrpc_process_hooks(&pool->output_hooks,
685819d4a33SNiels Provos ctx, req, req->output_buffer);
686819d4a33SNiels Provos
687819d4a33SNiels Provos switch (hook_res) {
688819d4a33SNiels Provos case EVRPC_TERMINATE:
689819d4a33SNiels Provos goto error;
690819d4a33SNiels Provos case EVRPC_PAUSE:
691819d4a33SNiels Provos /* we need to be explicitly resumed */
692819d4a33SNiels Provos if (evrpc_pause_request(pool, ctx,
693819d4a33SNiels Provos evrpc_schedule_request_closure) == -1)
694819d4a33SNiels Provos goto error;
695819d4a33SNiels Provos return (0);
696819d4a33SNiels Provos case EVRPC_CONTINUE:
697819d4a33SNiels Provos /* we can just continue */
698819d4a33SNiels Provos break;
699819d4a33SNiels Provos default:
7002e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
7012460aa59SNiels Provos hook_res == EVRPC_CONTINUE ||
7022460aa59SNiels Provos hook_res == EVRPC_PAUSE);
7032460aa59SNiels Provos }
704819d4a33SNiels Provos }
705819d4a33SNiels Provos
706819d4a33SNiels Provos evrpc_schedule_request_closure(ctx, EVRPC_CONTINUE);
707819d4a33SNiels Provos return (0);
708819d4a33SNiels Provos
709819d4a33SNiels Provos error:
710819d4a33SNiels Provos memset(&status, 0, sizeof(status));
711819d4a33SNiels Provos status.error = EVRPC_STATUS_ERR_UNSTARTED;
712819d4a33SNiels Provos (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
713819d4a33SNiels Provos evrpc_request_wrapper_free(ctx);
714819d4a33SNiels Provos return (-1);
715819d4a33SNiels Provos }
716819d4a33SNiels Provos
717819d4a33SNiels Provos static void
evrpc_schedule_request_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)718819d4a33SNiels Provos evrpc_schedule_request_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
719819d4a33SNiels Provos {
720819d4a33SNiels Provos struct evrpc_request_wrapper *ctx = arg;
721819d4a33SNiels Provos struct evhttp_connection *connection = ctx->evcon;
722819d4a33SNiels Provos struct evhttp_request *req = ctx->req;
723819d4a33SNiels Provos struct evrpc_pool *pool = ctx->pool;
724819d4a33SNiels Provos struct evrpc_status status;
725819d4a33SNiels Provos char *uri = NULL;
726819d4a33SNiels Provos int res = 0;
727819d4a33SNiels Provos
728819d4a33SNiels Provos if (hook_res == EVRPC_TERMINATE)
729819d4a33SNiels Provos goto error;
730819d4a33SNiels Provos
731819d4a33SNiels Provos uri = evrpc_construct_uri(ctx->name);
732819d4a33SNiels Provos if (uri == NULL)
7331d3a008aSNiels Provos goto error;
7341d3a008aSNiels Provos
7352d028ef6SNiels Provos if (pool->timeout > 0) {
7362d028ef6SNiels Provos /*
7372d028ef6SNiels Provos * a timeout after which the whole rpc is going to be aborted.
7382d028ef6SNiels Provos */
7392d028ef6SNiels Provos struct timeval tv;
740f74e7258SNick Mathewson evutil_timerclear(&tv);
7412d028ef6SNiels Provos tv.tv_sec = pool->timeout;
7422d028ef6SNiels Provos evtimer_add(&ctx->ev_timeout, &tv);
7432d028ef6SNiels Provos }
7442d028ef6SNiels Provos
745ff43ed5bSNiels Provos /* start the request over the connection */
746ff43ed5bSNiels Provos res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
74749868b61SNick Mathewson mm_free(uri);
748ff43ed5bSNiels Provos
749ff43ed5bSNiels Provos if (res == -1)
750ff43ed5bSNiels Provos goto error;
751ff43ed5bSNiels Provos
752819d4a33SNiels Provos return;
753fda1216bSNiels Provos
754fda1216bSNiels Provos error:
7553794534fSNiels Provos memset(&status, 0, sizeof(status));
7563794534fSNiels Provos status.error = EVRPC_STATUS_ERR_UNSTARTED;
7573794534fSNiels Provos (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
758ff43ed5bSNiels Provos evrpc_request_wrapper_free(ctx);
759819d4a33SNiels Provos }
760819d4a33SNiels Provos
761819d4a33SNiels Provos /* we just queue the paused request on the pool under the req object */
762819d4a33SNiels Provos static int
evrpc_pause_request(void * vbase,void * ctx,void (* cb)(void *,enum EVRPC_HOOK_RESULT))763819d4a33SNiels Provos evrpc_pause_request(void *vbase, void *ctx,
764819d4a33SNiels Provos void (*cb)(void *, enum EVRPC_HOOK_RESULT))
765819d4a33SNiels Provos {
766cb9da0bfSNick Mathewson struct evrpc_hooks_ *base = vbase;
76749868b61SNick Mathewson struct evrpc_hook_ctx *pause = mm_malloc(sizeof(*pause));
768819d4a33SNiels Provos if (pause == NULL)
769fda1216bSNiels Provos return (-1);
770819d4a33SNiels Provos
771819d4a33SNiels Provos pause->ctx = ctx;
772819d4a33SNiels Provos pause->cb = cb;
773819d4a33SNiels Provos
774819d4a33SNiels Provos TAILQ_INSERT_TAIL(&base->pause_requests, pause, next);
775819d4a33SNiels Provos return (0);
776819d4a33SNiels Provos }
777819d4a33SNiels Provos
778819d4a33SNiels Provos int
evrpc_resume_request(void * vbase,void * ctx,enum EVRPC_HOOK_RESULT res)779819d4a33SNiels Provos evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res)
780819d4a33SNiels Provos {
781cb9da0bfSNick Mathewson struct evrpc_hooks_ *base = vbase;
782819d4a33SNiels Provos struct evrpc_pause_list *head = &base->pause_requests;
783819d4a33SNiels Provos struct evrpc_hook_ctx *pause;
784819d4a33SNiels Provos
785819d4a33SNiels Provos TAILQ_FOREACH(pause, head, next) {
786819d4a33SNiels Provos if (pause->ctx == ctx)
787819d4a33SNiels Provos break;
788819d4a33SNiels Provos }
789819d4a33SNiels Provos
790819d4a33SNiels Provos if (pause == NULL)
791819d4a33SNiels Provos return (-1);
792819d4a33SNiels Provos
793819d4a33SNiels Provos (*pause->cb)(pause->ctx, res);
794819d4a33SNiels Provos TAILQ_REMOVE(head, pause, next);
79594ee1251SNick Mathewson mm_free(pause);
796819d4a33SNiels Provos return (0);
797fda1216bSNiels Provos }
798fda1216bSNiels Provos
799fda1216bSNiels Provos int
evrpc_make_request(struct evrpc_request_wrapper * ctx)800fda1216bSNiels Provos evrpc_make_request(struct evrpc_request_wrapper *ctx)
801fda1216bSNiels Provos {
802fda1216bSNiels Provos struct evrpc_pool *pool = ctx->pool;
8032d028ef6SNiels Provos
8042d028ef6SNiels Provos /* initialize the event structure for this rpc */
8055fbc7f0aSNick Mathewson evtimer_assign(&ctx->ev_timeout, pool->base, evrpc_request_timeout, ctx);
806fda1216bSNiels Provos
807fda1216bSNiels Provos /* we better have some available connections on the pool */
8082e36dbe1SNick Mathewson EVUTIL_ASSERT(TAILQ_FIRST(&pool->connections) != NULL);
809fda1216bSNiels Provos
810fda1216bSNiels Provos /*
811fda1216bSNiels Provos * if no connection is available, we queue the request on the pool,
812fda1216bSNiels Provos * the next time a connection is empty, the rpc will be send on that.
813fda1216bSNiels Provos */
814fda1216bSNiels Provos TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
8152d028ef6SNiels Provos
8162d028ef6SNiels Provos evrpc_pool_schedule(pool);
8172d028ef6SNiels Provos
818fda1216bSNiels Provos return (0);
819fda1216bSNiels Provos }
820fda1216bSNiels Provos
8215a5609c7SNiels Provos
8225a5609c7SNiels Provos 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)823e8f450f2SNiels Provos evrpc_make_request_ctx(
8245a5609c7SNiels Provos struct evrpc_pool *pool, void *request, void *reply,
8255a5609c7SNiels Provos const char *rpcname,
8265a5609c7SNiels Provos void (*req_marshal)(struct evbuffer*, void *),
8275a5609c7SNiels Provos void (*rpl_clear)(void *),
8285a5609c7SNiels Provos int (*rpl_unmarshal)(void *, struct evbuffer *),
8295a5609c7SNiels Provos void (*cb)(struct evrpc_status *, void *, void *, void *),
8305a5609c7SNiels Provos void *cbarg)
8315a5609c7SNiels Provos {
8325a5609c7SNiels Provos struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *)
83349868b61SNick Mathewson mm_malloc(sizeof(struct evrpc_request_wrapper));
8345a5609c7SNiels Provos if (ctx == NULL)
8355a5609c7SNiels Provos return (NULL);
8365a5609c7SNiels Provos
8375a5609c7SNiels Provos ctx->pool = pool;
8382460aa59SNiels Provos ctx->hook_meta = NULL;
8395a5609c7SNiels Provos ctx->evcon = NULL;
84049868b61SNick Mathewson ctx->name = mm_strdup(rpcname);
8415a5609c7SNiels Provos if (ctx->name == NULL) {
84249868b61SNick Mathewson mm_free(ctx);
8435a5609c7SNiels Provos return (NULL);
8445a5609c7SNiels Provos }
8455a5609c7SNiels Provos ctx->cb = cb;
8465a5609c7SNiels Provos ctx->cb_arg = cbarg;
8475a5609c7SNiels Provos ctx->request = request;
8485a5609c7SNiels Provos ctx->reply = reply;
8495a5609c7SNiels Provos ctx->request_marshal = req_marshal;
8505a5609c7SNiels Provos ctx->reply_clear = rpl_clear;
8515a5609c7SNiels Provos ctx->reply_unmarshal = rpl_unmarshal;
8525a5609c7SNiels Provos
8535a5609c7SNiels Provos return (ctx);
8545a5609c7SNiels Provos }
8555a5609c7SNiels Provos
856fda1216bSNiels Provos static void
857819d4a33SNiels Provos evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT);
858819d4a33SNiels Provos
859819d4a33SNiels Provos static void
evrpc_reply_done(struct evhttp_request * req,void * arg)860fda1216bSNiels Provos evrpc_reply_done(struct evhttp_request *req, void *arg)
861fda1216bSNiels Provos {
862fda1216bSNiels Provos struct evrpc_request_wrapper *ctx = arg;
8632d028ef6SNiels Provos struct evrpc_pool *pool = ctx->pool;
8642460aa59SNiels Provos int hook_res = EVRPC_CONTINUE;
8652d028ef6SNiels Provos
8662d028ef6SNiels Provos /* cancel any timeout we might have scheduled */
8672d028ef6SNiels Provos event_del(&ctx->ev_timeout);
868ff43ed5bSNiels Provos
869819d4a33SNiels Provos ctx->req = req;
870819d4a33SNiels Provos
871819d4a33SNiels Provos /* we need to get the reply now */
872819d4a33SNiels Provos if (req == NULL) {
873819d4a33SNiels Provos evrpc_reply_done_closure(ctx, EVRPC_CONTINUE);
874819d4a33SNiels Provos return;
875819d4a33SNiels Provos }
876819d4a33SNiels Provos
8772460aa59SNiels Provos if (TAILQ_FIRST(&pool->input_hooks) != NULL) {
8788ac3c4c2SNick Mathewson evrpc_hook_associate_meta_(&ctx->hook_meta, ctx->evcon);
8792460aa59SNiels Provos
880819d4a33SNiels Provos /* apply hooks to the incoming request */
881819d4a33SNiels Provos hook_res = evrpc_process_hooks(&pool->input_hooks,
882819d4a33SNiels Provos ctx, req, req->input_buffer);
883819d4a33SNiels Provos
884819d4a33SNiels Provos switch (hook_res) {
885819d4a33SNiels Provos case EVRPC_TERMINATE:
886819d4a33SNiels Provos case EVRPC_CONTINUE:
8872460aa59SNiels Provos break;
888819d4a33SNiels Provos case EVRPC_PAUSE:
889955c6abfSNiels Provos /*
8902460aa59SNiels Provos * if we get paused we also need to know the
8912460aa59SNiels Provos * request. unfortunately, the underlying
8922460aa59SNiels Provos * layer is going to free it. we need to
8932460aa59SNiels Provos * request ownership explicitly
894955c6abfSNiels Provos */
895955c6abfSNiels Provos evhttp_request_own(req);
896955c6abfSNiels Provos
8972460aa59SNiels Provos evrpc_pause_request(pool, ctx,
8982460aa59SNiels Provos evrpc_reply_done_closure);
899819d4a33SNiels Provos return;
900819d4a33SNiels Provos default:
9012e36dbe1SNick Mathewson EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
9022460aa59SNiels Provos hook_res == EVRPC_CONTINUE ||
9032460aa59SNiels Provos hook_res == EVRPC_PAUSE);
904819d4a33SNiels Provos }
9052460aa59SNiels Provos }
9062460aa59SNiels Provos
9072460aa59SNiels Provos evrpc_reply_done_closure(ctx, hook_res);
908955c6abfSNiels Provos
909955c6abfSNiels Provos /* http request is being freed by underlying layer */
910819d4a33SNiels Provos }
911819d4a33SNiels Provos
912819d4a33SNiels Provos static void
evrpc_reply_done_closure(void * arg,enum EVRPC_HOOK_RESULT hook_res)913819d4a33SNiels Provos evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
914819d4a33SNiels Provos {
915819d4a33SNiels Provos struct evrpc_request_wrapper *ctx = arg;
916819d4a33SNiels Provos struct evhttp_request *req = ctx->req;
917819d4a33SNiels Provos struct evrpc_pool *pool = ctx->pool;
918819d4a33SNiels Provos struct evrpc_status status;
919819d4a33SNiels Provos int res = -1;
920819d4a33SNiels Provos
9213794534fSNiels Provos memset(&status, 0, sizeof(status));
92265236aa8SNiels Provos status.http_req = req;
92365236aa8SNiels Provos
924ff43ed5bSNiels Provos /* we need to get the reply now */
925819d4a33SNiels Provos if (req == NULL) {
9263794534fSNiels Provos status.error = EVRPC_STATUS_ERR_TIMEOUT;
927819d4a33SNiels Provos } else if (hook_res == EVRPC_TERMINATE) {
928819d4a33SNiels Provos status.error = EVRPC_STATUS_ERR_HOOKABORTED;
929819d4a33SNiels Provos } else {
930819d4a33SNiels Provos res = ctx->reply_unmarshal(ctx->reply, req->input_buffer);
931819d4a33SNiels Provos if (res == -1)
932819d4a33SNiels Provos status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
9333794534fSNiels Provos }
9341d3a008aSNiels Provos
9353794534fSNiels Provos if (res == -1) {
936ff43ed5bSNiels Provos /* clear everything that we might have written previously */
937ff43ed5bSNiels Provos ctx->reply_clear(ctx->reply);
938ff43ed5bSNiels Provos }
939ff43ed5bSNiels Provos
9403794534fSNiels Provos (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
941ff43ed5bSNiels Provos
942ff43ed5bSNiels Provos evrpc_request_wrapper_free(ctx);
943ff43ed5bSNiels Provos
944e3fd294aSNick Mathewson /* the http layer owned the original request structure, but if we
945955c6abfSNiels Provos * got paused, we asked for ownership and need to free it here. */
946955c6abfSNiels Provos if (req != NULL && evhttp_request_is_owned(req))
947955c6abfSNiels Provos evhttp_request_free(req);
9482d028ef6SNiels Provos
9492d028ef6SNiels Provos /* see if we can schedule another request */
9502d028ef6SNiels Provos evrpc_pool_schedule(pool);
9512d028ef6SNiels Provos }
9522d028ef6SNiels Provos
9532d028ef6SNiels Provos static void
evrpc_pool_schedule(struct evrpc_pool * pool)9542d028ef6SNiels Provos evrpc_pool_schedule(struct evrpc_pool *pool)
9552d028ef6SNiels Provos {
9562d028ef6SNiels Provos struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
9572d028ef6SNiels Provos struct evhttp_connection *evcon;
9582d028ef6SNiels Provos
9592d028ef6SNiels Provos /* if no requests are pending, we have no work */
9602d028ef6SNiels Provos if (ctx == NULL)
9612d028ef6SNiels Provos return;
9622d028ef6SNiels Provos
9632d028ef6SNiels Provos if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
9642d028ef6SNiels Provos TAILQ_REMOVE(&pool->requests, ctx, next);
9652d028ef6SNiels Provos evrpc_schedule_request(evcon, ctx);
9662d028ef6SNiels Provos }
9672d028ef6SNiels Provos }
9682d028ef6SNiels Provos
9692d028ef6SNiels Provos static void
evrpc_request_timeout(evutil_socket_t fd,short what,void * arg)9701120f04fSNick Mathewson evrpc_request_timeout(evutil_socket_t fd, short what, void *arg)
9712d028ef6SNiels Provos {
9722d028ef6SNiels Provos struct evrpc_request_wrapper *ctx = arg;
9732d028ef6SNiels Provos struct evhttp_connection *evcon = ctx->evcon;
9742e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon != NULL);
9752d028ef6SNiels Provos
9767b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
977fda1216bSNiels Provos }
9785a5609c7SNiels Provos
9795a5609c7SNiels Provos /*
9805a5609c7SNiels Provos * frees potential meta data associated with a request.
9815a5609c7SNiels Provos */
9825a5609c7SNiels Provos
9835a5609c7SNiels Provos static void
evrpc_meta_data_free(struct evrpc_meta_list * meta_data)9845a5609c7SNiels Provos evrpc_meta_data_free(struct evrpc_meta_list *meta_data)
9855a5609c7SNiels Provos {
9865a5609c7SNiels Provos struct evrpc_meta *entry;
9872e36dbe1SNick Mathewson EVUTIL_ASSERT(meta_data != NULL);
9885a5609c7SNiels Provos
9895a5609c7SNiels Provos while ((entry = TAILQ_FIRST(meta_data)) != NULL) {
9905a5609c7SNiels Provos TAILQ_REMOVE(meta_data, entry, next);
99149868b61SNick Mathewson mm_free(entry->key);
99249868b61SNick Mathewson mm_free(entry->data);
99349868b61SNick Mathewson mm_free(entry);
9945a5609c7SNiels Provos }
9955a5609c7SNiels Provos }
9965a5609c7SNiels Provos
9972460aa59SNiels Provos static struct evrpc_hook_meta *
evrpc_hook_meta_new_(void)9988ac3c4c2SNick Mathewson evrpc_hook_meta_new_(void)
9992460aa59SNiels Provos {
10002460aa59SNiels Provos struct evrpc_hook_meta *ctx;
100149868b61SNick Mathewson ctx = mm_malloc(sizeof(struct evrpc_hook_meta));
10022e36dbe1SNick Mathewson EVUTIL_ASSERT(ctx != NULL);
10032460aa59SNiels Provos
10042460aa59SNiels Provos TAILQ_INIT(&ctx->meta_data);
10052460aa59SNiels Provos ctx->evcon = NULL;
10062460aa59SNiels Provos
10072460aa59SNiels Provos return (ctx);
10082460aa59SNiels Provos }
10092460aa59SNiels Provos
10102460aa59SNiels Provos static void
evrpc_hook_associate_meta_(struct evrpc_hook_meta ** pctx,struct evhttp_connection * evcon)10118ac3c4c2SNick Mathewson evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
10122460aa59SNiels Provos struct evhttp_connection *evcon)
10132460aa59SNiels Provos {
10142460aa59SNiels Provos struct evrpc_hook_meta *ctx = *pctx;
10152460aa59SNiels Provos if (ctx == NULL)
10168ac3c4c2SNick Mathewson *pctx = ctx = evrpc_hook_meta_new_();
10172460aa59SNiels Provos ctx->evcon = evcon;
10182460aa59SNiels Provos }
10192460aa59SNiels Provos
10202460aa59SNiels Provos static void
evrpc_hook_context_free_(struct evrpc_hook_meta * ctx)10218ac3c4c2SNick Mathewson evrpc_hook_context_free_(struct evrpc_hook_meta *ctx)
10222460aa59SNiels Provos {
10232460aa59SNiels Provos evrpc_meta_data_free(&ctx->meta_data);
102449868b61SNick Mathewson mm_free(ctx);
10252460aa59SNiels Provos }
10262460aa59SNiels Provos
10272460aa59SNiels Provos /* Adds meta data */
10285a5609c7SNiels Provos void
evrpc_hook_add_meta(void * ctx,const char * key,const void * data,size_t data_size)10295a5609c7SNiels Provos evrpc_hook_add_meta(void *ctx, const char *key,
10305a5609c7SNiels Provos const void *data, size_t data_size)
10315a5609c7SNiels Provos {
10325a5609c7SNiels Provos struct evrpc_request_wrapper *req = ctx;
10332460aa59SNiels Provos struct evrpc_hook_meta *store = NULL;
10345a5609c7SNiels Provos struct evrpc_meta *meta = NULL;
10355a5609c7SNiels Provos
10362460aa59SNiels Provos if ((store = req->hook_meta) == NULL)
10378ac3c4c2SNick Mathewson store = req->hook_meta = evrpc_hook_meta_new_();
10385a5609c7SNiels Provos
1039743f8665SNick Mathewson meta = mm_malloc(sizeof(struct evrpc_meta));
1040743f8665SNick Mathewson EVUTIL_ASSERT(meta != NULL);
1041743f8665SNick Mathewson meta->key = mm_strdup(key);
1042743f8665SNick Mathewson EVUTIL_ASSERT(meta->key != NULL);
10435a5609c7SNiels Provos meta->data_size = data_size;
1044743f8665SNick Mathewson meta->data = mm_malloc(data_size);
1045743f8665SNick Mathewson EVUTIL_ASSERT(meta->data != NULL);
10465a5609c7SNiels Provos memcpy(meta->data, data, data_size);
10475a5609c7SNiels Provos
10482460aa59SNiels Provos TAILQ_INSERT_TAIL(&store->meta_data, meta, next);
10495a5609c7SNiels Provos }
10505a5609c7SNiels Provos
10515a5609c7SNiels Provos int
evrpc_hook_find_meta(void * ctx,const char * key,void ** data,size_t * data_size)10525a5609c7SNiels Provos evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size)
10535a5609c7SNiels Provos {
10545a5609c7SNiels Provos struct evrpc_request_wrapper *req = ctx;
10555a5609c7SNiels Provos struct evrpc_meta *meta = NULL;
10565a5609c7SNiels Provos
10572460aa59SNiels Provos if (req->hook_meta == NULL)
10585a5609c7SNiels Provos return (-1);
10595a5609c7SNiels Provos
10602460aa59SNiels Provos TAILQ_FOREACH(meta, &req->hook_meta->meta_data, next) {
10615a5609c7SNiels Provos if (strcmp(meta->key, key) == 0) {
10625a5609c7SNiels Provos *data = meta->data;
10635a5609c7SNiels Provos *data_size = meta->data_size;
10645a5609c7SNiels Provos return (0);
10655a5609c7SNiels Provos }
10665a5609c7SNiels Provos }
10675a5609c7SNiels Provos
10685a5609c7SNiels Provos return (-1);
10695a5609c7SNiels Provos }
10702460aa59SNiels Provos
10712460aa59SNiels Provos struct evhttp_connection *
evrpc_hook_get_connection(void * ctx)10722460aa59SNiels Provos evrpc_hook_get_connection(void *ctx)
10732460aa59SNiels Provos {
10742460aa59SNiels Provos struct evrpc_request_wrapper *req = ctx;
1075a83caa6bSNiels Provos return (req->hook_meta != NULL ? req->hook_meta->evcon : NULL);
10762460aa59SNiels Provos }
1077aa4b9257SNiels Provos
1078a146af1dSNiels Provos 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 *))1079a146af1dSNiels Provos evrpc_send_request_generic(struct evrpc_pool *pool,
1080a146af1dSNiels Provos void *request, void *reply,
1081a146af1dSNiels Provos void (*cb)(struct evrpc_status *, void *, void *, void *),
1082a146af1dSNiels Provos void *cb_arg,
1083a146af1dSNiels Provos const char *rpcname,
1084a146af1dSNiels Provos void (*req_marshal)(struct evbuffer *, void *),
1085a146af1dSNiels Provos void (*rpl_clear)(void *),
1086a146af1dSNiels Provos int (*rpl_unmarshal)(void *, struct evbuffer *))
1087a146af1dSNiels Provos {
1088a146af1dSNiels Provos struct evrpc_status status;
1089a146af1dSNiels Provos struct evrpc_request_wrapper *ctx;
1090a146af1dSNiels Provos ctx = evrpc_make_request_ctx(pool, request, reply,
1091a146af1dSNiels Provos rpcname, req_marshal, rpl_clear, rpl_unmarshal, cb, cb_arg);
1092a146af1dSNiels Provos if (ctx == NULL)
1093a146af1dSNiels Provos goto error;
1094a146af1dSNiels Provos return (evrpc_make_request(ctx));
1095a146af1dSNiels Provos error:
1096a146af1dSNiels Provos memset(&status, 0, sizeof(status));
1097a146af1dSNiels Provos status.error = EVRPC_STATUS_ERR_UNSTARTED;
1098a146af1dSNiels Provos (*(cb))(&status, request, reply, cb_arg);
1099a146af1dSNiels Provos return (-1);
1100a146af1dSNiels Provos }
1101a146af1dSNiels Provos
1102a146af1dSNiels Provos /** Takes a request object and fills it in with the right magic */
1103a146af1dSNiels Provos 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 *))1104a146af1dSNiels Provos evrpc_register_object(const char *name,
1105755fbf16SShuo Chen void *(*req_new)(void*), void *req_new_arg, void (*req_free)(void *),
1106a146af1dSNiels Provos int (*req_unmarshal)(void *, struct evbuffer *),
1107755fbf16SShuo Chen void *(*rpl_new)(void*), void *rpl_new_arg, void (*rpl_free)(void *),
1108a146af1dSNiels Provos int (*rpl_complete)(void *),
1109a146af1dSNiels Provos void (*rpl_marshal)(struct evbuffer *, void *))
1110a146af1dSNiels Provos {
1111a146af1dSNiels Provos struct evrpc* rpc = (struct evrpc *)mm_calloc(1, sizeof(struct evrpc));
1112a146af1dSNiels Provos if (rpc == NULL)
1113a146af1dSNiels Provos return (NULL);
1114a146af1dSNiels Provos rpc->uri = mm_strdup(name);
1115a146af1dSNiels Provos if (rpc->uri == NULL) {
1116a146af1dSNiels Provos mm_free(rpc);
1117a146af1dSNiels Provos return (NULL);
1118a146af1dSNiels Provos }
1119a146af1dSNiels Provos rpc->request_new = req_new;
1120755fbf16SShuo Chen rpc->request_new_arg = req_new_arg;
1121a146af1dSNiels Provos rpc->request_free = req_free;
1122a146af1dSNiels Provos rpc->request_unmarshal = req_unmarshal;
1123a146af1dSNiels Provos rpc->reply_new = rpl_new;
1124755fbf16SShuo Chen rpc->reply_new_arg = rpl_new_arg;
1125a146af1dSNiels Provos rpc->reply_free = rpl_free;
1126a146af1dSNiels Provos rpc->reply_complete = rpl_complete;
1127a146af1dSNiels Provos rpc->reply_marshal = rpl_marshal;
1128a146af1dSNiels Provos return (rpc);
1129a146af1dSNiels Provos }
1130a146af1dSNiels Provos
1131a146af1dSNiels Provos 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 *))1132a146af1dSNiels Provos evrpc_register_generic(struct evrpc_base *base, const char *name,
1133a146af1dSNiels Provos void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
1134755fbf16SShuo Chen void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
1135a146af1dSNiels Provos int (*req_unmarshal)(void *, struct evbuffer *),
1136755fbf16SShuo Chen void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *),
1137a146af1dSNiels Provos int (*rpl_complete)(void *),
1138a146af1dSNiels Provos void (*rpl_marshal)(struct evbuffer *, void *))
1139a146af1dSNiels Provos {
1140a146af1dSNiels Provos struct evrpc* rpc =
1141755fbf16SShuo Chen evrpc_register_object(name, req_new, req_new_arg, req_free, req_unmarshal,
1142755fbf16SShuo Chen rpl_new, rpl_new_arg, rpl_free, rpl_complete, rpl_marshal);
1143a146af1dSNiels Provos if (rpc == NULL)
1144a146af1dSNiels Provos return (-1);
1145a146af1dSNiels Provos evrpc_register_rpc(base, rpc,
1146a146af1dSNiels Provos (void (*)(struct evrpc_req_generic*, void *))callback, cbarg);
1147a146af1dSNiels Provos return (0);
1148a146af1dSNiels Provos }
1149a146af1dSNiels Provos
1150aa4b9257SNiels Provos /** accessors for obscure and undocumented functionality */
1151aa4b9257SNiels Provos struct evrpc_pool *
evrpc_request_get_pool(struct evrpc_request_wrapper * ctx)1152aa4b9257SNiels Provos evrpc_request_get_pool(struct evrpc_request_wrapper *ctx)
1153aa4b9257SNiels Provos {
1154aa4b9257SNiels Provos return (ctx->pool);
1155aa4b9257SNiels Provos }
1156aa4b9257SNiels Provos
1157aa4b9257SNiels Provos void
evrpc_request_set_pool(struct evrpc_request_wrapper * ctx,struct evrpc_pool * pool)1158aa4b9257SNiels Provos evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
1159aa4b9257SNiels Provos struct evrpc_pool *pool)
1160aa4b9257SNiels Provos {
1161aa4b9257SNiels Provos ctx->pool = pool;
1162aa4b9257SNiels Provos }
1163aa4b9257SNiels Provos
1164aa4b9257SNiels Provos void
evrpc_request_set_cb(struct evrpc_request_wrapper * ctx,void (* cb)(struct evrpc_status *,void * request,void * reply,void * arg),void * cb_arg)1165aa4b9257SNiels Provos evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
1166aa4b9257SNiels Provos void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
1167aa4b9257SNiels Provos void *cb_arg)
1168aa4b9257SNiels Provos {
1169aa4b9257SNiels Provos ctx->cb = cb;
1170aa4b9257SNiels Provos ctx->cb_arg = cb_arg;
1171aa4b9257SNiels Provos }
1172