aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/local-def.h10
-rw-r--r--include/proto-def.h1
-rw-r--r--nbproject/configurations.xml84
-rw-r--r--nbproject/private/Default.properties1
-rw-r--r--nbproject/private/configurations.xml5
-rw-r--r--src/afbs-api.c82
-rw-r--r--src/alsa-api.c24
-rw-r--r--src/dbus-api.c14
-rw-r--r--src/http-svc.c3
-rw-r--r--src/rest-api.c241
-rw-r--r--src/session.c163
11 files changed, 364 insertions, 264 deletions
diff --git a/include/local-def.h b/include/local-def.h
index 021ef13e..cbbef0f9 100644
--- a/include/local-def.h
+++ b/include/local-def.h
@@ -77,7 +77,7 @@ typedef int BOOL;
extern int verbose; // this is the only global variable
// Plugin Type
-typedef enum {AFB_PLUGIN_JSON=123456789, AFB_PLUGIN_JSCRIPT=987654321, AFB_PLUGIN_RAW=987123546} AFB_pluginT;
+typedef enum {AFB_PLUGIN_JSON=123456789, AFB_PLUGIN_JSCRIPT=987654321, AFB_PLUGIN_RAW=987123546} AFB_pluginE;
// prebuild json error are constructed in config.c
typedef enum { AFB_FALSE, AFB_TRUE, AFB_FATAL, AFB_FAIL, AFB_WARNING, AFB_EMPTY, AFB_SUCCESS, AFB_DONE, AFB_UNAUTH} AFB_error;
@@ -116,7 +116,7 @@ typedef struct {
int uid; // post uid for debug
AFB_PostType type; // JSON or FORM
AFB_apiCB completeCB; // callback when post is completed
- void *private; // use internally to keep track or partial buffer
+ char *private; // use internally to keep track or partial buffer
struct MHD_PostProcessor *pp; // iterator handle
} AFB_PostHandle;
@@ -183,9 +183,13 @@ typedef struct {
size_t len;
} AFB_redirect_msg;
+// Enum for Session/Token/Authentication middleware
+typedef enum {AFB_SESSION_NONE, AFB_SESSION_CREATE, AFB_SESSION_CLOSE, AFB_SESSION_RENEW, AFB_SESSION_CHECK} AFB_sessionE;
+
// API definition
typedef struct {
char *name;
+ AFB_sessionE session;
AFB_apiCB callback;
char *info;
AFB_privateApi *private;
@@ -193,7 +197,7 @@ typedef struct {
// Plugin definition
typedef struct {
- AFB_pluginT type;
+ AFB_pluginE type;
char *info;
char *prefix;
size_t prefixlen;
diff --git a/include/proto-def.h b/include/proto-def.h
index 1a3145f5..d8001142 100644
--- a/include/proto-def.h
+++ b/include/proto-def.h
@@ -49,6 +49,7 @@ PUBLIC AFB_error ctxTokenCreate (AFB_request *request);
PUBLIC AFB_error ctxTokenCheck (AFB_request *request);
PUBLIC AFB_error ctxTokenReset (AFB_request *request);
PUBLIC AFB_error ctxClientGet (AFB_request *request, AFB_plugin *plugin);
+PUBLIC void ctxStoreInit (int);
diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml
index b1f18a07..6b0679df 100644
--- a/nbproject/configurations.xml
+++ b/nbproject/configurations.xml
@@ -66,12 +66,22 @@
</preBuild>
</makefileType>
<item path="src/afbs-api.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/alsa-api.c" ex="false" tool="0" flavor2="2">
@@ -94,39 +104,79 @@
</cTool>
</item>
<item path="src/config.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/dbus-api.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/http-svc.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/main.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/radio-api.c" ex="false" tool="0" flavor2="2">
@@ -143,12 +193,22 @@
</cTool>
</item>
<item path="src/rest-api.c" ex="false" tool="0" flavor2="2">
- <cTool flags="0">
+ <cTool flags="1">
<incDir>
- <pElem>include</pElem>
+ <pElem>src</pElem>
<pElem>/usr/include/json-c</pElem>
+ <pElem>include</pElem>
+ <pElem>/usr/include/uuid</pElem>
<pElem>build/src</pElem>
</incDir>
+ <preprocessorList>
+ <Elem>__PIC__=2</Elem>
+ <Elem>__PIE__=2</Elem>
+ <Elem>__REGISTER_PREFIX__=</Elem>
+ <Elem>__USER_LABEL_PREFIX__=</Elem>
+ <Elem>__pic__=2</Elem>
+ <Elem>__pie__=2</Elem>
+ </preprocessorList>
</cTool>
</item>
<item path="src/session.c" ex="false" tool="0" flavor2="2">
diff --git a/nbproject/private/Default.properties b/nbproject/private/Default.properties
index a45c3d27..e63c2370 100644
--- a/nbproject/private/Default.properties
+++ b/nbproject/private/Default.properties
@@ -1,2 +1 @@
/home/fulup/Workspace/afb-daemon/src/session.c=/home/fulup/Workspace/afb-daemon/build/src#-g3 -gdwarf-2 -fPIE -I/home/fulup/Workspace/afb-daemon/include -I/usr/include/json-c -o CMakeFiles/afb-daemon.dir/session.c.o -c /home/fulup/Workspace/afb-daemon/src/session.c
-/home/fulup/Workspace/afb-daemon/src/http-svc.c=/home/fulup/Workspace/afb-daemon/build/src#-g3 -gdwarf-2 -fPIE -I/home/fulup/Workspace/afb-daemon/include -I/usr/include/json-c -o CMakeFiles/afb-daemon.dir/http-svc.c.o -c /home/fulup/Workspace/afb-daemon/src/http-svc.c
diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml
index 7306ab22..706acf31 100644
--- a/nbproject/private/configurations.xml
+++ b/nbproject/private/configurations.xml
@@ -11,8 +11,6 @@
</df>
<df name="CMakeTmp">
</df>
- <df name="Progress">
- </df>
<in>feature_tests.c</in>
</df>
<df name="src">
@@ -29,6 +27,7 @@
<in>proto-def.h</in>
</df>
<df name="src">
+ <in>SamplePost.c</in>
<in>afbs-api.c</in>
<in>alsa-api.c</in>
<in>config.c</in>
@@ -49,8 +48,6 @@
</df>
<df name="CMakeTmp">
</df>
- <df name="Progress">
- </df>
</df>
<df name="src">
<df name="CMakeFiles">
diff --git a/src/afbs-api.c b/src/afbs-api.c
index 1a3399f9..9e1c7660 100644
--- a/src/afbs-api.c
+++ b/src/afbs-api.c
@@ -29,87 +29,45 @@ typedef struct {
// Request Creation of new context if it does not exist
STATIC json_object* clientContextCreate (AFB_request *request) {
json_object *jresp;
- int res;
- char *token;
- AFB_clientCtx *client=request->client; // get client context from request
-
- // check we do not already have a session
- if ((client != NULL) && (client->ctx != NULL)) {
- request->errcode=MHD_HTTP_FORBIDDEN;
- return (jsonNewMessage(AFB_FAIL, "Token exist use refresh"));
- }
-
- // request a new client context token and check result
- if (AFB_UNAUTH == ctxTokenCreate (request)) {
- request->errcode=MHD_HTTP_UNAUTHORIZED;
- jresp= jsonNewMessage(AFB_FAIL, "No/Invalid initial token provided [should match --token=xxxx]");
- return (jresp);
- }
-
- // request a new client context token and check result
- if (AFB_SUCCESS != ctxTokenCreate (request)) {
- request->errcode=MHD_HTTP_UNAUTHORIZED;
- jresp= jsonNewMessage(AFB_FAIL, "Token Session Not Activated [restart with --token=xxxx]");
- return (jresp);
- }
-
- // add a client context to session
- client->ctx = malloc (sizeof (MyClientApplicationHandle));
+
+ // add an application specific client context to session
+ request->client->ctx = malloc (sizeof (MyClientApplicationHandle));
// Send response to UI
jresp = json_object_new_object();
- json_object_object_add(jresp, "token", json_object_new_string (client->token));
+ json_object_object_add(jresp, "token", json_object_new_string ("A New Token and Session Context Was Created"));
return (jresp);
}
-// Renew an existing context
+// Before entering here token will be check and renew
STATIC json_object* clientContextRefresh (AFB_request *request) {
json_object *jresp;
- // note: we do not need to parse the old token as clientContextRefresh doit for us
- if (AFB_SUCCESS != ctxTokenRefresh (request)) {
- request->errcode=MHD_HTTP_UNAUTHORIZED;
- jresp= jsonNewMessage(AFB_FAIL, "Token Exchange Broken Refresh Refused");
- } else {
- jresp = json_object_new_object();
- json_object_object_add(jresp, "token", json_object_new_string (request->client->token));
- }
-
+
+ jresp = json_object_new_object();
+ json_object_object_add(jresp, "token", json_object_new_string ("Token was refreshed"));
+
return (jresp);
}
-// Verify a context is still valid
+// Session token will we verified before entering here
STATIC json_object* clientContextCheck (AFB_request *request) {
- json_object *jresp = json_object_new_object();
-
- // add an error code to respond
- if (AFB_SUCCESS != ctxTokenCheck (request)) {
- request->errcode=MHD_HTTP_UNAUTHORIZED;
- json_object_object_add(jresp, "isvalid", json_object_new_boolean (FALSE));
- } else {
- json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE));
- }
+ json_object *jresp = json_object_new_object();
+ json_object_object_add(jresp, "isvalid", json_object_new_boolean (TRUE));
return (jresp);
}
-
// Close and Free context
STATIC json_object* clientContextReset (AFB_request *request) {
json_object *jresp;
- // note: we do not need to parse the old token as clientContextRefresh doit for us
- if (AFB_SUCCESS != ctxTokenReset (request)) {
- request->errcode=MHD_HTTP_UNAUTHORIZED;
- jresp= jsonNewMessage(AFB_FAIL, "No Token Client Context [use --token=xxx]");
- } else {
- jresp = json_object_new_object();
- json_object_object_add(jresp, "uuid", json_object_new_string (request->client->uuid));
- }
+ jresp = json_object_new_object();
+ json_object_object_add(jresp, "uuid", json_object_new_string (request->client->uuid));
return (jresp);
}
@@ -214,12 +172,12 @@ STATIC void clientContextFree(AFB_clientCtx *client) {
}
STATIC AFB_restapi pluginApis[]= {
- {"ping" , (AFB_apiCB)apiPingTest ,"Ping Rest Test Service"},
- {"token-create" , (AFB_apiCB)clientContextCreate ,"Request Client Context Creation"},
- {"token-refresh" , (AFB_apiCB)clientContextRefresh,"Refresh Client Context Token"},
- {"token-check" , (AFB_apiCB)clientContextCheck ,"Check Client Context Token"},
- {"token-reset" , (AFB_apiCB)clientContextReset ,"Close Client Context and Free resources"},
- {"file-upload" , (AFB_apiCB)ProcessPostForm ,"Demo for file upload"},
+ {"ping" , AFB_SESSION_NONE , (AFB_apiCB)apiPingTest ,"Ping Rest Test Service"},
+ {"token-create" , AFB_SESSION_CREATE, (AFB_apiCB)clientContextCreate ,"Request Client Context Creation"},
+ {"token-refresh" , AFB_SESSION_RENEW , (AFB_apiCB)clientContextRefresh,"Refresh Client Context Token"},
+ {"token-check" , AFB_SESSION_CHECK , (AFB_apiCB)clientContextCheck ,"Check Client Context Token"},
+ {"token-reset" , AFB_SESSION_CLOSE , (AFB_apiCB)clientContextReset ,"Close Client Context and Free resources"},
+ {"file-upload" , AFB_SESSION_NONE , (AFB_apiCB)ProcessPostForm ,"Demo for file upload"},
{NULL}
};
diff --git a/src/alsa-api.c b/src/alsa-api.c
index 46b971b3..9d4f3cb6 100644
--- a/src/alsa-api.c
+++ b/src/alsa-api.c
@@ -27,23 +27,6 @@ STATIC json_object* wrongApi (AFB_request *request, void* handle) {
impossible=bug/zero;
}
-STATIC json_object* pingSample (AFB_request *request) {
- static pingcount = 0;
- json_object *response;
- char query [512];
-
- // request all query key/value
- getQueryAll (request,query, sizeof(query));
-
- // check if we have some post data
- if (request->post == NULL) request->post="NoData";
-
- // return response to caller
- response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} handle=[%s] PostData: \'%s\' "
- , pingcount++, query, request->post);
-
- return (response);
-}
STATIC struct {
@@ -52,10 +35,9 @@ STATIC struct {
STATIC AFB_restapi pluginApis[]= {
- {"ping" , (AFB_apiCB)pingSample , "Ping Application Framework"},
- {"error" , (AFB_apiCB)wrongApi , "Ping Application Framework"},
- {"ctx-store", (AFB_apiCB)pingSample , "Verbose Mode"},
- {"ctx-load" , (AFB_apiCB)pingSample , "Verbose Mode"},
+ {"ping" , AFB_SESSION_NONE, (AFB_apiCB)apiPingTest,"Ping Application Framework"},
+ {"error" , AFB_SESSION_NONE, (AFB_apiCB)wrongApi , "Ping Application Framework"},
+
{NULL}
};
diff --git a/src/dbus-api.c b/src/dbus-api.c
index f7b071bd..70de03f0 100644
--- a/src/dbus-api.c
+++ b/src/dbus-api.c
@@ -30,7 +30,7 @@ STATIC json_object* pingSample (AFB_request *request) {
if (len == 0) strcpy (query,"NoSearchQueryList");
// check if we have some post data
- if (request->post == NULL) request->post="NoData";
+ if (request->post == NULL) request->post->data="NoData";
// return response to caller
response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s} PostData: \'%s\' ", pingcount++, query, request->post);
@@ -75,12 +75,12 @@ STATIC json_object* pingJson (AFB_session *session, AFB_request *request) {
STATIC AFB_restapi pluginApis[]= {
- {"ping" , (AFB_apiCB)pingSample , "Ping Application Framework"},
- {"pingnull" , (AFB_apiCB)pingFail , "Return NULL"},
- {"pingbug" , (AFB_apiCB)pingBug , "Do a Memory Violation"},
- {"pingJson" , (AFB_apiCB)pingJson , "Return a JSON object"},
- {"ctx-store", (AFB_apiCB)pingSample , "Verbose Mode"},
- {"ctx-load" , (AFB_apiCB)pingSample , "Verbose Mode"},
+ {"ping" , AFB_SESSION_NONE, (AFB_apiCB)pingSample , "Ping Application Framework"},
+ {"pingnull" , AFB_SESSION_NONE, (AFB_apiCB)pingFail , "Return NULL"},
+ {"pingbug" , AFB_SESSION_NONE, (AFB_apiCB)pingBug , "Do a Memory Violation"},
+ {"pingJson" , AFB_SESSION_NONE, (AFB_apiCB)pingJson , "Return a JSON object"},
+ {"ctx-store", AFB_SESSION_NONE, (AFB_apiCB)pingSample , "Verbose Mode"},
+ {"ctx-load" , AFB_SESSION_NONE, (AFB_apiCB)pingSample , "Verbose Mode"},
{NULL}
};
diff --git a/src/http-svc.c b/src/http-svc.c
index ac0606eb..b3b9a1f7 100644
--- a/src/http-svc.c
+++ b/src/http-svc.c
@@ -267,6 +267,9 @@ PUBLIC AFB_error httpdStart(AFB_session *session) {
apiUrlLen = strlen (session->config->rootapi);
baseUrlLen= strlen (session->config->rootbase);
rootUrlLen= strlen (session->config->rootdir);
+
+ // Initialise Client Session Hash Table
+ ctxStoreInit (CTX_NBCLIENTS);
// TBD open libmagic cache [fail to pass EFENCE check]
// initLibMagic (session);
diff --git a/src/rest-api.c b/src/rest-api.c
index 35e81d7e..ad3a4f22 100644
--- a/src/rest-api.c
+++ b/src/rest-api.c
@@ -107,7 +107,7 @@ PUBLIC void endPostRequest(AFB_PostHandle *postHandle) {
if (!postHandle->completeCB) postHandle->completeCB (postHandle->private);
}
}
- freeRequest (postHandle->private);
+ free(postHandle->private);
free(postHandle);
}
@@ -138,6 +138,11 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
for (idx = 0; plugin->apis[idx].callback != NULL; idx++) {
if (!strcmp(plugin->apis[idx].name, request->api)) {
+ // Request was found and at least partially executed
+ request->jresp = json_object_new_object();
+ json_object_get (afbJsonType); // increate jsontype reference count
+ json_object_object_add (request->jresp, "jtype", afbJsonType);
+
// prepare an object to store calling values
jcall=json_object_new_object();
json_object_object_add(jcall, "prefix", json_object_new_string (plugin->prefix));
@@ -158,25 +163,94 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
if (request->config->apiTimeout > 0) {
for (sig=0; signals[sig] != 0; sig++) {
if (signal (signals[sig], pluginError) == SIG_ERR) {
- request->errcode = MHD_HTTP_UNPROCESSABLE_ENTITY;
- request->jresp = jsonNewMessage(AFB_FATAL, "%s ERR: Signal/timeout handler activation fail.", configTime());
- return AFB_FAIL;
+ request->errcode = MHD_HTTP_UNPROCESSABLE_ENTITY;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("Setting Timeout Handler Failed"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return AFB_DONE;
}
}
// Trigger a timer to protect from unacceptable long time execution
alarm (request->config->apiTimeout);
}
+
+ // Out of SessionNone every call get a client context session
+ if (AFB_SESSION_NONE != plugin->apis[idx].session) {
+
+ // add client context to request
+ ctxClientGet(request, plugin);
+
+ if (verbose) fprintf(stderr, "Plugin=[%s] Api=[%s] Middleware=[%d] Client=[0x%x] Uuid=[%s] Token=[%s]\n"
+ , request->plugin, request->api, plugin->apis[idx].session, request->client, request->client->uuid, request->client->token);
+
+ switch(plugin->apis[idx].session) {
+
+ case AFB_SESSION_CREATE:
+ if (request->client->token[0] != '\0') {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("exist"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CREATE Session already exist"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return (AFB_DONE);
+ }
+
+ if (AFB_SUCCESS != ctxTokenCreate (request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CREATE Invalid Initial Token"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (request->client->uuid));
+ json_object_object_add(jcall, "token", json_object_new_string (request->client->token));
+ }
+ break;
+
+
+ case AFB_SESSION_RENEW:
+ if (AFB_SUCCESS != ctxTokenRefresh (request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_REFRESH Broken Exchange Token Chain"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (request->client->uuid));
+ json_object_object_add(jcall, "token", json_object_new_string (request->client->token));
+ }
+ break;
+
+ case AFB_SESSION_CLOSE:
+ if (AFB_SUCCESS != ctxTokenCheck (request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("empty"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CLOSE Not a Valid Access Token"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return (AFB_DONE);
+ } else {
+ json_object_object_add(jcall, "uuid", json_object_new_string (request->client->uuid));
+ }
+ break;
+
+ case AFB_SESSION_CHECK:
+ default:
+ // default action is check
+ if (AFB_SUCCESS != ctxTokenCheck (request)) {
+ request->errcode=MHD_HTTP_UNAUTHORIZED;
+ json_object_object_add(jcall, "status", json_object_new_string ("fail"));
+ json_object_object_add(jcall, "info", json_object_new_string ("AFB_SESSION_CHECK Invalid Active Token"));
+ json_object_object_add(request->jresp, "request", jcall);
+ return (AFB_DONE);
+ }
+ break;
+ }
+ }
- // add client context to request
- ctxClientGet(request, plugin);
-
// Effectively call the API with a subset of the context
jresp = plugin->apis[idx].callback(request, context);
- // Allocate Json object and build response
- request->jresp = json_object_new_object();
- json_object_get (afbJsonType); // increate jsontype reference count
- json_object_object_add (request->jresp, "jtype", afbJsonType);
+ // Session close is done after the API call so API can still use session in closing API
+ if (AFB_SESSION_CLOSE == plugin->apis[idx].session) ctxTokenReset (request);
// API should return NULL of a valid Json Object
if (jresp == NULL) {
@@ -200,17 +274,18 @@ STATIC AFB_error callPluginApi(AFB_plugin *plugin, AFB_request *request, void *c
return (AFB_DONE);
}
}
+
return (AFB_FAIL);
}
STATIC AFB_error findAndCallApi (AFB_request *request, void *context) {
int idx;
- char *baseurl, *baseapi;
AFB_error status;
+
// Search for a plugin with this urlpath
for (idx = 0; request->plugins[idx] != NULL; idx++) {
- if (!strcmp(request->plugins[idx]->prefix, baseurl)) {
+ if (!strcmp(request->plugins[idx]->prefix, request->plugin)) {
status =callPluginApi(request->plugins[idx], request, context);
break;
}
@@ -226,7 +301,10 @@ STATIC AFB_error findAndCallApi (AFB_request *request, void *context) {
request->jresp = jsonNewMessage(AFB_FATAL, "No API=[%s] for Plugin=[%s]", request->api, request->plugin);
goto ExitOnError;
}
-
+
+
+
+
// Everything look OK
return (status);
@@ -262,10 +340,10 @@ doPostIterate (void *cls, enum MHD_ValueKind kind, const char *key,
item.offset = offset;
// Reformat Request to make it somehow similar to GET/PostJson case
- post.data= (char*) postctx;
- post.len = size;
- post.type= AFB_POST_FORM;;
- request->post = &post;
+ postRequest.data= (char*) postHandle;
+ postRequest.len = size;
+ postRequest.type= AFB_POST_FORM;;
+ request->post = &postRequest;
// effectively call plugin API
status = findAndCallApi (request, &item);
@@ -274,10 +352,11 @@ doPostIterate (void *cls, enum MHD_ValueKind kind, const char *key,
if (status != AFB_SUCCESS) return MHD_NO;
// let's allow iterator to move to next item
- return (MHD_YES;);
+ return (MHD_YES);
}
STATIC void freeRequest (AFB_request *request) {
+
free (request->plugin);
free (request->api);
free (request);
@@ -289,32 +368,32 @@ STATIC AFB_request *createRequest (struct MHD_Connection *connection, AFB_sessio
// Start with a clean request
request = calloc (1, sizeof (AFB_request));
- char *urlcpy1, urlcpy2;
+ char *urlcpy1, *urlcpy2;
+ char *baseapi, *baseurl;
// Extract plugin urlpath from request and make two copy because strsep overload copy
urlcpy1 = urlcpy2 = strdup(url);
baseurl = strsep(&urlcpy2, "/");
if (baseurl == NULL) {
- errMessage = jsonNewMessage(AFB_FATAL, "Invalid API call url=[%s]", url);
- goto ExitOnError;
+ request->jresp = jsonNewMessage(AFB_FATAL, "Invalid API call url=[%s]", url);
}
// let's compute URL and call API
baseapi = strsep(&urlcpy2, "/");
if (baseapi == NULL) {
- errMessage = jsonNewMessage(AFB_FATAL, "Invalid API call url=[%s]", url);
- goto ExitOnError;
+ request->jresp = jsonNewMessage(AFB_FATAL, "Invalid API call url=[%s]", url);
}
// build request structure
request->connection = connection;
- request->config = session.config;
+ request->config = session->config;
request->url = url;
request->plugin = strdup (baseurl);
request->api = strdup (baseapi);
request->plugins= session->plugins;
free(urlcpy1);
+ return (request);
}
// process rest API query
@@ -326,41 +405,45 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
AFB_error status;
struct MHD_Response *webResponse;
const char *serialized;
- AFB_request request;
- AFB_PostHandle *posthandle;
+ AFB_request *request;
+ AFB_PostHandle *postHandle;
+ AFB_PostRequest postRequest;
int ret;
// if post data may come in multiple calls
if (0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
const char *encoding, *param;
int contentlen = -1;
- posthandle = *con_cls;
+ postHandle = *con_cls;
// This is the initial post event let's create form post structure POST datas come in multiple events
- if (posthandle == NULL) {
- fprintf(stderr, "This is the 1st Post Event postuid=%d\n", posthandle->uid);
+ if (postHandle == NULL) {
// allocate application POST processor handle to zero
- posthandle = cmalloc(1, sizeof (AFB_PostHandle));
- posthandle->uid = postcount++; // build a UID for DEBUG
- *con_cls = posthandle; // attache POST handle to current HTTP request
+ postHandle = calloc(1, sizeof (AFB_PostHandle));
+ postHandle->uid = postcount++; // build a UID for DEBUG
+ *con_cls = postHandle; // attache POST handle to current HTTP request
// Let make sure we have the right encoding and a valid length
encoding = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
- param = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
- if (param) sscanf(param, "%i", &contentlen);
// Form post is handle through a PostProcessor and call API once per form key
if (strcasestr(encoding, FORM_CONTENT) != NULL) {
-
- posthandle = malloc(sizeof (AFB_PostHandle)); // allocate application POST processor handle
- posthandle->type = AFB_POST_FORM;
- posthandle->private= (void*)createRequest (connection, session, url);
- posthandle->pp = MHD_create_post_processor (connection, MAX_POST_SIZE, doPostIterate, posthandle);
-
- if (NULL == posthandle->pp) {
+ if (verbose) fprintf(stderr, "Create PostForm[uid=%d]\n", postHandle->uid);
+
+ request = createRequest (connection, session, url);
+ if (request->jresp != NULL) {
+ errMessage = request->jresp;
+ goto ExitOnError;
+ }
+ postHandle = malloc(sizeof (AFB_PostHandle)); // allocate application POST processor handle
+ postHandle->type = AFB_POST_FORM;
+ postHandle->pp = MHD_create_post_processor (connection, MAX_POST_SIZE, doPostIterate, postHandle);
+ postHandle->private= (void*)request;
+
+ if (NULL == postHandle->pp) {
fprintf(stderr,"OOPS: Internal error fail to allocate MHD_create_post_processor\n");
- free (posthandle);
+ free (postHandle);
return MHD_NO;
}
return MHD_YES;
@@ -369,40 +452,46 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
// POST json is store into a buffer and present in one piece to API
if (strcasestr(encoding, JSON_CONTENT) != NULL) {
+ param = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
+ if (param) sscanf(param, "%i", &contentlen);
+
+ // Because PostJson are build in RAM size is constrained
if (contentlen > MAX_POST_SIZE) {
errMessage = jsonNewMessage(AFB_FATAL, "Post Date to big %d > %d", contentlen, MAX_POST_SIZE);
goto ExitOnError;
}
- if (posthandle == NULL) {
- posthandle->type = AFB_POST_JSON;
- posthandle->private = malloc(contentlen + 1); // allocate memory for full POST data + 1 for '\0' enf of string
+ // Size is OK, let's allocate a buffer to hold post data
+ postHandle->type = AFB_POST_JSON;
+ postHandle->private = malloc(contentlen + 1); // allocate memory for full POST data + 1 for '\0' enf of string
- if (verbose) fprintf(stderr, "Create PostJson[%d] Size=%d\n", posthandle->uid, contentlen);
- return MHD_YES;
- }
+ if (verbose) fprintf(stderr, "Create PostJson[uid=%d] Size=%d\n", postHandle->uid, contentlen);
+ return MHD_YES;
+ } else {
// We only support Json and Form Post format
errMessage = jsonNewMessage(AFB_FATAL, "Post Date wrong type encoding=%s != %s", encoding, JSON_CONTENT);
goto ExitOnError;
- }
+
+ }
}
// This time we receive partial/all Post data. Note that even if we get all POST data. We should nevertheless
// return MHD_YES and not process the request directly. Otherwise Libmicrohttpd is unhappy and fails with
// 'Internal application error, closing connection'.
if (*upload_data_size) {
- if (verbose) fprintf(stderr, "Update Post[%d]\n", posthandle->uid);
- if (posthandle->type == AFB_POST_FORM) {
- MHD_post_process (con_info->postprocessor, upload_data, *upload_data_size);
+ if (postHandle->type == AFB_POST_FORM) {
+ if (verbose) fprintf(stderr, "Processing PostForm[uid=%d]\n", postHandle->uid);
+ MHD_post_process (postHandle->pp, upload_data, *upload_data_size);
}
// Process JsonPost request when buffer is completed let's call API
- if (posthandle->type == AFB_POST_JSON) {
+ if (postHandle->type == AFB_POST_JSON) {
+ if (verbose) fprintf(stderr, "Updating PostJson[uid=%d]\n", postHandle->uid);
- memcpy(&posthandle->private[posthandle->len], upload_data, *upload_data_size);
- posthandle->len = posthandle->len + *upload_data_size;
+ memcpy(&postHandle->private[postHandle->len], upload_data, *upload_data_size);
+ postHandle->len = postHandle->len + *upload_data_size;
*upload_data_size = 0;
}
return MHD_YES;
@@ -411,25 +500,31 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
// Create a request structure to finalise the request
request= createRequest (connection, session, url);
-
- // We should only start to process DATA after Libmicrohttpd call or application handler with *upload_data_size==0
- if (posthandle->type == AFB_POST_FORM) {
- MHD_post_process (posthandle->pp, upload_data, *upload_data_size);
+ if (request->jresp != NULL) {
+ errMessage = request->jresp;
+ goto ExitOnError;
}
+
- if (posthandle->type == AFB_POST_JSON) {
+ if (postHandle->type == AFB_POST_JSON) {
+ if (verbose) fprintf(stderr, "Processing PostJson[uid=%d]\n", postHandle->uid);
+
+ param = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH);
+ if (param) sscanf(param, "%i", &contentlen);
+
// At this level we're may verify that we got everything and process DATA
- if (posthandle->len != contentlen) {
- errMessage = jsonNewMessage(AFB_FATAL, "Post Data Incomplete UID=%d Len %d != %s", posthandle->uid, contentlen, posthandle->len);
+ if (postHandle->len != contentlen) {
+ errMessage = jsonNewMessage(AFB_FATAL, "Post Data Incomplete UID=%d Len %d != %d", postHandle->uid, contentlen, postHandle->len);
goto ExitOnError;
}
// Before processing data, make sure buffer string is properly ended
- posthandle->private[posthandle->len] = '\0';
- request->post.data = posthandle->private;
- request->post.type = posthandle->type;
+ postHandle->private[postHandle->len] = '\0';
+ postRequest.data = postHandle->private;
+ postRequest.type = postHandle->type;
+ request->post = &postRequest;
- if (verbose) fprintf(stderr, "Close Post[%d] Buffer=%s\n", posthandle->uid, request.post);
+ if (verbose) fprintf(stderr, "Close Post[%d] Buffer=%s\n", postHandle->uid, request->post->data);
}
}
} else {
@@ -441,23 +536,23 @@ PUBLIC int doRestApi(struct MHD_Connection *connection, AFB_session *session, co
status = findAndCallApi (request, NULL);
ExitOnResponse:
- freeRequest (request);
- serialized = json_object_to_json_string(request.jresp);
+ serialized = json_object_to_json_string(request->jresp);
webResponse = MHD_create_response_from_buffer(strlen(serialized), (void*) serialized, MHD_RESPMEM_MUST_COPY);
// client did not pass token on URI let's use cookies
- if ((!request.restfull) && (request.client != NULL)) {
+ if ((!request->restfull) && (request->client != NULL)) {
char cookie[64];
- snprintf (cookie, sizeof (cookie), "%s=%s", COOKIE_NAME, request.client->uuid);
+ snprintf (cookie, sizeof (cookie), "%s=%s", COOKIE_NAME, request->client->uuid);
MHD_add_response_header (webResponse, MHD_HTTP_HEADER_SET_COOKIE, cookie);
}
// if requested add an error status
- if (request.errcode != 0) ret=MHD_queue_response (connection, request.errcode, webResponse);
+ if (request->errcode != 0) ret=MHD_queue_response (connection, request->errcode, webResponse);
else MHD_queue_response(connection, MHD_HTTP_OK, webResponse);
MHD_destroy_response(webResponse);
- json_object_put(request.jresp); // decrease reference rqtcount to free the json object
+ json_object_put(request->jresp); // decrease reference rqtcount to free the json object
+ freeRequest (request);
return MHD_YES;
ExitOnError:
diff --git a/src/session.c b/src/session.c
index 3494dadb..55098b41 100644
--- a/src/session.c
+++ b/src/session.c
@@ -27,6 +27,9 @@
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <pthread.h>
+#include <search.h>
+
#define AFB_SESSION_JTYPE "AFB_session"
#define AFB_SESSION_JLIST "AFB_sessions"
@@ -36,9 +39,8 @@
#define AFB_CURRENT_SESSION "active-session" // file link name within sndcard dir
#define AFB_DEFAULT_SESSION "current-session" // should be in sync with UI
-
-static struct lh_table *clientCtxs=NULL; // let's use JsonObject Hashtable to Store Sessions
-
+static pthread_mutex_t mutexHash; // declare a mutex to protect hash table
+static struct hsearch_data sessions = {0}; // Create an empty hash table for sessions
// verify we can read/write in session dir
PUBLIC AFB_error sessionCheckdir (AFB_session *session) {
@@ -308,32 +310,11 @@ OnErrorExit:
}
-// Function to handle Cookies and Client session context it relies on json low level
-// linked list functionalities https://github.com/json-c/json-c/blob/master/linkhash.c
-
-// Hash client UUID before storing in table
-STATIC unsigned long ctxUuidHashCB (const void *k1) {
- unsigned long hash;
-
- AFB_clientCtx *ctx = (AFB_clientCtx*) k1;
- hash = lh_char_hash(ctx->uuid);
- return (hash);
-}
-// Compare client UUIDs within table
-STATIC int ctxUuidCompCB (const void *k1, const void *k2) {
- int res;
- AFB_clientCtx *ctx1 = (AFB_clientCtx*) k1;
- AFB_clientCtx *ctx2 = (AFB_clientCtx*) k2;
-
- res = lh_char_equal(ctx1->uuid, ctx2->uuid);
- return (res);
-}
// Free context [XXXX Should be protected again memory abort XXXX]
-STATIC void ctxUuidFreeCB (struct lh_entry *entry) {
- AFB_clientCtx *client = (AFB_clientCtx*) entry->v;
-
+STATIC void ctxUuidFreeCB (AFB_clientCtx *client) {
+
// If application add a handle let's free it now
if (client->ctx != NULL) {
@@ -341,41 +322,68 @@ STATIC void ctxUuidFreeCB (struct lh_entry *entry) {
if (client->plugin->freeCtxCB == NULL) free (client->ctx);
else if (client->plugin->freeCtxCB != (void*)-1) client->plugin->freeCtxCB(client);
}
- free ((void*)entry->v);
}
// Create a new store in RAM, not that is too small it will be automatically extended
-STATIC struct lh_table *ctxStoreCreate (int nbSession) {
- lh_table *table;
+PUBLIC void ctxStoreInit (int nbSession) {
+ int res;
+ // let's create session hash table
+ res = hcreate_r(nbSession, &sessions);
+}
+
+STATIC AFB_clientCtx *ctxStoreSearch (const char* uuid) {
+ ENTRY item = {(char*) uuid};
+ ENTRY *pitem = &item;
+ // printf ("searching uuid=%s\n", uuid);
- // function will exit process in case of error !!!
- table=lh_table_new (nbSession, "CtxClient", ctxUuidFreeCB, ctxUuidHashCB, ctxUuidCompCB);
- return (table);
+ pthread_mutex_lock(&mutexHash);
+ if (hsearch_r(item, FIND, &pitem, &sessions)) {
+ pthread_mutex_unlock(&mutexHash);
+ return (AFB_clientCtx*) pitem->data;
+ }
+ pthread_mutex_unlock(&mutexHash);
+ return NULL;
+}
+
+// Reference http://stackoverflow.com/questions/25971505/how-to-delete-element-from-hsearch
+void ctxStoreAdd (AFB_clientCtx *client) {
+ ENTRY item = {client->uuid, (void*)client};
+ ENTRY *pitem = &item;
+
+ pthread_mutex_lock(&mutexHash);
+ if (hsearch_r(item, ENTER, &pitem, &sessions)) {
+ // printf ("storing uuid=%s\n", client->uuid);
+ pitem->data = (void *)client;
+ }
+ pthread_mutex_unlock(&mutexHash);
+}
+
+void ctxStoreDel (AFB_clientCtx *client) {
+ ENTRY item = {client->uuid};
+ ENTRY *pitem = &item;
+
+ pthread_mutex_lock(&mutexHash);
+ if (hsearch_r(item, FIND, &pitem, &sessions)) {
+ pitem->data = NULL;
+ }
+ pthread_mutex_unlock(&mutexHash);
}
// Check if context timeout or not
STATIC int ctxStoreToOld (const void *k1, int timeout) {
- int res;
+ int res;
AFB_clientCtx *ctx = (AFB_clientCtx*) k1;
-
- res = ((ctx->timeStamp + timeout) < time(NULL));
+ time_t now = time(NULL);
+ res = ((ctx->timeStamp + timeout) <= now);
return (res);
}
// Loop on every entry and remove old context sessions
PUBLIC int ctxStoreGarbage (struct lh_table *lht, const int timeout) {
- struct lh_entry *c;
-
- // Loop on every entry within table
- for(c = lht->head; c != NULL; c = c->next) {
- if(lht->free_fn) {
- if(c->k == LH_EMPTY) return lht->count;
- if(c->k != LH_FREED && ctxStoreToOld(c->v, timeout)) lh_table_delete_entry (lht, c);
- }
- }
+
+ if (verbose) fprintf (stderr, "****** Garbage Count=%d timeout=%d\n", lht->count, timeout);
+
- // return current size after cleanup
- return (lht->count);
}
// This function will return exiting client context or newly created client context
@@ -387,11 +395,6 @@ PUBLIC AFB_error ctxClientGet (AFB_request *request, AFB_plugin *plugin) {
int ret;
if (request->config->token == NULL) return AFB_EMPTY;
-
- // if client session store is null create it
- if (clientCtxs == NULL) {
- clientCtxs= ctxStoreCreate(CTX_NBCLIENTS);
- }
// Check if client as a context or not inside the URL
uuid = MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, "uuid");
@@ -403,32 +406,34 @@ PUBLIC AFB_error ctxClientGet (AFB_request *request, AFB_plugin *plugin) {
uuid = MHD_lookup_connection_value (request->connection, MHD_COOKIE_KIND, COOKIE_NAME);
};
-
- if (uuid != NULL) {
+ // Warning when no cookie defined MHD_lookup_connection_value may return something !!!
+ if ((uuid != NULL) && (strnlen (uuid, 10) >= 10)) {
+ int search;
// search if client context exist and it not timeout let's use it
- if ((lh_table_lookup_ex (clientCtxs, uuid, (void**) &clientCtx))
- && ! ctxStoreToOld (clientCtx, request->config->cntxTimeout)) {
- request->client=clientCtx;
- if (verbose) fprintf (stderr, "ctxClientGet Old uuid=[%s] token=[%s] timestamp=%d\n"
- ,request->client->uuid, request->client->token, request->client->timeStamp);
- return;
+ printf ("search old UID=%s\n", uuid);
+ clientCtx = ctxStoreSearch (uuid);
+
+ if (clientCtx && ! ctxStoreToOld (clientCtx, request->config->cntxTimeout)) {
+ request->client=clientCtx;
+ return;
}
}
-
-
+
// we have no session let's create one otherwise let's clean any exiting values
if (clientCtx == NULL) clientCtx = calloc(1, sizeof(AFB_clientCtx)); // init NULL clientContext
uuid_generate(newuuid); // create a new UUID
uuid_unparse_lower(newuuid, clientCtx->uuid);
clientCtx->cid=cid++; // simple application uniqueID
clientCtx->plugin = plugin; // provide plugin callbacks a hook to plugin
+ clientCtx->plugin; // provide plugin callbacks a hook to plugin
// if table is full at 50% let's clean it up
- if(clientCtxs->count > (clientCtxs->size*0.5)) ctxStoreGarbage(clientCtxs, request->config->cntxTimeout);
+ // if(clientCtxs->count > (clientCtxs->size / 2)) ctxStoreGarbage(clientCtxs, request->config->cntxTimeout);
// finally add uuid into hashtable
- ret=lh_table_insert (clientCtxs, (void*)clientCtx->uuid, clientCtx);
- if (ret < 0) return (AFB_FAIL);
+ ctxStoreAdd (clientCtx);
+
+ // if (ret < 0) return (AFB_FAIL);
if (verbose) fprintf (stderr, "ctxClientGet New uuid=[%s] token=[%s] timestamp=%d\n", clientCtx->uuid, clientCtx->token, clientCtx->timeStamp);
request->client = clientCtx;
@@ -459,16 +464,18 @@ PUBLIC AFB_error ctxTokenCheck (AFB_request *request) {
// Free Client Session Context
PUBLIC AFB_error ctxTokenReset (AFB_request *request) {
- struct lh_entry* entry;
int ret;
+ AFB_clientCtx *clientCtx;
if (request->client == NULL) return AFB_EMPTY;
+
+ // Search for an existing client with the same UUID
+ clientCtx = ctxStoreSearch (request->client->uuid);
+ if (clientCtx == NULL) return AFB_FALSE;
- entry = lh_table_lookup_entry (clientCtxs, request->client->uuid);
- if (entry == NULL) return AFB_FALSE;
+ // Remove client from table
+ ctxStoreDel (clientCtx);
- lh_table_delete_entry (clientCtxs, entry);
-
return (AFB_SUCCESS);
}
@@ -492,7 +499,6 @@ PUBLIC AFB_error ctxTokenCreate (AFB_request *request) {
if (strcmp(request->config->token, token)) return AFB_UNAUTH;
}
-
// create a UUID as token value
uuid_generate(newuuid);
uuid_unparse_lower(newuuid, request->client->token);
@@ -514,17 +520,12 @@ PUBLIC AFB_error ctxTokenRefresh (AFB_request *request) {
if (request->client == NULL) return AFB_EMPTY;
// Check if the old token is valid
- oldTnkValid= ctxTokenCheck (request);
+ if (ctxTokenCheck (request) != AFB_SUCCESS) return (AFB_FAIL);
+
+ // Old token was valid let's regenerate a new one
+ uuid_generate(newuuid); // create a new UUID
+ uuid_unparse_lower(newuuid, request->client->token);
+ return (AFB_SUCCESS);
- // if token is not valid let check for query argument "oldornew"
- if (!oldTnkValid) {
- oldornew = MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, "oldornew");
- if (oldornew != NULL) oldTnkValid= TRUE;
- }
-
- // No existing token and no request to create one
- if (oldTnkValid != TRUE) return AFB_WARNING;
-
- return (ctxTokenCreate (request));
}