diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/fm/modules/common/ip-transport/ip.c | 403 |
1 files changed, 296 insertions, 107 deletions
diff --git a/usr/src/cmd/fm/modules/common/ip-transport/ip.c b/usr/src/cmd/fm/modules/common/ip-transport/ip.c index 8a5b500b9f..d789582e13 100644 --- a/usr/src/cmd/fm/modules/common/ip-transport/ip.c +++ b/usr/src/cmd/fm/modules/common/ip-transport/ip.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -40,11 +39,16 @@ #include <errno.h> #include <netdb.h> #include <poll.h> +#include <stdarg.h> #include <fm/fmd_api.h> #define IP_MAGIC "\177FMA" /* magic string identifying a packet header */ #define IP_MAGLEN 4 /* length of magic string */ +#define IP_DEBUG_OFF 0 /* No informational debugging printed */ +#define IP_DEBUG_FINE 1 /* Basic debug information printed (default) */ +#define IP_DEBUG_FINER 2 /* More debug information printed. */ +#define IP_DEBUG_FINEST 3 /* All debug information printed */ typedef struct ip_hdr { char iph_magic[IP_MAGLEN]; /* magic string */ @@ -56,6 +60,12 @@ typedef struct ip_buf { size_t ipb_size; /* size of buffer */ } ip_buf_t; +typedef struct ip_cinfo { /* Connection specific information */ + struct addrinfo *addr; /* Connection address(es) */ + char *name; /* The name of the server or interface */ + int retry; /* The number of connection retries */ +} ip_cinfo_t; + typedef struct ip_xprt { fmd_xprt_t *ipx_xprt; /* transport handle */ int ipx_flags; /* transport flags */ @@ -64,9 +74,13 @@ typedef struct ip_xprt { pthread_t ipx_tid; /* recv-side auxiliary thread */ ip_buf_t ipx_sndbuf; /* buffer for sending events */ ip_buf_t ipx_rcvbuf; /* buffer for receiving events */ - struct ip_xprt *ipx_next; /* next ip_xprt in global list */ + ip_cinfo_t *ipx_cinfo; /* info for reconnect */ + char *ipx_addr; /* address:port of remote connection */ + struct ip_xprt *ipx_next; /* next ip_xprt in global list */ } ip_xprt_t; +#define IPX_ID(a) ((a)->ipx_addr) + typedef struct ip_stat { fmd_stat_t ips_accfail; /* failed accepts */ fmd_stat_t ips_badmagic; /* invalid packet headers */ @@ -74,7 +88,7 @@ typedef struct ip_stat { fmd_stat_t ips_unpackfail; /* failed unpacks */ } ip_stat_t; -static void ip_xprt_create(fmd_xprt_t *, int, int); +static void ip_xprt_create(fmd_xprt_t *, int, int, ip_cinfo_t *, char *); static void ip_xprt_destroy(ip_xprt_t *); static ip_stat_t ip_stat = { @@ -100,17 +114,33 @@ static int ip_hc_present_only; /* only cache faults if hc-scheme and present */ static char *ip_domain_name; /* set domain name for received list.suspects */ static hrtime_t ip_burp; /* make mtbf slower by adding this much delay */ static int ip_translate; /* call fmd_xprt_translate() before sending */ -static char *ip_host; /* host to connect to (or NULL if server) */ static char *ip_port; /* port to connect to (or bind to if server) */ -static struct addrinfo *ip_ail; /* addr info list for ip_host/ip_port */ -static uint_t ip_retry; /* retry count for ip_xprt_setup() */ +static int ip_retry; /* retry count for ip_xprt_setup() -1=forever */ static hrtime_t ip_sleep; /* sleep delay for ip_xprt_setup() */ +static ip_cinfo_t ip_listen; /* Transport service conn info for server */ +static ip_cinfo_t ip_server; /* Remote server connection info for client */ +static ip_cinfo_t ip_server2; /* Second remote server conn info for client */ +static int ip_debug_level; /* level for printing debug messages */ + +/* + * Prints a debug message to the fmd debug framework if the debug level is set + * to at least the given level. + */ +static void +ip_debug(int level, char *fmt, ...) +{ + if (ip_debug_level >= level) { + va_list args; + va_start(args, fmt); + fmd_hdl_vdebug(ip_hdl, fmt, args); + va_end(args); + } +} /* * Allocate space in ipx_sndbuf for a header and a packed XDR encoding of * the specified nvlist, and then send the buffer to our remote peer. */ -/*ARGSUSED*/ static int ip_xprt_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl) { @@ -129,7 +159,7 @@ ip_xprt_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl) */ if (ip_mtbf != 0 && gethrtime() % ip_mtbf == 0) { if (ip_burp != 0) { - fmd_hdl_debug(ip_hdl, "burping ipx %p", (void *)ipx); + ip_debug(IP_DEBUG_FINE, "burping ipx %s", IPX_ID(ipx)); ipx->ipx_flags |= FMD_XPRT_SUSPENDED; (void) fmd_timer_install(ip_hdl, ipx, NULL, ip_burp); fmd_xprt_suspend(ip_hdl, xp); @@ -174,8 +204,8 @@ ip_xprt_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl) while (!ip_quit && r != 0) { if ((n = send(ipx->ipx_fd, buf, r, 0)) < 0) { if (errno != EINTR && errno != EWOULDBLOCK) { - fmd_hdl_debug(ip_hdl, - "failed to send on ipx %p", (void *)ipx); + ip_debug(IP_DEBUG_FINE, + "failed to send to %s", IPX_ID(ipx)); return (FMD_SEND_FAILED); } continue; @@ -184,6 +214,8 @@ ip_xprt_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl) r -= n; } + ip_debug(IP_DEBUG_FINEST, "Sent event %d bytes to %s", + size, IPX_ID(ipx)); return (FMD_SEND_SUCCESS); } @@ -215,11 +247,15 @@ ip_xprt_recv(ip_xprt_t *ipx, size_t size) if (n < 0) { if (errno != EINTR && errno != EWOULDBLOCK) { - fmd_hdl_debug(ip_hdl, - "failed to recv on ipx %p", (void *)ipx); + ip_debug(IP_DEBUG_FINE, + "failed to recv on ipx %s", IPX_ID(ipx)); } continue; } + /* Reset retry counter after a successful connection */ + if (ipx->ipx_cinfo) { + ipx->ipx_cinfo->retry = ip_retry; + } buf += n; r -= n; @@ -228,8 +264,13 @@ ip_xprt_recv(ip_xprt_t *ipx, size_t size) return (r ? NULL: ipx->ipx_rcvbuf.ipb_buf); } -static nvlist_t * -ip_xprt_auth(const struct sockaddr *sap) +/* + * Sets the address/port of the remote connection in the connection info struct + * This is called after a TCP session has been set up with a known remote + * address (sap) + */ +static void +ip_xprt_set_addr(ip_xprt_t *ipx, const struct sockaddr *sap) { const struct sockaddr_in6 *sin6 = (const void *)sap; const struct sockaddr_in *sin = (const void *)sap; @@ -237,23 +278,9 @@ ip_xprt_auth(const struct sockaddr *sap) char buf[INET6_ADDRSTRLEN + 16]; struct in_addr v4addr; in_port_t port; + int n; - nvlist_t *nvl; - size_t n; - int err; - - if (ip_auth != NULL) - err = nvlist_dup(ip_auth, &nvl, 0); - else - err = nvlist_alloc(&nvl, 0, 0); - - if (err != 0) { - fmd_hdl_abort(ip_hdl, "failed to create nvlist for " - "authority: %s\n", strerror(err)); - } - - if (ip_auth != NULL) - return (nvl); + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_set_name"); if (sap->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { @@ -270,10 +297,40 @@ ip_xprt_auth(const struct sockaddr *sap) n = strlen(buf); (void) snprintf(buf + n, sizeof (buf) - n, ":%u", port); - fmd_hdl_debug(ip_hdl, "ip_authority %s=%s\n", FM_FMRI_AUTH_SERVER, buf); + + if (ipx->ipx_addr) + fmd_hdl_strfree(ip_hdl, ipx->ipx_addr); + ipx->ipx_addr = fmd_hdl_strdup(ip_hdl, buf, FMD_SLEEP); + ip_debug(IP_DEBUG_FINE, "connection addr is %s on %p", + ipx->ipx_addr, (void *)ipx); +} + +static nvlist_t * +ip_xprt_auth(ip_xprt_t *ipx) +{ + nvlist_t *nvl; + int err; + + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_auth"); + + if (ip_auth != NULL) + err = nvlist_dup(ip_auth, &nvl, 0); + else + err = nvlist_alloc(&nvl, 0, 0); + + if (err != 0) { + fmd_hdl_abort(ip_hdl, "failed to create nvlist for " + "authority: %s\n", strerror(err)); + } + + if (ip_auth != NULL) + return (nvl); + + ip_debug(IP_DEBUG_FINE, "ip_authority %s=%s\n", + FM_FMRI_AUTH_SERVER, ipx->ipx_addr); (void) nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION); - (void) nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, buf); + (void) nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, ipx->ipx_addr); return (nvl); } @@ -286,15 +343,19 @@ ip_xprt_accept(ip_xprt_t *ipx) fmd_xprt_t *xp; int fd; + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_accept"); + if ((fd = accept(ipx->ipx_fd, (struct sockaddr *)&sa, &salen)) == -1) { fmd_hdl_error(ip_hdl, "failed to accept connection"); ip_stat.ips_accfail.fmds_value.ui64++; return; } + ip_debug(IP_DEBUG_FINE, "Accepted socket on fd %d", fd); + ip_xprt_set_addr(ipx, (struct sockaddr *)&sa); xp = fmd_xprt_open(ip_hdl, ipx->ipx_flags, - ip_xprt_auth((struct sockaddr *)&sa), NULL); - ip_xprt_create(xp, fd, ipx->ipx_flags); + ip_xprt_auth(ipx), NULL); + ip_xprt_create(xp, fd, ipx->ipx_flags, &ip_listen, ipx->ipx_addr); } static void @@ -311,9 +372,9 @@ ip_xprt_recv_event(ip_xprt_t *ipx) if (bcmp(iph->iph_magic, IP_MAGIC, IP_MAGLEN) != 0) { fmd_hdl_error(ip_hdl, - "invalid hdr magic %x.%x.%x.%x from transport %p\n", + "invalid hdr magic %x.%x.%x.%x from transport %s\n", iph->iph_magic[0], iph->iph_magic[1], iph->iph_magic[2], - iph->iph_magic[3], (void *)ipx->ipx_xprt); + iph->iph_magic[3], IPX_ID(ipx)); ip_stat.ips_badmagic.fmds_value.ui64++; return; } @@ -325,7 +386,8 @@ ip_xprt_recv_event(ip_xprt_t *ipx) if ((err = nvlist_unpack(buf, size, &nvl, 0)) != 0) { fmd_hdl_error(ip_hdl, "failed to unpack event from " - "transport %p: %s\n", (void *)ipx->ipx_xprt, strerror(err)); + "transport %s: %s\n", + IPX_ID(ipx), strerror(err)); ip_stat.ips_unpackfail.fmds_value.ui64++; } else { if (ip_domain_name) @@ -338,6 +400,8 @@ ip_xprt_recv_event(ip_xprt_t *ipx) (void *)ipx->ipx_xprt); ipx->ipx_done++; } + ip_debug(IP_DEBUG_FINEST, "Recv event %d bytes from %s", + size, IPX_ID(ipx)); } static void @@ -349,6 +413,8 @@ ip_xprt_thread(void *arg) struct pollfd pfd; id_t id; + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_thread"); + while (!ip_quit && !ipx->ipx_done) { if (ipx->ipx_xprt != NULL || (ipx->ipx_flags & FMD_XPRT_ACCEPT)) pfd.events = POLLIN; @@ -362,7 +428,7 @@ ip_xprt_thread(void *arg) continue; /* loop around and check ip_quit */ if (pfd.revents & (POLLHUP | POLLERR)) { - fmd_hdl_debug(ip_hdl, "hangup fd %d\n", ipx->ipx_fd); + ip_debug(IP_DEBUG_FINE, "hangup fd %d\n", ipx->ipx_fd); break; } @@ -381,11 +447,12 @@ ip_xprt_thread(void *arg) "for fd %d", ipx->ipx_fd); bzero(&sa, sizeof (sa)); } - + ip_xprt_set_addr(ipx, (struct sockaddr *)&sa); ipx->ipx_xprt = fmd_xprt_open(ip_hdl, ipx->ipx_flags, - ip_xprt_auth((struct sockaddr *)&sa), ipx); + ip_xprt_auth(ipx), ipx); - fmd_hdl_debug(ip_hdl, "connect fd %d\n", ipx->ipx_fd); + ip_debug(IP_DEBUG_FINE, "connect fd %d ipx %p", + ipx->ipx_fd, (void *)ipx); continue; } @@ -398,18 +465,22 @@ ip_xprt_thread(void *arg) } id = fmd_timer_install(ip_hdl, ipx, NULL, 0); - fmd_hdl_debug(ip_hdl, "close fd %d (timer %d)\n", ipx->ipx_fd, (int)id); + ip_debug(IP_DEBUG_FINE, "close fd %d (timer %d)", ipx->ipx_fd, (int)id); } static void -ip_xprt_create(fmd_xprt_t *xp, int fd, int flags) +ip_xprt_create(fmd_xprt_t *xp, int fd, int flags, ip_cinfo_t *cinfo, char *addr) { ip_xprt_t *ipx = fmd_hdl_zalloc(ip_hdl, sizeof (ip_xprt_t), FMD_SLEEP); + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_create %p", (void *)ipx); + ipx->ipx_xprt = xp; ipx->ipx_flags = flags; ipx->ipx_fd = fd; ipx->ipx_tid = fmd_thr_create(ip_hdl, ip_xprt_thread, ipx); + ipx->ipx_cinfo = cinfo; + ipx->ipx_addr = fmd_hdl_strdup(ip_hdl, addr, FMD_SLEEP); if (ipx->ipx_xprt != NULL) fmd_xprt_setspecific(ip_hdl, ipx->ipx_xprt, ipx); @@ -427,6 +498,9 @@ ip_xprt_destroy(ip_xprt_t *ipx) { ip_xprt_t *ipp, **ppx = &ip_xps; + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_destory %s %p", + IPX_ID(ipx), (void *)ipx); + (void) pthread_mutex_lock(&ip_lock); for (ipp = *ppx; ipp != NULL; ipp = ipp->ipx_next) { @@ -456,29 +530,37 @@ ip_xprt_destroy(ip_xprt_t *ipx) fmd_hdl_free(ip_hdl, ipx->ipx_rcvbuf.ipb_buf, ipx->ipx_rcvbuf.ipb_size); (void) close(ipx->ipx_fd); + if (ipx->ipx_addr) { + fmd_hdl_strfree(ip_hdl, ipx->ipx_addr); + ipx->ipx_addr = NULL; + } fmd_hdl_free(ip_hdl, ipx, sizeof (ip_xprt_t)); } /* - * Loop through the addresses that were returned by getaddrinfo() in _fmd_init + * Loop through the addresses in the connection info structure that were + * created by getaddrinfo() in ip_setup_addr during initialization (_fmd_init) * and for each one attempt to create a socket and initialize it. If we are * successful, return zero. If we fail, we check ip_retry: if it is non-zero * we return the last errno and let our caller retry ip_xprt_setup() later. If * ip_retry reaches zero, we call fmd_hdl_abort() with an appropriate message. */ static int -ip_xprt_setup(fmd_hdl_t *hdl) +ip_xprt_setup(fmd_hdl_t *hdl, ip_cinfo_t *cinfo) { int err, fd, oflags, xflags, optval = 1; struct addrinfo *aip; const char *s1, *s2; + struct addrinfo *ail = cinfo->addr; + + ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_setup"); /* * Set up flags as specified in the .conf file. Note that these are * mostly only used for testing purposes, allowing the transport to * be set up in various modes. */ - if (ip_host != NULL) + if (ail != ip_listen.addr) xflags = (ip_rdonly == FMD_B_TRUE) ? FMD_XPRT_RDONLY : FMD_XPRT_RDWR; else @@ -494,7 +576,7 @@ ip_xprt_setup(fmd_hdl_t *hdl) if (ip_hc_present_only == FMD_B_TRUE) xflags |= FMD_XPRT_HC_PRESENT_ONLY; - for (aip = ip_ail; aip != NULL; aip = aip->ai_next) { + for (aip = ail; aip != NULL; aip = aip->ai_next) { if (aip->ai_family != AF_INET && aip->ai_family != AF_INET6) continue; /* ignore anything that isn't IPv4 or IPv6 */ @@ -513,33 +595,123 @@ ip_xprt_setup(fmd_hdl_t *hdl) bind(fd, aip->ai_addr, aip->ai_addrlen) != 0 || listen(fd, ip_qlen) != 0; } else { - err = connect(fd, aip->ai_addr, - aip->ai_addrlen) != 0 && errno != EINPROGRESS; + err = connect(fd, aip->ai_addr, aip->ai_addrlen); + if (err) + err = errno; + if (err == EINPROGRESS) + err = 0; } if (err == 0) { - ip_xprt_create(NULL, fd, xflags); - freeaddrinfo(ip_ail); - ip_ail = NULL; + ip_xprt_create(NULL, fd, xflags, cinfo, NULL); + ip_debug(IP_DEBUG_FINER, "Exit ip_xprt_setup"); return (0); } + ip_debug(IP_DEBUG_FINE, "Error=%d errno=%d", err, errno); + err = errno; (void) close(fd); } - if (ip_host != NULL) { + if (cinfo->name != NULL) { s1 = "failed to connect to"; - s2 = ip_host; + s2 = cinfo->name; } else { s1 = "failed to listen on"; s2 = ip_port; } - if (err == EACCES || ip_retry-- == 0) + if (err == EACCES || cinfo->retry-- == 0) fmd_hdl_abort(hdl, "%s %s: %s\n", s1, s2, strerror(err)); - fmd_hdl_debug(hdl, "%s %s: %s (will retry)\n", s1, s2, strerror(err)); + ip_debug(IP_DEBUG_FINE, "%s %s: %s (will retry)\n", + s1, s2, strerror(err)); + ip_debug(IP_DEBUG_FINER, "Exit ip_xprt_setup"); + return (err); +} + +/* + * Free address based resources + */ +static void +ip_addr_cleanup() +{ + if (ip_listen.addr != NULL) { + freeaddrinfo(ip_listen.addr); + ip_listen.addr = NULL; + } + if (ip_server.addr != NULL) { + freeaddrinfo(ip_server.addr); + ip_server.addr = NULL; + } + if (ip_server2.addr != NULL) { + freeaddrinfo(ip_server2.addr); + ip_server2.addr = NULL; + } + fmd_prop_free_string(ip_hdl, ip_server.name); + fmd_prop_free_string(ip_hdl, ip_server2.name); + fmd_prop_free_string(ip_hdl, ip_port); +} + +/* + * Setup a single address for ip connection. + */ +static int +ip_setup_addr(ip_cinfo_t *cinfo) +{ + struct addrinfo aih; + char *server = cinfo->name; + int err; + + bzero(&aih, sizeof (aih)); + aih.ai_flags = AI_ADDRCONFIG; + aih.ai_family = AF_UNSPEC; + aih.ai_socktype = SOCK_STREAM; + if (server != NULL) { + ip_debug(IP_DEBUG_FINE, "resolving %s:%s\n", server, ip_port); + } else { + aih.ai_flags |= AI_PASSIVE; + cinfo->name = "localhost"; + } + + err = getaddrinfo(server, ip_port, &aih, &cinfo->addr); + if (err != 0) { + fmd_hdl_error(ip_hdl, "failed to resolve host %s port %s: %s\n", + cinfo->name, ip_port, gai_strerror(err)); + cinfo->addr = NULL; + } + return (err); +} + +/* + * Setup all IP addresses for network configuration. + * The listen address for for a service that will bind to clients. + * A client can connect up to two servers using ip_server and ip_server2 + * properties. + */ +static int +ip_setup_addrs() +{ + int err = 0; + ip_listen.addr = NULL; + ip_server.addr = NULL; + ip_server.retry = ip_retry; + ip_server2.addr = NULL; + + if ((ip_server.name == NULL && ip_server2.name == NULL) || + ip_listen.name) { + err = ip_setup_addr(&ip_listen); + } + if (ip_server.name != NULL && err == 0) { + err = ip_setup_addr(&ip_server); + } + if (ip_server2.name != NULL && err == 0) { + err = ip_setup_addr(&ip_server2); + } + if (err != 0) { + ip_addr_cleanup(); + } return (err); } @@ -552,22 +724,35 @@ ip_xprt_setup(fmd_hdl_t *hdl) * * Case (c) is required as we need to cause the module's main thread, which * runs this timeout handler, to join with the transport's auxiliary thread. + * If the connection is a client then a timer will be installed to retry + * connecting to the server. */ static void -ip_timeout(fmd_hdl_t *hdl, id_t id, void *arg) -{ - ip_xprt_t *ipx = arg; - - if (ipx == NULL) { - if (ip_xprt_setup(hdl) != 0) - (void) fmd_timer_install(hdl, NULL, NULL, ip_sleep); - } else if (ipx->ipx_flags & FMD_XPRT_SUSPENDED) { - fmd_hdl_debug(hdl, "timer %d waking ipx %p\n", (int)id, arg); - ipx->ipx_flags &= ~FMD_XPRT_SUSPENDED; - fmd_xprt_resume(hdl, ipx->ipx_xprt); +ip_timeout(fmd_hdl_t *hdl, id_t id, void *arg) { + ip_xprt_t *ipx; + + if (arg == NULL || + arg == &ip_server || arg == &ip_server2 || arg == &ip_listen) { + ip_debug(IP_DEBUG_FINER, + "Enter ip_timeout (a) install new timer"); + if (ip_xprt_setup(hdl, arg) != 0) + (void) fmd_timer_install(hdl, arg, NULL, ip_sleep); } else { - fmd_hdl_debug(hdl, "timer %d closing ipx %p\n", (int)id, arg); - ip_xprt_destroy(ipx); + ipx = arg; + if (ipx->ipx_flags & FMD_XPRT_SUSPENDED) { + ip_debug(IP_DEBUG_FINE, "timer %d waking ipx %p", + (int)id, arg); + ipx->ipx_flags &= ~FMD_XPRT_SUSPENDED; + fmd_xprt_resume(hdl, ipx->ipx_xprt); + } else { + ip_debug(IP_DEBUG_FINE, "timer %d closing ipx %p", + (int)id, arg); + ip_xprt_destroy(ipx); + if ((ipx->ipx_flags & FMD_XPRT_ACCEPT) != + FMD_XPRT_ACCEPT) + (void) fmd_timer_install( + hdl, ipx->ipx_cinfo, NULL, ip_sleep); + } } } @@ -585,10 +770,13 @@ static const fmd_prop_t fmd_props[] = { { "ip_domain_name", FMD_TYPE_STRING, NULL }, { "ip_port", FMD_TYPE_STRING, "664" }, { "ip_qlen", FMD_TYPE_INT32, "32" }, - { "ip_retry", FMD_TYPE_UINT32, "50" }, - { "ip_server", FMD_TYPE_STRING, NULL }, + { "ip_retry", FMD_TYPE_INT32, "-1" }, /* -1=forever */ + { "ip_server", FMD_TYPE_STRING, NULL }, /* server name */ + { "ip_server2", FMD_TYPE_STRING, NULL }, /* secondary server name */ { "ip_sleep", FMD_TYPE_TIME, "10s" }, { "ip_translate", FMD_TYPE_BOOL, "false" }, + { "ip_bind_addr", FMD_TYPE_STRING, NULL }, /* network interface addr */ + { "ip_debug_level", FMD_TYPE_INT32, "1" }, /* debug levels 0-3 */ { NULL, 0, NULL } }; @@ -608,7 +796,7 @@ static const fmd_hdl_info_t fmd_info = { /* * Initialize the ip-transport module as either a server or a client. Note * that the ip-transport module is not enabled by default under Solaris: - * at present we require a developer or tool to setprop ip_enable=true. + * at present we require a developer or tool to "setprop ip_enable true". * If ip-transport is needed in the future out-of-the-box on one or more Sun * platforms, the code to check 'ip_enable' should be replaced with: * @@ -619,13 +807,13 @@ static const fmd_hdl_info_t fmd_info = { * Note that (c) is only an issue when the transport module operates * in server mode (i.e. with the ip_server property set to NULL) on a * generic Solaris system which may be exposed directly to the Internet. + * The property ip_bind_addr can be used to define a private network interface + * to use so that the service is not exposed to the Internet. */ void _fmd_init(fmd_hdl_t *hdl) { - struct addrinfo aih; char *auth, *p, *q, *r, *s; - int err; if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) return; /* failed to register handle */ @@ -657,29 +845,18 @@ _fmd_init(fmd_hdl_t *hdl) ip_size = (size_t)fmd_prop_get_int64(hdl, "ip_bufsize"); ip_size = MAX(ip_size, sizeof (ip_hdr_t)); - ip_host = fmd_prop_get_string(hdl, "ip_server"); + ip_listen.name = fmd_prop_get_string(hdl, "ip_bind_addr"); + ip_server.name = fmd_prop_get_string(hdl, "ip_server"); + ip_server2.name = fmd_prop_get_string(hdl, "ip_server2"); ip_port = fmd_prop_get_string(hdl, "ip_port"); + ip_debug_level = fmd_prop_get_int32(hdl, "ip_debug_level"); - bzero(&aih, sizeof (aih)); - aih.ai_flags = AI_ADDRCONFIG; - aih.ai_family = AF_UNSPEC; - aih.ai_socktype = SOCK_STREAM; - - if (ip_host != NULL) - fmd_hdl_debug(hdl, "resolving %s:%s\n", ip_host, ip_port); - else - aih.ai_flags |= AI_PASSIVE; - - err = getaddrinfo(ip_host, ip_port, &aih, &ip_ail); - - if (err != 0) { - fmd_prop_free_string(hdl, ip_host); - fmd_prop_free_string(hdl, ip_port); - - fmd_hdl_abort(hdl, "failed to resolve host %s port %s: %s\n", - ip_host ? ip_host : "<none>", ip_port, gai_strerror(err)); + if (ip_setup_addrs()) { + fmd_hdl_abort(hdl, "Unable to setup IP addresses."); + return; } + /* * If ip_authority is set, tokenize this string and turn it into an * FMA authority represented as a name-value pair list. We will use @@ -699,10 +876,7 @@ _fmd_init(fmd_hdl_t *hdl) p = strtok_r(NULL, ",", &q)) { if ((r = strchr(p, '=')) == NULL) { - fmd_prop_free_string(hdl, ip_host); - fmd_prop_free_string(hdl, ip_port); - freeaddrinfo(ip_ail); - + ip_addr_cleanup(); fmd_hdl_abort(hdl, "ip_authority element <%s> " "must be in <name>=<value> form\n", p); } @@ -714,11 +888,30 @@ _fmd_init(fmd_hdl_t *hdl) } /* - * Call ip_xprt_setup() to connect or bind. If it fails and ip_retry - * is non-zero, install a timer to try again after 'ip_sleep' nsecs. + * Start ip transport server to listen for clients */ - if (ip_xprt_setup(hdl) != 0) - (void) fmd_timer_install(hdl, NULL, NULL, ip_sleep); + if (ip_listen.addr != NULL) { + if (ip_xprt_setup(hdl, &ip_listen) != 0) { + (void) fmd_timer_install(hdl, &ip_listen, NULL, + ip_sleep); + } + } + + /* + * Call ip_xprt_setup() to connect to server(s). If it fails and + * ip_retry is non-zero, install a timer to try again after + * 'ip_sleep' nsecs. + */ + if (ip_server.addr != NULL) { + if (ip_xprt_setup(hdl, &ip_server) != 0) + (void) fmd_timer_install(hdl, &ip_server, NULL, + ip_sleep); + } + if (ip_server2.addr != NULL) { + if (ip_xprt_setup(hdl, &ip_server2) != 0) + (void) fmd_timer_install(hdl, &ip_server2, NULL, + ip_sleep); + } } void @@ -731,11 +924,7 @@ _fmd_fini(fmd_hdl_t *hdl) if (ip_auth != NULL) nvlist_free(ip_auth); - if (ip_ail != NULL) - freeaddrinfo(ip_ail); - - fmd_prop_free_string(hdl, ip_host); - fmd_prop_free_string(hdl, ip_port); + ip_addr_cleanup(); fmd_hdl_unregister(hdl); } |