Annotation of embedaddon/libevent/evrpc.h, revision 1.1.1.1
1.1 misho 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##_unmarshal; \
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_ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>