summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fm/modules/common/ip-transport/ip.c403
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);
}