| 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 |