ip.c revision d9638e547d8811f2c689977f8dd2a353938b61fd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <alloca.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <poll.h>
typedef struct ip_hdr {
} ip_hdr_t;
typedef struct ip_buf {
void *ipb_buf; /* data buffer */
} ip_buf_t;
typedef struct ip_xprt {
int ipx_flags; /* transport flags */
int ipx_fd; /* socket file descriptor */
int ipx_done; /* flag indicating connection closed */
} ip_xprt_t;
typedef struct ip_stat {
} ip_stat_t;
static void ip_xprt_create(fmd_xprt_t *, int, int);
static void ip_xprt_destroy(ip_xprt_t *);
};
static volatile int ip_quit; /* signal to quit */
static int ip_qlen; /* queue length for listen(3SOCKET) */
static int ip_mtbf; /* mtbf for simulating packet drop */
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) */
/*
* 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
{
ssize_t r, n;
int err;
/*
* 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) {
"failed to send on ipx %p", (void *)ipx);
return (FMD_SEND_FAILED);
}
continue;
}
buf += n;
r -= n;
}
return (FMD_SEND_SUCCESS);
}
/*
* 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) {
"failed to recv on ipx %p", (void *)ipx);
}
continue;
}
buf += n;
r -= n;
}
}
static nvlist_t *
{
size_t n;
int err;
else
if (err != 0) {
}
return (nvl);
} else {
}
return (nvl);
}
static void
{
fmd_xprt_t *xp;
int fd;
return;
}
}
static void
{
void *buf;
int err;
return; /* connection broken */
"invalid hdr magic %x.%x.%x.%x from transport %p\n",
return;
}
return; /* connection broken */
} else
}
}
static void
ip_xprt_thread(void *arg)
{
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.
*/
}
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);
}
/*
* Loop through the addresses that were returned by getaddrinfo() in _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
{
else
continue; /* ignore anything that isn't IPv4 or IPv6 */
continue;
}
if (xflags & FMD_XPRT_ACCEPT) {
} else {
}
if (err == 0) {
return (0);
}
}
s1 = "failed to connect to";
} else {
s1 = "failed to listen on";
}
return (err);
}
/*
* Timeout handler for the transport module. We use three types of timeouts:
*
* (a) arg is NULL: attempt ip_xprt_setup(), re-install timeout to retry
* (b) arg is non-NULL, FMD_XPRT_SUSPENDED: call fmd_xprt_resume() on arg
* (c) arg is non-NULL, !FMD_XPRT_SUSPENDED: call ip_xprt_destroy() on arg
*
* 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.
*/
static void
{
if (ip_xprt_setup(hdl) != 0)
} else {
}
}
static const fmd_prop_t fmd_props[] = {
};
static const fmd_hdl_ops_t fmd_ops = {
NULL, /* fmdo_recv */
ip_timeout, /* fmdo_timeout */
NULL, /* fmdo_close */
NULL, /* fmdo_stats */
NULL, /* fmdo_gc */
ip_xprt_send, /* fmdo_send */
};
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.
* 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.
*/
void
{
char *auth, *p, *q, *r, *s;
int err;
return; /* failed to register handle */
return;
}
else
if (err != 0) {
}
/*
* 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 = '=';
}
}
/*
* 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.
*/
if (ip_xprt_setup(hdl) != 0)
}
void
{
ip_quit++; /* set quit flag before signalling auxiliary threads */
}