Annotation of embedaddon/libevent/evrpc.h, revision 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>