1 /* 2 * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu> 3 * Copyright (c) 2007-2011 Niels Provos and Nick Mathewson 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 28 /** @file rpc.h 29 * 30 * This header files provides basic support for an RPC server and client. 31 * 32 * To support RPCs in a server, every supported RPC command needs to be 33 * defined and registered. 34 * 35 * EVRPC_HEADER(SendCommand, Request, Reply); 36 * 37 * SendCommand is the name of the RPC command. 38 * Request is the name of a structure generated by event_rpcgen.py. 39 * It contains all parameters relating to the SendCommand RPC. The 40 * server needs to fill in the Reply structure. 41 * Reply is the name of a structure generated by event_rpcgen.py. It 42 * contains the answer to the RPC. 43 * 44 * To register an RPC with an HTTP server, you need to first create an RPC 45 * base with: 46 * 47 * evrpc_base* base = evrpc_init(http); 48 * 49 * A specific RPC can then be registered with 50 * 51 * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg); 52 * 53 * when the server receives an appropriately formatted RPC, the user callback 54 * is invoked. The callback needs to fill in the reply structure. 55 * 56 * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void* arg); 57 * 58 * To send the reply, call EVRPC_REQUEST_DONE(rpc); 59 * 60 * See the regression test for an example. 61 */ 62 module deimos.event2.rpc; 63 64 import deimos.event2._d_util; 65 66 extern (C): 67 nothrow: 68 69 /** 70 Determines if the member has been set in the message 71 72 @param msg the message to inspect 73 @param member the member variable to test for presences 74 @return 1 if it's present or 0 otherwise. 75 */ 76 int EVTAG_HAS(string member, T)(T msg) { 77 return mixin("*msg." ~ member ~ "_set") == 1; 78 } 79 80 /** 81 Assigns a value to the member in the message. 82 83 @param msg the message to which to assign a value 84 @param member the name of the member variable 85 @param value the value to assign 86 */ 87 void EVTAG_ASSIGN(string member, T, U)(T msg, U value) { 88 mixin("*msg.base." ~ member ~ "_assign")(msg, value); 89 } 90 91 /** 92 Assigns a value to the member in the message. 93 94 @param msg the message to which to assign a value 95 @param member the name of the member variable 96 @param value the value to assign 97 @param len the length of the value 98 */ 99 void EVTAG_ASSIGN_WITH_LEN(string member, T, U, V)(T msg, U value, V len) { 100 mixin("*msg.base." ~ member ~ "_assign")(msg, value, len); 101 } 102 103 /** 104 Returns the value for a member. 105 106 @param msg the message from which to get the value 107 @param member the name of the member variable 108 @param pvalue a pointer to the variable to hold the value 109 @return 0 on success, -1 otherwise. 110 */ 111 auto EVTAG_GET(string member, T, U)(T msg, U pvalue) { 112 return mixin("*msg.base." ~ member ~ "_get")(msg, pvalue); 113 } 114 115 /** 116 Returns the value for a member. 117 118 @param msg the message from which to get the value 119 @param member the name of the member variable 120 @param pvalue a pointer to the variable to hold the value 121 @param plen a pointer to the length of the value 122 @return 0 on success, -1 otherwise. 123 */ 124 auto EVTAG_GET(string member, T, U, V)(T msg, U pvalue, V plen) { 125 return mixin("*msg.base." ~ member ~ "_get")(msg, pvalue, plen); 126 } 127 128 /** 129 Adds a value to an array. 130 */ 131 auto EVTAG_ARRAY_ADD_VALUE(string member, T, U)(T msg, U value) { 132 return mixin("*msg.base." ~ member ~ "_add")(msg, value); 133 } 134 /** 135 Allocates a new entry in the array and returns it. 136 */ 137 auto EVTAG_ARRAY_ADD(string member, T)(T msg) { 138 return mixin("*msg.base." ~ member ~ "_add")(msg); 139 } 140 /** 141 Gets a variable at the specified offset from the array. 142 */ 143 auto EVTAG_ARRAY_ADD_VALUE(string member, T, U, V)(T msg, U offset, V pvalue) { 144 return mixin("*msg.base." ~ member ~ "_get")(msg, offset, pvalue); 145 } 146 /** 147 Returns the number of entries in the array. 148 */ 149 auto EVTAG_ARRAY_LEN(string member, T)(T msg) { 150 return mixin("msg." ~ member ~ "_length")(msg); 151 } 152 153 154 static import deimos.event2._opaque_structs; 155 156 alias event_base = deimos.event2._opaque_structs.event_base; 157 alias evrpc_req_generic = deimos.event2._opaque_structs.evrpc_req_generic; 158 alias evrpc_request_wrapper = deimos.event2._opaque_structs.evrpc_request_wrapper; 159 alias evrpc = deimos.event2._opaque_structs.evrpc; 160 161 /** The type of a specific RPC Message 162 * 163 * @param rpcname the name of the RPC message 164 */ 165 template EVRPC_STRUCT(string rpcname) { 166 enum EVRPC_STRUCT = "evrpc_req__" ~ rpcname; 167 } 168 169 alias evhttp_request = deimos.event2._opaque_structs.evhttp_request; 170 alias evrpc_status = deimos.event2._opaque_structs.evrpc_status; 171 alias evrpc_hook_meta = deimos.event2._opaque_structs.evrpc_hook_meta; 172 173 /** Creates the definitions and prototypes for an RPC 174 * 175 * You need to use EVRPC_HEADER to create structures and function prototypes 176 * needed by the server and client implementation. The structures have to be 177 * defined in an .rpc file and converted to source code via event_rpcgen.py 178 * 179 * @param rpcname the name of the RPC 180 * @param reqthe name of the RPC request structure 181 * @param replythe name of the RPC reply structure 182 * @see EVRPC_GENERATE() 183 */ 184 mixin template EVRPC_HEADER(string rpcname, reqstruct, rplystruct) { 185 mixin(EVRPC_STRUCT!rpcname ~ q{ 186 evrpc_hook_meta* hook_meta; 187 reqstruct* request; 188 rplystruct* reply; 189 evrpc* rpc; 190 evhttp_request* http_req; 191 evbuffer* rpc_data; 192 } ~ "}"); 193 mixin("int evrpc_send_request_" ~ rpcname ~ q{(evrpc_pool*, 194 reqstruct*, rplystruct*, 195 ExternC!(void function(evrpc_status*, 196 reqstruct*, rplystruct*, void* cbarg)) 197 void*)} ~ ";" 198 ); 199 } 200 struct evrpc_pool; 201 202 /** use EVRPC_GENERATE instead */ 203 evrpc_request_wrapper* evrpc_make_request_ctx( 204 evrpc_pool* pool, void* request, void* reply, 205 const(char)* rpcname, 206 ExternC!(void function(evbuffer*, void*)) req_marshal, 207 ExternC!(void function(void*)) rpl_clear, 208 ExternC!(int function(void*, evbuffer*)) rpl_unmarshal, 209 ExternC!(void function(evrpc_status*, void*, void*, void*)) cb, 210 void* cbarg); 211 212 /** Creates a context structure that contains rpc specific information. 213 * 214 * EVRPC_MAKE_CTX is used to populate a RPC specific context that 215 * contains information about marshaling the RPC data types. 216 * 217 * @param rpcname the name of the RPC 218 * @param reqthe name of the RPC request structure 219 * @param replythe name of the RPC reply structure 220 * @param pool the evrpc_pool over which to make the request 221 * @param request a pointer to the RPC request structure object 222 * @param reply a pointer to the RPC reply structure object 223 * @param cb the callback function to call when the RPC has completed 224 * @param cbarg the argument to supply to the callback 225 */ 226 auto EVRPC_MAKE_CTX(string rpcname, string reqstruct, string rplystruct, U, V)( 227 evrpc_pool* pool, void* request, void* reply, U cb, V cbarg) { 228 return evrpc_make_request_ctx(pool, request, reply, 229 rpcname, 230 cast(ExternC!(void function(evbuffer*, void*)) )mixin(reqstruct ~ "_marshal"), 231 cast(ExternC!(void function(void*)) )mixin(rplystruct ~ "_clear"), 232 cast(ExternC!(int function(void*, evbuffer*)) )mixin(rplystruct ~ "_unmarshal"), 233 cast(ExternC!(void function(evrpc_status*, void*, void*, void*)) )cb, 234 cbarg); 235 } 236 237 /** Generates the code for receiving and sending an RPC message 238 * 239 * EVRPC_GENERATE is used to create the code corresponding to sending 240 * and receiving a particular RPC message 241 * 242 * @param rpcname the name of the RPC 243 * @param reqthe name of the RPC request structure 244 * @param replythe name of the RPC reply structure 245 * @see EVRPC_HEADER() 246 */ 247 mixin template EVRPC_GENERATE(string rpcname, string reqstruct, string rplystruct) { 248 mixin("int evrpc_send_request_" ~ rpcname ~ "(evrpc_pool* pool, 249 reqstruct* request, " ~ rplystruct ~ "* reply, 250 void ExternC!(function(evrpc_status*, " ~ req ~ "*, " ~ rplystruct ~ "*, void* cbarg)) cb, 251 void* cbarg) { 252 return evrpc_send_request_generic(pool, request, reply, 253 (ExternC!(void function(evrpc_status*, void*, void*, void*)) )cb, 254 cbarg, 255 " ~ rpcname ~ ", 256 (ExternC!(void function(evbuffer*, void*)) )" ~ reqstruct ~ "_marshal, 257 (ExternC!(void function(void*)) )" ~ rplystruct ~ "_clear, 258 (ExternC!(int function(void*, evbuffer*)) )" ~ rplystruct ~ "_unmarshal); 259 }"); 260 } 261 262 263 /** Provides access to the HTTP request object underlying an RPC 264 * 265 * Access to the underlying http object; can be used to look at headers or 266 * for getting the remote ip address 267 * 268 * @param rpc_req the rpc request structure provided to the server callback 269 * @return an evhttp_request object that can be inspected for 270 * HTTP headers or sender information. 271 */ 272 auto EVRPC_REQUEST_HTTP(T)(T rpc_req) { 273 return rpc_req.http_req; 274 } 275 276 /** completes the server response to an rpc request */ 277 void evrpc_request_done(evrpc_req_generic* req); 278 279 /** accessors for request and reply */ 280 void* evrpc_get_request(evrpc_req_generic* req); 281 void* evrpc_get_reply(evrpc_req_generic* req); 282 283 /** Creates the reply to an RPC request 284 * 285 * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected 286 * to have been filled in. The request and reply pointers become invalid 287 * after this call has finished. 288 * 289 * @param rpc_req the rpc request structure provided to the server callback 290 */ 291 void EVRPC_REQUEST_DONE(T)(rpc_req) { 292 evrpc_req_generic* _req = cast(evrpc_req_generic*)(rpc_req); 293 evrpc_request_done(_req); 294 } 295 296 297 struct evrpc_base; 298 struct evhttp; 299 300 /* functions to start up the rpc system */ 301 302 /** Creates a new rpc base from which RPC requests can be received 303 * 304 * @param server a pointer to an existing HTTP server 305 * @return a newly allocated evrpc_base struct 306 * @see evrpc_free() 307 */ 308 evrpc_base* evrpc_init(evhttp* server); 309 310 /** 311 * Frees the evrpc base 312 * 313 * For now, you are responsible for making sure that no rpcs are ongoing. 314 * 315 * @param base the evrpc_base object to be freed 316 * @see evrpc_init 317 */ 318 void evrpc_free(evrpc_base* base); 319 320 /** register RPCs with the HTTP Server 321 * 322 * registers a new RPC with the HTTP server, each RPC needs to have 323 * a unique name under which it can be identified. 324 * 325 * @param base the evrpc_base structure in which the RPC should be 326 * registered. 327 * @param name the name of the RPC 328 * @param request the name of the RPC request structure 329 * @param reply the name of the RPC reply structure 330 * @param callback the callback that should be invoked when the RPC 331 * is received. The callback has the following prototype 332 * void (*callback)(EVRPC_STRUCT(Message)* rpc, void* arg) 333 * @param cbarg an additional parameter that can be passed to the callback. 334 * The parameter can be used to carry around state. 335 */ 336 template EVRPC_REGISTER(string base, string name, string request, string reply, 337 string callback, string cbarg 338 ) { 339 enum EVRPC_REGISTER = " 340 evrpc_register_generic(" ~ base ~ ", `" ~ name ~ "`, 341 (ExternC!(void function(evrpc_req_generic*, void*)) )" ~ callback ~ ", " ~ cbarg ~ ", 342 (ExternC!(void* function(void*)) )" ~ request ~ "_new, NULL, 343 (ExternC!(void function(void*)) )" ~ request ~ "_free, 344 (ExternC!(int function(void*, evbuffer*)) )" ~ request ~ "_unmarshal, 345 (ExternC!(void* function(void*)) )" ~ reply ~ "_new, NULL, 346 (ExternC!(void function(void*)) )" ~ reply ~ "_free, 347 (ExternC!(int function(void*)) )" ~ reply ~ "_complete, 348 (ExternC!(void function(evbuffer*, void*)) )" ~ reply ~ "_marshal) 349 "; 350 } 351 352 /** 353 Low level function for registering an RPC with a server. 354 355 Use EVRPC_REGISTER() instead. 356 357 @see EVRPC_REGISTER() 358 */ 359 int evrpc_register_rpc(evrpc_base*, evrpc*, 360 ExternC!(void function(evrpc_req_generic*, void*)) , void*); 361 362 /** 363 * Unregisters an already registered RPC 364 * 365 * @param base the evrpc_base object from which to unregister an RPC 366 * @param name the name of the rpc to unregister 367 * @return -1 on error or 0 when successful. 368 * @see EVRPC_REGISTER() 369 */ 370 alias evrpc_unregister_rpc EVRPC_UNREGISTER; 371 372 int evrpc_unregister_rpc(evrpc_base* base, const(char)* name); 373 374 /* 375 * Client-side RPC support 376 */ 377 378 struct evhttp_connection; 379 380 /** launches an RPC and sends it to the server 381 * 382 * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server. 383 * 384 * @param name the name of the RPC 385 * @param pool the evrpc_pool that contains the connection objects over which 386 * the request should be sent. 387 * @param request a pointer to the RPC request structure - it contains the 388 * data to be sent to the server. 389 * @param reply a pointer to the RPC reply structure. It is going to be filled 390 * if the request was answered successfully 391 * @param cb the callback to invoke when the RPC request has been answered 392 * @param cbarg an additional argument to be passed to the client 393 * @return 0 on success, -1 on failure 394 */ 395 template ENRPC_MAKE_REQUEST(string name, string pool, string request, 396 string reply, string cb, string cbarg 397 ) { 398 enum EVRPC_MAKE_REQUEST = "evrpc_send_request_" ~ name ~ "((" ~ pool ~ 399 "), (" ~ request ~" ), (" ~ reply ~ "), (" ~ cb ~ "), (" ~ cbarg ~ "))"; 400 } 401 402 /** 403 Makes an RPC request based on the provided context. 404 405 This is a low-level function and should not be used directly 406 unless a custom context object is provided. Use EVRPC_MAKE_REQUEST() 407 instead. 408 409 @param ctx a context from EVRPC_MAKE_CTX() 410 @returns 0 on success, -1 otherwise. 411 @see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX() 412 */ 413 int evrpc_make_request(evrpc_request_wrapper* ctx); 414 415 /** creates an rpc connection pool 416 * 417 * a pool has a number of connections associated with it. 418 * rpc requests are always made via a pool. 419 * 420 * @param base a pointer to an event_based object; can be left NULL 421 * in singled-threaded applications 422 * @return a newly allocated evrpc_pool object 423 * @see evrpc_pool_free() 424 */ 425 evrpc_pool* evrpc_pool_new(event_base* base); 426 /** frees an rpc connection pool 427 * 428 * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new() 429 * @see evrpc_pool_new() 430 */ 431 void evrpc_pool_free(evrpc_pool* pool); 432 433 /** 434 * Adds a connection over which rpc can be dispatched to the pool. 435 * 436 * The connection object must have been newly created. 437 * 438 * @param pool the pool to which to add the connection 439 * @param evcon the connection to add to the pool. 440 */ 441 void evrpc_pool_add_connection(evrpc_pool* pool, 442 evhttp_connection* evcon); 443 444 /** 445 * Removes a connection from the pool. 446 * 447 * The connection object must have been newly created. 448 * 449 * @param pool the pool from which to remove the connection 450 * @param evcon the connection to remove from the pool. 451 */ 452 void evrpc_pool_remove_connection(evrpc_pool* pool, 453 evhttp_connection* evcon); 454 455 /** 456 * Sets the timeout in secs after which a request has to complete. The 457 * RPC is completely aborted if it does not complete by then. Setting 458 * the timeout to 0 means that it never timeouts and can be used to 459 * implement callback type RPCs. 460 * 461 * Any connection already in the pool will be updated with the new 462 * timeout. Connections added to the pool after set_timeout has be 463 * called receive the pool timeout only if no timeout has been set 464 * for the connection itself. 465 * 466 * @param pool a pointer to a evrpc_pool object 467 * @param timeout_in_secs the number of seconds after which a request should 468 * timeout and a failure be returned to the callback. 469 */ 470 void evrpc_pool_set_timeout(evrpc_pool* pool, int timeout_in_secs); 471 472 /** 473 * Hooks for changing the input and output of RPCs; this can be used to 474 * implement compression, authentication, encryption, ... 475 */ 476 477 enum EVRPC_HOOK_TYPE { 478 EVRPC_INPUT, /**< apply the function to an input hook */ 479 EVRPC_OUTPUT /**< apply the function to an output hook */ 480 } 481 482 /** Deprecated alias for EVRPC_INPUT. Not available on windows, where it 483 * conflicts with platform headers. */ 484 enum INPUT = EVRPC_HOOK_TYPE.EVRPC_INPUT; 485 /** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it 486 * conflicts with platform headers. */ 487 enum OUTPUT = EVRPC_HOOK_TYPE.EVRPC_OUTPUT; 488 489 /** 490 * Return value from hook processing functions 491 */ 492 493 enum EVRPC_HOOK_RESULT { 494 EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */ 495 EVRPC_CONTINUE = 0, /**< continue processing the rpc */ 496 EVRPC_PAUSE = 1 /**< pause processing request until resumed */ 497 }; 498 499 struct evbuffer; 500 /** adds a processing hook to either an rpc base or rpc pool 501 * 502 * If a hook returns TERMINATE, the processing is aborted. On CONTINUE, 503 * the request is immediately processed after the hook returns. If the 504 * hook returns PAUSE, request processing stops until evrpc_resume_request() 505 * has been called. 506 * 507 * The add functions return handles that can be used for removing hooks. 508 * 509 * @param vbase a pointer to either evrpc_base or struct evrpc_pool 510 * @param hook_type either INPUT or OUTPUT 511 * @param cb the callback to call when the hook is activated 512 * @param cb_arg an additional argument for the callback 513 * @return a handle to the hook so it can be removed later 514 * @see evrpc_remove_hook() 515 */ 516 void* evrpc_add_hook(void* vbase, 517 EVRPC_HOOK_TYPE hook_type, 518 ExternC!(int function(void*, evhttp_request*, evbuffer*, void*)) cb, 519 void* cb_arg); 520 521 /** removes a previously added hook 522 * 523 * @param vbase a pointer to either evrpc_base or struct evrpc_pool 524 * @param hook_type either INPUT or OUTPUT 525 * @param handle a handle returned by evrpc_add_hook() 526 * @return 1 on success or 0 on failure 527 * @see evrpc_add_hook() 528 */ 529 int evrpc_remove_hook(void* vbase, 530 EVRPC_HOOK_TYPE hook_type, 531 void* handle); 532 533 /** resume a paused request 534 * 535 * @param vbase a pointer to either evrpc_base or struct evrpc_pool 536 * @param ctx the context pointer provided to the original hook call 537 */ 538 int 539 evrpc_resume_request(void* vbase, void* ctx, EVRPC_HOOK_RESULT res); 540 541 /** adds meta data to request 542 * 543 * evrpc_hook_add_meta() allows hooks to add meta data to a request. for 544 * a client request, the meta data can be inserted by an outgoing request hook 545 * and retrieved by the incoming request hook. 546 * 547 * @param ctx the context provided to the hook call 548 * @param key a NUL-terminated c-string 549 * @param data the data to be associated with the key 550 * @param data_size the size of the data 551 */ 552 void evrpc_hook_add_meta(void* ctx, const(char)* key, 553 const(void)* data, size_t data_size); 554 555 /** retrieves meta data previously associated 556 * 557 * evrpc_hook_find_meta() can be used to retrieve meta data associated to a 558 * request by a previous hook. 559 * @param ctx the context provided to the hook call 560 * @param key a NUL-terminated c-string 561 * @param data pointer to a data pointer that will contain the retrieved data 562 * @param data_size pointer to the size of the data 563 * @return 0 on success or -1 on failure 564 */ 565 int evrpc_hook_find_meta(void* ctx, const(char)* key, 566 void* *data, size_t* data_size); 567 568 /** 569 * returns the connection object associated with the request 570 * 571 * @param ctx the context provided to the hook call 572 * @return a pointer to the evhttp_connection object 573 */ 574 evhttp_connection* evrpc_hook_get_connection(void* ctx); 575 576 /** 577 Function for sending a generic RPC request. 578 579 Do not call this function directly, use EVRPC_MAKE_REQUEST() instead. 580 581 @see EVRPC_MAKE_REQUEST() 582 */ 583 int evrpc_send_request_generic(evrpc_pool* pool, 584 void* request, void* reply, 585 ExternC!(void function(evrpc_status*, void*, void*, void*)) cb, 586 void* cb_arg, 587 const(char)* rpcname, 588 ExternC!(void function(evbuffer*, void*)) req_marshal, 589 ExternC!(void function(void*)) rpl_clear, 590 ExternC!(int function(void*, evbuffer*)) rpl_unmarshal); 591 592 /** 593 Function for registering a generic RPC with the RPC base. 594 595 Do not call this function directly, use EVRPC_REGISTER() instead. 596 597 @see EVRPC_REGISTER() 598 */ 599 int 600 evrpc_register_generic(evrpc_base* base, const(char)* name, 601 ExternC!(void function(evrpc_req_generic*, void*)) callback, void* cbarg, 602 ExternC!(void* function(void*)) req_new, void* req_new_arg, ExternC!(void function(void*)) req_free, 603 ExternC!(int function(void*, evbuffer*)) req_unmarshal, 604 ExternC!(void* function(void*)) rpl_new, void* rpl_new_arg, ExternC!(void function(void*)) rpl_free, 605 ExternC!(int function(void*)) rpl_complete, 606 ExternC!(void function(evbuffer*, void*)) rpl_marshal); 607 608 /** accessors for obscure and undocumented functionality */ 609 evrpc_pool* evrpc_request_get_pool(evrpc_request_wrapper* ctx); 610 void evrpc_request_set_pool(evrpc_request_wrapper* ctx, 611 evrpc_pool* pool); 612 void evrpc_request_set_cb(evrpc_request_wrapper* ctx, 613 ExternC!(void function(evrpc_status*, void* request, void* reply, void* arg)) cb, 614 void* cb_arg);