evrpc.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. The name of the author may not be used to endorse or promote products
00014  *    derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00017  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00018  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00019  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00020  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00021  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00022  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00023  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00025  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 #ifndef _EVRPC_H_
00028 #define _EVRPC_H_
00029 
00030 #ifdef __cplusplus
00031 extern "C" {
00032 #endif
00033 
00069 struct evbuffer;
00070 struct event_base;
00071 struct evrpc_req_generic;
00072 
00073 /* Encapsulates a request */
00074 struct evrpc {
00075         TAILQ_ENTRY(evrpc) next;
00076 
00077         /* the URI at which the request handler lives */
00078         const char* uri;
00079 
00080         /* creates a new request structure */
00081         void *(*request_new)(void);
00082 
00083         /* frees the request structure */
00084         void (*request_free)(void *);
00085 
00086         /* unmarshals the buffer into the proper request structure */
00087         int (*request_unmarshal)(void *, struct evbuffer *);
00088 
00089         /* creates a new reply structure */
00090         void *(*reply_new)(void);
00091 
00092         /* creates a new reply structure */
00093         void (*reply_free)(void *);
00094 
00095         /* verifies that the reply is valid */
00096         int (*reply_complete)(void *);
00097         
00098         /* marshals the reply into a buffer */
00099         void (*reply_marshal)(struct evbuffer*, void *);
00100 
00101         /* the callback invoked for each received rpc */
00102         void (*cb)(struct evrpc_req_generic *, void *);
00103         void *cb_arg;
00104 
00105         /* reference for further configuration */
00106         struct evrpc_base *base;
00107 };
00108 
00113 #define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
00114 
00115 struct evhttp_request;
00116 struct evrpc_status;
00117 
00118 /* We alias the RPC specific structs to this voided one */
00119 struct evrpc_req_generic {
00120         /* the unmarshaled request object */
00121         void *request;
00122 
00123         /* the empty reply object that needs to be filled in */
00124         void *reply;
00125 
00126         /* 
00127          * the static structure for this rpc; that can be used to
00128          * automatically unmarshal and marshal the http buffers.
00129          */
00130         struct evrpc *rpc;
00131 
00132         /*
00133          * the http request structure on which we need to answer.
00134          */
00135         struct evhttp_request* http_req;
00136 
00137         /*
00138          * callback to reply and finish answering this rpc
00139          */
00140         void (*done)(struct evrpc_req_generic* rpc); 
00141 };
00142 
00154 #define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
00155 EVRPC_STRUCT(rpcname) { \
00156         struct reqstruct* request; \
00157         struct rplystruct* reply; \
00158         struct evrpc* rpc; \
00159         struct evhttp_request* http_req; \
00160         void (*done)(struct evrpc_status *, \
00161             struct evrpc* rpc, void *request, void *reply);          \
00162 };                                                                   \
00163 int evrpc_send_request_##rpcname(struct evrpc_pool *, \
00164     struct reqstruct *, struct rplystruct *, \
00165     void (*)(struct evrpc_status *, \
00166         struct reqstruct *, struct rplystruct *, void *cbarg),  \
00167     void *);
00168 
00179 #define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
00180 int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
00181     struct reqstruct *request, struct rplystruct *reply, \
00182     void (*cb)(struct evrpc_status *, \
00183         struct reqstruct *, struct rplystruct *, void *cbarg),  \
00184     void *cbarg) { \
00185         struct evrpc_status status;                                 \
00186         struct evrpc_request_wrapper *ctx;                          \
00187         ctx = (struct evrpc_request_wrapper *) \
00188             malloc(sizeof(struct evrpc_request_wrapper));           \
00189         if (ctx == NULL)                                            \
00190                 goto error;                                         \
00191         ctx->pool = pool;                                           \
00192         ctx->evcon = NULL;                                          \
00193         ctx->name = strdup(#rpcname);                               \
00194         if (ctx->name == NULL) {                                    \
00195                 free(ctx);                                          \
00196                 goto error;                                         \
00197         }                                                           \
00198         ctx->cb = (void (*)(struct evrpc_status *, \
00199                 void *, void *, void *))cb;                         \
00200         ctx->cb_arg = cbarg;                                        \
00201         ctx->request = (void *)request;                             \
00202         ctx->reply = (void *)reply;                                 \
00203         ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
00204         ctx->reply_clear = (void (*)(void *))rplystruct##_clear;    \
00205         ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
00206         return (evrpc_make_request(ctx));                           \
00207 error:                                                              \
00208         memset(&status, 0, sizeof(status));                         \
00209         status.error = EVRPC_STATUS_ERR_UNSTARTED;                  \
00210         (*(cb))(&status, request, reply, cbarg);                    \
00211         return (-1);                                                \
00212 }
00213 
00223 #define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
00224 
00233 #define EVRPC_REQUEST_DONE(rpc_req) do { \
00234   struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
00235   _req->done(_req); \
00236 } while (0)
00237   
00238 
00239 /* Takes a request object and fills it in with the right magic */
00240 #define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
00241   do { \
00242     (rpc)->uri = strdup(#name); \
00243     if ((rpc)->uri == NULL) {                    \
00244       fprintf(stderr, "failed to register object\n");   \
00245       exit(1);                                          \
00246     } \
00247     (rpc)->request_new = (void *(*)(void))request##_new; \
00248     (rpc)->request_free = (void (*)(void *))request##_free; \
00249     (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
00250     (rpc)->reply_new = (void *(*)(void))reply##_new; \
00251     (rpc)->reply_free = (void (*)(void *))reply##_free; \
00252     (rpc)->reply_complete = (int (*)(void *))reply##_complete; \
00253     (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
00254   } while (0)
00255 
00256 struct evrpc_base;
00257 struct evhttp;
00258 
00259 /* functions to start up the rpc system */
00260 
00267 struct evrpc_base *evrpc_init(struct evhttp *server);
00268 
00277 void evrpc_free(struct evrpc_base *base);
00278 
00295 #define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
00296   do { \
00297     struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
00298     EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
00299     evrpc_register_rpc(base, rpc, \
00300         (void (*)(struct evrpc_req_generic*, void *))callback, cbarg);  \
00301   } while (0)
00302 
00303 int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
00304     void (*)(struct evrpc_req_generic*, void *), void *);
00305 
00314 #define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
00315 
00316 int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
00317 
00318 /*
00319  * Client-side RPC support
00320  */
00321 
00322 struct evrpc_pool;
00323 struct evhttp_connection;
00324 
00328 struct evrpc_status {
00329 #define EVRPC_STATUS_ERR_NONE           0
00330 #define EVRPC_STATUS_ERR_TIMEOUT        1
00331 #define EVRPC_STATUS_ERR_BADPAYLOAD     2
00332 #define EVRPC_STATUS_ERR_UNSTARTED      3
00333 #define EVRPC_STATUS_ERR_HOOKABORTED    4
00334         int error;
00335 
00336         /* for looking at headers or other information */
00337         struct evhttp_request *http_req;
00338 };
00339 
00340 struct evrpc_request_wrapper {
00341         TAILQ_ENTRY(evrpc_request_wrapper) next;
00342 
00343         /* pool on which this rpc request is being made */
00344         struct evrpc_pool *pool;
00345 
00346         /* connection on which the request is being sent */
00347         struct evhttp_connection *evcon;
00348 
00349         /* event for implementing request timeouts */
00350         struct event ev_timeout;
00351 
00352         /* the name of the rpc */
00353         char *name;
00354 
00355         /* callback */
00356         void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
00357         void *cb_arg;
00358 
00359         void *request;
00360         void *reply;
00361 
00362         /* unmarshals the buffer into the proper request structure */
00363         void (*request_marshal)(struct evbuffer *, void *);
00364 
00365         /* removes all stored state in the reply */
00366         void (*reply_clear)(void *);
00367 
00368         /* marshals the reply into a buffer */
00369         int (*reply_unmarshal)(void *, struct evbuffer*);
00370 };
00371 
00387 #define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg)       \
00388         evrpc_send_request_##name(pool, request, reply, cb, cbarg)
00389 
00390 int evrpc_make_request(struct evrpc_request_wrapper *);
00391 
00402 struct evrpc_pool *evrpc_pool_new(struct event_base *base);
00408 void evrpc_pool_free(struct evrpc_pool *pool);
00409 /*
00410  * adds a connection over which rpc can be dispatched.  the connection
00411  * object must have been newly created.
00412  */
00413 void evrpc_pool_add_connection(struct evrpc_pool *, 
00414     struct evhttp_connection *);
00415 
00431 void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
00432 
00438 enum EVRPC_HOOK_TYPE {
00439         INPUT,          
00440         OUTPUT          
00441 };
00442 
00456 void *evrpc_add_hook(void *vbase,
00457     enum EVRPC_HOOK_TYPE hook_type,
00458     int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
00459     void *cb_arg);
00460 
00469 int evrpc_remove_hook(void *vbase,
00470     enum EVRPC_HOOK_TYPE hook_type,
00471     void *handle);
00472 
00473 #ifdef __cplusplus
00474 }
00475 #endif
00476 
00477 #endif /* _EVRPC_H_ */

Generated on Fri Apr 11 08:26:23 2008 for libevent by  doxygen 1.5.3