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