Date: Mon, 27 Jun 2011 20:04:13 +0000 (UTC) From: Mikolaj Golub <trociny@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r223603 - stable/8/sbin/hastd Message-ID: <201106272004.p5RK4D0V011620@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106272004.p5RK4D0V011620>