From owner-svn-src-projects@FreeBSD.ORG Fri May 20 15:48:09 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A97E4106564A; Fri, 20 May 2011 15:48:08 +0000 (UTC) (envelope-from attilio@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9708A8FC0A; Fri, 20 May 2011 15:48:08 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p4KFm8Hs090645; Fri, 20 May 2011 15:48:08 GMT (envelope-from attilio@svn.freebsd.org) Received: (from attilio@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p4KFm8r9090637; Fri, 20 May 2011 15:48:08 GMT (envelope-from attilio@svn.freebsd.org) Message-Id: <201105201548.p4KFm8r9090637@svn.freebsd.org> From: Attilio Rao Date: Fri, 20 May 2011 15:48:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r222133 - in projects/largeSMP: bin/ps contrib/top sbin/hastd share/mk sys/dev/alc sys/dev/ale sys/vm usr.bin/ar X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 May 2011 15:48:09 -0000 Author: attilio Date: Fri May 20 15:48:08 2011 New Revision: 222133 URL: http://svn.freebsd.org/changeset/base/222133 Log: MFC Added: projects/largeSMP/sbin/hastd/proto_tcp.c - copied unchanged from r222132, head/sbin/hastd/proto_tcp.c Deleted: projects/largeSMP/sbin/hastd/proto_tcp4.c Modified: projects/largeSMP/bin/ps/ps.1 projects/largeSMP/sbin/hastd/Makefile projects/largeSMP/sbin/hastd/hast.conf.5 projects/largeSMP/sbin/hastd/hast.h projects/largeSMP/sbin/hastd/hastd.c projects/largeSMP/sbin/hastd/parse.y projects/largeSMP/sbin/hastd/token.l projects/largeSMP/sys/dev/alc/if_alcreg.h projects/largeSMP/sys/dev/ale/if_alereg.h projects/largeSMP/sys/vm/uma_core.c projects/largeSMP/usr.bin/ar/acpyacc.y projects/largeSMP/usr.bin/ar/ar.c projects/largeSMP/usr.bin/ar/write.c Directory Properties: projects/largeSMP/ (props changed) projects/largeSMP/cddl/contrib/opensolaris/ (props changed) projects/largeSMP/contrib/bind9/ (props changed) projects/largeSMP/contrib/binutils/ (props changed) projects/largeSMP/contrib/bzip2/ (props changed) projects/largeSMP/contrib/dialog/ (props changed) projects/largeSMP/contrib/ee/ (props changed) projects/largeSMP/contrib/expat/ (props changed) projects/largeSMP/contrib/file/ (props changed) projects/largeSMP/contrib/gcc/ (props changed) projects/largeSMP/contrib/gdb/ (props changed) projects/largeSMP/contrib/gdtoa/ (props changed) projects/largeSMP/contrib/gnu-sort/ (props changed) projects/largeSMP/contrib/groff/ (props changed) projects/largeSMP/contrib/less/ (props changed) projects/largeSMP/contrib/libpcap/ (props changed) projects/largeSMP/contrib/libstdc++/ (props changed) projects/largeSMP/contrib/llvm/ (props changed) projects/largeSMP/contrib/llvm/tools/clang/ (props changed) projects/largeSMP/contrib/ncurses/ (props changed) projects/largeSMP/contrib/netcat/ (props changed) projects/largeSMP/contrib/ntp/ (props changed) projects/largeSMP/contrib/one-true-awk/ (props changed) projects/largeSMP/contrib/openbsm/ (props changed) projects/largeSMP/contrib/openpam/ (props changed) projects/largeSMP/contrib/pf/ (props changed) projects/largeSMP/contrib/sendmail/ (props changed) projects/largeSMP/contrib/tcpdump/ (props changed) projects/largeSMP/contrib/tcsh/ (props changed) projects/largeSMP/contrib/top/ (props changed) projects/largeSMP/contrib/top/install-sh (props changed) projects/largeSMP/contrib/tzcode/stdtime/ (props changed) projects/largeSMP/contrib/tzcode/zic/ (props changed) projects/largeSMP/contrib/tzdata/ (props changed) projects/largeSMP/contrib/wpa/ (props changed) projects/largeSMP/contrib/xz/ (props changed) projects/largeSMP/crypto/openssh/ (props changed) projects/largeSMP/crypto/openssl/ (props changed) projects/largeSMP/gnu/lib/ (props changed) projects/largeSMP/gnu/usr.bin/binutils/ (props changed) projects/largeSMP/gnu/usr.bin/cc/cc_tools/ (props changed) projects/largeSMP/gnu/usr.bin/gdb/ (props changed) projects/largeSMP/lib/libc/ (props changed) projects/largeSMP/lib/libc/stdtime/ (props changed) projects/largeSMP/lib/libutil/ (props changed) projects/largeSMP/lib/libz/ (props changed) projects/largeSMP/sbin/ (props changed) projects/largeSMP/sbin/ipfw/ (props changed) projects/largeSMP/share/mk/bsd.arch.inc.mk (props changed) projects/largeSMP/share/zoneinfo/ (props changed) projects/largeSMP/sys/ (props changed) projects/largeSMP/sys/amd64/include/xen/ (props changed) projects/largeSMP/sys/boot/ (props changed) projects/largeSMP/sys/boot/i386/efi/ (props changed) projects/largeSMP/sys/boot/ia64/efi/ (props changed) projects/largeSMP/sys/boot/ia64/ski/ (props changed) projects/largeSMP/sys/boot/powerpc/boot1.chrp/ (props changed) projects/largeSMP/sys/boot/powerpc/ofw/ (props changed) projects/largeSMP/sys/cddl/contrib/opensolaris/ (props changed) projects/largeSMP/sys/conf/ (props changed) projects/largeSMP/sys/contrib/dev/acpica/ (props changed) projects/largeSMP/sys/contrib/octeon-sdk/ (props changed) projects/largeSMP/sys/contrib/pf/ (props changed) projects/largeSMP/sys/contrib/x86emu/ (props changed) projects/largeSMP/usr.bin/calendar/ (props changed) projects/largeSMP/usr.bin/csup/ (props changed) projects/largeSMP/usr.bin/procstat/ (props changed) projects/largeSMP/usr.sbin/ndiscvt/ (props changed) projects/largeSMP/usr.sbin/zic/ (props changed) Modified: projects/largeSMP/bin/ps/ps.1 ============================================================================== --- projects/largeSMP/bin/ps/ps.1 Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/bin/ps/ps.1 Fri May 20 15:48:08 2011 (r222133) @@ -301,7 +301,7 @@ the include file .It Dv "P_PPWAIT" Ta No "0x00010 Parent is waiting for child to exec/exit" .It Dv "P_PROFIL" Ta No "0x00020 Has started profiling" .It Dv "P_STOPPROF" Ta No "0x00040 Has thread in requesting to stop prof" -.It Dv "P_HASTHREADS" Ta No "0x00080 Has had threads (no cleanup shortcuts)" +.It Dv "P_HADTHREADS" Ta No "0x00080 Has had threads (no cleanup shortcuts)" .It Dv "P_SUGID" Ta No "0x00100 Had set id privileges since last exec" .It Dv "P_SYSTEM" Ta No "0x00200 System proc: no sigs, stats or swapping" .It Dv "P_SINGLE_EXIT" Ta No "0x00400 Threads suspending should exit, not wait" @@ -549,7 +549,7 @@ wait channel (as an address) total blocks written (alias .Cm oublock ) .It Cm paddr -swap address +process pointer .It Cm pagein pageins (same as majflt) .It Cm pgid Modified: projects/largeSMP/sbin/hastd/Makefile ============================================================================== --- projects/largeSMP/sbin/hastd/Makefile Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/sbin/hastd/Makefile Fri May 20 15:48:08 2011 (r222133) @@ -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 @@ -20,7 +20,7 @@ SRCS+= y.tab.h 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: projects/largeSMP/sbin/hastd/hast.conf.5 ============================================================================== --- projects/largeSMP/sbin/hastd/hast.conf.5 Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/sbin/hastd/hast.conf.5 Fri May 20 15:48:08 2011 (r222133) @@ -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: projects/largeSMP/sbin/hastd/hast.h ============================================================================== --- projects/largeSMP/sbin/hastd/hast.h Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/sbin/hastd/hast.h Fri May 20 15:48:08 2011 (r222133) @@ -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: projects/largeSMP/sbin/hastd/hastd.c ============================================================================== --- projects/largeSMP/sbin/hastd/hastd.c Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/sbin/hastd/hastd.c Fri May 20 15:48:08 2011 (r222133) @@ -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: projects/largeSMP/sbin/hastd/parse.y ============================================================================== --- projects/largeSMP/sbin/hastd/parse.y Fri May 20 15:26:31 2011 (r222132) +++ projects/largeSMP/sbin/hastd/parse.y Fri May 20 15:48:08 2011 (r222133) @@ -33,12 +33,14 @@ #include /* MAXHOSTNAMELEN */ #include +#include #include #include #include #include +#include #include #include #include @@ -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"); Copied: projects/largeSMP/sbin/hastd/proto_tcp.c (from r222132, head/sbin/hastd/proto_tcp.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/largeSMP/sbin/hastd/proto_tcp.c Fri May 20 15:48:08 2011 (r222133, copy of r222132, head/sbin/hastd/proto_tcp.c) @@ -0,0 +1,638 @@ +/*- + * Copyright (c) 2009-2010 The FreeBSD Foundation + * Copyright (c) 2011 Pawel Jakub Dawidek + * All rights reserved. + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include /* MAXHOSTNAMELEN */ +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pjdlog.h" +#include "proto_impl.h" +#include "subr.h" + +#define TCP_CTX_MAGIC 0x7c41c +struct tcp_ctx { + int tc_magic; + struct sockaddr_storage tc_sa; + int tc_fd; + int tc_side; +#define TCP_SIDE_CLIENT 0 +#define TCP_SIDE_SERVER_LISTEN 1 +#define TCP_SIDE_SERVER_WORK 2 +}; + +static int tcp_connect_wait(void *ctx, int timeout); +static void tcp_close(void *ctx); + +/* + * Function converts the given string to unsigned number. + */ +static int +numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump) +{ + intmax_t digit, num; + + if (str[0] == '\0') + goto invalid; /* Empty string. */ + num = 0; + for (; *str != '\0'; str++) { + if (*str < '0' || *str > '9') + goto invalid; /* Non-digit character. */ + digit = *str - '0'; + if (num > num * 10 + digit) + goto invalid; /* Overflow. */ + num = num * 10 + digit; + if (num > maxnum) + goto invalid; /* Too big. */ + } + if (num < minnum) + goto invalid; /* Too small. */ + *nump = num; + return (0); +invalid: + errno = EINVAL; + return (-1); +} + +static int +tcp_addr(const char *addr, int defport, struct sockaddr_storage *sap) +{ + char iporhost[MAXHOSTNAMELEN], portstr[6]; + struct addrinfo hints; + struct addrinfo *res; + const char *pp; + intmax_t port; + size_t size; + int error; + + if (addr == NULL) + return (-1); + + 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; + hints.ai_family = PF_INET6; + } else if (strncasecmp(addr, "tcp://", 6) == 0) { + addr += 6; + } else { + /* + * Because TCP is the default assume IP or host is given without + * prefix. + */ + } + + /* + * 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. */ + port = defport; + } else { + if (numfromstr(pp + 1, 1, 65535, &port) < 0) + return (errno); + } + (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); + } + + error = getaddrinfo(iporhost, portstr, &hints, &res); + if (error != 0) { + pjdlog_debug(1, "getaddrinfo(%s, %s) failed: %s.", iporhost, + portstr, gai_strerror(error)); + return (EINVAL); + } + if (res == NULL) + return (ENOENT); + + memcpy(sap, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + + return (0); +} + +static int +tcp_setup_new(const char *addr, int side, void **ctxp) +{ + struct tcp_ctx *tctx; + int ret, nodelay; + + PJDLOG_ASSERT(addr != NULL); + PJDLOG_ASSERT(side == TCP_SIDE_CLIENT || + side == TCP_SIDE_SERVER_LISTEN); + PJDLOG_ASSERT(ctxp != NULL); + + tctx = malloc(sizeof(*tctx)); + if (tctx == NULL) + return (errno); + + /* Parse given address. */ + if ((ret = tcp_addr(addr, PROTO_TCP_DEFAULT_PORT, &tctx->tc_sa)) != 0) { + free(tctx); + return (ret); + } + + PJDLOG_ASSERT(tctx->tc_sa.ss_family != AF_UNSPEC); + + 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_sa.ss_family != AF_UNSPEC); + + /* Socket settings. */ + nodelay = 1; + if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, + sizeof(nodelay)) == -1) { + pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY"); + } + + tctx->tc_side = side; + tctx->tc_magic = TCP_CTX_MAGIC; + *ctxp = tctx; + + return (0); +} + +static int +tcp_setup_wrap(int fd, int side, void **ctxp) +{ + struct tcp_ctx *tctx; + + PJDLOG_ASSERT(fd >= 0); + PJDLOG_ASSERT(side == TCP_SIDE_CLIENT || + side == TCP_SIDE_SERVER_WORK); + PJDLOG_ASSERT(ctxp != NULL); + + tctx = malloc(sizeof(*tctx)); + if (tctx == NULL) + return (errno); + + tctx->tc_fd = fd; + tctx->tc_sa.ss_family = AF_UNSPEC; + tctx->tc_side = side; + tctx->tc_magic = TCP_CTX_MAGIC; + *ctxp = tctx; + + return (0); +} + +static int +tcp_client(const char *srcaddr, const char *dstaddr, void **ctxp) +{ + struct tcp_ctx *tctx; + struct sockaddr_storage sa; + int ret; + + ret = tcp_setup_new(dstaddr, TCP_SIDE_CLIENT, ctxp); + if (ret != 0) + return (ret); + tctx = *ctxp; + if (srcaddr == NULL) + return (0); + ret = tcp_addr(srcaddr, 0, &sa); + if (ret != 0) { + tcp_close(tctx); + return (ret); + } + if (bind(tctx->tc_fd, (struct sockaddr *)&sa, sa.ss_len) < 0) { + ret = errno; + tcp_close(tctx); + return (ret); + } + return (0); +} + +static int +tcp_connect(void *ctx, int timeout) +{ + struct tcp_ctx *tctx = ctx; + int error, flags; + + PJDLOG_ASSERT(tctx != NULL); + 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_sa.ss_family != AF_UNSPEC); + PJDLOG_ASSERT(timeout >= -1); + + flags = fcntl(tctx->tc_fd, F_GETFL); + if (flags == -1) { + KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_GETFL) failed")); + return (errno); + } + /* + * We make socket non-blocking so we can handle connection timeout + * manually. + */ + flags |= O_NONBLOCK; + if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { + KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_SETFL, O_NONBLOCK) failed")); + return (errno); + } + + if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sa, + tctx->tc_sa.ss_len) == 0) { + if (timeout == -1) + return (0); + error = 0; + goto done; + } + if (errno != EINPROGRESS) { + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed"); + goto done; + } + if (timeout == -1) + return (0); + return (tcp_connect_wait(ctx, timeout)); +done: + flags &= ~O_NONBLOCK; + if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { + if (error == 0) + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_SETFL, ~O_NONBLOCK) failed"); + } + return (error); +} + +static int +tcp_connect_wait(void *ctx, int timeout) +{ + 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 == TCP_CTX_MAGIC); + PJDLOG_ASSERT(tctx->tc_side == TCP_SIDE_CLIENT); + PJDLOG_ASSERT(tctx->tc_fd >= 0); + PJDLOG_ASSERT(timeout >= 0); + + tv.tv_sec = timeout; + tv.tv_usec = 0; +again: + FD_ZERO(&fdset); + FD_SET(tctx->tc_fd, &fdset); + ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv); + if (ret == 0) { + error = ETIMEDOUT; + goto done; + } else if (ret == -1) { + if (errno == EINTR) + goto again; + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, "select() failed"); + goto done; + } + PJDLOG_ASSERT(ret > 0); + PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset)); + esize = sizeof(error); + if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error, + &esize) == -1) { + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, + "getsockopt(SO_ERROR) failed"); + goto done; + } + if (error != 0) { + pjdlog_common(LOG_DEBUG, 1, error, + "getsockopt(SO_ERROR) returned error"); + goto done; + } + error = 0; +done: + flags = fcntl(tctx->tc_fd, F_GETFL); + if (flags == -1) { + if (error == 0) + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed"); + return (error); + } + flags &= ~O_NONBLOCK; + if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) { + if (error == 0) + error = errno; + pjdlog_common(LOG_DEBUG, 1, errno, + "fcntl(F_SETFL, ~O_NONBLOCK) failed"); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***