OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu> | |
3 * All rights reserved. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
8 * 1. Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright | |
11 * notice, this list of conditions and the following disclaimer in the | |
12 * documentation and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 #ifndef _EVRPC_H_ | |
28 #define _EVRPC_H_ | |
29 | |
30 #ifdef __cplusplus | |
31 extern "C" { | |
32 #endif | |
33 | |
34 /** @file evrpc.h | |
35 * | |
36 * This header files provides basic support for an RPC server and client. | |
37 * | |
38 * To support RPCs in a server, every supported RPC command needs to be | |
39 * defined and registered. | |
40 * | |
41 * EVRPC_HEADER(SendCommand, Request, Reply); | |
42 * | |
43 * SendCommand is the name of the RPC command. | |
44 * Request is the name of a structure generated by event_rpcgen.py. | |
45 * It contains all parameters relating to the SendCommand RPC. The | |
46 * server needs to fill in the Reply structure. | |
47 * Reply is the name of a structure generated by event_rpcgen.py. It | |
48 * contains the answer to the RPC. | |
49 * | |
50 * To register an RPC with an HTTP server, you need to first create an RPC | |
51 * base with: | |
52 * | |
53 * struct evrpc_base *base = evrpc_init(http); | |
54 * | |
55 * A specific RPC can then be registered with | |
56 * | |
57 * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg); | |
58 * | |
59 * when the server receives an appropriately formatted RPC, the user callback | |
60 * is invokved. The callback needs to fill in the reply structure. | |
61 * | |
62 * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg); | |
63 * | |
64 * To send the reply, call EVRPC_REQUEST_DONE(rpc); | |
65 * | |
66 * See the regression test for an example. | |
67 */ | |
68 | |
69 struct evbuffer; | |
70 struct event_base; | |
71 struct evrpc_req_generic; | |
72 | |
73 /* Encapsulates a request */ | |
74 struct evrpc { | |
75 TAILQ_ENTRY(evrpc) next; | |
76 | |
77 /* the URI at which the request handler lives */ | |
78 const char* uri; | |
79 | |
80 /* creates a new request structure */ | |
81 void *(*request_new)(void); | |
82 | |
83 /* frees the request structure */ | |
84 void (*request_free)(void *); | |
85 | |
86 /* unmarshals the buffer into the proper request structure */ | |
87 int (*request_unmarshal)(void *, struct evbuffer *); | |
88 | |
89 /* creates a new reply structure */ | |
90 void *(*reply_new)(void); | |
91 | |
92 /* creates a new reply structure */ | |
93 void (*reply_free)(void *); | |
94 | |
95 /* verifies that the reply is valid */ | |
96 int (*reply_complete)(void *); | |
97 | |
98 /* marshals the reply into a buffer */ | |
99 void (*reply_marshal)(struct evbuffer*, void *); | |
100 | |
101 /* the callback invoked for each received rpc */ | |
102 void (*cb)(struct evrpc_req_generic *, void *); | |
103 void *cb_arg; | |
104 | |
105 /* reference for further configuration */ | |
106 struct evrpc_base *base; | |
107 }; | |
108 | |
109 /** The type of a specific RPC Message | |
110 * | |
111 * @param rpcname the name of the RPC message | |
112 */ | |
113 #define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname | |
114 | |
115 struct evhttp_request; | |
116 struct evrpc_status; | |
117 | |
118 /* We alias the RPC specific structs to this voided one */ | |
119 struct evrpc_req_generic { | |
120 /* the unmarshaled request object */ | |
121 void *request; | |
122 | |
123 /* the empty reply object that needs to be filled in */ | |
124 void *reply; | |
125 | |
126 /* | |
127 * the static structure for this rpc; that can be used to | |
128 * automatically unmarshal and marshal the http buffers. | |
129 */ | |
130 struct evrpc *rpc; | |
131 | |
132 /* | |
133 * the http request structure on which we need to answer. | |
134 */ | |
135 struct evhttp_request* http_req; | |
136 | |
137 /* | |
138 * callback to reply and finish answering this rpc | |
139 */ | |
140 void (*done)(struct evrpc_req_generic* rpc); | |
141 }; | |
142 | |
143 /** Creates the definitions and prototypes for an RPC | |
144 * | |
145 * You need to use EVRPC_HEADER to create structures and function prototypes | |
146 * needed by the server and client implementation. The structures have to be | |
147 * defined in an .rpc file and converted to source code via event_rpcgen.py | |
148 * | |
149 * @param rpcname the name of the RPC | |
150 * @param reqstruct the name of the RPC request structure | |
151 * @param replystruct the name of the RPC reply structure | |
152 * @see EVRPC_GENERATE() | |
153 */ | |
154 #define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \ | |
155 EVRPC_STRUCT(rpcname) { \ | |
156 struct reqstruct* request; \ | |
157 struct rplystruct* reply; \ | |
158 struct evrpc* rpc; \ | |
159 struct evhttp_request* http_req; \ | |
160 void (*done)(struct evrpc_status *, \ | |
161 struct evrpc* rpc, void *request, void *reply); \ | |
162 }; \ | |
163 int evrpc_send_request_##rpcname(struct evrpc_pool *, \ | |
164 struct reqstruct *, struct rplystruct *, \ | |
165 void (*)(struct evrpc_status *, \ | |
166 struct reqstruct *, struct rplystruct *, void *cbarg), \ | |
167 void *); | |
168 | |
169 /** Generates the code for receiving and sending an RPC message | |
170 * | |
171 * EVRPC_GENERATE is used to create the code corresponding to sending | |
172 * and receiving a particular RPC message | |
173 * | |
174 * @param rpcname the name of the RPC | |
175 * @param reqstruct the name of the RPC request structure | |
176 * @param replystruct the name of the RPC reply structure | |
177 * @see EVRPC_HEADER() | |
178 */ | |
179 #define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \ | |
180 int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \ | |
181 struct reqstruct *request, struct rplystruct *reply, \ | |
182 void (*cb)(struct evrpc_status *, \ | |
183 struct reqstruct *, struct rplystruct *, void *cbarg), \ | |
184 void *cbarg) { \ | |
185 struct evrpc_status status; \ | |
186 struct evrpc_request_wrapper *ctx; \ | |
187 ctx = (struct evrpc_request_wrapper *) \ | |
188 malloc(sizeof(struct evrpc_request_wrapper)); \ | |
189 if (ctx == NULL) \ | |
190 goto error; \ | |
191 ctx->pool = pool; \ | |
192 ctx->evcon = NULL; \ | |
193 ctx->name = strdup(#rpcname); \ | |
194 if (ctx->name == NULL) { \ | |
195 free(ctx); \ | |
196 goto error; \ | |
197 } \ | |
198 ctx->cb = (void (*)(struct evrpc_status *, \ | |
199 void *, void *, void *))cb; \ | |
200 ctx->cb_arg = cbarg; \ | |
201 ctx->request = (void *)request; \ | |
202 ctx->reply = (void *)reply; \ | |
203 ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_
marshal; \ | |
204 ctx->reply_clear = (void (*)(void *))rplystruct##_clear; \ | |
205 ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_
unmarshal; \ | |
206 return (evrpc_make_request(ctx)); \ | |
207 error: \ | |
208 memset(&status, 0, sizeof(status)); \ | |
209 status.error = EVRPC_STATUS_ERR_UNSTARTED; \ | |
210 (*(cb))(&status, request, reply, cbarg); \ | |
211 return (-1); \ | |
212 } | |
213 | |
214 /** Provides access to the HTTP request object underlying an RPC | |
215 * | |
216 * Access to the underlying http object; can be used to look at headers or | |
217 * for getting the remote ip address | |
218 * | |
219 * @param rpc_req the rpc request structure provided to the server callback | |
220 * @return an struct evhttp_request object that can be inspected for | |
221 * HTTP headers or sender information. | |
222 */ | |
223 #define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req | |
224 | |
225 /** Creates the reply to an RPC request | |
226 * | |
227 * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected | |
228 * to have been filled in. The request and reply pointers become invalid | |
229 * after this call has finished. | |
230 * | |
231 * @param rpc_req the rpc request structure provided to the server callback | |
232 */ | |
233 #define EVRPC_REQUEST_DONE(rpc_req) do { \ | |
234 struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \ | |
235 _req->done(_req); \ | |
236 } while (0) | |
237 | |
238 | |
239 /* Takes a request object and fills it in with the right magic */ | |
240 #define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \ | |
241 do { \ | |
242 (rpc)->uri = strdup(#name); \ | |
243 if ((rpc)->uri == NULL) { \ | |
244 fprintf(stderr, "failed to register object\n"); \ | |
245 exit(1); \ | |
246 } \ | |
247 (rpc)->request_new = (void *(*)(void))request##_new; \ | |
248 (rpc)->request_free = (void (*)(void *))request##_free; \ | |
249 (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unm
arshal; \ | |
250 (rpc)->reply_new = (void *(*)(void))reply##_new; \ | |
251 (rpc)->reply_free = (void (*)(void *))reply##_free; \ | |
252 (rpc)->reply_complete = (int (*)(void *))reply##_complete; \ | |
253 (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal;
\ | |
254 } while (0) | |
255 | |
256 struct evrpc_base; | |
257 struct evhttp; | |
258 | |
259 /* functions to start up the rpc system */ | |
260 | |
261 /** Creates a new rpc base from which RPC requests can be received | |
262 * | |
263 * @param server a pointer to an existing HTTP server | |
264 * @return a newly allocated evrpc_base struct | |
265 * @see evrpc_free() | |
266 */ | |
267 struct evrpc_base *evrpc_init(struct evhttp *server); | |
268 | |
269 /** | |
270 * Frees the evrpc base | |
271 * | |
272 * For now, you are responsible for making sure that no rpcs are ongoing. | |
273 * | |
274 * @param base the evrpc_base object to be freed | |
275 * @see evrpc_init | |
276 */ | |
277 void evrpc_free(struct evrpc_base *base); | |
278 | |
279 /** register RPCs with the HTTP Server | |
280 * | |
281 * registers a new RPC with the HTTP server, each RPC needs to have | |
282 * a unique name under which it can be identified. | |
283 * | |
284 * @param base the evrpc_base structure in which the RPC should be | |
285 * registered. | |
286 * @param name the name of the RPC | |
287 * @param request the name of the RPC request structure | |
288 * @param reply the name of the RPC reply structure | |
289 * @param callback the callback that should be invoked when the RPC | |
290 * is received. The callback has the following prototype | |
291 * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg) | |
292 * @param cbarg an additional parameter that can be passed to the callback. | |
293 * The parameter can be used to carry around state. | |
294 */ | |
295 #define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \ | |
296 do { \ | |
297 struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \ | |
298 EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \ | |
299 evrpc_register_rpc(base, rpc, \ | |
300 (void (*)(struct evrpc_req_generic*, void *))callback, cbarg); \ | |
301 } while (0) | |
302 | |
303 int evrpc_register_rpc(struct evrpc_base *, struct evrpc *, | |
304 void (*)(struct evrpc_req_generic*, void *), void *); | |
305 | |
306 /** | |
307 * Unregisters an already registered RPC | |
308 * | |
309 * @param base the evrpc_base object from which to unregister an RPC | |
310 * @param name the name of the rpc to unregister | |
311 * @return -1 on error or 0 when successful. | |
312 * @see EVRPC_REGISTER() | |
313 */ | |
314 #define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name) | |
315 | |
316 int evrpc_unregister_rpc(struct evrpc_base *base, const char *name); | |
317 | |
318 /* | |
319 * Client-side RPC support | |
320 */ | |
321 | |
322 struct evrpc_pool; | |
323 struct evhttp_connection; | |
324 | |
325 /** | |
326 * provides information about the completed RPC request. | |
327 */ | |
328 struct evrpc_status { | |
329 #define EVRPC_STATUS_ERR_NONE 0 | |
330 #define EVRPC_STATUS_ERR_TIMEOUT 1 | |
331 #define EVRPC_STATUS_ERR_BADPAYLOAD 2 | |
332 #define EVRPC_STATUS_ERR_UNSTARTED 3 | |
333 #define EVRPC_STATUS_ERR_HOOKABORTED 4 | |
334 int error; | |
335 | |
336 /* for looking at headers or other information */ | |
337 struct evhttp_request *http_req; | |
338 }; | |
339 | |
340 struct evrpc_request_wrapper { | |
341 TAILQ_ENTRY(evrpc_request_wrapper) next; | |
342 | |
343 /* pool on which this rpc request is being made */ | |
344 struct evrpc_pool *pool; | |
345 | |
346 /* connection on which the request is being sent */ | |
347 struct evhttp_connection *evcon; | |
348 | |
349 /* event for implementing request timeouts */ | |
350 struct event ev_timeout; | |
351 | |
352 /* the name of the rpc */ | |
353 char *name; | |
354 | |
355 /* callback */ | |
356 void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg); | |
357 void *cb_arg; | |
358 | |
359 void *request; | |
360 void *reply; | |
361 | |
362 /* unmarshals the buffer into the proper request structure */ | |
363 void (*request_marshal)(struct evbuffer *, void *); | |
364 | |
365 /* removes all stored state in the reply */ | |
366 void (*reply_clear)(void *); | |
367 | |
368 /* marshals the reply into a buffer */ | |
369 int (*reply_unmarshal)(void *, struct evbuffer*); | |
370 }; | |
371 | |
372 /** launches an RPC and sends it to the server | |
373 * | |
374 * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server. | |
375 * | |
376 * @param name the name of the RPC | |
377 * @param pool the evrpc_pool that contains the connection objects over which | |
378 * the request should be sent. | |
379 * @param request a pointer to the RPC request structure - it contains the | |
380 * data to be sent to the server. | |
381 * @param reply a pointer to the RPC reply structure. It is going to be filled | |
382 * if the request was answered successfully | |
383 * @param cb the callback to invoke when the RPC request has been answered | |
384 * @param cbarg an additional argument to be passed to the client | |
385 * @return 0 on success, -1 on failure | |
386 */ | |
387 #define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \ | |
388 evrpc_send_request_##name(pool, request, reply, cb, cbarg) | |
389 | |
390 int evrpc_make_request(struct evrpc_request_wrapper *); | |
391 | |
392 /** creates an rpc connection pool | |
393 * | |
394 * a pool has a number of connections associated with it. | |
395 * rpc requests are always made via a pool. | |
396 * | |
397 * @param base a pointer to an struct event_based object; can be left NULL | |
398 * in singled-threaded applications | |
399 * @return a newly allocated struct evrpc_pool object | |
400 * @see evrpc_pool_free() | |
401 */ | |
402 struct evrpc_pool *evrpc_pool_new(struct event_base *base); | |
403 /** frees an rpc connection pool | |
404 * | |
405 * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new() | |
406 * @see evrpc_pool_new() | |
407 */ | |
408 void evrpc_pool_free(struct evrpc_pool *pool); | |
409 /* | |
410 * adds a connection over which rpc can be dispatched. the connection | |
411 * object must have been newly created. | |
412 */ | |
413 void evrpc_pool_add_connection(struct evrpc_pool *, | |
414 struct evhttp_connection *); | |
415 | |
416 /** | |
417 * Sets the timeout in secs after which a request has to complete. The | |
418 * RPC is completely aborted if it does not complete by then. Setting | |
419 * the timeout to 0 means that it never timeouts and can be used to | |
420 * implement callback type RPCs. | |
421 * | |
422 * Any connection already in the pool will be updated with the new | |
423 * timeout. Connections added to the pool after set_timeout has be | |
424 * called receive the pool timeout only if no timeout has been set | |
425 * for the connection itself. | |
426 * | |
427 * @param pool a pointer to a struct evrpc_pool object | |
428 * @param timeout_in_secs the number of seconds after which a request should | |
429 * timeout and a failure be returned to the callback. | |
430 */ | |
431 void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs); | |
432 | |
433 /** | |
434 * Hooks for changing the input and output of RPCs; this can be used to | |
435 * implement compression, authentication, encryption, ... | |
436 */ | |
437 | |
438 enum EVRPC_HOOK_TYPE { | |
439 EVRPC_INPUT, /**< apply the function to an input hook */ | |
440 EVRPC_OUTPUT /**< apply the function to an output hook */ | |
441 }; | |
442 | |
443 #ifndef WIN32 | |
444 /** Deprecated alias for EVRPC_INPUT. Not available on windows, where it | |
445 * conflicts with platform headers. */ | |
446 #define INPUT EVRPC_INPUT | |
447 /** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it | |
448 * conflicts with platform headers. */ | |
449 #define OUTPUT EVRPC_OUTPUT | |
450 #endif | |
451 | |
452 /** adds a processing hook to either an rpc base or rpc pool | |
453 * | |
454 * If a hook returns -1, the processing is aborted. | |
455 * | |
456 * The add functions return handles that can be used for removing hooks. | |
457 * | |
458 * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool | |
459 * @param hook_type either INPUT or OUTPUT | |
460 * @param cb the callback to call when the hook is activated | |
461 * @param cb_arg an additional argument for the callback | |
462 * @return a handle to the hook so it can be removed later | |
463 * @see evrpc_remove_hook() | |
464 */ | |
465 void *evrpc_add_hook(void *vbase, | |
466 enum EVRPC_HOOK_TYPE hook_type, | |
467 int (*cb)(struct evhttp_request *, struct evbuffer *, void *), | |
468 void *cb_arg); | |
469 | |
470 /** removes a previously added hook | |
471 * | |
472 * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool | |
473 * @param hook_type either INPUT or OUTPUT | |
474 * @param handle a handle returned by evrpc_add_hook() | |
475 * @return 1 on success or 0 on failure | |
476 * @see evrpc_add_hook() | |
477 */ | |
478 int evrpc_remove_hook(void *vbase, | |
479 enum EVRPC_HOOK_TYPE hook_type, | |
480 void *handle); | |
481 | |
482 #ifdef __cplusplus | |
483 } | |
484 #endif | |
485 | |
486 #endif /* _EVRPC_H_ */ | |
OLD | NEW |