new main loop in place
authorJosé Bollo <jose.bollo@iot.bzh>
Tue, 5 Apr 2016 13:25:28 +0000 (15:25 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 5 Apr 2016 13:25:28 +0000 (15:25 +0200)
Change-Id: If297e0a76e74422d456447be52cca460c9e237b3
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
include/afb-plugin.h
include/afb-poll-itf.h
src/CMakeLists.txt
src/afb-apis.c
src/afb-hsrv.c [moved from src/http-svc.c with 92% similarity]
src/local-def.h
src/main.c
src/proto-def.h [deleted file]
src/utils-upoll.c
src/utils-upoll.h
src/verbose.h

index ba86e18..4064f9e 100644 (file)
@@ -67,7 +67,7 @@ struct AFB_interface
 {
        int verbosity;
        enum AFB_Mode mode;
-       struct afb_poll (*poll_open)(int fd, uint32_t events, void (*process)(void *closure, int fd, uint32_t events), void *closure);
+       struct afb_poll (*poll_open)(int fd, void *closure);
 };
 
 extern const struct AFB_plugin *pluginRegister (const struct AFB_interface *interface);
index 4ce1fa4..2c8889b 100644 (file)
@@ -17,7 +17,9 @@
 
 struct afb_poll_itf
 {
-       int (*update)(void *data, uint32_t events);
+       int (*on_readable)(void *, void (*cb)(void *));
+       int (*on_writable)(void *, void (*cb)(void *));
+       int (*on_hangup)(void *, void (*cb)(void *));
        void (*close)(void *data);
 };
 
index d8bddcf..3f8b84c 100644 (file)
@@ -2,7 +2,7 @@
 ADD_LIBRARY(src OBJECT
        main.c
        session.c
-       http-svc.c
+       afb-hsrv.c
        afb-apis.c
        afb-method.c
        afb-hreq.c
index 55e68c9..9dcb180 100644 (file)
@@ -63,7 +63,9 @@ static int apis_count = 0;
 static const char plugin_register_function[] = "pluginRegister";
 
 static const struct afb_poll_itf upoll_itf = {
-       .update = (void*)upoll_update,
+       .on_readable = (void*)upoll_on_readable,
+       .on_writable = (void*)upoll_on_writable,
+       .on_hangup = (void*)upoll_on_hangup,
        .close = (void*)upoll_close
 };
 
@@ -85,10 +87,10 @@ void afb_apis_free_context(int apiidx, void *context)
                free(context);
 }
 
-static struct afb_poll itf_poll_open(int fd, uint32_t events, void (*process)(void *closure, int fd, uint32_t events), void *closure)
+static struct afb_poll itf_poll_open(int fd, void *closure)
 {
        struct afb_poll result;
-       result.data = upoll_open(fd, events, process, closure);
+       result.data = upoll_open(fd, closure);
        result.itf = result.data ? &upoll_itf : NULL;
        return result;
 }
similarity index 92%
rename from src/http-svc.c
rename to src/afb-hsrv.c
index b36d5f7..a358cbd 100644 (file)
@@ -33,6 +33,7 @@
 #include "afb-apis.h"
 #include "afb-req-itf.h"
 #include "verbose.h"
+#include "utils-upoll.h"
 
 #define JSON_CONTENT  "application/json"
 #define FORM_CONTENT  MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
@@ -54,6 +55,8 @@ struct afb_diralias {
        int dirfd;
 };
 
+static struct upoll *upoll = NULL;
+
 int afb_hreq_one_page_api_redirect(
                struct afb_hreq *hreq,
                void *data)
@@ -422,27 +425,36 @@ static int my_default_init(AFB_session * session)
        if (!afb_hsrv_add_handler(session, session->config->rootbase, afb_hreq_one_page_api_redirect, NULL, -20))
                return 0;
 
+#if defined(USE_MAGIC_MIME_TYPE)
+       /*TBD open libmagic cache [fail to pass EFENCE check (allocating 0 bytes)] */
+       init_lib_magic (session);
+#endif
+
        return 1;
 }
 
-AFB_error httpdStart(AFB_session * session)
+/* infinite loop */
+static void hsrv_handle_event(struct MHD_Daemon *httpd)
 {
+       MHD_run(httpd);
+}
+
+int afb_hsrv_start(AFB_session * session)
+{
+       struct MHD_Daemon *httpd;
+       const union MHD_DaemonInfo *info;
+
        if (!my_default_init(session)) {
                printf("Error: initialisation of httpd failed");
-               return AFB_FATAL;
+               return 0;
        }
 
-#if defined(USE_MAGIC_MIME_TYPE)
-       /*TBD open libmagic cache [fail to pass EFENCE check (allocating 0 bytes)] */
-       init_lib_magic (session);
-#endif
-
        if (verbosity) {
                printf("AFB:notice Waiting port=%d rootdir=%s\n", session->config->httpdPort, session->config->rootdir);
                printf("AFB:notice Browser URL= http:/*localhost:%d\n", session->config->httpdPort);
        }
 
-       session->httpd = MHD_start_daemon(
+       httpd = MHD_start_daemon(
                MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_TCP_FASTOPEN | MHD_USE_DEBUG | MHD_USE_SUSPEND_RESUME,
                (uint16_t) session->config->httpdPort,  /* port */
                new_client_handler, NULL,       /* Tcp Accept call back + extra attribute */
@@ -451,48 +463,37 @@ AFB_error httpdStart(AFB_session * session)
                MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)15,        /* 15 seconds */
                MHD_OPTION_END);        /* options-end */
 
-       if (session->httpd == NULL) {
+       if (httpd == NULL) {
                printf("Error: httpStart invalid httpd port: %d", session->config->httpdPort);
-               return AFB_FATAL;
+               return 0;
        }
-       return AFB_SUCCESS;
-}
 
-/* infinite loop */
-AFB_error httpdLoop(AFB_session * session)
-{
-       int count = 0;
-       const union MHD_DaemonInfo *info;
-       struct pollfd pfd;
-
-       info = MHD_get_daemon_info(session->httpd, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
+       info = MHD_get_daemon_info(httpd, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
        if (info == NULL) {
-               printf("Error: httpLoop no pollfd");
-               goto error;
+               MHD_stop_daemon(httpd);
+               fprintf(stderr, "Error: httpStart no pollfd");
+               return 0;
        }
-       pfd.fd = info->listen_fd;
-       pfd.events = POLLIN;
 
-       if (verbosity)
-               fprintf(stderr, "AFB:notice entering httpd waiting loop\n");
-       while (TRUE) {
-               if (verbosity)
-                       fprintf(stderr, "AFB:notice httpd alive [%d]\n", count++);
-               poll(&pfd, 1, 15000);   /* 15 seconds (as above timeout when starting) */
-               MHD_run(session->httpd);
+       upoll = upoll_open(info->listen_fd, httpd);
+       if (upoll == NULL) {
+               MHD_stop_daemon(httpd);
+               fprintf(stderr, "Error: connection to upoll of httpd failed");
+               return 0;
        }
+       upoll_on_readable(upoll, (void*)hsrv_handle_event);
 
- error:
-       /* should never return from here */
-       return AFB_FATAL;
+       session->httpd = httpd;
+       return 1;
 }
 
-int httpdStatus(AFB_session * session)
+void afb_hsrv_stop(AFB_session * session)
 {
-       return MHD_run(session->httpd);
+       if (upoll)
+               upoll_close(upoll);
+       upoll = NULL;
+       if (session->httpd != NULL)
+               MHD_stop_daemon(session->httpd);
+       session->httpd = NULL;
 }
 
-void httpdStop(AFB_session * session)
-{
-       MHD_stop_daemon(session->httpd);
-}
index 3298322..c21918c 100644 (file)
 #define DEFLT_HTTP_TIMEOUT  15     // Max MibMicroHttp timeout
 #define AFB_MAX_PLUGINS     20     // Max number of plugins for a given binder
 
-#ifndef FALSE
-  #define FALSE 0
-#endif
-#ifndef TRUE
-  #define TRUE 1
-#endif
-
-#define PUBLIC
-#define STATIC    static
-#define FAILED    -1
-
-#define AUDIO_BUFFER "/tmp/buf"
-
-// prebuild json error are constructed in helper-api.c
-typedef enum  { AFB_FALSE, AFB_TRUE, AFB_FATAL, AFB_FAIL, AFB_WARNING, AFB_EMPTY, AFB_SUCCESS, AFB_DONE, AFB_UNAUTH} AFB_error;
-
 #define MAX_POST_SIZE  4096   // maximum size for POST data
 #define CTX_NBCLIENTS   10   // allow a default of 10 authenticated clients
 
@@ -63,11 +47,6 @@ typedef enum  { AFB_FALSE, AFB_TRUE, AFB_FATAL, AFB_FAIL, AFB_WARNING, AFB_EMPTY
 
 
 
-
-
-
-
-
 enum AFB_Mode;
 
 
@@ -133,6 +112,4 @@ struct AFB_session
 typedef struct AFB_config AFB_config;
 typedef struct AFB_session AFB_session;
 
-#include "proto-def.h"
-
 #endif /* LOCAL_DEF_H */
index 15f84b1..41296e2 100644 (file)
 
 #include "local-def.h"
 #include "afb-apis.h"
+#include "afb-hsrv.h"
 #include "session.h"
 #include "verbose.h"
+#include "utils-upoll.h"
 
 #if !defined(PLUGIN_INSTALL_DIR)
 #error "you should define PLUGIN_INSTALL_DIR"
@@ -126,24 +128,29 @@ static void printVersion (void)
 }
 
 // load config from disk and merge with CLI option
-static AFB_error config_set_default (AFB_session * session)
+static void config_set_default (AFB_session * session)
 {
    static char cacheTimeout [10];
    
    // default HTTP port
-   if (session->config->httpdPort == 0) session->config->httpdPort=1234;
+   if (session->config->httpdPort == 0)
+       session->config->httpdPort = 1234;
    
    // default Plugin API timeout
-   if (session->config->apiTimeout == 0) session->config->apiTimeout=DEFLT_API_TIMEOUT;
+   if (session->config->apiTimeout == 0)
+       session->config->apiTimeout = DEFLT_API_TIMEOUT;
    
    // default AUTH_TOKEN
-   if (session->config->token == NULL) session->config->token= DEFLT_AUTH_TOKEN;
+   if (session->config->token == NULL)
+               session->config->token = DEFLT_AUTH_TOKEN;
 
    // cache timeout default one hour
-   if (session->config->cacheTimeout == 0) session->config->cacheTimeout=DEFLT_CACHE_TIMEOUT;
+   if (session->config->cacheTimeout == 0)
+               session->config->cacheTimeout = DEFLT_CACHE_TIMEOUT;
 
    // cache timeout default one hour
-   if (session->config->cntxTimeout == 0) session->config->cntxTimeout=DEFLT_CNTX_TIMEOUT;
+   if (session->config->cntxTimeout == 0)
+               session->config->cntxTimeout = DEFLT_CNTX_TIMEOUT;
 
    if (session->config->rootdir == NULL) {
        session->config->rootdir = getenv("AFBDIR");
@@ -157,17 +164,14 @@ static AFB_error config_set_default (AFB_session * session)
    }
    
    // if no Angular/HTML5 rootbase let's try '/' as default
-   if  (session->config->rootbase == NULL) {
+   if  (session->config->rootbase == NULL)
        session->config->rootbase = "/opa";
-   }
    
-   if  (session->config->rootapi == NULL) {
+   if  (session->config->rootapi == NULL)
        session->config->rootapi = "/api";
-   }
 
-   if  (session->config->ldpaths == NULL) {
+   if  (session->config->ldpaths == NULL)
        session->config->ldpaths = PLUGIN_INSTALL_DIR;
-   }
 
    // if no session dir create a default path from rootdir
    if  (session->config->sessiondir == NULL) {
@@ -186,8 +190,6 @@ static AFB_error config_set_default (AFB_session * session)
    // cacheTimeout is an integer but HTTPd wants it as a string
    snprintf (cacheTimeout, sizeof (cacheTimeout),"%d", session->config->cacheTimeout);
    session->cacheTimeout = cacheTimeout; // httpd uses cacheTimeout string version
-
-   return AFB_SUCCESS;
 }
 
 
@@ -406,20 +408,11 @@ static void closeSession (int status, void *data) {
 
 /*----------------------------------------------------------
  | timeout signalQuit
- |
  +--------------------------------------------------------- */
-void signalQuit (int signum) {
-
-  sigset_t sigset;
-
-  // unlock timeout signal to allow a new signal to come
-  sigemptyset (&sigset);
-  sigaddset   (&sigset, SIGABRT);
-  sigprocmask (SIG_UNBLOCK, &sigset, 0);
-
-  fprintf (stderr, "ERR: Received signal quit\n");
-  syslog (LOG_ERR, "Daemon got kill3 & quit [please report bug]");
-  exit(1);
+void signalQuit (int signum)
+{
+       fprintf(stderr, "Terminating signal received %s\n", strsignal(signum));
+       exit(1);
 }
 
 
@@ -439,6 +432,10 @@ static void signalError(int signum)
                sigprocmask(SIG_UNBLOCK, &sigset, 0);
                longjmp(*error_handler, signum);
        }
+       if (signum == SIGALRM)
+               return;
+       fprintf(stderr, "Unmonitored signal received %s\n", strsignal(signum));
+       exit(2);
 }
 
 static void install_error_handlers()
@@ -453,30 +450,6 @@ static void install_error_handlers()
        }
 }
 
-/*----------------------------------------------------------
- | listenLoop
- |   Main listening HTTP loop
- +--------------------------------------------------------- */
-static void listenLoop (AFB_session *session) {
-  AFB_error  err;
-
-  // ------ Start httpd server
-
-   err = httpdStart (session);
-   if (err != AFB_SUCCESS) return;
-
-       if (session->readyfd != 0) {
-               static const char readystr[] = "READY=1";
-               write(session->readyfd, readystr, sizeof(readystr) - 1);
-               close(session->readyfd);
-       }
-
-   // infinite loop
-   httpdLoop(session);
-
-   fprintf (stderr, "hoops returned from infinite loop [report bug]\n");
-}
-  
 /*----------------------------------------------------------
  | daemonize
  |   set the process in background
@@ -530,6 +503,7 @@ static void daemonize(AFB_session *session)
  +--------------------------------------------------------- */
 
 int main(int argc, char *argv[])  {
+  int rc;
   AFB_session    *session;
 
   // open syslog if ever needed
@@ -560,7 +534,8 @@ int main(int argc, char *argv[])  {
   install_error_handlers();
 
   // ------------------ Some useful default values -------------------------
-  if  ((session->background == 0) && (session->foreground == 0)) session->foreground=1;
+  if  ((session->background == 0) && (session->foreground == 0))
+       session->foreground = 1;
 
   // ------------------ clean exit on CTR-C signal ------------------------
   if (signal (SIGINT, signalQuit) == SIG_ERR || signal (SIGABRT, signalQuit) == SIG_ERR) {
@@ -568,7 +543,6 @@ int main(int argc, char *argv[])  {
      return 1;
   }
 
-
   // let's run this program with a low priority
   nice (20);
 
@@ -576,13 +550,6 @@ int main(int argc, char *argv[])  {
   // let's not take the risk to run as ROOT
   //if (getuid() == 0)  goto errorNoRoot;
 
-#if defined(ALLOWS_SESSION_FILES)
-  // check session dir and create if it does not exist
-  if (sessionCheckdir (session) != AFB_SUCCESS) {
-       fprintf (stderr,"\nERR: AFB-daemon cannot read/write session dir\n\n");
-       exit (1);
-  }
-#endif
   if (verbosity) fprintf (stderr, "AFB: notice Init config done\n");
 
   // ---- run in foreground mode --------------------
@@ -606,10 +573,26 @@ int main(int argc, char *argv[])  {
   } // end background-foreground
 
 
-  listenLoop(session);
-  if (verbosity) printf ("\n---- Application Framework Binder Normal End ------\n");
-  exit(0);
+  // ------ Start httpd server
+
+   rc = afb_hsrv_start (session);
+   if (!rc)
+       exit(1);
+
+   if (session->readyfd != 0) {
+               static const char readystr[] = "READY=1";
+               write(session->readyfd, readystr, sizeof(readystr) - 1);
+               close(session->readyfd);
+  }
+
+   // infinite loop
+  for(;;)
+   upoll_wait(30000); 
+
+   if (verbosity)
+       fprintf (stderr, "hoops returned from infinite loop [report bug]\n");
 
+  return 0;
 }
 
 
diff --git a/src/proto-def.h b/src/proto-def.h
deleted file mode 100644 (file)
index b549a62..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-   proto-def.h -- provide a REST/HTTP interface
-
-   Copyright (C) 2015, Fulup Ar Foll
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-
-// Httpd server
-extern AFB_error httpdStart          (AFB_session *session);
-extern AFB_error httpdLoop           (AFB_session *session);
-extern void  httpdStop               (AFB_session *session);
-
-
-
-
index af4a616..eb0e967 100644 (file)
@@ -28,7 +28,9 @@
 struct upoll
 {
        int fd;
-       void (*process)(void *closure, int fd, uint32_t events);
+       void (*read)(void *);
+       void (*write)(void *);
+       void (*hangup)(void *);
        void *closure;
        struct upoll *next;
 };
@@ -48,7 +50,7 @@ int upoll_is_valid(struct upoll *upoll)
        return 0;
 }
 
-struct upoll *upoll_open(int fd, uint32_t events, void (*process)(void *closure, int fd, uint32_t events), void *closure)
+struct upoll *upoll_open(int fd, void *closure)
 {
        struct epoll_event e;
        struct upoll *result;
@@ -68,13 +70,12 @@ struct upoll *upoll_open(int fd, uint32_t events, void (*process)(void *closure,
        }
 
        /* allocates */
-       result = malloc(sizeof *result);
+       result = calloc(1, sizeof *result);
        if (result == NULL)
                return NULL;
 
        /* init */
        result->fd = fd;
-       result->process = process;
        result->closure = closure;
        pthread_mutex_lock(&mutex);
        result->next = head;
@@ -82,7 +83,7 @@ struct upoll *upoll_open(int fd, uint32_t events, void (*process)(void *closure,
        pthread_mutex_unlock(&mutex);
 
        /* records */
-       e.events = events;
+       e.events = 0;
        e.data.ptr = result;
        rc = epoll_ctl(pollfd, EPOLL_CTL_ADD, fd, &e);
        if (rc == 0)
@@ -95,16 +96,39 @@ struct upoll *upoll_open(int fd, uint32_t events, void (*process)(void *closure,
        return NULL;
 }
 
-int upoll_update(struct upoll *upoll, uint32_t events)
+static int update(struct upoll *upoll)
 {
        struct epoll_event e;
+       e.events = (upoll->read != NULL ? EPOLLIN : 0 )
+                | (upoll->write != NULL ? EPOLLOUT : 0);
+       e.data.ptr = upoll;
+       return epoll_ctl(pollfd, EPOLL_CTL_MOD, upoll->fd, &e);
+}
 
+int upoll_on_readable(struct upoll *upoll, void (*process)(void *))
+{
        assert(pollfd != 0);
        assert(upoll_is_valid(upoll));
 
-       e.events = events;
-       e.data.ptr = upoll;
-       return epoll_ctl(pollfd, EPOLL_CTL_MOD, upoll->fd, &e);
+       upoll->read = process;
+       return update(upoll);
+}
+
+int upoll_on_writable(struct upoll *upoll, void (*process)(void *))
+{
+       assert(pollfd != 0);
+       assert(upoll_is_valid(upoll));
+
+       upoll->write = process;
+       return update(upoll);
+}
+
+void upoll_on_hangup(struct upoll *upoll, void (*process)(void *))
+{
+       assert(pollfd != 0);
+       assert(upoll_is_valid(upoll));
+
+       upoll->hangup = process;
 }
 
 void upoll_close(struct upoll *upoll)
@@ -136,7 +160,12 @@ void upoll_wait(int timeout)
        rc = epoll_wait(pollfd, &e, 1, timeout);
        if (rc == 1) {
                upoll = e.data.ptr;
-               upoll->process(upoll->closure, upoll->fd, e.events);
+               if ((e.events & EPOLLIN) && upoll->read)
+                       upoll->read(upoll->closure);
+               if ((e.events & EPOLLOUT) && upoll->write)
+                       upoll->write(upoll->closure);
+               if ((e.events & EPOLLHUP) && upoll->hangup)
+                       upoll->hangup(upoll->closure);
        }
 }
 
index 24aaf41..705fbc3 100644 (file)
@@ -19,9 +19,12 @@ struct upoll;
 
 extern int upoll_is_valid(struct upoll *upoll);
 
-extern struct upoll *upoll_open(int fd, uint32_t events, void (*process)(void *closure, int fd, uint32_t events), void *closure);
+extern struct upoll *upoll_open(int fd, void *closure);
 
-extern int upoll_update(struct upoll *upoll, uint32_t events);
+extern int upoll_on_readable(struct upoll *upoll, void (*process)(void *closure));
+extern int upoll_on_writable(struct upoll *upoll, void (*process)(void *closure));
+
+extern void upoll_on_hangup(struct upoll *upoll, void (*process)(void *closure));
 
 extern void upoll_close(struct upoll *upoll);
 
index 7b32a66..09254b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- Copyright 2015 IoT.bzh
+ Copyright 2016 IoT.bzh
 
  author: José Bollo <jose.bollo@iot.bzh>