From bbe18a624f4961165cf52d7f4c25de6f3a7ec012 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Fri, 1 Apr 2016 16:20:12 +0200 Subject: [PATCH] work in progress MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: I3df95def03bb26ca4d1a52f7cd94b0fb67375d4c Signed-off-by: José Bollo --- CMakeLists.txt | 2 +- include/local-def.h | 49 +++----- include/proto-def.h | 8 +- plugins/samples/ClientCtx.c | 1 + plugins/samples/HelloWorld.c | 35 +++--- plugins/session/token-api.c | 1 + src/afb-apis.c | 52 +++++--- src/afb-hreq.c | 111 ++++++++++------- src/afb-hreq.h | 5 +- src/afb-req-itf.h | 50 ++++++++ src/afb-rest-api.c | 18 +-- src/afb-websock.c | 3 +- src/helper-api.c | 69 ++++++++++- src/http-svc.c | 11 +- src/main.c | 21 ++-- src/session.c | 278 +++++-------------------------------------- src/session.h | 16 +-- 17 files changed, 327 insertions(+), 403 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1780784..15e7f7ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ INCLUDE(FindThreads) FIND_PACKAGE(Threads) SET(include_dirs ${INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/include ${json-c_INCLUDE_DIRS} ${libmicrohttpd_INCLUDE_DIRS} ${uuid_INCLUDE_DIRS} ${dbus_INCLUDE_DIRS} ${alsa_INCLUDE_DIRS} ${pulseaudio_INCLUDE_DIRS} ${librtlsdr_INCLUDE_DIRS} ${gupnp_INCLUDE_DIRS} ${openssl_INCLUDE_DIRS}) -SET(link_libraries ${json-c_LIBRARIES} ${libmicrohttpd_LIBRARIES} ${uuid_LIBRARIES} ${dbus_LIBRARIES} ${alsa_LIBRARIES} ${pulseaudio_LIBRARIES} ${librtlsdr_LIBRARIES} ${gupnp_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${libefence_LIBRARIES} ${openssl_LIBRARIES} -lmagic -lm -ldl) +SET(link_libraries ${json-c_LIBRARIES} ${libmicrohttpd_LIBRARIES} ${uuid_LIBRARIES} ${dbus_LIBRARIES} ${alsa_LIBRARIES} ${pulseaudio_LIBRARIES} ${librtlsdr_LIBRARIES} ${gupnp_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${libefence_LIBRARIES} ${openssl_LIBRARIES} -lmagic -lm -ldl -lrt) SET(plugin_install_dir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/afb) ADD_DEFINITIONS(-DPLUGIN_INSTALL_DIR="${plugin_install_dir}") diff --git a/include/local-def.h b/include/local-def.h index 3f618717..605c05a3 100644 --- a/include/local-def.h +++ b/include/local-def.h @@ -21,29 +21,9 @@ #ifndef LOCAL_DEF_H #define LOCAL_DEF_H -#ifndef _GNU_SOURCE - #define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include - - +#include /* other definitions --------------------------------------------------- */ @@ -111,7 +91,7 @@ struct AFB_restapi { const char *name; enum AFB_sessionE session; - json_object* (*callback)(); + struct json_object* (*callback)(); const char *info; }; @@ -127,7 +107,7 @@ struct AFB_plugin typedef enum AFB_pluginE AFB_pluginE; typedef enum AFB_sessionE AFB_sessionE; -typedef json_object* (*AFB_apiCB)(); +typedef struct json_object* (*AFB_apiCB)(); typedef void (*AFB_freeCtxCB)(void*); typedef struct AFB_restapi AFB_restapi; typedef struct AFB_plugin AFB_plugin; @@ -141,12 +121,12 @@ typedef struct AFB_plugin AFB_plugin; +typedef enum {AFB_MODE_LOCAL=0, AFB_MODE_REMOTE, AFB_MODE_GLOBAL} AFB_Mode; - +#if 0 typedef enum {AFB_POST_NONE=0, AFB_POST_JSON, AFB_POST_FORM, AFB_POST_EMPTY} AFB_PostType; -typedef enum {AFB_MODE_LOCAL=0, AFB_MODE_REMOTE, AFB_MODE_GLOBAL} AFB_Mode; @@ -155,7 +135,7 @@ typedef struct { int fd; char *path; int errcode; - json_object* jresp; + struct json_object* jresp; } AFB_PostCtx; typedef struct { @@ -191,17 +171,19 @@ typedef struct { int fd; } AFB_staticfile; +typedef struct { + char *msg; + size_t len; +} AFB_redirect_msg; + +#endif + typedef struct { char *url; char *path; size_t len; } AFB_aliasdir; -typedef struct { - char *msg; - size_t len; -} AFB_redirect_msg; - // main config structure struct AFB_config { @@ -229,7 +211,7 @@ typedef struct { /* AFB_PostRequest *post; */ - json_object *jresp; + struct json_object *jresp; void *context; // Hold Client Context when using session int restfull; // request is resfull [uuid token provided] int errcode; // http error code @@ -240,7 +222,8 @@ typedef struct { struct afb_hsrv_handler; struct MHD_Daemon; -struct AFB_session { +struct AFB_session +{ struct AFB_config *config; // pointer to current config // List of commands to execute int background; // run in backround mode diff --git a/include/proto-def.h b/include/proto-def.h index c364035a..e2190eb1 100644 --- a/include/proto-def.h +++ b/include/proto-def.h @@ -21,7 +21,7 @@ // helper-api extern const char* getQueryValue (const AFB_request * request, const char *name); -extern int getQueryAll(AFB_request * request, char *query, size_t len); +extern size_t getQueryAll(AFB_request * request, char *query, size_t len); /* extern json_object* getPostFile (AFB_request *request, AFB_PostItem *item, char* destination) ; extern char* getPostPath (AFB_request *request); @@ -29,12 +29,6 @@ extern char* getPostPath (AFB_request *request); extern json_object *jsonNewMessage (AFB_error level, char* format, ...); -// rest-api -extern void endPostRequest(AFB_PostHandle *posthandle); -extern int doRestApi(struct MHD_Connection *connection, AFB_session *session, const char* url, const char *method - , const char *upload_data, size_t *upload_data_size, void **con_cls); - - // Httpd server extern AFB_error httpdStart (AFB_session *session); diff --git a/plugins/samples/ClientCtx.c b/plugins/samples/ClientCtx.c index b59400e1..175b9387 100644 --- a/plugins/samples/ClientCtx.c +++ b/plugins/samples/ClientCtx.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include #include "local-def.h" diff --git a/plugins/samples/HelloWorld.c b/plugins/samples/HelloWorld.c index 6c2d0cf9..85e92f45 100644 --- a/plugins/samples/HelloWorld.c +++ b/plugins/samples/HelloWorld.c @@ -16,31 +16,35 @@ * along with this program. If not, see . */ +#include +#include #include "local-def.h" +#include "afb-req-itf.h" -STATIC json_object* pingSample (AFB_request *request) { +static json_object* pingSample (AFB_request *request) { static int pingcount = 0; json_object *response; char query [512]; - int len; + size_t len; // request all query key/value len = getQueryAll (request, query, sizeof(query)); if (len == 0) strcpy (query,"NoSearchQueryList"); // return response to caller - response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s}", pingcount++, query); +// response = jsonNewMessage(AFB_SUCCESS, "Ping Binder Daemon %d query={%s}", pingcount++, query); + afb_req_success_f(*request->areq, NULL, "Ping Binder Daemon %d query={%s}", pingcount++, query); if (verbose) fprintf(stderr, "%d: \n", pingcount); - return (response); + return NULL; //(response); } -STATIC json_object* pingFail (AFB_request *request) { +static json_object* pingFail (AFB_request *request) { return NULL; } -STATIC json_object* pingBug (AFB_request *request) { +static json_object* pingBug (AFB_request *request) { int a,b,c; fprintf (stderr, "Use --timeout=10 to trap error\n"); @@ -54,7 +58,7 @@ STATIC json_object* pingBug (AFB_request *request) { // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/ -STATIC json_object* pingJson (AFB_request *request) { +static json_object* pingJson (AFB_request *request) { json_object *jresp, *embed; jresp = json_object_new_object(); @@ -72,7 +76,7 @@ STATIC json_object* pingJson (AFB_request *request) { // NOTE: this sample does not use session to keep test a basic as possible // in real application most APIs should be protected with AFB_SESSION_CHECK -STATIC AFB_restapi pluginApis[]= { +static AFB_restapi pluginApis[]= { {"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"}, @@ -80,12 +84,13 @@ STATIC AFB_restapi pluginApis[]= { {NULL} }; +static const AFB_plugin plugin = { + .type = AFB_PLUGIN_JSON, + .info = "Minimal Hello World Sample", + .prefix = "hello", + .apis = pluginApis +}; -PUBLIC AFB_plugin *pluginRegister () { - AFB_plugin *plugin = malloc (sizeof (AFB_plugin)); - plugin->type = AFB_PLUGIN_JSON; - plugin->info = "Minimal Hello World Sample"; - plugin->prefix= "hello"; - plugin->apis = pluginApis; - return (plugin); +const AFB_plugin *pluginRegister () { + return &plugin; }; diff --git a/plugins/session/token-api.c b/plugins/session/token-api.c index 9a078328..feb269dd 100644 --- a/plugins/session/token-api.c +++ b/plugins/session/token-api.c @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include #include "local-def.h" diff --git a/src/afb-apis.c b/src/afb-apis.c index 856e3f5d..effef8a9 100644 --- a/src/afb-apis.c +++ b/src/afb-apis.c @@ -32,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include "../include/local-def.h" @@ -279,36 +283,56 @@ int afb_apis_add_pathset(const char *pathset) }; } -/* // Check of apiurl is declare in this plugin and call it extern __thread sigjmp_buf *error_handler; static int callPluginApi(AFB_request * request) { + volatile int status, timerset; + timer_t timerid; sigjmp_buf jmpbuf, *older; + struct sigevent sevp; + struct itimerspec its; // save context before calling the API + timerset = 0; + older = error_handler; status = setjmp(jmpbuf); if (status != 0) { - return 0; + status = 0; } + else { + error_handler = &jmpbuf; + if (request->config->apiTimeout > 0) { + timerset = 1; /* TODO: check statuses */ + sevp.sigev_notify = SIGEV_THREAD_ID; + sevp.sigev_signo = SIGALRM; +#if defined(sigev_notify_thread_id) + sevp.sigev_notify_thread_id = syscall(SYS_gettid); +#else + sevp._sigev_un._tid = syscall(SYS_gettid); +#endif + timer_create(CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid); + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = 15; + its.it_value.tv_nsec = 0; + timer_settime(timerid, 0, &its, NULL); + } - // Trigger a timer to protect from unacceptable long time execution - if (request->config->apiTimeout > 0) - alarm((unsigned)request->config->apiTimeout); - - older = error_handler; - error_handler = &jmpbuf; - doCallPluginApi(request, apiidx, verbidx, context); + //doCallPluginApi(request, apiidx, verbidx, context); + status = 1; + } + if (timerset) + timer_delete(timerid); error_handler = older; - // cancel timeout and plugin signal handle before next call - alarm(0); - return 1; + return status; } -*/ static void handle(struct afb_req req, const struct api_desc *api, const struct AFB_restapi *verb) { + json_object *jresp, *jcall, *jreqt; + AFB_request request; request.uuid = request.url = "fake"; @@ -336,7 +360,7 @@ static void handle(struct afb_req req, const struct api_desc *api, const struct verb->callback(&request, NULL); if (verb->session == AFB_SESSION_CLOSE) - /*del*/; + /*close*/; } int afb_apis_handle(struct afb_req req, const char *api, size_t lenapi, const char *verb, size_t lenverb) diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 506091cb..58dbb04e 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -16,12 +16,18 @@ */ #define _GNU_SOURCE -#include + +#include +#include +#include #include -#include +#include +#include #include -#include "../include/local-def.h" +#include + +#include "local-def.h" #include "afb-method.h" #include "afb-req-itf.h" #include "afb-hreq.h" @@ -36,13 +42,19 @@ struct hreq_data { char *value; }; -static struct afb_arg getarg(struct afb_hreq *hreq, const char *name); -static void iterargs(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure); +static struct afb_arg req_get(struct afb_hreq *hreq, const char *name); +static void req_iterate(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure); +static void req_fail(struct afb_hreq *hreq, const char *status, const char *info); +static void req_success(struct afb_hreq *hreq, json_object *obj, const char *info); static const struct afb_req_itf afb_hreq_itf = { - .get = (void*)getarg, - .iterate = (void*)iterargs + .get = (void*)req_get, + .iterate = (void*)req_iterate, + .fail = (void*)req_fail, + .success = (void*)req_success }; + void (*fail)(void *data, const char *status, const char *info); + void (*success)(void *data, json_object *obj, const char *info); static struct hreq_data *get_data(struct afb_hreq *hreq, const char *key, int create) { @@ -163,12 +175,20 @@ int afb_hreq_reply_file_if_exist(struct afb_hreq *hreq, int dirfd, const char *f struct MHD_Response *response; /* Opens the file or directory */ - fd = openat(dirfd, filename, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return 0; - afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); - return 1; + if (filename[0]) { + fd = openat(dirfd, filename, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return 0; + afb_hreq_reply_error(hreq, MHD_HTTP_FORBIDDEN); + return 1; + } + } else { + fd = dup(dirfd); + if (fd < 0) { + afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); + return 1; + } } /* Retrieves file's status */ @@ -354,33 +374,7 @@ struct afb_req afb_hreq_to_req(struct afb_hreq *hreq) return (struct afb_req){ .itf = &afb_hreq_itf, .data = hreq }; } -struct iterator_data -{ - struct afb_hreq *hreq; - int (*iterator)(void *closure, const char *key, const char *value, int isfile); - void *closure; -}; - -static int itargs(struct iterator_data *id, enum MHD_ValueKind kind, const char *key, const char *value) -{ - if (get_data(id->hreq, key, 0)) - return 1; - return id->iterator(id->closure, key, value, 0); -} - -void afb_hreq_iterate_arguments(struct afb_hreq *hreq, int (*iterator)(void *closure, const char *key, const char *value, int isfile), void *closure) -{ - struct iterator_data id = { .hreq = hreq, .iterator = iterator, .closure = closure }; - struct hreq_data *data = hreq->data; - while (data) { - if (!iterator(closure, data->key, data->value, !!data->file)) - return; - data = data->next; - } - MHD_get_connection_values (hreq->connection, MHD_GET_ARGUMENT_KIND, (void*)itargs, &id); -} - -static struct afb_arg getarg(struct afb_hreq *hreq, const char *name) +static struct afb_arg req_get(struct afb_hreq *hreq, const char *name) { struct hreq_data *hdat = get_data(hreq, name, 0); if (hdat) @@ -418,7 +412,7 @@ static int _iterargs_(struct iterdata *id, enum MHD_ValueKind kind, const char * }); } -static void iterargs(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure) +static void req_iterate(struct afb_hreq *hreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure) { struct iterdata id = { .hreq = hreq, .iterator = iterator, .closure = closure }; struct hreq_data *hdat = hreq->data; @@ -445,4 +439,39 @@ void afb_hreq_drop_data(struct afb_hreq *hreq) data = hreq->data; } } +static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t max) +{ + ssize_t len = stpncpy(buf, json_object_to_json_string(obj)+pos, max) - buf; + return len ? : -1; +} + +static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp) +{ + json_object *root, *request; + struct MHD_Response *response; + + root = json_object_new_object(); + json_object_object_add(root, "jtype", json_object_new_string("afb-reply")); + request = json_object_new_object(); + json_object_object_add(root, "request", request); + json_object_object_add(request, "status", json_object_new_string(status)); + if (info) + json_object_object_add(request, "info", json_object_new_string(info)); + if (resp) + json_object_object_add(root, "response", resp); + + response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 65500, (void*)send_json_cb, root, (void*)json_object_put); + MHD_queue_response(hreq->connection, retcode, response); + MHD_destroy_response(response); +} + +static void req_fail(struct afb_hreq *hreq, const char *status, const char *info) +{ + req_reply(hreq, MHD_HTTP_OK, status, info, NULL); +} + +static void req_success(struct afb_hreq *hreq, json_object *obj, const char *info) +{ + req_reply(hreq, MHD_HTTP_OK, "success", info, obj); +} diff --git a/src/afb-hreq.h b/src/afb-hreq.h index 01409a58..fb914f13 100644 --- a/src/afb-hreq.h +++ b/src/afb-hreq.h @@ -15,9 +15,10 @@ * limitations under the License. */ +struct AFB_session; struct afb_hreq { - AFB_session *session; + struct AFB_session *session; struct MHD_Connection *connection; enum afb_method method; const char *version; @@ -60,5 +61,3 @@ extern struct afb_req afb_hreq_to_req(struct afb_hreq *hreq); extern void afb_hreq_drop_data(struct afb_hreq *hreq); -extern void afb_hreq_iterate_arguments(struct afb_hreq *hreq, int (*iterator)(void *closure, const char *key, const char *value, int isfile), void *closure); - diff --git a/src/afb-req-itf.h b/src/afb-req-itf.h index ab72a5ce..eea78317 100644 --- a/src/afb-req-itf.h +++ b/src/afb-req-itf.h @@ -25,6 +25,8 @@ struct afb_arg { struct afb_req_itf { struct afb_arg (*get)(void *data, const char *name); void (*iterate)(void *data, int (*iterator)(void *closure, struct afb_arg arg), void *closure); + void (*fail)(void *data, const char *status, const char *info); + void (*success)(void *data, json_object *obj, const char *info); }; struct afb_req { @@ -52,3 +54,51 @@ static inline void afb_req_iterate(struct afb_req req, int (*iterator)(void *clo req.itf->iterate(req.data, iterator, closure); } +#include +#include +#include + +static inline void afb_req_fail(struct afb_req req, const char *status, const char *info) +{ + req.itf->fail(req.data, status, info); +} + +static inline void afb_req_fail_v(struct afb_req req, const char *status, const char *info, va_list args) +{ + char *message; + if (info == NULL || vasprintf(&message, info, args) < 0) + message = NULL; + afb_req_fail(req, status, message); + free(message); +} + +static inline void afb_req_fail_f(struct afb_req req, const char *status, const char *info, ...) +{ + va_list args; + va_start(args, info); + afb_req_fail_v(req, status, info, args); + va_end(args); +} + +static inline void afb_req_success(struct afb_req req, json_object *obj, const char *info) +{ + req.itf->success(req.data, obj, info); +} + +static inline void afb_req_success_v(struct afb_req req, json_object *obj, const char *info, va_list args) +{ + char *message; + if (info == NULL || vasprintf(&message, info, args) < 0) + message = NULL; + afb_req_success(req, obj, message); + free(message); +} + +static inline void afb_req_success_f(struct afb_req req, json_object *obj, const char *info, ...) +{ + va_list args; + va_start(args, info); + afb_req_success_v(req, obj, info, args); + va_end(args); +} + diff --git a/src/afb-rest-api.c b/src/afb-rest-api.c index 80de7d65..28346b19 100644 --- a/src/afb-rest-api.c +++ b/src/afb-rest-api.c @@ -82,8 +82,7 @@ static AFB_error doCallPluginApi(AFB_request * request, int apiidx, int verbidx, clientCtx = ctxClientGet(request); if (clientCtx == NULL) { request->errcode = MHD_HTTP_INSUFFICIENT_STORAGE; - json_object_object_add(jcall, "status", json_object_new_string("fail")); - json_object_object_add(jcall, "info", json_object_new_string("Client Session Context Full !!!")); + json_add_status(jcall, "fail", "Client Session Context Full !!!"); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } @@ -98,16 +97,14 @@ static AFB_error doCallPluginApi(AFB_request * request, int apiidx, int verbidx, case AFB_SESSION_CREATE: if (clientCtx->token[0] != '\0' && request->config->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_add_status(jcall, "exist", "AFB_SESSION_CREATE Session already exist"); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } if (AFB_SUCCESS != ctxTokenCreate(clientCtx, 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_add_status(jcall, "fail", "AFB_SESSION_CREATE Invalid Initial Token"); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } else { @@ -120,8 +117,7 @@ static AFB_error doCallPluginApi(AFB_request * request, int apiidx, int verbidx, case AFB_SESSION_RENEW: if (AFB_SUCCESS != ctxTokenRefresh(clientCtx, 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_add_status(jcall, "fail", "AFB_SESSION_REFRESH Broken Exchange Token Chain"); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } else { @@ -134,8 +130,7 @@ static AFB_error doCallPluginApi(AFB_request * request, int apiidx, int verbidx, case AFB_SESSION_CLOSE: if (AFB_SUCCESS != ctxTokenCheck(clientCtx, 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_add_status(jcall, "fail", "AFB_SESSION_CLOSE Not a Valid Access Token")); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } else { @@ -148,8 +143,7 @@ static AFB_error doCallPluginApi(AFB_request * request, int apiidx, int verbidx, // default action is check if (AFB_SUCCESS != ctxTokenCheck(clientCtx, 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_add_status(jcall, "fail", "AFB_SESSION_CHECK Invalid Active Token")); json_object_object_add(jreqt, "request", jcall); goto ExitOnDone; } diff --git a/src/afb-websock.c b/src/afb-websock.c index 23d489ab..b9417cbe 100644 --- a/src/afb-websock.c +++ b/src/afb-websock.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,7 @@ #include "websock.h" -#include "../include/local-def.h" +#include "local-def.h" #include "afb-method.h" #include "afb-hreq.h" diff --git a/src/helper-api.c b/src/helper-api.c index fd42c482..1e3d8820 100644 --- a/src/helper-api.c +++ b/src/helper-api.c @@ -17,12 +17,19 @@ * */ -#include "../include/local-def.h" +#define _GNU_SOURCE + +#include +#include +#include + +/* #include #include #include -#include +*/ +#include "local-def.h" #include "afb-req-itf.h" // handle to hold queryAll values @@ -56,19 +63,19 @@ const char* getQueryValue(const AFB_request * request, const char *name) { static int getQueryCB (queryHandleT *query, struct afb_arg arg) { if (query->idx >= query->len) return 0; - query->idx += snprintf (&query->msg[query->idx], query->len-query->idx, " %s: %s\'%s\',", arg.name, arg.is_file?"FILE=":"", arg.value); + query->idx += (unsigned)snprintf (&query->msg[query->idx], query->len-query->idx, " %s: %s\'%s\',", arg.name, arg.is_file?"FILE=":"", arg.value); return 1; /* continue to iterate */ } // Helper to retrieve argument from connection -int getQueryAll(AFB_request * request, char *buffer, size_t len) { +size_t getQueryAll(AFB_request * request, char *buffer, size_t len) { queryHandleT query; buffer[0] = '\0'; // start with an empty string query.msg = buffer; query.len = len; query.idx = 0; - afb_req_iterate(*request->areq, getQueryCB, &query); + afb_req_iterate(*request->areq, (void*)getQueryCB, &query); buffer[len-1] = 0; return query.idx >= len ? len - 1 : query.idx; } @@ -217,6 +224,41 @@ static void jsoninit() } +// build an ERROR message and return it as a valid json object +json_object *json_add_status (json_object *obj, const char *status, const char *info) +{ + if (obj == NULL) + obj = json_object_new_object(); + json_object_object_add(obj, "status", json_object_new_string(status)); + if (info) + json_object_object_add(obj, "info", json_object_new_string(info)); + return obj; +} + +// build an ERROR message and return it as a valid json object +json_object *json_add_status_v (json_object *obj, const char *status, const char *info, va_list args) +{ + char *message; + if (info == NULL || vasprintf(&message, info, args) < 0) + message = NULL; + obj = json_add_status(obj, status, message); + free(message); + return obj; +} + + +// build an ERROR message and return it as a valid json object +json_object *json_add_status_f (json_object *obj, const char *status, const char *info, ...) +{ + va_list args; + va_start(args, info); + obj = json_add_status_v(obj, status, info, args); + va_end(args); + return obj; +} + + + // build an ERROR message and return it as a valid json object struct json_object *jsonNewMessage (AFB_error level, char* format, ...) { static int count = 0; @@ -252,3 +294,20 @@ struct json_object *jsonNewMessage (AFB_error level, char* format, ...) { return (AFBResponse); } +#if 0 +{ + jtype: "AFB_message" + request: + { + prefix: "", + api: "", + status: "", /* exist, fail, empty, null, processed */ + info: "", + uuid: "", + token: "", + timeout: "" + } + response: ... +} +#endif + diff --git a/src/http-svc.c b/src/http-svc.c index 706abbc5..9235bf87 100644 --- a/src/http-svc.c +++ b/src/http-svc.c @@ -16,12 +16,17 @@ */ #define _GNU_SOURCE -#include + +#include +#include #include #include +#include #include -#include "../include/local-def.h" +#include + +#include "local-def.h" #include "afb-method.h" #include "afb-hreq.h" #include "afb-websock.h" @@ -146,7 +151,7 @@ static struct AFB_clientCtx *afb_hreq_context(struct afb_hreq *hreq) uuid = afb_hreq_get_argument(hreq, uuid_arg); if (uuid == NULL) uuid = afb_hreq_get_cookie(hreq, uuid_cookie); - hreq->context = _ctxClientGet(uuid); + hreq->context = ctxClientGet(uuid); } return hreq->context; } diff --git a/src/main.c b/src/main.c index a602af92..2401043c 100644 --- a/src/main.c +++ b/src/main.c @@ -16,15 +16,22 @@ * limitations under the License. */ -#include +#define _GNU_SOURCE +#include +#include +#include #include #include -#include -#include -#include +#include +#include #include #include +/* +#include +#include +*/ + #include "local-def.h" #include "afb-apis.h" #include "session.h" @@ -427,10 +434,10 @@ static void signalError(int signum) sigset_t sigset; // unlock signal to allow a new signal to come - sigemptyset(&sigset); - sigaddset(&sigset, signum); - sigprocmask(SIG_UNBLOCK, &sigset, 0); if (error_handler != NULL) { + sigemptyset(&sigset); + sigaddset(&sigset, signum); + sigprocmask(SIG_UNBLOCK, &sigset, 0); longjmp(*error_handler, signum); } } diff --git a/src/session.c b/src/session.c index eded1416..ad411239 100644 --- a/src/session.c +++ b/src/session.c @@ -20,16 +20,24 @@ * */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + -#include "local-def.h" +/* #include #include -#include #include #include -#include #include #include +*/ #include "afb-apis.h" #include "session.h" @@ -103,7 +111,7 @@ found: return client; } -static AFB_error ctxStoreDel (AFB_clientCtx *client) +static int ctxStoreDel (AFB_clientCtx *client) { int idx; int status; @@ -117,22 +125,22 @@ static AFB_error ctxStoreDel (AFB_clientCtx *client) sessions.store[idx]=NULL; sessions.count--; ctxUuidFreeCB (client); - status = AFB_SUCCESS; + status = 1; goto deleted; } } - status = AFB_FAIL; + status = 0; deleted: pthread_mutex_unlock(&sessions.mutex); return status; } -static AFB_error ctxStoreAdd (AFB_clientCtx *client) +static int ctxStoreAdd (AFB_clientCtx *client) { int idx; int status; - if (client == NULL) - return AFB_FAIL; + + assert (client != NULL); //fprintf (stderr, "ctxStoreAdd request uuid=%s count=%d\n", client->uuid, sessions.count); @@ -142,12 +150,11 @@ static AFB_error ctxStoreAdd (AFB_clientCtx *client) if (NULL == sessions.store[idx]) { sessions.store[idx]= client; sessions.count++; - status = AFB_SUCCESS; + status = 1; goto added; } } - status = AFB_FAIL; - + status = 0; added: pthread_mutex_unlock(&sessions.mutex); return status; @@ -169,241 +176,14 @@ void ctxStoreGarbage () // Loop on Sessions Table and remove anything that is older than timeout for (idx=0; idx < sessions.max; idx++) { ctx = sessions.store[idx]; - if ((ctx != NULL) && (ctxStoreTooOld(ctx, now))) { + if (ctx != NULL && ctxStoreTooOld(ctx, now)) { ctxStoreDel (ctx); } } } // This function will return exiting client context or newly created client context -AFB_clientCtx *ctxClientGet (AFB_request *request) -{ - AFB_clientCtx *clientCtx=NULL; - const char *uuid; - uuid_t newuuid; - - if (request->config->token == NULL) return NULL; - - // Check if client as a context or not inside the URL - uuid = NULL; //MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, key_uuid); - - // if UUID in query we're restfull with no cookies otherwise check for cookie - if (uuid != NULL) - request->restfull = TRUE; - else { - char cookie[64]; - request->restfull = FALSE; - snprintf(cookie, sizeof cookie, "%s-%d", COOKIE_NAME, request->config->httpdPort); - uuid = NULL; //MHD_lookup_connection_value (request->connection, MHD_COOKIE_KIND, cookie); - }; - - // Warning when no cookie defined MHD_lookup_connection_value may return something !!! - if ((uuid != NULL) && (strnlen (uuid, 10) >= 10)) { - // search if client context exist and it not timeout let's use it - clientCtx = ctxStoreSearch (uuid); - - if (clientCtx) { - if (ctxStoreTooOld (clientCtx, NOW)) { - // this session is too old let's delete it - ctxStoreDel (clientCtx); - clientCtx = NULL; - } else { - return clientCtx; - } - } - } - - // 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 - clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof (void*)); - } - - uuid_generate(newuuid); // create a new UUID - uuid_unparse_lower(newuuid, clientCtx->uuid); - - // if table is full at 50% let's clean it up - if(sessions.count > (sessions.max / 2)) ctxStoreGarbage(); - - // finally add uuid into hashtable - if (AFB_SUCCESS != ctxStoreAdd (clientCtx)) { - free (clientCtx); - return NULL; - } - return clientCtx; -} - -// Sample Generic Ping Debug API -AFB_error ctxTokenCheck (AFB_clientCtx *clientCtx, AFB_request *request) -{ - const char *token; - - if (clientCtx->contexts == NULL) - return AFB_EMPTY; - - // this time have to extract token from query list - token = NULL; //MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, key_token); - - // if not token is providing we refuse the exchange - if ((token == NULL) || (clientCtx->token == NULL)) - return AFB_FALSE; - - // compare current token with previous one - if ((0 == strcmp (token, clientCtx->token)) && (!ctxStoreTooOld (clientCtx, NOW))) { - return AFB_SUCCESS; - } - - // Token is not valid let move level of assurance to zero and free attached client handle - return AFB_FAIL; -} - -// Free Client Session Context -AFB_error ctxTokenReset (AFB_clientCtx *clientCtx, AFB_request *request) -{ - if (clientCtx == NULL) - return AFB_EMPTY; - //if (verbose) fprintf (stderr, "ctxClientReset New uuid=[%s] token=[%s] timestamp=%d\n", clientCtx->uuid, clientCtx->token, clientCtx->timeStamp); - - // Search for an existing client with the same UUID - clientCtx = ctxStoreSearch (clientCtx->uuid); - if (clientCtx == NULL) - return AFB_FALSE; - - // Remove client from table - ctxStoreDel (clientCtx); - - return AFB_SUCCESS; -} - -// generate a new token -AFB_error ctxTokenCreate (AFB_clientCtx *clientCtx, AFB_request *request) -{ - uuid_t newuuid; - const char *token; - - if (clientCtx == NULL) - return AFB_EMPTY; - - // if config->token!="" then verify that we have the right initial share secret - if (request->config->token[0] != '\0') { - - // check for initial token secret and return if not presented - token = NULL; //MHD_lookup_connection_value(request->connection, MHD_GET_ARGUMENT_KIND, key_token); - if (token == NULL) - return AFB_UNAUTH; - - // verify that it fits with initial tokens fit - if (strcmp(request->config->token, token)) - return AFB_UNAUTH; - } - - // create a UUID as token value - uuid_generate(newuuid); - uuid_unparse_lower(newuuid, clientCtx->token); - - // keep track of time for session timeout and further clean up - clientCtx->timeStamp = time(NULL) + sessions.timeout; - - // Token is also store in context but it might be convenient for plugin to access it directly - return AFB_SUCCESS; -} - - -// generate a new token and update client context -AFB_error ctxTokenRefresh (AFB_clientCtx *clientCtx, AFB_request *request) -{ - uuid_t newuuid; - - if (clientCtx == NULL) - return AFB_EMPTY; - - // Check if the old token is valid - if (ctxTokenCheck (clientCtx, 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, clientCtx->token); - - // keep track of time for session timeout and further clean up - clientCtx->timeStamp = time(NULL) + sessions.timeout; - - return AFB_SUCCESS; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// This function will return exiting client context or newly created client context -AFB_clientCtx *_ctxClientGet (const char *uuid) +AFB_clientCtx *ctxClientGet (const char *uuid) { uuid_t newuuid; AFB_clientCtx *clientCtx; @@ -434,7 +214,7 @@ AFB_clientCtx *_ctxClientGet (const char *uuid) uuid_unparse_lower(newuuid, clientCtx->uuid); clientCtx->timeStamp = time(NULL) + sessions.timeout; strcpy(clientCtx->token, sessions.initok); - if (AFB_SUCCESS == ctxStoreAdd (clientCtx)) + if (ctxStoreAdd (clientCtx)) return clientCtx; free(clientCtx->contexts); } @@ -444,32 +224,32 @@ AFB_clientCtx *_ctxClientGet (const char *uuid) } // Free Client Session Context -AFB_error _ctxClientDel (AFB_clientCtx *clientCtx) +int ctxClientClose (AFB_clientCtx *clientCtx) { assert(clientCtx != NULL); return ctxStoreDel (clientCtx); } // Sample Generic Ping Debug API -AFB_error _ctxTokenCheck (AFB_clientCtx *clientCtx, const char *token) +int ctxTokenCheck (AFB_clientCtx *clientCtx, const char *token) { assert(clientCtx != NULL); assert(token != NULL); // compare current token with previous one if (ctxStoreTooOld (clientCtx, NOW)) - return AFB_FAIL; + return 0; if (!clientCtx->token[0] || 0 == strcmp (token, clientCtx->token)) { clientCtx->timeStamp = time(NULL) + sessions.timeout; - return AFB_SUCCESS; + return 1; } // Token is not valid let move level of assurance to zero and free attached client handle - return AFB_FAIL; + return 0; } // generate a new token and update client context -AFB_error _ctxTokenNew (AFB_clientCtx *clientCtx) +int ctxTokenNew (AFB_clientCtx *clientCtx) { uuid_t newuuid; @@ -482,6 +262,6 @@ AFB_error _ctxTokenNew (AFB_clientCtx *clientCtx) // keep track of time for session timeout and further clean up clientCtx->timeStamp = time(NULL) + sessions.timeout; - return AFB_SUCCESS; + return 1; } diff --git a/src/session.h b/src/session.h index 0862b37b..9b54179b 100644 --- a/src/session.h +++ b/src/session.h @@ -19,26 +19,18 @@ struct AFB_clientCtx { time_t timeStamp; // last time token was refresh - int restfull; // client does not use cookie void **contexts; // application specific context [one per plugin]] char uuid[37]; // long term authentication of remote client char token[37]; // short term authentication of remote client }; typedef struct AFB_clientCtx AFB_clientCtx; -/* -extern AFB_error ctxTokenRefresh (AFB_clientCtx *clientCtx, AFB_request *request); -extern AFB_error ctxTokenCreate (AFB_clientCtx *clientCtx, AFB_request *request); -extern AFB_error ctxTokenCheck (AFB_clientCtx *clientCtx, AFB_request *request); -extern AFB_error ctxTokenReset (AFB_clientCtx *clientCtx, AFB_request *request); -extern AFB_clientCtx *ctxClientGet (AFB_request *request); -*/ extern void ctxStoreGarbage (); extern void ctxStoreInit (int nbSession, int timeout, int apicount, const char *initok); -extern AFB_clientCtx *_ctxClientGet (const char *uuid); -extern AFB_error _ctxClientDel (AFB_clientCtx *clientCtx); -extern AFB_error _ctxTokenCheck (AFB_clientCtx *clientCtx, const char *token); -extern AFB_error _ctxTokenNew (AFB_clientCtx *clientCtx); +extern AFB_clientCtx *ctxClientGet (const char *uuid); +extern int ctxClientClose (AFB_clientCtx *clientCtx); +extern int ctxTokenCheck (AFB_clientCtx *clientCtx, const char *token); +extern int ctxTokenNew (AFB_clientCtx *clientCtx); -- 2.16.6