diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2015-12-09 15:47:22 +0100 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2015-12-09 15:47:22 +0100 |
commit | f51e658a95edeb35b7b3027f7f066d3af0de04c7 (patch) | |
tree | c3f1e246a9da867c6fec7d355c86cd903f73d65a | |
parent | b55efc33fb8df8b0518570b2584b6da9abb3221b (diff) |
Implemented --alias and made timeout reentrant
-rw-r--r-- | include/local-def.h | 13 | ||||
-rw-r--r-- | src/config.c | 7 | ||||
-rw-r--r-- | src/http-svc.c | 31 | ||||
-rw-r--r-- | src/main.c | 27 | ||||
-rw-r--r-- | src/rest-api.c | 80 |
5 files changed, 101 insertions, 57 deletions
diff --git a/include/local-def.h b/include/local-def.h index 72c51dea..70d7762c 100644 --- a/include/local-def.h +++ b/include/local-def.h @@ -35,6 +35,10 @@ #include <json.h> #include <microhttpd.h> #include <magic.h> +#include <setjmp.h> +#include <signal.h> + + #define AJQ_VERSION "0.1" @@ -43,6 +47,7 @@ // Note: because of a bug in libmagic MAGIC_DB NULL should not be used for default #define MAGIC_DB "/usr/share/misc/magic.mgc" #define OPA_INDEX "index.html" +#define MAX_ALIAS 10 // max number of aliases typedef int BOOL; #ifndef FALSE @@ -88,6 +93,12 @@ typedef struct { int fd; } AFB_staticfile; +typedef struct { + char *url; + char *path; + size_t len; +} AFB_aliasdir; + // some usefull static object initialized when entering listen loop. extern int verbose; @@ -98,6 +109,7 @@ typedef struct { char *api; char *post; struct MHD_Connection *connection; + sigjmp_buf checkPluginCall; // context save for timeout set/longjmp } AFB_request; typedef struct { @@ -122,6 +134,7 @@ typedef struct { uid_t setuid; int cacheTimeout; int apiTimeout; + AFB_aliasdir *aliasdir; // alias mapping for icons,apps,... } AFB_config; // Command line structure hold cli --command + help text diff --git a/src/config.c b/src/config.c index ae1830d1..e30a687b 100644 --- a/src/config.c +++ b/src/config.c @@ -61,12 +61,15 @@ PUBLIC AFB_error configLoadFile (AFB_session * session, AFB_config *cliconfig) { int fd; json_object * AFBConfig, *value; + // TBD integrate alias-dir array with config-file + session->config->aliasdir = cliconfig->aliasdir; + // default HTTP port if (cliconfig->httpdPort == 0) session->config->httpdPort=1234; else session->config->httpdPort=cliconfig->httpdPort; // default Plugin API timeout - if (cliconfig->apiTimeout == 0) session->config->apiTimeout=10; + if (cliconfig->apiTimeout == 0) session->config->apiTimeout=0; else session->config->apiTimeout=cliconfig->apiTimeout; // cache timeout default one hour @@ -111,8 +114,6 @@ PUBLIC AFB_error configLoadFile (AFB_session * session, AFB_config *cliconfig) { session->config->plugins= cliconfig->plugins; } - - // if no session dir create a default path from rootdir if (cliconfig->sessiondir == NULL) { session->config->sessiondir = malloc (512); diff --git a/src/http-svc.c b/src/http-svc.c index cd488961..a5bd4b80 100644 --- a/src/http-svc.c +++ b/src/http-svc.c @@ -38,6 +38,7 @@ // let's compute fixed URL length only once static apiUrlLen=0; static baseUrlLen=0; +static rootUrlLen=0; // proto missing from GCC char *strcasestr(const char *haystack, const char *needle); @@ -190,15 +191,26 @@ STATIC int redirectHTML5(struct MHD_Connection *connection, AFB_session *session // minimal httpd file server for static HTML,JS,CSS,etc... STATIC int requestFile(struct MHD_Connection *connection, AFB_session *session, const char* url) { - int fd; - int ret; + int fd, ret, idx; AFB_staticfile staticfile; - + char *requestdir, *requesturl; + + // default search for file is rootdir base + requestdir = session->config->rootdir; + requesturl=url; + + // Check for optional aliases + for (idx=0; session->config->aliasdir[idx].url != NULL; idx++) { + if (0 == strncmp(url, session->config->aliasdir[idx].url, session->config->aliasdir[idx].len)) { + requestdir = session->config->aliasdir[idx].path; + requesturl=&url[session->config->aliasdir[idx].len]; + break; + } + } + // build full path from rootdir + url - - - strncpy(staticfile.path, session->config->rootdir, sizeof (staticfile.path)); - strncat(staticfile.path, url, sizeof (staticfile.path)); + strncpy(staticfile.path, requestdir, sizeof (staticfile.path)); + strncat(staticfile.path, requesturl, sizeof (staticfile.path)); // try to open file and get its size if (-1 == (staticfile.fd = open(staticfile.path, O_RDONLY))) { @@ -259,8 +271,9 @@ PUBLIC AFB_error httpdStart(AFB_session *session) { // compute fixed URL length at startup time apiUrlLen = strlen (session->config->rootapi); baseUrlLen= strlen (session->config->rootbase); - - // open libmagic cache + rootUrlLen= strlen (session->config->rootdir); + + // TBD open libmagic cache [fail to pass EFENCE check] // initLibMagic (session); @@ -61,6 +61,7 @@ static sigjmp_buf restartpoint; // context save for set/longjmp #define SET_ROOT_DIR 121 #define SET_ROOT_BASE 122 #define SET_ROOT_API 123 + #define SET_ROOT_ALIAS 124 #define SET_CACHE_TO 130 #define SET_cardid 131 @@ -91,6 +92,7 @@ static AFB_options cliOptions [] = { {SET_ROOT_DIR ,1,"rootdir" , "HTTP Root Directory [default $HOME/.AFB"}, {SET_ROOT_BASE ,1,"rootbase" , "Angular Base Root URL [default /opa"}, {SET_ROOT_API ,1,"rootapi" , "HTML Root API URL [default /api"}, + {SET_ROOT_ALIAS ,1,"alias" , "Muliple url map outside of rootdir [eg: --alias=/icons:/usr/share/icons]"}, {SET_APITIMEOUT ,1,"apitimeout" , "Plugin API timeout in seconds [default 10]"}, {SET_CACHE_TO ,1,"cache-eol" , "Client cache end of live [default 3600s]"}, @@ -109,6 +111,9 @@ static AFB_options cliOptions [] = { {0, 0, 0} }; +static AFB_aliasdir aliasdir[MAX_ALIAS]; +static int aliascount=0; + /*---------------------------------------------------------- | signalQuit | return to intitial exitpoint on order to close backend @@ -265,7 +270,9 @@ int main(int argc, char *argv[]) { // ------------- Build session handler & init config ------- session = configInit (); - memset (&cliconfig,0,sizeof(cliconfig)); + memset(&cliconfig,0,sizeof(cliconfig)); + memset(&aliasdir ,0,sizeof(aliasdir)); + cliconfig.aliasdir = aliasdir; // GNU CLI getopts nterface. struct option ggcOption; @@ -312,16 +319,34 @@ int main(int argc, char *argv[]) { case SET_ROOT_DIR: if (optarg == 0) goto needValueForOption; cliconfig.rootdir = optarg; + if (verbose) fprintf(stderr, "Forcing Rootdir=%s\n",cliconfig.rootdir); break; case SET_ROOT_BASE: if (optarg == 0) goto needValueForOption; cliconfig.rootbase = optarg; + if (verbose) fprintf(stderr, "Forcing Rootbase=%s\n",cliconfig.rootbase); break; case SET_ROOT_API: if (optarg == 0) goto needValueForOption; cliconfig.rootapi = optarg; + if (verbose) fprintf(stderr, "Forcing Rootapi=%s\n",cliconfig.rootapi); + break; + + case SET_ROOT_ALIAS: + if (optarg == 0) goto needValueForOption; + if (aliascount < MAX_ALIAS) { + aliasdir[aliascount].url = strsep(&optarg,":"); + aliasdir[aliascount].path = strsep(&optarg,":"); + aliasdir[aliascount].len = strlen(aliasdir[aliascount].url); + if (verbose) fprintf(stderr, "Alias url=%s path=%s\n", aliasdir[aliascount].url, aliasdir[aliascount].path); + aliascount++; + } else { + fprintf(stderr, "Too many aliases [max:%s] %s ignored\n", optarg, MAX_ALIAS-1); + } + + break; case SET_SMACK: diff --git a/src/rest-api.c b/src/rest-api.c index 39a7286d..be16b814 100644 --- a/src/rest-api.c +++ b/src/rest-api.c @@ -23,8 +23,6 @@ #include <setjmp.h> #include <signal.h> -// context save for timeout set/longjmp -static sigjmp_buf checkPluginCall; // handle to hold queryAll values typedef struct { @@ -92,67 +90,62 @@ STATIC void endRequest(void *cls, struct MHD_Connection *connection, void **con_ } } -/*---------------------------------------------------------- - | timeout signalQuit - +--------------------------------------------------------- */ -STATIC void pluginError (int signum) { - - sigset_t sigset; - - // unlock timeout signal to allow a new signal to come - sigemptyset (&sigset); - sigaddset (&sigset, SIGALRM); - sigprocmask (SIG_UNBLOCK, &sigset, 0); - - fprintf (stderr, "Oops:%s Plugin Api Timeout timeout\n", configTime()); - longjmp (checkPluginCall, signum); -} - - // Check of apiurl is declare in this plugin and call it - STATIC json_object * callPluginApi(AFB_plugin *plugin, AFB_session *session, AFB_request *request) { json_object *response; - int idx, status; + int idx, status, sig; + int signals[]= {SIGALRM, SIGSEGV, SIGFPE, 0}; + + /*--------------------------------------------------------------- + | Signal handler defined inside CallPluginApi to access Request + +---------------------------------------------------------------- */ + void pluginError (int signum) { + + sigset_t sigset; + + // unlock timeout signal to allow a new signal to come + sigemptyset (&sigset); + sigaddset (&sigset, SIGALRM); + sigprocmask (SIG_UNBLOCK, &sigset, 0); + + fprintf (stderr, "Oops:%s Plugin Api Timeout timeout\n", configTime()); + longjmp (request->checkPluginCall, signum); + } // If a plugin hold this urlpath call its callback for (idx = 0; plugin->apis[idx].callback != NULL; idx++) { if (!strcmp(plugin->apis[idx].name, request->api)) { // save context before calling the API - status = setjmp (checkPluginCall); + status = setjmp (request->checkPluginCall); if (status != 0) { response = jsonNewMessage(AFB_FATAL, "Plugin Call Fail prefix=%s api=%s info=%s", plugin->prefix, request->api, plugin->info); } else { - if (signal (SIGALRM, pluginError) == SIG_ERR) { - fprintf (stderr, "%s ERR: main no Signal/timeout handler installed.", configTime()); - return NULL; - } - - if (signal (SIGSEGV, pluginError) == SIG_ERR) { - fprintf (stderr, "%s ERR: main no Signal/memory handler installed.", configTime()); - return NULL; - } - if (signal (SIGFPE , pluginError) == SIG_ERR) { - fprintf (stderr, "%s ERR: main no Signal/memory handler installed.", configTime()); - return NULL; + if (session->config->apiTimeout > 0) { + for (sig=0; signals[sig] != 0; sig++) { + if (signal (signals[sig], pluginError) == SIG_ERR) { + fprintf (stderr, "%s ERR: main no Signal/timeout handler installed.", configTime()); + return NULL; + } + } + + // Trigger a timer to protect plugin for no return API + alarm (session->config->apiTimeout); } - // protect plugin call with a timeout - alarm (session->config->apiTimeout); - response = plugin->apis[idx].callback(session, request, plugin->apis[idx].handle); if (response != NULL) json_object_object_add(response, "jtype", plugin->jtype); - // cancel timeout and sleep before next aquisition - alarm (0); - signal(SIGALRM, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGFPE , SIG_DFL); + // cancel timeout and plugin signal handle before next call + if (session->config->apiTimeout > 0) { + alarm (0); + for (sig=0; signals[sig] != 0; sig++) { + signal (signals[sig], SIG_DFL); + } + } } return (response); - } } return (NULL); @@ -299,7 +292,6 @@ ExitOnError: // Loop on plugins. Check that they have the right type, prepare a JSON object with prefix - STATIC AFB_plugin ** RegisterPlugins(AFB_plugin **plugins) { int idx; |