refactoring context handling
authorJosé Bollo <jose.bollo@iot.bzh>
Tue, 19 Apr 2016 11:23:08 +0000 (13:23 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 19 Apr 2016 11:23:08 +0000 (13:23 +0200)
Change-Id: I0e5a900efbd94b66f309ff4d0d49a6406585203f
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
12 files changed:
include/afb-plugin.h
include/afb-req-itf.h
plugins/samples/ClientCtx.c
plugins/session/token-api.c
src/afb-api-so.c
src/afb-apis.c
src/afb-apis.h
src/afb-hreq.c
src/afb-ws-json.c
src/main.c
src/session.c
src/session.h

index c7252d6..dfb6fba 100644 (file)
@@ -55,7 +55,6 @@ struct AFB_plugin
        const char *info;
        const char *prefix;
        const struct AFB_restapi *apis;
-       void (*freeCtxCB)(void*);  // callback to free application context [null for standard free]
 };
 
 /* config mode */
index 357ffd7..f03ce86 100644 (file)
@@ -26,26 +26,27 @@ struct afb_arg {
 };
 
 struct afb_req_itf {
-       struct json_object *(*json)(void *data);
-       struct afb_arg (*get)(void *data, const char *name);
-       void (*success)(void *data, struct json_object *obj, const char *info);
-       void (*fail)(void *data, const char *status, const char *info);
-       const char *(*raw)(void *data, size_t *size);
-       void (*send)(void *data, char *buffer, size_t size);
-       int (*session_create)(void *data);
-       int (*session_check)(void *data, int refresh);
-       void (*session_close)(void *data);
+       struct json_object *(*json)(void *req_closure);
+       struct afb_arg (*get)(void *req_closure, const char *name);
+       void (*success)(void *req_closure, struct json_object *obj, const char *info);
+       void (*fail)(void *req_closure, const char *status, const char *info);
+       const char *(*raw)(void *req_closure, size_t *size);
+       void (*send)(void *req_closure, char *buffer, size_t size);
+       void *(*context_get)(void *ctx_closure);
+       void (*context_set)(void *ctx_closure, void *context, void (*free_context)(void*));
+       int (*session_create)(void *req_closure);
+       int (*session_check)(void *req_closure, int refresh);
+       void (*session_close)(void *req_closure);
 };
 
 struct afb_req {
        const struct afb_req_itf *itf;
-       void *data;
-       void **context;
+       void *req_closure;
+       void *ctx_closure;
 };
-
 static inline struct afb_arg afb_req_get(struct afb_req req, const char *name)
 {
-       return req.itf->get(req.data, name);
+       return req.itf->get(req.req_closure, name);
 }
 
 static inline const char *afb_req_value(struct afb_req req, const char *name)
@@ -60,32 +61,47 @@ static inline const char *afb_req_path(struct afb_req req, const char *name)
 
 static inline struct json_object *afb_req_json(struct afb_req req)
 {
-       return req.itf->json(req.data);
+       return req.itf->json(req.req_closure);
 }
 
 static inline void afb_req_success(struct afb_req req, struct json_object *obj, const char *info)
 {
-       req.itf->success(req.data, obj, info);
+       req.itf->success(req.req_closure, obj, info);
 }
 
 static inline void afb_req_fail(struct afb_req req, const char *status, const char *info)
 {
-       req.itf->fail(req.data, status, info);
+       req.itf->fail(req.req_closure, status, info);
 }
 
 static inline const char *afb_req_raw(struct afb_req req, size_t *size)
 {
-       return req.itf->raw(req.data, size);
+       return req.itf->raw(req.req_closure, size);
 }
 
 static inline void afb_req_send(struct afb_req req, char *buffer, size_t size)
 {
-       req.itf->send(req.data, buffer, size);
+       req.itf->send(req.req_closure, buffer, size);
+}
+
+static inline void *afb_req_context_get(struct afb_req req)
+{
+       return req.itf->context_get(req.ctx_closure);
+}
+
+static inline void afb_req_context_set(struct afb_req req, void *context, void (*free_context)(void*))
+{
+       return req.itf->context_set(req.ctx_closure, context, free_context);
+}
+
+static inline void afb_req_context_clear(struct afb_req req)
+{
+       afb_req_context_set(req, NULL, NULL);
 }
 
 static inline int afb_req_session_create(struct afb_req req)
 {
-       int result = req.itf->session_create(req.data);
+       int result = req.itf->session_create(req.req_closure);
        if (!result)
                afb_req_fail(req, "fail", "Can't create the session");
        return result;
@@ -93,7 +109,7 @@ static inline int afb_req_session_create(struct afb_req req)
 
 static inline int afb_req_session_check(struct afb_req req, int refresh)
 {
-       int result = req.itf->session_check(req.data, refresh);
+       int result = req.itf->session_check(req.req_closure, refresh);
        if (!result)
                afb_req_fail(req, "fail", "Token chek failed for the session");
        return result;
@@ -101,7 +117,7 @@ static inline int afb_req_session_check(struct afb_req req, int refresh)
 
 static inline void afb_req_session_close(struct afb_req req)
 {
-       req.itf->session_close(req.data);
+       req.itf->session_close(req.req_closure);
 }
 
 #if !defined(_GNU_SOURCE)
index 24cb4f3..11d1024 100644 (file)
 
 #include "afb-plugin.h"
 
-typedef struct {
-  /* 
-   * In case your plugin is implemented on multiple files or used share routines
-   * with other plugins, it might not be possible to use global static variable.
-   * In this case you can attach a static handle to your plugin. This handle
-   * is passed within each API call under request->handle
-   * 
-   */  
-  void *anythingYouWant;
-
-  
-} MyPluginHandleT;
-
 typedef struct {
   /* 
    * client context is attached a session but private to a each plugin.
@@ -57,24 +44,19 @@ typedef struct {
   
 } MyClientContextT;
 
-
-// Plugin handle should not be in stack (malloc or static)
-static MyPluginHandleT global_handle;
-    
 // This function is call at session open time. Any client trying to 
 // call it with an already open session will be denied.
 // Ex: http://localhost:1234/api/context/create?token=123456789
 static void myCreate (struct afb_req request)
 {
     MyClientContextT *ctx = malloc (sizeof (MyClientContextT));
-    MyPluginHandleT  *handle = (MyPluginHandleT*) &global_handle;
 
     // store something in our plugin private client context
     ctx->count = 0;
     ctx->abcd  = "SomeThingUseful";        
 
-    *request.context = ctx;
-    afb_req_success_f(request, NULL, "SUCCESS: create client context for plugin [%s]", handle->anythingYouWant);
+    afb_req_context_set(request, ctx, free);
+    afb_req_success_f(request, NULL, "SUCCESS: create client context for plugin [%s]", ctx->abcd);
 }
 
 // This function can only be called with a valid token. Token should be renew before
@@ -83,12 +65,11 @@ static void myCreate (struct afb_req request)
 // ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
 static void myAction (struct afb_req request)
 {
-    MyPluginHandleT  *handle = (MyPluginHandleT*) &global_handle;
-    MyClientContextT *ctx = (MyClientContextT*) *request.context;
+    MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
     
     // store something in our plugin private client context
     ctx->count++;
-    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Check=[%d]\n", handle->anythingYouWant, ctx->count);
+    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Check=[%d]\n", ctx->abcd, ctx->count);
 }
 
 // After execution of this function, client session will be close and if they
@@ -97,20 +78,11 @@ static void myAction (struct afb_req request)
 // ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
 static void myClose (struct afb_req request)
 {
-    MyPluginHandleT  *handle = (MyPluginHandleT*) &global_handle;
-    MyClientContextT *ctx = (MyClientContextT*) *request.context;
+    MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
     
     // store something in our plugin private client context
     ctx->count++;
-    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Close=[%d]\n", handle->anythingYouWant, ctx->count);
-}
-
-static void freeCtxCB (MyClientContextT *ctx) {
-    MyPluginHandleT  *handle = (MyPluginHandleT*) &global_handle;
-    fprintf (stderr, "FreeCtxCB Plugin=[%s]  count=[%d]", (char*)handle->anythingYouWant, ctx->count);
-    free (ctx);
-    
-    // Note: handle should be free it is a static resource attached to plugin and not to session
+    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Close=[%d]\n", ctx->abcd, ctx->count);
 }
 
 // NOTE: this sample does not use session to keep test a basic as possible
@@ -127,12 +99,10 @@ static const struct AFB_plugin plugin_desc = {
        .info = "Sample of Client Context Usage",
        .prefix = "context",
        .apis = pluginApis,
-       .freeCtxCB = (void*)freeCtxCB
 };
 
 const struct AFB_plugin *pluginRegister (const struct AFB_interface *itf)
 {
-       global_handle.anythingYouWant = "anythingYouWant";
        return &plugin_desc;
 }
 
index 91f9cd8..bd76cee 100644 (file)
@@ -28,13 +28,20 @@ typedef struct {
 } MyClientApplicationHandle;
 
 
+// This function is call when Client Session Context is removed
+// Note: when freeCtxCB==NULL standard free/malloc is called
+static void clientContextFree(void *context) {
+    fprintf (stderr,"Plugin[token] Closing Session\n");
+    free (context);
+}
+
 // Request Creation of new context if it does not exist
 static void clientContextCreate (struct afb_req request)
 {
     json_object *jresp;
 
     // add an application specific client context to session
-    request.context = malloc (sizeof (MyClientApplicationHandle));
+    afb_req_context_set(request, malloc (sizeof (MyClientApplicationHandle)), clientContextFree);
     
     // Send response to UI
     jresp = json_object_new_object();               
@@ -92,13 +99,6 @@ static void clientGetPing (struct afb_req request) {
 }
 
 
-// This function is call when Client Session Context is removed
-// Note: when freeCtxCB==NULL standard free/malloc is called
-static void clientContextFree(void *context) {
-    fprintf (stderr,"Plugin[token] Closing Session\n");
-    free (context);
-}
-
 static const struct AFB_restapi pluginApis[]= {
   {"ping"    , AFB_SESSION_NONE  , clientGetPing       ,"Ping Rest Test Service"},
   {"create"  , AFB_SESSION_CREATE, clientContextCreate ,"Request Client Context Creation"},
@@ -112,8 +112,7 @@ static const struct AFB_plugin plugin_desc = {
        .type = AFB_PLUGIN_JSON,
        .info = "Application Framework Binder Service",
        .prefix = "token",
-       .apis = pluginApis,
-       .freeCtxCB = clientContextFree
+       .apis = pluginApis
 };
 
 const struct AFB_plugin *pluginRegister (const struct AFB_interface *itf)
index 60af72e..c3cb08d 100644 (file)
@@ -86,17 +86,6 @@ static const struct afb_daemon_itf daemon_itf = {
        .get_pollmgr = (void*)afb_api_so_get_pollmgr
 };
 
-static void free_context(struct api_so_desc *desc, void *context)
-{
-       void (*cb)(void*);
-
-       cb = desc->plugin->freeCtxCB;
-       if (cb)
-               cb(context);
-       else
-               free(context);
-}
-
 static void trapping_call(struct afb_req req, void(*cb)(struct afb_req))
 {
        volatile int signum, timerset;
@@ -159,7 +148,6 @@ static void call_check(struct afb_req req, const struct AFB_restapi *verb)
                break;
        }
        trapping_call(req, verb->callback);
-
        if (verb->session == AFB_SESSION_CLOSE)
                afb_req_session_close(req);
 }
@@ -238,8 +226,7 @@ int afb_api_so_add_plugin(const char *path)
        /* records the plugin */
        if (afb_apis_add(desc->plugin->prefix, (struct afb_api){
                        .closure = desc,
-                       .call = (void*)call,
-                       .free_context = (void*)free_context}) < 0) {
+                       .call = (void*)call}) < 0) {
                fprintf(stderr, "ERROR: plugin [%s] can't be registered...\n", path);
                goto error3;
        }
index 0af3b42..2822575 100644 (file)
@@ -41,13 +41,6 @@ int afb_apis_count()
        return apis_count;
 }
 
-void afb_apis_free_context(int apiidx, void *context)
-{
-       const struct afb_api *api;
-       api = &apis_array[apiidx].api;
-       api->free_context(api->closure, context);
-}
-
 int afb_apis_add(const char *name, struct afb_api api)
 {
        struct api_desc *apis;
@@ -98,7 +91,7 @@ void afb_apis_call(struct afb_req req, struct AFB_clientCtx *context, const char
        a = apis_array;
        for (i = 0 ; i < apis_count ; i++, a++) {
                if (a->namelen == lenapi && !strncasecmp(a->name, api, lenapi)) {
-                       req.context = &context->contexts[i];
+                       req.ctx_closure = &context->contexts[i];
                        a->api.call(a->api.closure, req, verb, lenverb);
                        return;
                }
index 59c7008..985923f 100644 (file)
@@ -24,7 +24,6 @@ struct afb_api
 {
        void *closure;
        void (*call)(void *closure, struct afb_req req, const char *verb, size_t lenverb);
-       void (*free_context)(void *closure, void *context);
 };
 
 
@@ -32,5 +31,4 @@ extern int afb_apis_count();
 extern int afb_apis_add(const char *name, struct afb_api api);
 extern void afb_apis_call(struct afb_req req, struct AFB_clientCtx *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
 
-extern void afb_apis_free_context(int apiidx, void *context);
 
index 93cce62..72b9050 100644 (file)
@@ -81,7 +81,9 @@ static const struct afb_req_itf afb_hreq_itf = {
        .send = (void*)req_send,
        .session_create = (void*)req_session_create,
        .session_check = (void*)req_session_check,
-       .session_close = (void*)req_session_close
+       .session_close = (void*)req_session_close,
+       .context_get = (void*)afb_context_get,
+       .context_set = (void*)afb_context_set
 };
 
 static struct hreq_data *get_data(struct afb_hreq *hreq, const char *key, int create)
@@ -584,7 +586,7 @@ int afb_hreq_post_add_file(struct afb_hreq *hreq, const char *key, const char *f
 
 struct afb_req afb_hreq_to_req(struct afb_hreq *hreq)
 {
-       return (struct afb_req){ .itf = &afb_hreq_itf, .data = hreq };
+       return (struct afb_req){ .itf = &afb_hreq_itf, .req_closure = hreq };
 }
 
 static struct afb_arg req_get(struct afb_hreq *hreq, const char *name)
index a176688..a34142c 100644 (file)
@@ -141,7 +141,10 @@ static const struct afb_req_itf wsreq_itf = {
        .send = (void*)wsreq_send,
        .session_create = (void*)wsreq_session_create,
        .session_check = (void*)wsreq_session_check,
-       .session_close = (void*)wsreq_session_close
+       .session_close = (void*)wsreq_session_close,
+       .context_get = (void*)afb_context_get,
+       .context_set = (void*)afb_context_set
+
 };
 
 static int aws_wsreq_parse(struct afb_wsreq *r, char *text, size_t size)
@@ -297,7 +300,7 @@ static void aws_on_text(struct afb_ws_json *ws, char *text, size_t size)
        wsreq->next = ws->requests;
        ws->requests = wsreq;
 
-       r.data = wsreq;
+       r.req_closure = wsreq;
        r.itf = &wsreq_itf;
        afb_apis_call(r, ws->context, wsreq->api, wsreq->apilen, wsreq->verb, wsreq->verblen);
        return;
index e899739..8ec684f 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "afb-config.h"
 #include "afb-hswitch.h"
+#include "afb-apis.h"
 #include "afb-api-so.h"
 #include "afb-hsrv.h"
 #include "afb-hreq.h"
@@ -577,7 +578,7 @@ int main(int argc, char *argv[])  {
   if (config->ldpaths) 
     afb_api_so_add_pathset(config->ldpaths);
 
-  ctxStoreInit(CTX_NBCLIENTS, config->cntxTimeout, config->token);
+  ctxStoreInit(CTX_NBCLIENTS, config->cntxTimeout, config->token, afb_apis_count());
   if (!afb_hreq_init_cookie(config->httpdPort, config->rootapi, DEFLT_CNTX_TIMEOUT)) {
     fprintf (stderr, "ERR: initialisation of cookies failed\n");
      exit (1);
index 329e17a..fbc7f2f 100644 (file)
@@ -24,7 +24,6 @@
 #include <uuid/uuid.h>
 #include <assert.h>
 
-#include "afb-apis.h"
 #include "session.h"
 
 #define NOW (time(NULL))
@@ -40,6 +39,20 @@ static struct {
   const char *initok;
 } sessions;
 
+void *afb_context_get(struct afb_context *actx)
+{
+       return actx->context;
+}
+
+void afb_context_set(struct afb_context *actx, void *context, void (*free_context)(void*))
+{
+fprintf(stderr, "afb_context_set(%p,%p) was (%p,%p)\n",context, free_context, actx->context, actx->free_context);
+       if (actx->context != NULL && actx->free_context != NULL)
+               actx->free_context(actx->context);
+       actx->context = context;
+       actx->free_context = free_context;
+}
+
 // Free context [XXXX Should be protected again memory abort XXXX]
 static void ctxUuidFreeCB (struct AFB_clientCtx *client)
 {
@@ -49,22 +62,18 @@ static void ctxUuidFreeCB (struct AFB_clientCtx *client)
        assert (client->contexts != NULL);
 
        // Free client handle with a standard Free function, with app callback or ignore it
-       for (idx=0; idx < sessions.apicount; idx ++) {
-               if (client->contexts[idx] != NULL) {
-                       afb_apis_free_context(idx, client->contexts[idx]);
-                       client->contexts[idx] = NULL;
-               }
-       }
+       for (idx=0; idx < sessions.apicount; idx ++)
+               afb_context_set(&client->contexts[idx], NULL, NULL);
 }
 
 // Create a new store in RAM, not that is too small it will be automatically extended
-void ctxStoreInit (int nbSession, int timeout, const char *initok)
+void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count)
 {
        // let's create as store as hashtable does not have any
-       sessions.store = calloc (1 + (unsigned)nbSession, sizeof(struct AFB_clientCtx));
-       sessions.max = nbSession;
+       sessions.store = calloc (1 + (unsigned)max_session_count, sizeof(struct AFB_clientCtx));
+       sessions.max = max_session_count;
        sessions.timeout = timeout;
-       sessions.apicount = afb_apis_count();
+       sessions.apicount = context_count;
        if (strlen(initok) >= 37) {
                fprintf(stderr, "Error: initial token '%s' too long (max length 36)", initok);
                exit(1);
@@ -191,7 +200,7 @@ TODO remove? not remove?
        /* returns a new one */
         clientCtx = calloc(1, sizeof(struct AFB_clientCtx)); // init NULL clientContext
        if (clientCtx != NULL) {
-               clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof (void*));
+               clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof(*clientCtx->contexts));
                if (clientCtx->contexts != NULL) {
                        /* generate the uuid */
                        if (uuid == NULL) {
index 0a61612..569af65 100644 (file)
 
 #pragma once
 
+struct afb_context
+{
+       void *context;
+       void (*free_context)(void*);
+};
+
+extern void *afb_context_get(struct afb_context *actx);
+extern void afb_context_set(struct afb_context *actx, void *context, void (*free_context)(void*));
+
 struct AFB_clientCtx
 {
        time_t expiration;    // expiration time of the token
        int created;
        unsigned refcount;
-       void **contexts;      // application specific context [one per plugin]
+       struct afb_context *contexts;
        char uuid[37];        // long term authentication of remote client
        char token[37];       // short term authentication of remote client
 };
 
-extern void ctxStoreInit (int nbSession, int timeout, const char *initok);
+extern void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count);
 
 extern struct AFB_clientCtx *ctxClientGetForUuid (const char *uuid);
 extern struct AFB_clientCtx *ctxClientGet(struct AFB_clientCtx *clientCtx);