From 13549775092afa9215de8468e34f6d194c2fd8db Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Tue, 5 Apr 2016 15:25:28 +0200 Subject: [PATCH] new main loop in place MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: If297e0a76e74422d456447be52cca460c9e237b3 Signed-off-by: José Bollo --- include/afb-plugin.h | 2 +- include/afb-poll-itf.h | 4 +- src/CMakeLists.txt | 2 +- src/afb-apis.c | 8 +-- src/{http-svc.c => afb-hsrv.c} | 81 +++++++++++++++--------------- src/local-def.h | 23 --------- src/main.c | 109 +++++++++++++++++------------------------ src/proto-def.h | 30 ------------ src/utils-upoll.c | 49 ++++++++++++++---- src/utils-upoll.h | 7 ++- src/verbose.h | 2 +- 11 files changed, 142 insertions(+), 175 deletions(-) rename src/{http-svc.c => afb-hsrv.c} (92%) delete mode 100644 src/proto-def.h diff --git a/include/afb-plugin.h b/include/afb-plugin.h index ba86e181..4064f9e9 100644 --- a/include/afb-plugin.h +++ b/include/afb-plugin.h @@ -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); diff --git a/include/afb-poll-itf.h b/include/afb-poll-itf.h index 4ce1fa48..2c8889b6 100644 --- a/include/afb-poll-itf.h +++ b/include/afb-poll-itf.h @@ -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); }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8bddcf0..3f8b84c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/afb-apis.c b/src/afb-apis.c index 55e68c93..9dcb1809 100644 --- a/src/afb-apis.c +++ b/src/afb-apis.c @@ -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; } diff --git a/src/http-svc.c b/src/afb-hsrv.c similarity index 92% rename from src/http-svc.c rename to src/afb-hsrv.c index b36d5f7e..a358cbd7 100644 --- a/src/http-svc.c +++ b/src/afb-hsrv.c @@ -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); -} diff --git a/src/local-def.h b/src/local-def.h index 3298322e..c21918cd 100644 --- a/src/local-def.h +++ b/src/local-def.h @@ -40,22 +40,6 @@ #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 */ diff --git a/src/main.c b/src/main.c index 15f84b18..41296e2c 100644 --- a/src/main.c +++ b/src/main.c @@ -32,8 +32,10 @@ #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 index b549a62e..00000000 --- a/src/proto-def.h +++ /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); - - - - diff --git a/src/utils-upoll.c b/src/utils-upoll.c index af4a6161..eb0e9674 100644 --- a/src/utils-upoll.c +++ b/src/utils-upoll.c @@ -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); } } diff --git a/src/utils-upoll.h b/src/utils-upoll.h index 24aaf41a..705fbc36 100644 --- a/src/utils-upoll.h +++ b/src/utils-upoll.h @@ -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); diff --git a/src/verbose.h b/src/verbose.h index 7b32a663..09254b22 100644 --- a/src/verbose.h +++ b/src/verbose.h @@ -1,5 +1,5 @@ /* - Copyright 2015 IoT.bzh + Copyright 2016 IoT.bzh author: José Bollo -- 2.16.6