Author: trociny
Date: Mon Jun 27 20:04:13 2011
New Revision: 223603
URL: http://svn.freebsd.org/changeset/base/223603

Log:
  MFC r222087, r222108, r222115, r222116, r222117, r222118, r222119,
    r222120, r222121:
  
  r222087 (pjd):
  
  - Add support for AF_INET6 sockets for %S format character.
  - Use inet_ntop(3) instead of reimplementing it.
  - Use %hhu for unsigned char instead of casting it to unsigned int and
    using %u.
  
  r222108 (pjd):
  
  In preparation for IPv6 support allow to specify multiple addresses to
  listen on.
  
  r222115 (pjd):
  
  Rename proto_tcp4.c to proto_tcp.c in preparation for IPv6 support.
  
  r222116 (pjd):
  
  Rename tcp4 to tcp in preparation for IPv6 support.
  
  r222117 (pjd):
  
  Allow [ ] characters in strings. They might be used in IPv6 addresses.
  
  r222118 (pjd):
  
  Now that hell is fully frozen it is good time to add IPv6 support to HAST.
  
  r222119 (pjd):
  
  Rename ipv4/ipv6 to tcp4/tcp6.
  
  r222120 (pjd):
  
  If no listen address is specified, bind by default to:
  
          tcp4://0.0.0.0:8457
          tcp6://[::]:8457
  
  r222121 (pjd):
  
  Document IPv6 support.
  
  Approved by:  pjd (mentor)

Added:
  stable/8/sbin/hastd/proto_tcp.c
     - copied, changed from r222115, head/sbin/hastd/proto_tcp.c
Deleted:
  stable/8/sbin/hastd/proto_tcp4.c
Modified:
  stable/8/sbin/hastd/Makefile
  stable/8/sbin/hastd/hast.conf.5
  stable/8/sbin/hastd/hast.h
  stable/8/sbin/hastd/hastd.c
  stable/8/sbin/hastd/parse.y
  stable/8/sbin/hastd/pjdlog.c
  stable/8/sbin/hastd/token.l
Directory Properties:
  stable/8/sbin/hastd/   (props changed)

Modified: stable/8/sbin/hastd/Makefile
==============================================================================
--- stable/8/sbin/hastd/Makefile        Mon Jun 27 18:56:43 2011        
(r223602)
+++ stable/8/sbin/hastd/Makefile        Mon Jun 27 20:04:13 2011        
(r223603)
@@ -12,7 +12,7 @@ SRCS+=        metadata.c
 SRCS+= nv.c
 SRCS+= secondary.c
 SRCS+= parse.y pjdlog.c primary.c
-SRCS+= proto.c proto_common.c proto_socketpair.c proto_tcp4.c proto_uds.c
+SRCS+= proto.c proto_common.c proto_socketpair.c proto_tcp.c proto_uds.c
 SRCS+= rangelock.c
 SRCS+= subr.c
 SRCS+= token.l
@@ -21,7 +21,7 @@ WARNS?=       6
 MAN=   hastd.8 hast.conf.5
 
 NO_WFORMAT=
-CFLAGS+=-DPROTO_TCP4_DEFAULT_PORT=8457
+CFLAGS+=-DPROTO_TCP_DEFAULT_PORT=8457
 CFLAGS+=-I${.CURDIR}
 CFLAGS+=-DINET
 .if ${MK_INET6_SUPPORT} != "no"

Modified: stable/8/sbin/hastd/hast.conf.5
==============================================================================
--- stable/8/sbin/hastd/hast.conf.5     Mon Jun 27 18:56:43 2011        
(r223602)
+++ stable/8/sbin/hastd/hast.conf.5     Mon Jun 27 20:04:13 2011        
(r223603)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 2, 2011
+.Dd May 20, 2011
 .Dt HAST.CONF 5
 .Os
 .Sh NAME
@@ -159,8 +159,14 @@ tcp4://0.0.0.0
 tcp4://0.0.0.0:8457
 .Ed
 .Pp
-The default value is
-.Pa tcp4://0.0.0.0:8457 .
+Multiple listen addresses can be specified.
+By default
+.Nm hastd
+listens on
+.Pa tcp4://0.0.0.0:8457
+and
+.Pa tcp6://[::]:8457
+if kernel supports IPv4 and IPv6 respectively.
 .It Ic replication Aq mode
 .Pp
 Replication mode should be one of the following:
@@ -364,26 +370,35 @@ daemon.
 .Sh EXAMPLES
 The example configuration file can look as follows:
 .Bd -literal -offset indent
+listen tcp://0.0.0.0
+
+on hasta {
+       listen tcp://2001:db8::1/64
+}
+on hastb {
+       listen tcp://2001:db8::2/64
+}
+
 resource shared {
        local /dev/da0
 
        on hasta {
-               remote tcp4://10.0.0.2
+               remote tcp://10.0.0.2
        }
        on hastb {
-               remote tcp4://10.0.0.1
+               remote tcp://10.0.0.1
        }
 }
 resource tank {
        on hasta {
                local /dev/mirror/tanka
-               source tcp4://10.0.0.1
-               remote tcp4://10.0.0.2
+               source tcp://10.0.0.1
+               remote tcp://10.0.0.2
        }
        on hastb {
                local /dev/mirror/tankb
-               source tcp4://10.0.0.2
-               remote tcp4://10.0.0.1
+               source tcp://10.0.0.2
+               remote tcp://10.0.0.1
        }
 }
 .Ed

Modified: stable/8/sbin/hastd/hast.h
==============================================================================
--- stable/8/sbin/hastd/hast.h  Mon Jun 27 18:56:43 2011        (r223602)
+++ stable/8/sbin/hastd/hast.h  Mon Jun 27 20:04:13 2011        (r223603)
@@ -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_TCP4       "tcp4://0.0.0.0:8457"
+#define        HASTD_LISTEN_TCP6       "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: stable/8/sbin/hastd/hastd.c
==============================================================================
--- stable/8/sbin/hastd/hastd.c Mon Jun 27 18:56:43 2011        (r223602)
+++ stable/8/sbin/hastd/hastd.c Mon Jun 27 20:04:13 2011        (r223603)
@@ -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: stable/8/sbin/hastd/parse.y
==============================================================================
--- stable/8/sbin/hastd/parse.y Mon Jun 27 18:56:43 2011        (r223602)
+++ stable/8/sbin/hastd/parse.y Mon Jun 27 20:04:13 2011        (r223603)
@@ -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_tcp4[HAST_ADDRSIZE];
+static char depth0_listen_tcp6[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_tcp4, HASTD_LISTEN_TCP4,
+           sizeof(depth0_listen_tcp4));
+       strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
+           sizeof(depth0_listen_tcp6));
        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,50 @@ 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_tcp4,
+                           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.");
+               }
+               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_tcp6,
+                           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.");
+               }
+               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 +337,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 +434,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");

Modified: stable/8/sbin/hastd/pjdlog.c
==============================================================================
--- stable/8/sbin/hastd/pjdlog.c        Mon Jun 27 18:56:43 2011        
(r223602)
+++ stable/8/sbin/hastd/pjdlog.c        Mon Jun 27 20:04:13 2011        
(r223603)
@@ -31,8 +31,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -103,22 +105,39 @@ pjdlog_printf_render_sockaddr(struct __p
        switch (ss->ss_family) {
        case AF_INET:
            {
+               char addr[INET_ADDRSTRLEN];
                const struct sockaddr_in *sin;
-               in_addr_t ip;
                unsigned int port;
 
                sin = (const struct sockaddr_in *)ss;
-               ip = ntohl(sin->sin_addr.s_addr);
                port = ntohs(sin->sin_port);
+               if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
+                   sizeof(addr)) == NULL) {
+                       PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
+                           strerror(errno));
+               }
+               snprintf(buf, sizeof(buf), "%s:%u", addr, port);
+               break;
+           }
+       case AF_INET6:
+           {
+               char addr[INET6_ADDRSTRLEN];
+               const struct sockaddr_in6 *sin;
+               unsigned int port;
 
-               snprintf(buf, sizeof(buf), "%u.%u.%u.%u:%u",
-                   ((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
-                   ((ip >> 8) & 0xff), (ip & 0xff), port);
+               sin = (const struct sockaddr_in6 *)ss;
+               port = ntohs(sin->sin6_port);
+               if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
+                   sizeof(addr)) == NULL) {
+                       PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
+                           strerror(errno));
+               }
+               snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
                break;
            }
        default:
-               snprintf(buf, sizeof(buf), "[unsupported family %u]",
-                   (unsigned int)ss->ss_family);
+               snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
+                   ss->ss_family);
                break;
        }
        ret = __printf_out(io, pi, buf, strlen(buf));

Copied and modified: stable/8/sbin/hastd/proto_tcp.c (from r222115, 
head/sbin/hastd/proto_tcp.c)
==============================================================================
--- head/sbin/hastd/proto_tcp.c Fri May 20 11:06:17 2011        (r222115, copy 
source)
+++ stable/8/sbin/hastd/proto_tcp.c     Mon Jun 27 20:04:13 2011        
(r223603)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * Copyright (c) 2011 Pawel Jakub Dawidek <[email protected]>
  * All rights reserved.
  *
  * This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -51,37 +52,19 @@ __FBSDID("$FreeBSD$");
 #include "proto_impl.h"
 #include "subr.h"
 
-#define        TCP4_CTX_MAGIC  0x7c441c
-struct tcp4_ctx {
+#define        TCP_CTX_MAGIC   0x7c41c
+struct tcp_ctx {
        int                     tc_magic;
-       struct sockaddr_in      tc_sin;
+       struct sockaddr_storage tc_sa;
        int                     tc_fd;
        int                     tc_side;
-#define        TCP4_SIDE_CLIENT        0
-#define        TCP4_SIDE_SERVER_LISTEN 1
-#define        TCP4_SIDE_SERVER_WORK   2
+#define        TCP_SIDE_CLIENT         0
+#define        TCP_SIDE_SERVER_LISTEN  1
+#define        TCP_SIDE_SERVER_WORK    2
 };
 
-static int tcp4_connect_wait(void *ctx, int timeout);
-static void tcp4_close(void *ctx);
-
-static in_addr_t
-str2ip(const char *str)
-{
-       struct hostent *hp;
-       in_addr_t ip;
-
-       ip = inet_addr(str);
-       if (ip != INADDR_NONE) {
-               /* It is a valid IP address. */
-               return (ip);
-       }
-       /* Check if it is a valid host name. */
-       hp = gethostbyname(str);
-       if (hp == NULL)
-               return (INADDR_NONE);
-       return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
-}
+static int tcp_connect_wait(void *ctx, int timeout);
+static void tcp_close(void *ctx);
 
 /*
  * Function converts the given string to unsigned number.
@@ -114,70 +97,106 @@ invalid:
 }
 
 static int
-tcp4_addr(const char *addr, int defport, struct sockaddr_in *sinp)
+tcp_addr(const char *addr, int defport, struct sockaddr_storage *sap)
 {
-       char iporhost[MAXHOSTNAMELEN];
+       char iporhost[MAXHOSTNAMELEN], portstr[6];
+       struct addrinfo hints;
+       struct addrinfo *res;
        const char *pp;
+       intmax_t port;
        size_t size;
-       in_addr_t ip;
+       int error;
 
        if (addr == NULL)
                return (-1);
 
-       if (strncasecmp(addr, "tcp4://", 7) == 0)
+       bzero(&hints, sizeof(hints));
+       hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_protocol = IPPROTO_TCP;
+
+       if (strncasecmp(addr, "tcp4://", 7) == 0) {
+               addr += 7;
+               hints.ai_family = PF_INET;
+       } else if (strncasecmp(addr, "tcp6://", 7) == 0) {
                addr += 7;
-       else if (strncasecmp(addr, "tcp://", 6) == 0)
+               hints.ai_family = PF_INET6;
+       } else if (strncasecmp(addr, "tcp://", 6) == 0) {
                addr += 6;
-       else {
+       } else {
                /*
-                * Because TCP4 is the default assume IP or host is given 
without
+                * Because TCP is the default assume IP or host is given without
                 * prefix.
                 */
        }
 
-       sinp->sin_family = AF_INET;
-       sinp->sin_len = sizeof(*sinp);
-       /* Extract optional port. */
-       pp = strrchr(addr, ':');
+       /*
+        * Extract optional port.
+        * There are three cases to consider.
+        * 1. hostname with port, eg. freefall.freebsd.org:8457
+        * 2. IPv4 address with port, eg. 192.168.0.101:8457
+        * 3. IPv6 address with port, eg. [fe80::1]:8457
+        * We discover IPv6 address by checking for two colons and if port is
+        * given, the address has to start with [.
+        */
+       pp = NULL;
+       if (strchr(addr, ':') != strrchr(addr, ':')) {
+               if (addr[0] == '[')
+                       pp = strrchr(addr, ':');
+       } else {
+               pp = strrchr(addr, ':');
+       }
        if (pp == NULL) {
                /* Port not given, use the default. */
-               sinp->sin_port = htons(defport);
+               port = defport;
        } else {
-               intmax_t port;
-
                if (numfromstr(pp + 1, 1, 65535, &port) < 0)
                        return (errno);
-               sinp->sin_port = htons(port);
        }
+       (void)snprintf(portstr, sizeof(portstr), "%jd", (intmax_t)port);
        /* Extract host name or IP address. */
        if (pp == NULL) {
                size = sizeof(iporhost);
                if (strlcpy(iporhost, addr, size) >= size)
                        return (ENAMETOOLONG);
+       } else if (addr[0] == '[' && pp[-1] == ']') {
+               size = (size_t)(pp - addr - 2 + 1);
+               if (size > sizeof(iporhost))
+                       return (ENAMETOOLONG);
+               (void)strlcpy(iporhost, addr + 1, size);
        } else {
                size = (size_t)(pp - addr + 1);
                if (size > sizeof(iporhost))
                        return (ENAMETOOLONG);
                (void)strlcpy(iporhost, addr, size);
        }
-       /* Convert string (IP address or host name) to in_addr_t. */
-       ip = str2ip(iporhost);
-       if (ip == INADDR_NONE)
+
+       error = getaddrinfo(iporhost, portstr, &hints, &res);
+       if (error != 0) {
+               pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost,
+                   portstr, gai_strerror(error));
                return (EINVAL);
-       sinp->sin_addr.s_addr = ip;
+       }
+       if (res == NULL)
+               return (ENOENT);
+
+       memcpy(sap, res->ai_addr, res->ai_addrlen);
+
+       freeaddrinfo(res);
 
        return (0);
 }
 
 static int
-tcp4_setup_new(const char *addr, int side, void **ctxp)
+tcp_setup_new(const char *addr, int side, void **ctxp)
 {
-       struct tcp4_ctx *tctx;
+       struct tcp_ctx *tctx;
        int ret, nodelay;
 
        PJDLOG_ASSERT(addr != NULL);
-       PJDLOG_ASSERT(side == TCP4_SIDE_CLIENT ||
-           side == TCP4_SIDE_SERVER_LISTEN);
+       PJDLOG_ASSERT(side == TCP_SIDE_CLIENT ||
+           side == TCP_SIDE_SERVER_LISTEN);
        PJDLOG_ASSERT(ctxp != NULL);
 
        tctx = malloc(sizeof(*tctx));
@@ -185,22 +204,21 @@ tcp4_setup_new(const char *addr, int sid
                return (errno);
 
        /* Parse given address. */
-       if ((ret = tcp4_addr(addr, PROTO_TCP4_DEFAULT_PORT,
-           &tctx->tc_sin)) != 0) {
+       if ((ret = tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &tctx->tc_sa)) != 0) {
                free(tctx);
                return (ret);
        }
 
-       PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+       PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
 
-       tctx->tc_fd = socket(AF_INET, SOCK_STREAM, 0);
+       tctx->tc_fd = socket(tctx->tc_sa.ss_family, SOCK_STREAM, 0);
        if (tctx->tc_fd == -1) {
                ret = errno;
                free(tctx);
                return (ret);
        }
 
-       PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+       PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
 
        /* Socket settings. */
        nodelay = 1;
@@ -210,20 +228,20 @@ tcp4_setup_new(const char *addr, int sid
        }
 
        tctx->tc_side = side;
-       tctx->tc_magic = TCP4_CTX_MAGIC;
+       tctx->tc_magic = TCP_CTX_MAGIC;
        *ctxp = tctx;
 
        return (0);
 }
 
 static int
-tcp4_setup_wrap(int fd, int side, void **ctxp)
+tcp_setup_wrap(int fd, int side, void **ctxp)
 {
-       struct tcp4_ctx *tctx;
+       struct tcp_ctx *tctx;
 
        PJDLOG_ASSERT(fd >= 0);
-       PJDLOG_ASSERT(side == TCP4_SIDE_CLIENT ||
-           side == TCP4_SIDE_SERVER_WORK);
+       PJDLOG_ASSERT(side == TCP_SIDE_CLIENT ||
+           side == TCP_SIDE_SERVER_WORK);
        PJDLOG_ASSERT(ctxp != NULL);
 
        tctx = malloc(sizeof(*tctx));
@@ -231,51 +249,51 @@ tcp4_setup_wrap(int fd, int side, void *
                return (errno);
 
        tctx->tc_fd = fd;
-       tctx->tc_sin.sin_family = AF_UNSPEC;
+       tctx->tc_sa.ss_family = AF_UNSPEC;
        tctx->tc_side = side;
-       tctx->tc_magic = TCP4_CTX_MAGIC;
+       tctx->tc_magic = TCP_CTX_MAGIC;
        *ctxp = tctx;
 
        return (0);
 }
 
 static int
-tcp4_client(const char *srcaddr, const char *dstaddr, void **ctxp)
+tcp_client(const char *srcaddr, const char *dstaddr, void **ctxp)
 {
-       struct tcp4_ctx *tctx;
-       struct sockaddr_in sin;
+       struct tcp_ctx *tctx;
+       struct sockaddr_storage sa;
        int ret;
 
-       ret = tcp4_setup_new(dstaddr, TCP4_SIDE_CLIENT, ctxp);
+       ret = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, ctxp);
        if (ret != 0)
                return (ret);
        tctx = *ctxp;
        if (srcaddr == NULL)
                return (0);
-       ret = tcp4_addr(srcaddr, 0, &sin);
+       ret = tcp_addr(srcaddr, 0, &sa);
        if (ret != 0) {
-               tcp4_close(tctx);
+               tcp_close(tctx);
                return (ret);
        }
-       if (bind(tctx->tc_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+       if (bind(tctx->tc_fd, (struct sockaddr *)&sa, sa.ss_len) < 0) {
                ret = errno;
-               tcp4_close(tctx);
+               tcp_close(tctx);
                return (ret);
        }
        return (0);
 }
 
 static int
-tcp4_connect(void *ctx, int timeout)
+tcp_connect(void *ctx, int timeout)
 {
-       struct tcp4_ctx *tctx = ctx;
+       struct tcp_ctx *tctx = ctx;
        int error, flags;
 
        PJDLOG_ASSERT(tctx != NULL);
-       PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
-       PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT);
+       PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+       PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT);
        PJDLOG_ASSERT(tctx->tc_fd >= 0);
-       PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+       PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC);
        PJDLOG_ASSERT(timeout >= -1);
 
        flags = fcntl(tctx->tc_fd, F_GETFL);
@@ -295,8 +313,8 @@ tcp4_connect(void *ctx, int timeout)
                return (errno);
        }
 
-       if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
-           sizeof(tctx->tc_sin)) == 0) {
+       if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa,
+           tctx->tc_sa.ss_len) == 0) {
                if (timeout == -1)
                        return (0);
                error = 0;
@@ -309,7 +327,7 @@ tcp4_connect(void *ctx, int timeout)
        }
        if (timeout == -1)
                return (0);
-       return (tcp4_connect_wait(ctx, timeout));
+       return (tcp_connect_wait(ctx, timeout));
 done:
        flags &= ~O_NONBLOCK;
        if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
@@ -322,17 +340,17 @@ done:
 }
 
 static int
-tcp4_connect_wait(void *ctx, int timeout)
+tcp_connect_wait(void *ctx, int timeout)
 {
-       struct tcp4_ctx *tctx = ctx;
+       struct tcp_ctx *tctx = ctx;
        struct timeval tv;
        fd_set fdset;
        socklen_t esize;
        int error, flags, ret;
 
        PJDLOG_ASSERT(tctx != NULL);
-       PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
-       PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT);
+       PJDLOG_ASSERT(tctx->tc_magic == TCP_CTX_MAGIC);
+       PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT);
        PJDLOG_ASSERT(tctx->tc_fd >= 0);
        PJDLOG_ASSERT(timeout >= 0);
 
@@ -387,12 +405,12 @@ done:
 }
 
 static int
-tcp4_server(const char *addr, void **ctxp)
+tcp_server(const char *addr, void **ctxp)
 {
-       struct tcp4_ctx *tctx;
+       struct tcp_ctx *tctx;
        int ret, val;
 
-       ret = tcp4_setup_new(addr, TCP4_SIDE_SERVER_LISTEN, ctxp);
+       ret = tcp_setup_new(addr, TCP_SIDE_SERVER_LISTEN, ctxp);
        if (ret != 0)
                return (ret);
 
@@ -403,17 +421,17 @@ tcp4_server(const char *addr, void **ctx
        (void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[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