afb-hsrv: Prepare selection of listening interfaces 47/18747/2
authorJose Bollo <jose.bollo@iot.bzh>
Tue, 30 Oct 2018 13:31:33 +0000 (14:31 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Thu, 13 Dec 2018 10:47:50 +0000 (10:47 +0000)
The listening socket will no more be the default one
but will be the selected ones, with ability to select
more than just one listening interface.

Nevertheless, the behavior is not changed at the moment.
The default interface (0.0.0.0) is still used. A further
change will add the ability to select the listening
interfaces.

That evolution depends on a fix of libmicrohttpd to
enable at the same time epoll and no-listen-fd.

Bug-AGL: SPEC-1833
Bug-AGL: SPEC-1016

Change-Id: Ia78671cbee90a243ba7b2c724b6155cffbde6920
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
src/afb-hsrv.c
src/afb-hsrv.h
src/main-afb-daemon.c
src/main-afs-supervisor.c

index 685c55b..2a08a2e 100644 (file)
@@ -25,6 +25,8 @@
 #include <poll.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <netdb.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 
 #include <json-c/json.h>
@@ -39,6 +41,7 @@
 #include "afb-hreq.h"
 #include "afb-hsrv.h"
 #include "afb-fdev.h"
+#include "afb-socket.h"
 #include "fdev.h"
 #include "verbose.h"
 #include "locale-root.h"
 #define JSON_CONTENT  "application/json"
 #define FORM_CONTENT  MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA
 
+struct hsrv_itf {
+       struct hsrv_itf *next;
+       struct afb_hsrv *hsrv;
+       struct fdev *fdev;
+       char uri[1];
+};
 
 struct hsrv_handler {
        struct hsrv_handler *next;
@@ -67,6 +76,7 @@ struct hsrv_alias {
 struct afb_hsrv {
        unsigned refcount;
        struct hsrv_handler *handlers;
+       struct hsrv_itf *interfaces;
        struct MHD_Daemon *httpd;
        struct fdev *fdev;
        char *cache_to;
@@ -413,34 +423,39 @@ int afb_hsrv_set_cache_timeout(struct afb_hsrv *hsrv, int duration)
        return 1;
 }
 
-int afb_hsrv_start(struct afb_hsrv *hsrv, uint16_t port, unsigned int connection_timeout)
+int afb_hsrv_start(struct afb_hsrv *hsrv, unsigned int connection_timeout)
 {
        struct fdev *fdev;
        struct MHD_Daemon *httpd;
        const union MHD_DaemonInfo *info;
 
        httpd = MHD_start_daemon(
-               MHD_USE_EPOLL | MHD_ALLOW_UPGRADE | MHD_USE_TCP_FASTOPEN | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME,
-               port,                           /* port */
-               new_client_handler, NULL,       /* Tcp Accept call back + extra attribute */
-               access_handler, hsrv,   /* Http Request Call back + extra attribute */
-               MHD_OPTION_NOTIFY_COMPLETED, end_handler, hsrv,
-               MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
-               MHD_OPTION_END);        /* options-end */
+                       MHD_USE_EPOLL
+                       | MHD_ALLOW_UPGRADE
+                       | MHD_USE_TCP_FASTOPEN
+                       | MHD_USE_NO_LISTEN_SOCKET
+                       | MHD_USE_DEBUG
+                       | MHD_ALLOW_SUSPEND_RESUME,
+                       0,                              /* port */
+                       new_client_handler, NULL,       /* Tcp Accept call back + extra attribute */
+                       access_handler, hsrv,   /* Http Request Call back + extra attribute */
+                       MHD_OPTION_NOTIFY_COMPLETED, end_handler, hsrv,
+                       MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
+                       MHD_OPTION_END);        /* options-end */
 
        if (httpd == NULL) {
-               ERROR("httpStart invalid httpd port: %d", (int)port);
+               ERROR("httpStart invalid httpd");
                return 0;
        }
 
-       info = MHD_get_daemon_info(httpd, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
+       info = MHD_get_daemon_info(httpd, MHD_DAEMON_INFO_EPOLL_FD);
        if (info == NULL) {
                MHD_stop_daemon(httpd);
                ERROR("httpStart no pollfd");
                return 0;
        }
 
-       fdev = afb_fdev_create(info->listen_fd);
+       fdev = afb_fdev_create(info->epoll_fd);
        if (fdev == NULL) {
                MHD_stop_daemon(httpd);
                ERROR("connection to events for httpd failed");
@@ -483,3 +498,89 @@ void afb_hsrv_put(struct afb_hsrv *hsrv)
        }
 }
 
+static int hsrv_itf_connect(struct hsrv_itf *itf);
+
+static void hsrv_itf_callback(void *closure, uint32_t revents, struct fdev *fdev)
+{
+       struct hsrv_itf *itf = closure;
+       int fd, sts;
+       struct sockaddr addr;
+       socklen_t lenaddr;
+
+       if ((revents & EPOLLHUP) != 0) {
+               ERROR("disconnection for server %s: %m", itf->uri);
+               hsrv_itf_connect(itf);
+               fdev_unref(fdev);
+       } else if ((revents & EPOLLIN) != 0) {
+               lenaddr = (socklen_t)sizeof addr;
+               fd = accept(fdev_fd(fdev), &addr, &lenaddr);
+               if (fd < 0)
+                       ERROR("can't accept connection to %s: %m", itf->uri);
+               else {
+                       sts = MHD_add_connection(itf->hsrv->httpd, fd, &addr, lenaddr);
+                       if (sts != MHD_YES) {
+                               ERROR("can't add incoming connection to %s: %m", itf->uri);
+                               close(fd);
+                       }
+               }
+       }
+}
+
+static int hsrv_itf_connect(struct hsrv_itf *itf)
+{
+       struct sockaddr addr;
+       socklen_t lenaddr;
+       char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+       int rgni;
+
+       itf->fdev = afb_socket_open_fdev(itf->uri, 1);
+       if (!itf->fdev) {
+               ERROR("can't create socket %s", itf->uri);
+               return 0;
+       }
+       fdev_set_events(itf->fdev, EPOLLIN);
+       fdev_set_callback(itf->fdev, hsrv_itf_callback, itf);
+       lenaddr = (socklen_t)sizeof addr;
+       getsockname(fdev_fd(itf->fdev), &addr, &lenaddr);
+       rgni = getnameinfo(&addr, lenaddr, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICSERV);
+       if (rgni != 0) {
+               ERROR("getnameinfo returned %d: %s", rgni, gai_strerror(rgni));
+               hbuf[0] = sbuf[0] = '?';
+               hbuf[1] = sbuf[1] = 0;
+       }
+       NOTICE("Listening interface %s:%s", hbuf, sbuf);
+       return 1;
+}
+
+int afb_hsrv_add_interface(struct afb_hsrv *hsrv, const char *uri)
+{
+       struct hsrv_itf *itf;
+
+       itf = malloc(sizeof *itf + strlen(uri));
+       if (itf == NULL)
+               return -1;
+
+       itf->hsrv = hsrv;
+       itf->fdev = NULL;
+       strcpy(itf->uri, uri);
+       itf->next = hsrv->interfaces;
+       hsrv->interfaces = itf;
+       return hsrv_itf_connect(itf);
+}
+
+int afb_hsrv_add_interface_tcp(struct afb_hsrv *hsrv, const char *itf, uint16_t port)
+{
+       int rc;
+       char buffer[1024];
+
+       if (itf == NULL) {
+               itf = "*"; /* awaiting getifaddrs impl */
+       }
+       rc = snprintf(buffer, sizeof buffer, "tcp:%s:%d", itf, (int)port);
+       if (rc < 0 || rc >= (int)sizeof buffer) {
+               if (rc > 0)
+                       errno = EINVAL;
+               return 0;
+       }
+       return afb_hsrv_add_interface(hsrv, buffer);
+}
\ No newline at end of file
index f72fc3b..0966d53 100644 (file)
@@ -26,10 +26,12 @@ extern struct afb_hsrv *afb_hsrv_create();
 extern void afb_hsrv_put(struct afb_hsrv *hsrv);
 
 extern void afb_hsrv_stop(struct afb_hsrv *hsrv);
-extern int afb_hsrv_start(struct afb_hsrv *hsrv, uint16_t port, unsigned int connection_timeout);
+extern int afb_hsrv_start(struct afb_hsrv *hsrv, unsigned int connection_timeout);
 extern int afb_hsrv_set_cache_timeout(struct afb_hsrv *hsrv, int duration);
 extern int afb_hsrv_add_alias(struct afb_hsrv *hsrv, const char *prefix, int dirfd, const char *alias, int priority, int relax);
 extern int afb_hsrv_add_alias_root(struct afb_hsrv *hsrv, const char *prefix, struct locale_root *root, int priority, int relax);
 extern int afb_hsrv_add_handler(struct afb_hsrv *hsrv, const char *prefix, int (*handler) (struct afb_hreq *, void *), void *data, int priority);
+extern int afb_hsrv_add_interface(struct afb_hsrv *hsrv, const char *uri);
+extern int afb_hsrv_add_interface_tcp(struct afb_hsrv *hsrv, const char *itf, uint16_t port);
 
 extern void afb_hsrv_run(struct afb_hsrv *hsrv);
index 4fb4792..bb2f0a5 100644 (file)
 #include "jobs.h"
 #include "sig-monitor.h"
 
+#if !defined(DEFAULT_BINDER_INTERFACE)
+#  define DEFAULT_BINDER_INTERFACE NULL
+#endif
+
 /*
    if SELF_PGROUP == 0 the launched command is the group leader
    if SELF_PGROUP != 0 afb-daemon is the group leader
@@ -371,13 +375,20 @@ static struct afb_hsrv *start_http_server()
        NOTICE("Waiting port=%d rootdir=%s", http_port, rootdir);
        NOTICE("Browser URL= http://localhost:%d", http_port);
 
-       rc = afb_hsrv_start(hsrv, (uint16_t) http_port, 15);
+       rc = afb_hsrv_start(hsrv, 15);
        if (!rc) {
                ERROR("starting of httpd failed");
                afb_hsrv_put(hsrv);
                return NULL;
        }
 
+       rc = afb_hsrv_add_interface_tcp(hsrv, DEFAULT_BINDER_INTERFACE, (uint16_t) http_port);
+       if (!rc) {
+               ERROR("setting interface failed");
+               afb_hsrv_put(hsrv);
+               return NULL;
+       }
+
        return hsrv;
 }
 
index 461b0a0..6daaf64 100644 (file)
 #include "jobs.h"
 #include "process-name.h"
 
+#if !defined(DEFAULT_SUPERVISOR_INTERFACE)
+#  define DEFAULT_SUPERVISOR_INTERFACE NULL
+#endif
+
 /* the main config */
 struct afs_config *main_config;
 
@@ -99,13 +103,20 @@ static struct afb_hsrv *start_http_server()
        NOTICE("Waiting port=%d rootdir=%s", main_config->httpdPort, main_config->rootdir);
        NOTICE("Browser URL= http://localhost:%d", main_config->httpdPort);
 
-       rc = afb_hsrv_start(hsrv, (uint16_t) main_config->httpdPort, 15);
+       rc = afb_hsrv_start(hsrv, 15);
        if (!rc) {
                ERROR("starting of httpd failed");
                afb_hsrv_put(hsrv);
                return NULL;
        }
 
+       rc = afb_hsrv_add_interface_tcp(hsrv, DEFAULT_SUPERVISOR_INTERFACE, (uint16_t) main_config->httpdPort);
+       if (!rc) {
+               ERROR("setting interface failed");
+               afb_hsrv_put(hsrv);
+               return NULL;
+       }
+
        return hsrv;
 }