Author: pjd
Date: Thu May 19 23:18:42 2011
New Revision: 222108
URL: http://svn.freebsd.org/changeset/base/222108

Log:
  In preparation for IPv6 support allow to specify multiple addresses to
  listen on.
  
  MFC after:    3 weeks

Modified:
  head/sbin/hastd/hast.conf.5
  head/sbin/hastd/hast.h
  head/sbin/hastd/hastd.c
  head/sbin/hastd/parse.y

Modified: head/sbin/hastd/hast.conf.5
==============================================================================
--- head/sbin/hastd/hast.conf.5 Thu May 19 23:13:08 2011        (r222107)
+++ head/sbin/hastd/hast.conf.5 Thu May 19 23:18:42 2011        (r222108)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 2, 2011
+.Dd May 20, 2011
 .Dt HAST.CONF 5
 .Os
 .Sh NAME
@@ -159,6 +159,7 @@ tcp4://0.0.0.0
 tcp4://0.0.0.0:8457
 .Ed
 .Pp
+Multiple listen addresses can be specified.
 The default value is
 .Pa tcp4://0.0.0.0:8457 .
 .It Ic replication Aq mode

Modified: head/sbin/hastd/hast.h
==============================================================================
--- head/sbin/hastd/hast.h      Thu May 19 23:13:08 2011        (r222107)
+++ head/sbin/hastd/hast.h      Thu May 19 23:18:42 2011        (r222108)
@@ -82,12 +82,13 @@
 #define        HIO_FLUSH               4
 #define        HIO_KEEPALIVE           5
 
-#define        HAST_USER       "hast"
-#define        HAST_TIMEOUT    20
-#define        HAST_CONFIG     "/etc/hast.conf"
-#define        HAST_CONTROL    "/var/run/hastctl"
-#define        HASTD_LISTEN    "tcp4://0.0.0.0:8457"
-#define        HASTD_PIDFILE   "/var/run/hastd.pid"
+#define        HAST_USER               "hast"
+#define        HAST_TIMEOUT            20
+#define        HAST_CONFIG             "/etc/hast.conf"
+#define        HAST_CONTROL            "/var/run/hastctl"
+#define        HASTD_LISTEN_IPV4       "tcp4://0.0.0.0:8457"
+#define        HASTD_LISTEN_IPV6       "tcp6://[::]:8457"
+#define        HASTD_PIDFILE           "/var/run/hastd.pid"
 
 /* Default extent size. */
 #define        HAST_EXTENTSIZE 2097152
@@ -100,6 +101,14 @@
 /* Number of seconds to sleep between reconnect retries or keepalive packets. 
*/
 #define        HAST_KEEPALIVE  10
 
+struct hastd_listen {
+       /* Address to listen on. */
+       char     hl_addr[HAST_ADDRSIZE];
+       /* Protocol-specific data. */
+       struct proto_conn *hl_conn;
+       TAILQ_ENTRY(hastd_listen) hl_next;
+};
+
 struct hastd_config {
        /* Address to communicate with hastctl(8). */
        char     hc_controladdr[HAST_ADDRSIZE];
@@ -107,10 +116,8 @@ struct hastd_config {
        struct proto_conn *hc_controlconn;
        /* Incoming control connection. */
        struct proto_conn *hc_controlin;
-       /* Address to listen on. */
-       char     hc_listenaddr[HAST_ADDRSIZE];
-       /* Protocol-specific data. */
-       struct proto_conn *hc_listenconn;
+       /* List of addresses to listen on. */
+       TAILQ_HEAD(, hastd_listen) hc_listen;
        /* List of resources. */
        TAILQ_HEAD(, hast_resource) hc_resources;
 };

Modified: head/sbin/hastd/hastd.c
==============================================================================
--- head/sbin/hastd/hastd.c     Thu May 19 23:13:08 2011        (r222107)
+++ head/sbin/hastd/hastd.c     Thu May 19 23:18:42 2011        (r222108)
@@ -98,6 +98,7 @@ void
 descriptors_cleanup(struct hast_resource *res)
 {
        struct hast_resource *tres;
+       struct hastd_listen *lst;
 
        TAILQ_FOREACH(tres, &cfg->hc_resources, hr_next) {
                if (tres == res) {
@@ -120,7 +121,10 @@ descriptors_cleanup(struct hast_resource
        if (cfg->hc_controlin != NULL)
                proto_close(cfg->hc_controlin);
        proto_close(cfg->hc_controlconn);
-       proto_close(cfg->hc_listenconn);
+       TAILQ_FOREACH(lst, &cfg->hc_listen, hl_next) {
+               if (lst->hl_conn != NULL)
+                       proto_close(lst->hl_conn);
+       }
        (void)pidfile_close(pfh);
        hook_fini();
        pjdlog_fini();
@@ -462,6 +466,8 @@ hastd_reload(void)
 {
        struct hastd_config *newcfg;
        struct hast_resource *nres, *cres, *tres;
+       struct hastd_listen *nlst, *clst;
+       unsigned int nlisten;
        uint8_t role;
 
        pjdlog_info("Reloading configuration...");
@@ -483,19 +489,37 @@ hastd_reload(void)
                }
        }
        /*
-        * Check if listen address has changed.
+        * Check if any listen address has changed.
         */
-       if (strcmp(cfg->hc_listenaddr, newcfg->hc_listenaddr) != 0) {
-               if (proto_server(newcfg->hc_listenaddr,
-                   &newcfg->hc_listenconn) < 0) {
-                       pjdlog_errno(LOG_ERR, "Unable to listen on address %s",
-                           newcfg->hc_listenaddr);
-                       goto failed;
+       nlisten = 0;
+       TAILQ_FOREACH(nlst, &newcfg->hc_listen, hl_next) {
+               TAILQ_FOREACH(clst, &cfg->hc_listen, hl_next) {
+                       if (strcmp(nlst->hl_addr, clst->hl_addr) == 0)
+                               break;
+               }
+               if (clst != NULL && clst->hl_conn != NULL) {
+                       pjdlog_info("Keep listening on address %s.",
+                           nlst->hl_addr);
+                       nlst->hl_conn = clst->hl_conn;
+                       nlisten++;
+               } else if (proto_server(nlst->hl_addr, &nlst->hl_conn) == 0) {
+                       pjdlog_info("Listening on new address %s.",
+                           nlst->hl_addr);
+                       nlisten++;
+               } else {
+                       pjdlog_errno(LOG_WARNING,
+                           "Unable to listen on address %s", nlst->hl_addr);
                }
        }
+       if (nlisten == 0) {
+               pjdlog_error("No addresses to listen on.");
+               goto failed;
+       }
+
+       /* No failures from now on. */
+
        /*
-        * Only when both control and listen sockets are successfully
-        * initialized switch them to new configuration.
+        * Switch to new control socket.
         */
        if (newcfg->hc_controlconn != NULL) {
                pjdlog_info("Control socket changed from %s to %s.",
@@ -506,15 +530,23 @@ hastd_reload(void)
                strlcpy(cfg->hc_controladdr, newcfg->hc_controladdr,
                    sizeof(cfg->hc_controladdr));
        }
-       if (newcfg->hc_listenconn != NULL) {
-               pjdlog_info("Listen socket changed from %s to %s.",
-                   cfg->hc_listenaddr, newcfg->hc_listenaddr);
-               proto_close(cfg->hc_listenconn);
-               cfg->hc_listenconn = newcfg->hc_listenconn;
-               newcfg->hc_listenconn = NULL;
-               strlcpy(cfg->hc_listenaddr, newcfg->hc_listenaddr,
-                   sizeof(cfg->hc_listenaddr));
+       /*
+        * Switch to new listen addresses. Close all that were removed.
+        */
+       while ((clst = TAILQ_FIRST(&cfg->hc_listen)) != NULL) {
+               TAILQ_FOREACH(nlst, &newcfg->hc_listen, hl_next) {
+                       if (strcmp(nlst->hl_addr, clst->hl_addr) == 0)
+                               break;
+               }
+               if (nlst == NULL && clst->hl_conn != NULL) {
+                       proto_close(clst->hl_conn);
+                       pjdlog_info("No longer listening on address %s.",
+                           clst->hl_addr);
+               }
+               TAILQ_REMOVE(&cfg->hc_listen, clst, hl_next);
+               free(clst);
        }
+       TAILQ_CONCAT(&cfg->hc_listen, &newcfg->hc_listen, hl_next);
 
        /*
         * Stop and remove resources that were removed from the configuration.
@@ -607,8 +639,20 @@ failed:
        if (newcfg != NULL) {
                if (newcfg->hc_controlconn != NULL)
                        proto_close(newcfg->hc_controlconn);
-               if (newcfg->hc_listenconn != NULL)
-                       proto_close(newcfg->hc_listenconn);
+               while ((nlst = TAILQ_FIRST(&newcfg->hc_listen)) != NULL) {
+                       if (nlst->hl_conn != NULL) {
+                               TAILQ_FOREACH(clst, &cfg->hc_listen, hl_next) {
+                                       if (strcmp(nlst->hl_addr,
+                                           clst->hl_addr) == 0) {
+                                               break;
+                                       }
+                               }
+                               if (clst == NULL || clst->hl_conn == NULL)
+                                       proto_close(nlst->hl_conn);
+                       }
+                       TAILQ_REMOVE(&newcfg->hc_listen, nlst, hl_next);
+                       free(nlst);
+               }
                yy_config_free(newcfg);
        }
        pjdlog_warning("Configuration not reloaded.");
@@ -634,7 +678,7 @@ terminate_workers(void)
 }
 
 static void
-listen_accept(void)
+listen_accept(struct hastd_listen *lst)
 {
        struct hast_resource *res;
        struct proto_conn *conn;
@@ -646,10 +690,10 @@ listen_accept(void)
        pid_t pid;
        int status;
 
-       proto_local_address(cfg->hc_listenconn, laddr, sizeof(laddr));
+       proto_local_address(lst->hl_conn, laddr, sizeof(laddr));
        pjdlog_debug(1, "Accepting connection to %s.", laddr);
 
-       if (proto_accept(cfg->hc_listenconn, &conn) < 0) {
+       if (proto_accept(lst->hl_conn, &conn) < 0) {
                pjdlog_errno(LOG_ERR, "Unable to accept connection %s", laddr);
                return;
        }
@@ -943,6 +987,7 @@ static void
 main_loop(void)
 {
        struct hast_resource *res;
+       struct hastd_listen *lst;
        struct timeval seltimeout;
        int fd, maxfd, ret;
        time_t lastcheck, now;
@@ -952,9 +997,6 @@ main_loop(void)
        seltimeout.tv_sec = REPORT_INTERVAL;
        seltimeout.tv_usec = 0;
 
-       pjdlog_info("Started successfully, running protocol version %d.",
-           HAST_PROTO_VERSION);
-
        for (;;) {
                check_signals();
 
@@ -963,10 +1005,14 @@ main_loop(void)
                maxfd = fd = proto_descriptor(cfg->hc_controlconn);
                PJDLOG_ASSERT(fd >= 0);
                FD_SET(fd, &rfds);
-               fd = proto_descriptor(cfg->hc_listenconn);
-               PJDLOG_ASSERT(fd >= 0);
-               FD_SET(fd, &rfds);
-               maxfd = fd > maxfd ? fd : maxfd;
+               TAILQ_FOREACH(lst, &cfg->hc_listen, hl_next) {
+                       if (lst->hl_conn == NULL)
+                               continue;
+                       fd = proto_descriptor(lst->hl_conn);
+                       PJDLOG_ASSERT(fd >= 0);
+                       FD_SET(fd, &rfds);
+                       maxfd = fd > maxfd ? fd : maxfd;
+               }
                TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
                        if (res->hr_event == NULL)
                                continue;
@@ -1014,8 +1060,12 @@ main_loop(void)
 
                if (FD_ISSET(proto_descriptor(cfg->hc_controlconn), &rfds))
                        control_handle(cfg);
-               if (FD_ISSET(proto_descriptor(cfg->hc_listenconn), &rfds))
-                       listen_accept();
+               TAILQ_FOREACH(lst, &cfg->hc_listen, hl_next) {
+                       if (lst->hl_conn == NULL)
+                               continue;
+                       if (FD_ISSET(proto_descriptor(lst->hl_conn), &rfds))
+                               listen_accept(lst);
+               }
                TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) {
                        if (res->hr_event == NULL)
                                continue;
@@ -1053,6 +1103,7 @@ dummy_sighandler(int sig __unused)
 int
 main(int argc, char *argv[])
 {
+       struct hastd_listen *lst;
        const char *pidfile;
        pid_t otherpid;
        bool foreground;
@@ -1136,10 +1187,12 @@ main(int argc, char *argv[])
                    cfg->hc_controladdr);
        }
        /* Listen for remote connections. */
-       if (proto_server(cfg->hc_listenaddr, &cfg->hc_listenconn) < 0) {
-               KEEP_ERRNO((void)pidfile_remove(pfh));
-               pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
-                   cfg->hc_listenaddr);
+       TAILQ_FOREACH(lst, &cfg->hc_listen, hl_next) {
+               if (proto_server(lst->hl_addr, &lst->hl_conn) < 0) {
+                       KEEP_ERRNO((void)pidfile_remove(pfh));
+                       pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
+                           lst->hl_addr);
+               }
        }
 
        if (!foreground) {
@@ -1158,6 +1211,14 @@ main(int argc, char *argv[])
                }
        }
 
+       pjdlog_info("Started successfully, running protocol version %d.",
+           HAST_PROTO_VERSION);
+
+       pjdlog_debug(1, "Listening on control address %s.",
+           cfg->hc_controladdr);
+       TAILQ_FOREACH(lst, &cfg->hc_listen, hl_next)
+               pjdlog_info("Listening on address %s.", lst->hl_addr);
+
        hook_init();
 
        main_loop();

Modified: head/sbin/hastd/parse.y
==============================================================================
--- head/sbin/hastd/parse.y     Thu May 19 23:13:08 2011        (r222107)
+++ head/sbin/hastd/parse.y     Thu May 19 23:18:42 2011        (r222108)
@@ -33,12 +33,14 @@
 
 #include <sys/param.h> /* MAXHOSTNAMELEN */
 #include <sys/queue.h>
+#include <sys/socket.h>
 #include <sys/sysctl.h>
 
 #include <arpa/inet.h>
 
 #include <assert.h>
 #include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <sysexits.h>
@@ -59,7 +61,9 @@ static struct hast_resource *curres;
 static bool mynode, hadmynode;
 
 static char depth0_control[HAST_ADDRSIZE];
-static char depth0_listen[HAST_ADDRSIZE];
+static char depth0_listen_ipv4[HAST_ADDRSIZE];
+static char depth0_listen_ipv6[HAST_ADDRSIZE];
+static TAILQ_HEAD(, hastd_listen) depth0_listen;
 static int depth0_replication;
 static int depth0_checksum;
 static int depth0_compression;
@@ -114,6 +118,19 @@ isitme(const char *name)
        return (0);
 }
 
+static bool
+family_supported(int family)
+{
+       int sock;
+
+       sock = socket(family, SOCK_STREAM, 0);
+       if (sock == -1 && errno == EPROTONOSUPPORT)
+               return (false);
+       if (sock >= 0)
+               (void)close(sock);
+       return (true);
+}
+
 static int
 node_names(char **namesp)
 {
@@ -175,7 +192,11 @@ yy_config_parse(const char *config, bool
        depth0_checksum = HAST_CHECKSUM_NONE;
        depth0_compression = HAST_COMPRESSION_HOLE;
        strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
-       strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen));
+       TAILQ_INIT(&depth0_listen);
+       strlcpy(depth0_listen_ipv4, HASTD_LISTEN_IPV4,
+           sizeof(depth0_listen_ipv4));
+       strlcpy(depth0_listen_ipv6, HASTD_LISTEN_IPV6,
+           sizeof(depth0_listen_ipv6));
        depth0_exec[0] = '\0';
 
        lconfig = calloc(1, sizeof(*lconfig));
@@ -186,6 +207,7 @@ yy_config_parse(const char *config, bool
                return (NULL);
        }
 
+       TAILQ_INIT(&lconfig->hc_listen);
        TAILQ_INIT(&lconfig->hc_resources);
 
        yyin = fopen(config, "r");
@@ -214,9 +236,52 @@ yy_config_parse(const char *config, bool
                strlcpy(lconfig->hc_controladdr, depth0_control,
                    sizeof(lconfig->hc_controladdr));
        }
-       if (lconfig->hc_listenaddr[0] == '\0') {
-               strlcpy(lconfig->hc_listenaddr, depth0_listen,
-                   sizeof(lconfig->hc_listenaddr));
+       if (!TAILQ_EMPTY(&depth0_listen))
+               TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
+       if (TAILQ_EMPTY(&lconfig->hc_listen)) {
+               struct hastd_listen *lst;
+
+               if (family_supported(AF_INET)) {
+                       lst = calloc(1, sizeof(*lst));
+                       if (lst == NULL) {
+                               pjdlog_error("Unable to allocate memory for 
listen address.");
+                               yy_config_free(lconfig);
+                               if (exitonerror)
+                                       exit(EX_TEMPFAIL);
+                               return (NULL);
+                       }
+                       (void)strlcpy(lst->hl_addr, depth0_listen_ipv4,
+                           sizeof(lst->hl_addr));
+                       TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
+               } else {
+                       pjdlog_debug(1,
+                           "No IPv4 support in the kernel, not listening on 
IPv4 address.");
+               }
+#ifdef notyet
+               if (family_supported(AF_INET6)) {
+                       lst = calloc(1, sizeof(*lst));
+                       if (lst == NULL) {
+                               pjdlog_error("Unable to allocate memory for 
listen address.");
+                               yy_config_free(lconfig);
+                               if (exitonerror)
+                                       exit(EX_TEMPFAIL);
+                               return (NULL);
+                       }
+                       (void)strlcpy(lst->hl_addr, depth0_listen_ipv6,
+                           sizeof(lst->hl_addr));
+                       TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
+               } else {
+                       pjdlog_debug(1,
+                           "No IPv6 support in the kernel, not listening on 
IPv6 address.");
+               }
+#endif
+               if (TAILQ_EMPTY(&lconfig->hc_listen)) {
+                       pjdlog_error("No address to listen on.");
+                       yy_config_free(lconfig);
+                       if (exitonerror)
+                               exit(EX_TEMPFAIL);
+                       return (NULL);
+               }
        }
        TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
                assert(curres->hr_provname[0] != '\0');
@@ -274,8 +339,17 @@ yy_config_parse(const char *config, bool
 void
 yy_config_free(struct hastd_config *config)
 {
+       struct hastd_listen *lst;
        struct hast_resource *res;
 
+       while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
+               TAILQ_REMOVE(&depth0_listen, lst, hl_next);
+               free(lst);
+       }
+       while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
+               TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
+               free(lst);
+       }
        while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
                TAILQ_REMOVE(&config->hc_resources, res, hr_next);
                free(res);
@@ -362,26 +436,30 @@ control_statement:        CONTROL STR
 
 listen_statement:      LISTEN STR
        {
+               struct hastd_listen *lst;
+
+               lst = calloc(1, sizeof(*lst));
+               if (lst == NULL) {
+                       pjdlog_error("Unable to allocate memory for listen 
address.");
+                       free($2);
+                       return (1);
+               }
+               if (strlcpy(lst->hl_addr, $2, sizeof(lst->hl_addr)) >=
+                   sizeof(lst->hl_addr)) {
+                       pjdlog_error("listen argument is too long.");
+                       free($2);
+                       free(lst);
+                       return (1);
+               }
                switch (depth) {
                case 0:
-                       if (strlcpy(depth0_listen, $2,
-                           sizeof(depth0_listen)) >=
-                           sizeof(depth0_listen)) {
-                               pjdlog_error("listen argument is too long.");
-                               free($2);
-                               return (1);
-                       }
+                       TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
                        break;
                case 1:
-                       if (!mynode)
-                               break;
-                       if (strlcpy(lconfig->hc_listenaddr, $2,
-                           sizeof(lconfig->hc_listenaddr)) >=
-                           sizeof(lconfig->hc_listenaddr)) {
-                               pjdlog_error("listen argument is too long.");
-                               free($2);
-                               return (1);
-                       }
+                       if (mynode)
+                               TAILQ_INSERT_TAIL(&depth0_listen, lst, hl_next);
+                       else
+                               free(lst);
                        break;
                default:
                        assert(!"listen at wrong depth level");
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to