blob: 659acc81a96f9d3a8c8741b2925a54ed65b02ded [file] [log] [blame]
/*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code mut retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#include <config.h>
#include <sys/cdefs.h>
/*
* rpc_generic.c, Miscl routines for RPC.
*
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rpc/types.h>
#include <misc/portable.h>
#include <rpc/rpc.h>
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <netdb.h>
#include <netconfig.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/nettype.h>
#include "rpc_com.h"
tirpc_pkg_params __ntirpc_pkg_params = {
TIRPC_FLAG_NONE,
TIRPC_DEBUG_FLAG_NONE,
warnx
};
bool
tirpc_control(const u_int rq, void *in)
{
switch (rq) {
case TIRPC_GET_FLAGS:
*(u_int *) in = __ntirpc_pkg_params.flags;
break;
case TIRPC_SET_FLAGS:
__ntirpc_pkg_params.flags = *(int *)in;
break;
case TIRPC_GET_DEBUG_FLAGS:
*(u_int *) in = __ntirpc_pkg_params.debug_flags;
break;
case TIRPC_SET_DEBUG_FLAGS:
__ntirpc_pkg_params.debug_flags = *(int *)in;
break;
case TIRPC_GET_WARNX:
*(warnx_t *) in = __ntirpc_pkg_params.warnx;
break;
case TIRPC_SET_WARNX:
__ntirpc_pkg_params.warnx = *(warnx_t) in;
break;
default:
return (false);
}
return (true);
}
struct handle {
NCONF_HANDLE *nhandle;
int nflag; /* Whether NETPATH or NETCONFIG */
int nettype;
};
static const struct _rpcnettype {
const char *name;
const int type;
} _rpctypelist[] = {
{
"netpath", _RPC_NETPATH}, {
"visible", _RPC_VISIBLE}, {
"circuit_v", _RPC_CIRCUIT_V}, {
"datagram_v", _RPC_DATAGRAM_V}, {
"circuit_n", _RPC_CIRCUIT_N}, {
"datagram_n", _RPC_DATAGRAM_N}, {
"tcp", _RPC_TCP}, {
"udp", _RPC_UDP}, {
0, _RPC_NONE}
};
struct netid_af {
const char *netid;
int af;
int protocol;
};
static const struct netid_af na_cvt[] = {
{"udp", AF_INET, IPPROTO_UDP},
{"tcp", AF_INET, IPPROTO_TCP},
#ifdef INET6
{"udp6", AF_INET6, IPPROTO_UDP},
{"tcp6", AF_INET6, IPPROTO_TCP},
#endif
{"local", AF_LOCAL, 0}
};
#if 0
static char *strlocase(char *);
#endif
static int getnettype(const char *);
/*
* Cache the result of getrlimit(), so we don't have to do an
* expensive call every time.
*/
int
__rpc_dtbsize(void)
{
static int tbsize;
struct rlimit rl;
if (tbsize)
return (tbsize);
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
return (tbsize = (int)rl.rlim_max);
/*
* Something wrong. I'll try to save face by returning a
* pessimistic number.
*/
return (32);
}
/*
* Find the appropriate buffer size
*/
u_int /*ARGSUSED*/
__rpc_get_t_size(int af, int proto, int size)
{
int maxsize, defsize;
maxsize = 256 * 1024; /* XXX */
switch (proto) {
case IPPROTO_TCP:
defsize = 64 * 1024; /* XXX */
break;
case IPPROTO_UDP:
defsize = UDPMSGSIZE;
break;
default:
defsize = RPC_MAXDATASIZE;
break;
}
if (size == 0)
return defsize;
/* Check whether the value is within the upper max limit */
return (size > maxsize ? (u_int) maxsize : (u_int) size);
}
/*
* Find the appropriate address buffer size
*/
u_int
__rpc_get_a_size(int af)
{
switch (af) {
case AF_INET:
return sizeof(struct sockaddr_in);
#ifdef INET6
case AF_INET6:
return sizeof(struct sockaddr_in6);
#endif
case AF_LOCAL:
return sizeof(struct sockaddr_un);
default:
break;
}
return ((u_int) RPC_MAXADDRSIZE);
}
#if 0
static char *
strlocase(char *p)
{
char *t = p;
for (; *p; p++)
if (isupper(*p))
*p = tolower(*p);
return (t);
}
#endif
/*
* Returns the type of the network as defined in <rpc/nettype.h>
* If nettype is NULL, it defaults to NETPATH.
*/
static int
getnettype(const char *nettype)
{
int i;
if ((nettype == NULL) || (nettype[0] == 0))
return (_RPC_NETPATH); /* Default */
#if 0
nettype = strlocase(nettype);
#endif
for (i = 0; _rpctypelist[i].name; i++) {
if (strcasecmp(nettype, _rpctypelist[i].name) == 0)
return (_rpctypelist[i].type);
}
return (_rpctypelist[i].type);
}
/*
* For the given nettype (tcp or udp only), return the first structure found.
* This should be freed by calling freenetconfigent()
*/
struct netconfig *
__rpc_getconfip(const char *nettype)
{
char *netid;
char *netid_tcp = (char *)NULL;
char *netid_udp = (char *)NULL;
struct netconfig *dummy;
extern thread_key_t tcp_key, udp_key;
extern mutex_t tsd_lock;
if (tcp_key == -1) {
mutex_lock(&tsd_lock);
if (tcp_key == -1)
thr_keycreate(&tcp_key, free); /* XXX */
mutex_unlock(&tsd_lock);
}
netid_tcp = (char *)thr_getspecific(tcp_key);
if (udp_key == -1) {
mutex_lock(&tsd_lock);
if (udp_key == -1)
thr_keycreate(&udp_key, free);
mutex_unlock(&tsd_lock);
}
netid_udp = (char *)thr_getspecific(udp_key);
if (!netid_udp && !netid_tcp) {
struct netconfig *nconf;
void *confighandle;
confighandle = setnetconfig();
if (!confighandle) {
__warnx(TIRPC_DEBUG_FLAG_DEFAULT,
"rpc: failed to open %s", NETCONFIG);
return (NULL);
}
while ((nconf = getnetconfig(confighandle)) != NULL) {
if (strcmp(nconf->nc_protofmly, NC_INET) == 0
|| strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
if (strcmp(nconf->nc_proto, NC_TCP) == 0
&& netid_tcp == NULL) {
netid_tcp = rpc_strdup(nconf->nc_netid);
thr_setspecific(tcp_key,
(void *)netid_tcp);
} else if (strcmp(nconf->nc_proto, NC_UDP) == 0
&& netid_udp == NULL) {
netid_udp = rpc_strdup(nconf->nc_netid);
thr_setspecific(udp_key,
(void *)netid_udp);
}
}
}
endnetconfig(confighandle);
}
if (strcmp(nettype, "udp") == 0)
netid = netid_udp;
else if (strcmp(nettype, "tcp") == 0)
netid = netid_tcp;
else
return (NULL);
if ((netid == NULL) || (netid[0] == 0))
return (NULL);
dummy = getnetconfigent(netid);
return (dummy);
}
/*
* Returns the type of the nettype, which should then be used with
* __rpc_getconf().
*/
void *
__rpc_setconf(const char *nettype)
{
struct handle *handle;
handle = (struct handle *)mem_zalloc(sizeof(struct handle));
if (handle == NULL)
return (NULL);
switch (handle->nettype = getnettype(nettype)) {
case _RPC_NETPATH:
case _RPC_CIRCUIT_N:
case _RPC_DATAGRAM_N:
handle->nhandle = setnetpath();
if (!handle->nhandle) {
mem_free(handle, 0); /* XXX */
return (NULL);
}
handle->nflag = true;
break;
case _RPC_VISIBLE:
case _RPC_CIRCUIT_V:
case _RPC_DATAGRAM_V:
case _RPC_TCP:
case _RPC_UDP:
handle->nhandle = setnetconfig();
if (!handle->nhandle) {
__warnx(TIRPC_DEBUG_FLAG_DEFAULT,
"rpc: failed to open %s", NETCONFIG);
mem_free(handle, 0);
return (NULL);
}
handle->nflag = false;
break;
default:
mem_free(handle, 0);
return (NULL);
}
return (handle);
}
/*
* Returns the next netconfig struct for the given "net" type.
* __rpc_setconf() should have been called previously.
*/
struct netconfig *
__rpc_getconf(void *vhandle)
{
struct handle *handle;
struct netconfig *nconf;
handle = (struct handle *)vhandle;
if (handle == NULL)
return (NULL);
for (;;) {
if (handle->nflag)
nconf = getnetpath(handle->nhandle);
else
nconf = getnetconfig(handle->nhandle);
if (nconf == NULL)
break;
if ((nconf->nc_semantics != NC_TPI_CLTS)
&& (nconf->nc_semantics != NC_TPI_COTS)
&& (nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
switch (handle->nettype) {
case _RPC_VISIBLE:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_NETPATH: /* Be happy */
break;
case _RPC_CIRCUIT_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_CIRCUIT_N:
if ((nconf->nc_semantics != NC_TPI_COTS)
&& (nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
break;
case _RPC_DATAGRAM_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_DATAGRAM_N:
if (nconf->nc_semantics != NC_TPI_CLTS)
continue;
break;
case _RPC_TCP:
if (((nconf->nc_semantics != NC_TPI_COTS)
&& (nconf->nc_semantics != NC_TPI_COTS_ORD))
|| (strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
|| strcmp(nconf->nc_proto, NC_TCP))
continue;
break;
case _RPC_UDP:
if ((nconf->nc_semantics != NC_TPI_CLTS)
|| (strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
|| strcmp(nconf->nc_proto, NC_UDP))
continue;
break;
}
break;
}
return (nconf);
}
void
__rpc_endconf(void *vhandle)
{
struct handle *handle;
handle = (struct handle *)vhandle;
if (handle == NULL)
return;
if (handle->nflag)
endnetpath(handle->nhandle);
else
endnetconfig(handle->nhandle);
mem_free(handle, 0);
}
/*
* Used to ping the NULL procedure for clnt handle.
* Returns NULL if fails, else a non-NULL pointer.
*/
void *
rpc_nullproc(CLIENT *clnt)
{
struct timeval TIMEOUT = { 25, 0 };
AUTH *auth;
auth = authnone_create(); /* idempotent */
if (clnt_call
(clnt, auth, NULLPROC, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return ((void *)clnt);
}
/*
* Try all possible transports until
* one succeeds in finding the netconf for the given fd.
*/
struct netconfig *
__rpcgettp(int fd)
{
const char *netid;
struct __rpc_sockinfo si;
if (!__rpc_fd2sockinfo(fd, &si))
return NULL;
if (!__rpc_sockinfo2netid(&si, &netid))
return NULL;
/*LINTED const castaway */
return getnetconfigent((char *)netid);
}
int
__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
{
socklen_t len;
int type, proto;
struct sockaddr_storage ss;
len = sizeof(ss);
if (getsockname(fd, (struct sockaddr *)&ss, &len) < 0)
return 0;
sip->si_alen = len;
len = sizeof(type);
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
return 0;
/* XXX */
if (ss.ss_family != AF_LOCAL) {
if (type == SOCK_STREAM)
proto = IPPROTO_TCP;
else if (type == SOCK_DGRAM)
proto = IPPROTO_UDP;
else
return 0;
} else
proto = 0;
sip->si_af = ss.ss_family;
sip->si_proto = proto;
sip->si_socktype = type;
return 1;
}
/*
* Linear search, but the number of entries is small.
*/
int
__rpc_nconf2sockinfo(const struct netconfig *nconf,
struct __rpc_sockinfo *sip)
{
int i;
for (i = 0; i < (sizeof(na_cvt)) / (sizeof(struct netid_af)); i++)
if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0
|| (strcmp(nconf->nc_netid, "unix") == 0
&& strcmp(na_cvt[i].netid, "local") == 0)) {
sip->si_af = na_cvt[i].af;
sip->si_proto = na_cvt[i].protocol;
sip->si_socktype =
__rpc_seman2socktype((int)nconf->nc_semantics);
if (sip->si_socktype == -1)
return 0;
sip->si_alen = __rpc_get_a_size(sip->si_af);
return 1;
}
return 0;
}
int
__rpc_nconf2fd_flags(const struct netconfig *nconf, int flags)
{
struct __rpc_sockinfo si;
int fd;
if (!__rpc_nconf2sockinfo(nconf, &si))
return 0;
fd = socket(si.si_af, si.si_socktype | flags, si.si_proto);
if ((fd >= 0) &&
(si.si_af == AF_INET6)) {
#ifdef SOL_IPV6
int val = 1;
(void) setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &val,
sizeof(val));
#endif
}
return fd;
}
int
__rpc_nconf2fd(const struct netconfig *nconf)
{
return __rpc_nconf2fd_flags(nconf, 0);
}
int
__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
{
int i;
struct netconfig *nconf;
nconf = getnetconfigent("local");
for (i = 0; i < (sizeof(na_cvt)) / (sizeof(struct netid_af)); i++) {
if (na_cvt[i].af == sip->si_af
&& na_cvt[i].protocol == sip->si_proto) {
if (strcmp(na_cvt[i].netid, "local") == 0
&& nconf == NULL) {
if (netid)
*netid = "unix";
} else {
if (netid)
*netid = na_cvt[i].netid;
}
if (nconf != NULL)
freenetconfigent(nconf);
return 1;
}
}
if (nconf != NULL)
freenetconfigent(nconf);
return 0;
}
char *
taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_taddr2uaddr_af(si.si_af, nbuf);
}
struct netbuf *
uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_uaddr2taddr_af(si.si_af, uaddr);
}
char *
__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
{
char *ret = NULL;
struct sockaddr_in *sin;
struct sockaddr_un *sun;
char namebuf[INET_ADDRSTRLEN];
#ifdef INET6
struct sockaddr_in6 *sin6;
char namebuf6[INET6_ADDRSTRLEN];
#endif
u_int16_t port;
if (nbuf->len <= 0)
goto out;
/* XXX check (fix) this */
ret = mem_zalloc(INET6_ADDRSTRLEN + (2 * 6) + 1);
if (!ret)
return (NULL);
switch (af) {
case AF_INET:
sin = nbuf->buf;
if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof(namebuf))
== NULL)
return NULL;
port = ntohs(sin->sin_port);
if (sprintf
(ret, "%s.%u.%u", namebuf, ((u_int32_t) port) >> 8,
port & 0xff) < 0) {
mem_free(ret, 0);
return NULL;
}
break;
#ifdef INET6
case AF_INET6:
sin6 = nbuf->buf;
if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof(namebuf6))
== NULL) {
mem_free(ret, 0);
return NULL;
}
port = ntohs(sin6->sin6_port);
if (sprintf
(ret, "%s.%u.%u", namebuf6, ((u_int32_t) port) >> 8,
port & 0xff) < 0) {
mem_free(ret, 0);
return NULL;
}
break;
#endif
case AF_LOCAL:
sun = nbuf->buf;
/* if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
offsetof(struct sockaddr_un, sun_path)),
sun->sun_path) < 0) */
if (sprintf(ret, "%.*s",
(int)(sizeof(*sun) -
offsetof(struct sockaddr_un, sun_path)),
sun->sun_path) < 0) {
mem_free(ret, 0);
return NULL;
}
break;
default:
mem_free(ret, 0);
return NULL;
}
out:
return ret;
}
struct netbuf *
__rpc_uaddr2taddr_af(int af, const char *uaddr)
{
struct netbuf *ret = NULL;
char *addrstr, *p;
unsigned port, portlo, porthi;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockaddr_un *sun;
port = 0;
sin = NULL;
addrstr = rpc_strdup(uaddr);
if (addrstr == NULL)
return NULL;
/*
* AF_LOCAL addresses are expected to be absolute
* pathnames, anything else will be AF_INET or AF_INET6.
*/
if (*addrstr != '/') {
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
portlo = (unsigned)atoi(p + 1);
*p = '\0';
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
porthi = (unsigned)atoi(p + 1);
*p = '\0';
port = (porthi << 8) | portlo;
}
ret = (struct netbuf *)mem_zalloc(sizeof(*ret));
if (ret == NULL)
goto out;
switch (af) {
case AF_INET:
sin = (struct sockaddr_in *)mem_zalloc(sizeof(*sin));
if (sin == NULL)
goto out;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
mem_free(sin, 0); /* XXX */
mem_free(ret, 0);
ret = NULL;
goto out;
}
ret->maxlen = ret->len = sizeof(*sin);
ret->buf = sin;
break;
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)mem_zalloc(sizeof(*sin6));
if (sin6 == NULL)
goto out;
memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
mem_free(sin6, 0);
mem_free(ret, 0);
ret = NULL;
goto out;
}
ret->maxlen = ret->len = sizeof(*sin6);
ret->buf = sin6;
break;
#endif
case AF_LOCAL:
sun = (struct sockaddr_un *)mem_zalloc(sizeof(*sun));
if (sun == NULL)
goto out;
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
ret->len = SUN_LEN(sun);
ret->maxlen = sizeof(struct sockaddr_un);
ret->buf = sun;
break;
default:
mem_free(ret, 0);
ret = NULL;
break;
}
out:
mem_free(addrstr, 0);
return ret;
}
int
__rpc_seman2socktype(int semantics)
{
switch (semantics) {
case NC_TPI_CLTS:
return SOCK_DGRAM;
case NC_TPI_COTS_ORD:
return SOCK_STREAM;
case NC_TPI_RAW:
return SOCK_RAW;
default:
break;
}
return -1;
}
int
__rpc_socktype2seman(int socktype)
{
switch (socktype) {
case SOCK_DGRAM:
return NC_TPI_CLTS;
case SOCK_STREAM:
return NC_TPI_COTS_ORD;
case SOCK_RAW:
return NC_TPI_RAW;
default:
break;
}
return -1;
}
/*
* XXXX - IPv6 scope IDs can't be handled in universal addresses.
* Here, we compare the original server address to that of the RPC
* service we just received back from a call to rpcbind on the remote
* machine. If they are both "link local" or "site local", copy
* the scope id of the server address over to the service address.
*/
int
__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
{
#ifdef INET6
struct sockaddr *sa_new, *sa_svc;
struct sockaddr_in6 *sin6_new, *sin6_svc;
sa_svc = (struct sockaddr *)svc->buf;
sa_new = (struct sockaddr *)new->buf;
if (sa_new->sa_family == sa_svc->sa_family
&& sa_new->sa_family == AF_INET6) {
sin6_new = (struct sockaddr_in6 *)new->buf;
sin6_svc = (struct sockaddr_in6 *)svc->buf;
if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr)
&& IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr))
|| (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr)
&& IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
}
}
#endif
return 1;
}
int __rpc_sockisbound(int fd)
{
struct sockaddr_storage ss;
union {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_un usin;
} u_addr;
socklen_t slen;
slen = sizeof(struct sockaddr_storage);
if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
return 0;
switch (ss.ss_family) {
case AF_INET:
memcpy(&u_addr.sin, &ss, sizeof(u_addr.sin));
return (u_addr.sin.sin_port != 0);
#ifdef INET6
case AF_INET6:
memcpy(&u_addr.sin6, &ss, sizeof(u_addr.sin6));
return (u_addr.sin6.sin6_port != 0);
#endif
case AF_LOCAL:
/* XXX check this */
memcpy(&u_addr.usin, &ss, sizeof(u_addr.usin));
return (u_addr.usin.sun_path[0] != 0);
default:
break;
}
return 0;
}
/*
* Helper function to set up a netbuf
*/
struct netbuf *
__rpc_set_netbuf(struct netbuf *nb, const void *ptr, size_t len)
{
if (nb->len != len) {
if (nb->len)
mem_free(nb->buf, nb->len);
nb->buf = mem_zalloc(len);
if (nb->buf == NULL)
return NULL;
nb->maxlen = nb->len = len;
}
memcpy(nb->buf, ptr, len);
return nb;
}