/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/sysmacros.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdarg.h>
typedef struct ip_hdr {
} ip_hdr_t;
typedef struct ip_buf {
} ip_buf_t;
} ip_cinfo_t;
typedef struct ip_xprt {
} ip_xprt_t;
typedef struct ip_stat {
} ip_stat_t;
static void ip_xprt_destroy(ip_xprt_t *);
};
/*
* Prints a debug message to the fmd debug framework if the debug level is set
* to at least the given level.
*/
static void
{
if (ip_debug_level >= level) {
}
}
/*
* 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.
*/
static int
{
ssize_t r, n;
int err;
return (FMD_SEND_FAILED);
}
/*
* For testing purposes, if ip_mtbf is non-zero, use this to pseudo-
* randomly simulate the need for retries. If ip_burp is also set,
* then we also suspend the transport for a bit and wake it up again.
*/
if (ip_burp != 0) {
}
return (FMD_SEND_RETRY);
}
return (FMD_SEND_FAILED);
}
}
if (ip_translate)
if (err != 0) {
return (FMD_SEND_FAILED);
}
while (!ip_quit && r != 0) {
return (FMD_SEND_FAILED);
}
continue;
}
buf += n;
r -= n;
}
return (FMD_SEND_SUCCESS);
}
/*
* Sends events over transports that are configured read only. When the module
* is in read only mode it will receive all events and only send events that
* have a subscription set.
*
* The configuration file will have to set prop ip_rdonly true and also
* subscribe for events that are desired to be sent over the transport in order
* for this function to be used.
*/
/* ARGSUSED */
static void
{
int err;
(void) pthread_mutex_lock(&ip_lock);
while (FMD_SEND_RETRY == err) {
}
}
(void) pthread_mutex_unlock(&ip_lock);
}
}
/*
* Receive a chunk of data of the specified size from our remote peer. The
* data is received into ipx_rcvbuf, and then a pointer to the buffer is
* returned. NOTE: The data is only valid until the next call to ip_xprt_recv.
* If the connection breaks or ip_quit is set during receive, NULL is returned.
*/
static void *
{
}
while (!ip_quit && r != 0) {
return (NULL);
}
if (n < 0) {
}
continue;
}
/* Reset retry counter after a successful connection */
}
buf += n;
r -= n;
}
}
/*
* This is called after a TCP session has been set up with a known remote
* address (sap)
*/
static void
{
int n;
} else {
}
}
static nvlist_t *
{
int err;
else
if (err != 0) {
}
return (nvl);
return (nvl);
}
static void
{
int fd;
return;
}
}
static void
{
void *buf;
int err;
return; /* connection broken */
"invalid hdr magic %x.%x.%x.%x from transport %s\n",
return;
}
return; /* connection broken */
"transport %s: %s\n",
} else {
if (ip_domain_name)
}
}
}
static void
{
else
continue; /* loop around and check ip_quit */
break;
}
/*
* Once we're connected, there's no reason to have our
* calls to recv() and send() be non-blocking since we
* we have separate threads for each: clear O_NONBLOCK.
*/
&salen) != 0) {
"Not connected, no remote name for fd %d. "
" Will retry.",
break;
}
continue;
}
else
}
}
}
static void
{
(void) pthread_mutex_lock(&ip_lock);
(void) pthread_mutex_unlock(&ip_lock);
}
static void
{
(void) pthread_mutex_lock(&ip_lock);
else
break;
}
(void) pthread_mutex_unlock(&ip_lock);
}
(void) pthread_mutex_unlock(&ip_lock);
if (ipx->ipx_spnd_timer)
}
}
/*
* 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
{
/*
* 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 (cinfo->ipc_accept)
if (ip_external == FMD_B_TRUE)
if (ip_no_remote_repair == FMD_B_TRUE)
if (ip_hconly == FMD_B_TRUE)
if (ip_hc_present_only == FMD_B_TRUE)
continue; /* ignore anything that isn't IPv4 or IPv6 */
continue;
}
if (xflags & FMD_XPRT_ACCEPT) {
} else {
if (err)
if (err == EINPROGRESS)
err = 0;
}
if (err == 0) {
return (0);
}
}
s1 = "failed to connect to";
} else {
s1 = "failed to listen on";
}
return (err);
}
/*
* Free address based resources
*/
static void
{
(void) pthread_mutex_lock(&ip_conns_lock);
}
(void) pthread_mutex_unlock(&ip_conns_lock);
}
static boolean_t
{
(void) pthread_mutex_lock(&ip_conns_lock);
break;
}
}
(void) pthread_mutex_unlock(&ip_conns_lock);
return (exists);
}
static ip_cinfo_t *
{
int err;
return (NULL);
return (NULL);
}
}
} else {
return (NULL);
}
}
if (err != 0) {
}
return (cinfo);
}
/*
* Setup a single ip address for ip connection.
* If unable to setup any of the addresses then all addresses will be cleaned up
* and non-zero will be returned.
*/
static int
{
int err = 0;
err++;
} else {
(void) pthread_mutex_lock(&ip_conns_lock);
(void) pthread_mutex_unlock(&ip_conns_lock);
}
return (err);
}
/*
* Setup a ip addresses for an ip connection. The address can be a comma
* separated list of addresses as well.
* If unable to setup any of the addresses then all addresses will be cleaned up
* and non-zero will be returned.
*/
static int
{
int err = 0;
char *p;
for (p = server; *p != '\0'; p++) {
if (*p == ',') {
*p = '\0';
*p = ',';
if (err)
return (err);
addr = ++p;
if (*addr == '\0')
break;
}
}
if (*addr != '\0') {
}
return (err);
}
/*
* Starts all connections for each configured network address. If there is an
* error starting a connection a timer will be started for a retry.
*/
static void
{
(void) pthread_mutex_lock(&ip_conns_lock);
ip_sleep);
}
}
(void) pthread_mutex_unlock(&ip_conns_lock);
}
/*
* Timeout handler for the transport module. We use these types of timeouts:
*
* (a) arg is ip_cinfo_t: attempt ip_xprt_setup(), re-install timeout to retry
* (b) arg is ip_xprt_t, FMD_XPRT_SUSPENDED: call fmd_xprt_resume() on arg
* (c) arg is ip_xprt_t, !FMD_XPRT_SUSPENDED: call ip_xprt_destroy() on arg
* (d) arg is NULL, ignore as this shouldn't happen
*
* 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
int install_timer;
} else if (ip_argis_cinfo(arg)) {
"Enter ip_timeout (a) install new timer");
else
} else {
} else {
if (install_timer && !ip_quit)
else
}
}
}
};
ip_fmdo_recv, /* fmdo_recv */
ip_timeout, /* fmdo_timeout */
NULL, /* fmdo_close */
NULL, /* fmdo_stats */
NULL, /* fmdo_gc */
ip_fmdo_send, /* fmdo_send */
};
};
/*
* 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".
* 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:
*
* (a) configuring ip-transport to operate in client mode by default,
* (b) a platform-specific configuration mechanism, or
* (c) a means to assure security and prevent denial-of-service attacks.
*
* 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
{
int err;
return; /* failed to register handle */
return;
}
if (err) {
addr);
return;
}
}
if (err) {
addr);
return;
}
}
/*
* If no specific connecitons configured then set up general server
* listening on all network ports.
*/
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
* this authority for all transports created by this module. If
* ip_authority isn't set, we'll compute authorities on the fly.
*/
(void) nvlist_alloc(&ip_auth, 0, 0);
(void) nvlist_add_uint8(ip_auth,
"must be in <name>=<value> form\n", p);
}
*r = '\0';
*r = '=';
}
}
}
void
{
ip_quit++; /* set quit flag before signalling auxiliary threads */
if (ip_domain_name != NULL)
}