svn commit: r223603 - stable/8/sbin/hastd

Mikolaj Golub trociny at FreeBSD.org
Mon Jun 27 20:04:13 UTC 2011


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 <pawel at dawidek.net>
  * 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 ***


More information about the svn-src-stable-8 mailing list