From: <np...@us...> - 2007-12-29 22:46:00
|
Revision: 622 http://levent.svn.sourceforge.net/levent/?rev=622&view=rev Author: nprovos Date: 2007-12-29 14:45:54 -0800 (Sat, 29 Dec 2007) Log Message: ----------- allow association of meta data with RPC requests for hook processing Modified Paths: -------------- trunk/libevent/ChangeLog trunk/libevent/evrpc-internal.h trunk/libevent/evrpc.c trunk/libevent/evrpc.h trunk/libevent/test/regress_rpc.c Modified: trunk/libevent/ChangeLog =================================================================== --- trunk/libevent/ChangeLog 2007-12-28 07:58:29 UTC (rev 621) +++ trunk/libevent/ChangeLog 2007-12-29 22:45:54 UTC (rev 622) @@ -32,6 +32,7 @@ o support string arrays in event_rpcgen o change evrpc hooking to allow pausing of RPCs; this will make it possible for the hook to do some meaning ful work; this is not backwards compatible. o allow an http request callback to take ownership of a request structure + o allow association of meta data with RPC requests for hook processing Changes in 1.4.0: o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr. Modified: trunk/libevent/evrpc-internal.h =================================================================== --- trunk/libevent/evrpc-internal.h 2007-12-28 07:58:29 UTC (rev 621) +++ trunk/libevent/evrpc-internal.h 2007-12-29 22:45:54 UTC (rev 622) @@ -36,7 +36,9 @@ struct evrpc_hook { TAILQ_ENTRY(evrpc_hook) (next); - /* returns -1; if the rpc should be aborted, is allowed to rewrite */ + /* returns EVRPC_TERMINATE; if the rpc should be aborted. + * a hook is is allowed to rewrite the evbuffer + */ int (*process)(void *, struct evhttp_request *, struct evbuffer *, void *); void *process_arg; @@ -98,4 +100,17 @@ void (*cb)(void *, enum EVRPC_HOOK_RESULT); }; +struct evrpc_meta { + TAILQ_ENTRY(evrpc_meta) (next); + char *key; + + void *data; + size_t data_size; +}; + +TAILQ_HEAD(evrpc_meta_list, evrpc_meta); + +/* frees the meta data associated with a request */ +static void evrpc_meta_data_free(struct evrpc_meta_list *meta_data); + #endif /* _EVRPC_INTERNAL_H_ */ Modified: trunk/libevent/evrpc.c =================================================================== --- trunk/libevent/evrpc.c 2007-12-28 07:58:29 UTC (rev 621) +++ trunk/libevent/evrpc.c 2007-12-29 22:45:54 UTC (rev 622) @@ -365,6 +365,8 @@ rpc = rpc_state->rpc; /* clean up all memory */ + if (rpc_state->meta_data != NULL) + evrpc_meta_data_free(rpc_state->meta_data); if (rpc_state->request != NULL) rpc->request_free(rpc_state->request); if (rpc_state->reply != NULL) @@ -477,6 +479,8 @@ static void evrpc_request_wrapper_free(struct evrpc_request_wrapper *request) { + if (request->meta_data != NULL) + evrpc_meta_data_free(request->meta_data); event_free(request->name); event_free(request); } @@ -749,6 +753,41 @@ return (0); } + +struct evrpc_request_wrapper * +evrpc_send_request_generic( + struct evrpc_pool *pool, void *request, void *reply, + const char *rpcname, + void (*req_marshal)(struct evbuffer*, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *), + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cbarg) +{ + struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *) + event_malloc(sizeof(struct evrpc_request_wrapper)); + if (ctx == NULL) + return (NULL); + + ctx->pool = pool; + ctx->meta_data = NULL; + ctx->evcon = NULL; + ctx->name = event_strdup(rpcname); + if (ctx->name == NULL) { + event_free(ctx); + return (NULL); + } + ctx->cb = cb; + ctx->cb_arg = cbarg; + ctx->request = request; + ctx->reply = reply; + ctx->request_marshal = req_marshal; + ctx->reply_clear = rpl_clear; + ctx->reply_unmarshal = rpl_unmarshal; + + return (ctx); +} + static void evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT); @@ -864,3 +903,66 @@ evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); } + +/* + * frees potential meta data associated with a request. + */ + +static void +evrpc_meta_data_free(struct evrpc_meta_list *meta_data) +{ + struct evrpc_meta *entry; + assert(meta_data != NULL); + + while ((entry = TAILQ_FIRST(meta_data)) != NULL) { + TAILQ_REMOVE(meta_data, entry, next); + event_free(entry->key); + event_free(entry->data); + event_free(entry); + } + + event_free(meta_data); +} + +/* adds meta data */ +void +evrpc_hook_add_meta(void *ctx, const char *key, + const void *data, size_t data_size) +{ + struct evrpc_request_wrapper *req = ctx; + struct evrpc_meta *meta = NULL; + + if (req->meta_data == NULL) { + req->meta_data = event_malloc(sizeof(struct evrpc_meta_list)); + assert(req->meta_data != NULL); + TAILQ_INIT(req->meta_data); + } + + assert((meta = event_malloc(sizeof(struct evrpc_meta))) != NULL); + assert((meta->key = event_strdup(key)) != NULL); + meta->data_size = data_size; + assert((meta->data = event_malloc(data_size)) != NULL); + memcpy(meta->data, data, data_size); + + TAILQ_INSERT_TAIL(req->meta_data, meta, next); +} + +int +evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size) +{ + struct evrpc_request_wrapper *req = ctx; + struct evrpc_meta *meta = NULL; + + if (req->meta_data == NULL) + return (-1); + + TAILQ_FOREACH(meta, req->meta_data, next) { + if (strcmp(meta->key, key) == 0) { + *data = meta->data; + *data_size = meta->data_size; + return (0); + } + } + + return (-1); +} Modified: trunk/libevent/evrpc.h =================================================================== --- trunk/libevent/evrpc.h 2007-12-28 07:58:29 UTC (rev 621) +++ trunk/libevent/evrpc.h 2007-12-29 22:45:54 UTC (rev 622) @@ -114,9 +114,16 @@ struct evhttp_request; struct evrpc_status; +struct evrpc_meta_list; /* We alias the RPC specific structs to this voided one */ struct evrpc_req_generic { + /* + * allows association of meta data via hooks - needs to be + * synchronized with evrpc_request_wrapper + */ + struct evrpc_meta_list *meta_data; + /* the unmarshaled request object */ void *request; @@ -158,6 +165,7 @@ */ #define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \ EVRPC_STRUCT(rpcname) { \ + struct evrpc_meta_list *meta_data; \ struct reqstruct* request; \ struct rplystruct* reply; \ struct evrpc* rpc; \ @@ -172,6 +180,18 @@ struct reqstruct *, struct rplystruct *, void *cbarg), \ void *); +struct evrpc_pool; + +/** use EVRPC_GENERATE instead */ +struct evrpc_request_wrapper *evrpc_send_request_generic( + struct evrpc_pool *pool, void *request, void *reply, + const char *rpcname, + void (*req_marshal)(struct evbuffer*, void *), + void (*rpl_clear)(void *), + int (*rpl_unmarshal)(void *, struct evbuffer *), + void (*cb)(struct evrpc_status *, void *, void *, void *), + void *cbarg); + /** Generates the code for receiving and sending an RPC message * * EVRPC_GENERATE is used to create the code corresponding to sending @@ -190,25 +210,15 @@ void *cbarg) { \ struct evrpc_status status; \ struct evrpc_request_wrapper *ctx; \ - ctx = (struct evrpc_request_wrapper *) \ - malloc(sizeof(struct evrpc_request_wrapper)); \ + ctx = evrpc_send_request_generic(pool, request, reply, \ + #rpcname, \ + (void (*)(struct evbuffer *, void *))reqstruct##_marshal, \ + (void (*)(void *))rplystruct##_clear, \ + (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \ + (void (*)(struct evrpc_status *, void *, void *, void *))cb, \ + cbarg); \ if (ctx == NULL) \ goto error; \ - ctx->pool = pool; \ - ctx->evcon = NULL; \ - ctx->name = strdup(#rpcname); \ - if (ctx->name == NULL) { \ - free(ctx); \ - goto error; \ - } \ - ctx->cb = (void (*)(struct evrpc_status *, \ - void *, void *, void *))cb; \ - ctx->cb_arg = cbarg; \ - ctx->request = (void *)request; \ - ctx->reply = (void *)reply; \ - ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \ - ctx->reply_clear = (void (*)(void *))rplystruct##_clear; \ - ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \ return (evrpc_make_request(ctx)); \ error: \ memset(&status, 0, sizeof(status)); \ @@ -325,7 +335,6 @@ * Client-side RPC support */ -struct evrpc_pool; struct evhttp_connection; /** @@ -344,6 +353,12 @@ }; struct evrpc_request_wrapper { + /* + * allows association of meta data via hooks - needs to be + * synchronized with evrpc_req_generic. + */ + struct evrpc_meta_list *meta_data; + TAILQ_ENTRY(evrpc_request_wrapper) next; /* pool on which this rpc request is being made */ @@ -500,6 +515,33 @@ int evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res); +/** adds meta data to request + * + * evrpc_hook_add_meta() allows hooks to add meta data to a request. for + * a client requet, the meta data can be inserted by an outgoing request hook + * and retrieved by the incoming request hook. + * + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data the data to be associated with the key + * @param data_size the size of the data + */ +void evrpc_hook_add_meta(void *ctx, const char *key, + const void *data, size_t data_size); + +/** retrieves meta data previously associated + * + * evrpc_hook_find_meta() can be used to retrieve meta data associated to a + * request by a previous hook. + * @param ctx the context provided to the hook call + * @param key a NUL-terminated c-string + * @param data pointer to a data pointer that will contain the retrieved data + * @param data_size pointer tothe size of the data + * @return 0 on success or -1 on failure + */ +int evrpc_hook_find_meta(void *ctx, const char *key, + void **data, size_t *data_size); + #ifdef __cplusplus } #endif Modified: trunk/libevent/test/regress_rpc.c =================================================================== --- trunk/libevent/test/regress_rpc.c 2007-12-28 07:58:29 UTC (rev 621) +++ trunk/libevent/test/regress_rpc.c 2007-12-29 22:45:54 UTC (rev 622) @@ -417,20 +417,38 @@ evhttp_add_header(req->input_headers, "X-Hook", hook_type); else evhttp_add_header(req->output_headers, "X-Hook", hook_type); - return (0); + + return (EVRPC_CONTINUE); } static int +rpc_hook_add_meta(void *ctx, struct evhttp_request *req, + struct evbuffer *evbuf, void *arg) +{ + evrpc_hook_add_meta(ctx, "meta", "test", 5); + + return (EVRPC_CONTINUE); +} + +static int rpc_hook_remove_header(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf, void *arg) { const char *header = evhttp_find_header(req->input_headers, "X-Hook"); + void *data = NULL; + size_t data_len = 0; + assert(header != NULL); assert(strcmp(header, arg) == 0); + evhttp_remove_header(req->input_headers, "X-Hook"); evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran"); - return (0); + assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0); + assert(data != NULL); + assert(data_len == 5); + + return (EVRPC_CONTINUE); } static void @@ -457,6 +475,7 @@ pool = rpc_pool_with_connection(port); + assert(evrpc_add_hook(pool, OUTPUT, rpc_hook_add_meta, NULL)); assert(evrpc_add_hook(pool, INPUT, rpc_hook_remove_header, (void*)"output")); /* set up the basic message */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |