Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 May 2011 23:18:42 +0000 (UTC)
From:      Pawel Jakub Dawidek <pjd@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r222108 - head/sbin/hastd
Message-ID:  <201105192318.p4JNIgsA057343@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105192318.p4JNIgsA057343>