Implemented --alias and made timeout reentrant
authorFulup Ar Foll <fulup@iot.bzh>
Wed, 9 Dec 2015 14:47:22 +0000 (15:47 +0100)
committerFulup Ar Foll <fulup@iot.bzh>
Wed, 9 Dec 2015 14:47:22 +0000 (15:47 +0100)
include/local-def.h
src/config.c
src/http-svc.c
src/main.c
src/rest-api.c

index 72c51de..70d7762 100644 (file)
 #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
index ae1830d..e30a687 100644 (file)
@@ -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);
index cd48896..a5bd4b8 100644 (file)
@@ -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);
     
     
index 9586bb5..b681bd0 100644 (file)
@@ -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:
index 39a7286..be16b81 100644 (file)
@@ -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;