summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2015-12-09 15:47:22 +0100
committerFulup Ar Foll <fulup@iot.bzh>2015-12-09 15:47:22 +0100
commitf51e658a95edeb35b7b3027f7f066d3af0de04c7 (patch)
treec3f1e246a9da867c6fec7d355c86cd903f73d65a
parentb55efc33fb8df8b0518570b2584b6da9abb3221b (diff)
Implemented --alias and made timeout reentrant
-rw-r--r--include/local-def.h13
-rw-r--r--src/config.c7
-rw-r--r--src/http-svc.c31
-rw-r--r--src/main.c27
-rw-r--r--src/rest-api.c80
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);
diff --git a/src/main.c b/src/main.c
index 9586bb56..b681bd09 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;