Home | History | Annotate | Line # | Download | only in rpc
rpc_generic.c revision 1.24.8.1
      1 /*	$NetBSD: rpc_generic.c,v 1.24.8.1 2013/03/14 22:03:15 riz Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2010, Oracle America, Inc.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are
      8  * met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  *       notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  *       copyright notice, this list of conditions and the following
     14  *       disclaimer in the documentation and/or other materials
     15  *       provided with the distribution.
     16  *     * Neither the name of the "Oracle America, Inc." nor the names of its
     17  *       contributors may be used to endorse or promote products derived
     18  *       from this software without specific prior written permission.
     19  *
     20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 /*
     34  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
     35  */
     36 
     37 /* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
     38 
     39 /*
     40  * rpc_generic.c, Miscl routines for RPC.
     41  *
     42  */
     43 
     44 #include <sys/cdefs.h>
     45 #if defined(LIBC_SCCS) && !defined(lint)
     46 __RCSID("$NetBSD: rpc_generic.c,v 1.24.8.1 2013/03/14 22:03:15 riz Exp $");
     47 #endif
     48 
     49 #include "namespace.h"
     50 #include "reentrant.h"
     51 #include <sys/types.h>
     52 #include <sys/param.h>
     53 #include <sys/socket.h>
     54 #include <sys/un.h>
     55 #include <sys/resource.h>
     56 #include <netinet/in.h>
     57 #include <netinet/tcp.h>
     58 #include <arpa/inet.h>
     59 #include <rpc/rpc.h>
     60 #include <assert.h>
     61 #include <ctype.h>
     62 #include <stdio.h>
     63 #include <netdb.h>
     64 #include <netconfig.h>
     65 #include <malloc.h>
     66 #include <string.h>
     67 #include <syslog.h>
     68 #include <rpc/nettype.h>
     69 #include "rpc_internal.h"
     70 
     71 #ifdef __weak_alias
     72 __weak_alias(taddr2uaddr,_taddr2uaddr)
     73 __weak_alias(uaddr2taddr,_uaddr2taddr)
     74 #endif
     75 
     76 struct handle {
     77 	NCONF_HANDLE *nhandle;
     78 	int nflag;		/* Whether NETPATH or NETCONFIG */
     79 	int nettype;
     80 };
     81 
     82 static const struct _rpcnettype {
     83 	const char *name;
     84 	const int type;
     85 } _rpctypelist[] = {
     86 	{ "netpath", _RPC_NETPATH },
     87 	{ "visible", _RPC_VISIBLE },
     88 	{ "circuit_v", _RPC_CIRCUIT_V },
     89 	{ "datagram_v", _RPC_DATAGRAM_V },
     90 	{ "circuit_n", _RPC_CIRCUIT_N },
     91 	{ "datagram_n", _RPC_DATAGRAM_N },
     92 	{ "tcp", _RPC_TCP },
     93 	{ "udp", _RPC_UDP },
     94 	{ 0, _RPC_NONE }
     95 };
     96 
     97 struct netid_af {
     98 	const char	*netid;
     99 	int		af;
    100 	int		protocol;
    101 };
    102 
    103 static const struct netid_af na_cvt[] = {
    104 	{ "udp",  AF_INET,  IPPROTO_UDP },
    105 	{ "tcp",  AF_INET,  IPPROTO_TCP },
    106 #ifdef INET6
    107 	{ "udp6", AF_INET6, IPPROTO_UDP },
    108 	{ "tcp6", AF_INET6, IPPROTO_TCP },
    109 #endif
    110 	{ "local", AF_LOCAL, 0 }
    111 };
    112 
    113 #if 0
    114 static char *strlocase __P((char *));
    115 #endif
    116 static int getnettype __P((const char *));
    117 
    118 /*
    119  * Cache the result of getrlimit(), so we don't have to do an
    120  * expensive call every time.
    121  */
    122 int
    123 __rpc_dtbsize()
    124 {
    125 	static int tbsize;
    126 	struct rlimit rl;
    127 
    128 	if (tbsize) {
    129 		return (tbsize);
    130 	}
    131 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
    132 		return (tbsize = (int)rl.rlim_max);
    133 	}
    134 	/*
    135 	 * Something wrong.  I'll try to save face by returning a
    136 	 * pessimistic number.
    137 	 */
    138 	return (32);
    139 }
    140 
    141 
    142 /*
    143  * Find the appropriate buffer size
    144  */
    145 u_int
    146 /*ARGSUSED*/
    147 __rpc_get_t_size(af, proto, size)
    148 	int af, proto;
    149 	int size;	/* Size requested */
    150 {
    151 	int maxsize, defsize;
    152 
    153 	maxsize = 256 * 1024;	/* XXX */
    154 	switch (proto) {
    155 	case IPPROTO_TCP:
    156 		defsize = 64 * 1024;	/* XXX */
    157 		break;
    158 	case IPPROTO_UDP:
    159 		defsize = UDPMSGSIZE;
    160 		break;
    161 	default:
    162 		defsize = RPC_MAXDATASIZE;
    163 		break;
    164 	}
    165 	if (size == 0)
    166 		return defsize;
    167 
    168 	/* Check whether the value is within the upper max limit */
    169 	return (size > maxsize ? (u_int)maxsize : (u_int)size);
    170 }
    171 
    172 /*
    173  * Find the appropriate address buffer size
    174  */
    175 u_int
    176 __rpc_get_a_size(af)
    177 	int af;
    178 {
    179 	switch (af) {
    180 	case AF_INET:
    181 		return sizeof (struct sockaddr_in);
    182 #ifdef INET6
    183 	case AF_INET6:
    184 		return sizeof (struct sockaddr_in6);
    185 #endif
    186 	case AF_LOCAL:
    187 		return sizeof (struct sockaddr_un);
    188 	default:
    189 		break;
    190 	}
    191 	return ((u_int)RPC_MAXADDRSIZE);
    192 }
    193 
    194 #if 0
    195 static char *
    196 strlocase(p)
    197 	char *p;
    198 {
    199 	char *t = p;
    200 
    201 	_DIAGASSERT(p != NULL);
    202 
    203 	for (; *p; p++)
    204 		if (isupper(*p))
    205 			*p = tolower(*p);
    206 	return (t);
    207 }
    208 #endif
    209 
    210 /*
    211  * Returns the type of the network as defined in <rpc/nettype.h>
    212  * If nettype is NULL, it defaults to NETPATH.
    213  */
    214 static int
    215 getnettype(nettype)
    216 	const char *nettype;
    217 {
    218 	int i;
    219 
    220 	if ((nettype == NULL) || (nettype[0] == 0)) {
    221 		return (_RPC_NETPATH);	/* Default */
    222 	}
    223 
    224 #if 0
    225 	nettype = strlocase(nettype);
    226 #endif
    227 	for (i = 0; _rpctypelist[i].name; i++)
    228 		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
    229 			return (_rpctypelist[i].type);
    230 		}
    231 	return (_rpctypelist[i].type);
    232 }
    233 
    234 /*
    235  * For the given nettype (tcp or udp only), return the first structure found.
    236  * This should be freed by calling freenetconfigent()
    237  */
    238 
    239 #ifdef _REENTRANT
    240 static thread_key_t tcp_key, udp_key;
    241 static once_t __rpc_getconfigp_once = ONCE_INITIALIZER;
    242 
    243 static void
    244 __rpc_getconfigp_setup(void)
    245 {
    246 
    247 	thr_keycreate(&tcp_key, free);
    248 	thr_keycreate(&udp_key, free);
    249 }
    250 #endif
    251 
    252 struct netconfig *
    253 __rpc_getconfip(nettype)
    254 	const char *nettype;
    255 {
    256 	char *netid;
    257 	char *netid_tcp = NULL;
    258 	char *netid_udp = NULL;
    259 	static char *netid_tcp_main;
    260 	static char *netid_udp_main;
    261 	struct netconfig *dummy;
    262 #ifdef _REENTRANT
    263 	if (__isthreaded == 0) {
    264 		netid_udp = netid_udp_main;
    265 		netid_tcp = netid_tcp_main;
    266 	} else {
    267 		thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup);
    268 		netid_tcp = thr_getspecific(tcp_key);
    269 		netid_udp = thr_getspecific(udp_key);
    270 	}
    271 #else
    272 	netid_udp = netid_udp_main;
    273 	netid_tcp = netid_tcp_main;
    274 #endif
    275 
    276 	_DIAGASSERT(nettype != NULL);
    277 
    278 	if (!netid_udp && !netid_tcp) {
    279 		struct netconfig *nconf;
    280 		void *confighandle;
    281 
    282 		if (!(confighandle = setnetconfig())) {
    283 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
    284 			return (NULL);
    285 		}
    286 		while ((nconf = getnetconfig(confighandle)) != NULL) {
    287 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
    288 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
    289 					netid_tcp = strdup(nconf->nc_netid);
    290 					if (netid_tcp == NULL)
    291 						return NULL;
    292 #ifdef _REENTRANT
    293 					if (__isthreaded == 0)
    294 						netid_tcp_main = netid_tcp;
    295 					else
    296 						thr_setspecific(tcp_key,
    297 							(void *) netid_tcp);
    298 #else
    299 					netid_tcp_main = netid_tcp;
    300 #endif
    301 				} else
    302 				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
    303 					netid_udp = strdup(nconf->nc_netid);
    304 					if (netid_udp == NULL)
    305 						return NULL;
    306 #ifdef _REENTRANT
    307 					if (__isthreaded == 0)
    308 						netid_udp_main = netid_udp;
    309 					else
    310 						thr_setspecific(udp_key,
    311 							(void *) netid_udp);
    312 #else
    313 					netid_udp_main = netid_udp;
    314 #endif
    315 				}
    316 			}
    317 		}
    318 		endnetconfig(confighandle);
    319 	}
    320 	if (strcmp(nettype, "udp") == 0)
    321 		netid = netid_udp;
    322 	else if (strcmp(nettype, "tcp") == 0)
    323 		netid = netid_tcp;
    324 	else {
    325 		return (NULL);
    326 	}
    327 	if ((netid == NULL) || (netid[0] == 0)) {
    328 		return (NULL);
    329 	}
    330 	dummy = getnetconfigent(netid);
    331 	return (dummy);
    332 }
    333 
    334 /*
    335  * Returns the type of the nettype, which should then be used with
    336  * __rpc_getconf().
    337  */
    338 void *
    339 __rpc_setconf(nettype)
    340 	const char *nettype;
    341 {
    342 	struct handle *handle;
    343 
    344 	/* nettype may be NULL; getnettype() supports that */
    345 
    346 	handle = malloc(sizeof(*handle));
    347 	if (handle == NULL) {
    348 		return (NULL);
    349 	}
    350 	switch (handle->nettype = getnettype(nettype)) {
    351 	case _RPC_NETPATH:
    352 	case _RPC_CIRCUIT_N:
    353 	case _RPC_DATAGRAM_N:
    354 		if (!(handle->nhandle = setnetpath())) {
    355 			free(handle);
    356 			return (NULL);
    357 		}
    358 		handle->nflag = TRUE;
    359 		break;
    360 	case _RPC_VISIBLE:
    361 	case _RPC_CIRCUIT_V:
    362 	case _RPC_DATAGRAM_V:
    363 	case _RPC_TCP:
    364 	case _RPC_UDP:
    365 		if (!(handle->nhandle = setnetconfig())) {
    366 		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
    367 			free(handle);
    368 			return (NULL);
    369 		}
    370 		handle->nflag = FALSE;
    371 		break;
    372 	default:
    373 		free(handle);
    374 		return (NULL);
    375 	}
    376 
    377 	return (handle);
    378 }
    379 
    380 /*
    381  * Returns the next netconfig struct for the given "net" type.
    382  * __rpc_setconf() should have been called previously.
    383  */
    384 struct netconfig *
    385 __rpc_getconf(vhandle)
    386 	void *vhandle;
    387 {
    388 	struct handle *handle;
    389 	struct netconfig *nconf;
    390 
    391 	handle = (struct handle *)vhandle;
    392 	if (handle == NULL) {
    393 		return (NULL);
    394 	}
    395 	for (;;) {
    396 		if (handle->nflag)
    397 			nconf = getnetpath(handle->nhandle);
    398 		else
    399 			nconf = getnetconfig(handle->nhandle);
    400 		if (nconf == NULL)
    401 			break;
    402 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
    403 			(nconf->nc_semantics != NC_TPI_COTS) &&
    404 			(nconf->nc_semantics != NC_TPI_COTS_ORD))
    405 			continue;
    406 		switch (handle->nettype) {
    407 		case _RPC_VISIBLE:
    408 			if (!(nconf->nc_flag & NC_VISIBLE))
    409 				continue;
    410 			/* FALLTHROUGH */
    411 		case _RPC_NETPATH:	/* Be happy */
    412 			break;
    413 		case _RPC_CIRCUIT_V:
    414 			if (!(nconf->nc_flag & NC_VISIBLE))
    415 				continue;
    416 			/* FALLTHROUGH */
    417 		case _RPC_CIRCUIT_N:
    418 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
    419 				(nconf->nc_semantics != NC_TPI_COTS_ORD))
    420 				continue;
    421 			break;
    422 		case _RPC_DATAGRAM_V:
    423 			if (!(nconf->nc_flag & NC_VISIBLE))
    424 				continue;
    425 			/* FALLTHROUGH */
    426 		case _RPC_DATAGRAM_N:
    427 			if (nconf->nc_semantics != NC_TPI_CLTS)
    428 				continue;
    429 			break;
    430 		case _RPC_TCP:
    431 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
    432 				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
    433 				(strcmp(nconf->nc_protofmly, NC_INET)
    434 #ifdef INET6
    435 				 && strcmp(nconf->nc_protofmly, NC_INET6))
    436 #else
    437 				)
    438 #endif
    439 				||
    440 				strcmp(nconf->nc_proto, NC_TCP))
    441 				continue;
    442 			break;
    443 		case _RPC_UDP:
    444 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
    445 				(strcmp(nconf->nc_protofmly, NC_INET)
    446 #ifdef INET6
    447 				&& strcmp(nconf->nc_protofmly, NC_INET6))
    448 #else
    449 				)
    450 #endif
    451 				||
    452 				strcmp(nconf->nc_proto, NC_UDP))
    453 				continue;
    454 			break;
    455 		}
    456 		break;
    457 	}
    458 	return (nconf);
    459 }
    460 
    461 void
    462 __rpc_endconf(vhandle)
    463 	void * vhandle;
    464 {
    465 	struct handle *handle;
    466 
    467 	handle = (struct handle *) vhandle;
    468 	if (handle == NULL) {
    469 		return;
    470 	}
    471 	if (handle->nflag) {
    472 		endnetpath(handle->nhandle);
    473 	} else {
    474 		endnetconfig(handle->nhandle);
    475 	}
    476 	free(handle);
    477 }
    478 
    479 /*
    480  * Used to ping the NULL procedure for clnt handle.
    481  * Returns NULL if fails, else a non-NULL pointer.
    482  */
    483 void *
    484 rpc_nullproc(clnt)
    485 	CLIENT *clnt;
    486 {
    487 	struct timeval TIMEOUT = {25, 0};
    488 
    489 	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
    490 		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
    491 		return (NULL);
    492 	}
    493 	return ((void *) clnt);
    494 }
    495 
    496 /*
    497  * Try all possible transports until
    498  * one succeeds in finding the netconf for the given fd.
    499  */
    500 struct netconfig *
    501 __rpcgettp(fd)
    502 	int fd;
    503 {
    504 	const char *netid;
    505 	struct __rpc_sockinfo si;
    506 
    507 	if (!__rpc_fd2sockinfo(fd, &si))
    508 		return NULL;
    509 
    510 	if (!__rpc_sockinfo2netid(&si, &netid))
    511 		return NULL;
    512 
    513 	return getnetconfigent(__UNCONST(netid));
    514 }
    515 
    516 int
    517 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
    518 {
    519 	socklen_t len;
    520 	int type, proto;
    521 	struct sockaddr_storage ss;
    522 
    523 	_DIAGASSERT(sip != NULL);
    524 
    525 	len = sizeof ss;
    526 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
    527 		return 0;
    528 	sip->si_alen = len;
    529 
    530 	len = sizeof type;
    531 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
    532 		return 0;
    533 
    534 	/* XXX */
    535 	if (ss.ss_family != AF_LOCAL) {
    536 		if (type == SOCK_STREAM)
    537 			proto = IPPROTO_TCP;
    538 		else if (type == SOCK_DGRAM)
    539 			proto = IPPROTO_UDP;
    540 		else
    541 			return 0;
    542 	} else
    543 		proto = 0;
    544 
    545 	sip->si_af = ss.ss_family;
    546 	sip->si_proto = proto;
    547 	sip->si_socktype = type;
    548 
    549 	return 1;
    550 }
    551 
    552 /*
    553  * Linear search, but the number of entries is small.
    554  */
    555 int
    556 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
    557 {
    558 	size_t i;
    559 
    560 	_DIAGASSERT(nconf != NULL);
    561 	_DIAGASSERT(sip != NULL);
    562 
    563 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    564 		if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
    565 			sip->si_af = na_cvt[i].af;
    566 			sip->si_proto = na_cvt[i].protocol;
    567 			sip->si_socktype =
    568 			    __rpc_seman2socktype((int)nconf->nc_semantics);
    569 			if (sip->si_socktype == -1)
    570 				return 0;
    571 			sip->si_alen = __rpc_get_a_size(sip->si_af);
    572 			return 1;
    573 		}
    574 
    575 	return 0;
    576 }
    577 
    578 int
    579 __rpc_nconf2fd(const struct netconfig *nconf)
    580 {
    581 	struct __rpc_sockinfo si;
    582 
    583 	_DIAGASSERT(nconf != NULL);
    584 
    585 	if (!__rpc_nconf2sockinfo(nconf, &si))
    586 		return 0;
    587 
    588 	return socket(si.si_af, si.si_socktype, si.si_proto);
    589 }
    590 
    591 int
    592 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
    593 {
    594 	size_t i;
    595 
    596 	_DIAGASSERT(sip != NULL);
    597 	/* netid may be NULL */
    598 
    599 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    600 		if (na_cvt[i].af == sip->si_af &&
    601 		    na_cvt[i].protocol == sip->si_proto) {
    602 			if (netid)
    603 				*netid = na_cvt[i].netid;
    604 			return 1;
    605 		}
    606 
    607 	return 0;
    608 }
    609 
    610 char *
    611 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
    612 {
    613 	struct __rpc_sockinfo si;
    614 
    615 	_DIAGASSERT(nconf != NULL);
    616 	_DIAGASSERT(nbuf != NULL);
    617 
    618 	if (!__rpc_nconf2sockinfo(nconf, &si))
    619 		return NULL;
    620 	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
    621 }
    622 
    623 struct netbuf *
    624 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
    625 {
    626 	struct __rpc_sockinfo si;
    627 
    628 	_DIAGASSERT(nconf != NULL);
    629 	_DIAGASSERT(uaddr != NULL);
    630 
    631 	if (!__rpc_nconf2sockinfo(nconf, &si))
    632 		return NULL;
    633 	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
    634 }
    635 
    636 char *
    637 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
    638 {
    639 	char *ret;
    640 	struct sockaddr_in *sinp;
    641 	struct sockaddr_un *sun;
    642 	char namebuf[INET_ADDRSTRLEN];
    643 #ifdef INET6
    644 	struct sockaddr_in6 *sin6;
    645 	char namebuf6[INET6_ADDRSTRLEN];
    646 #endif
    647 	u_int16_t port;
    648 
    649 	_DIAGASSERT(nbuf != NULL);
    650 
    651 	switch (af) {
    652 	case AF_INET:
    653 		sinp = nbuf->buf;
    654 		if (inet_ntop(af, &sinp->sin_addr, namebuf, sizeof namebuf)
    655 		    == NULL)
    656 			return NULL;
    657 		port = ntohs(sinp->sin_port);
    658 		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
    659 		    port & 0xff) < 0)
    660 			return NULL;
    661 		break;
    662 #ifdef INET6
    663 	case AF_INET6:
    664 		sin6 = nbuf->buf;
    665 		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
    666 		    == NULL)
    667 			return NULL;
    668 		port = ntohs(sin6->sin6_port);
    669 		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
    670 		    port & 0xff) < 0)
    671 			return NULL;
    672 		break;
    673 #endif
    674 	case AF_LOCAL:
    675 		sun = nbuf->buf;
    676 		sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
    677 		ret = strdup(sun->sun_path);
    678 		break;
    679 	default:
    680 		return NULL;
    681 	}
    682 
    683 	return ret;
    684 }
    685 
    686 struct netbuf *
    687 __rpc_uaddr2taddr_af(int af, const char *uaddr)
    688 {
    689 	struct netbuf *ret = NULL;
    690 	char *addrstr, *p;
    691 	unsigned port, portlo, porthi;
    692 	struct sockaddr_in *sinp;
    693 #ifdef INET6
    694 	struct sockaddr_in6 *sin6;
    695 #endif
    696 	struct sockaddr_un *sun;
    697 
    698 	_DIAGASSERT(uaddr != NULL);
    699 
    700 	addrstr = strdup(uaddr);
    701 	if (addrstr == NULL)
    702 		return NULL;
    703 
    704 	/*
    705 	 * AF_LOCAL addresses are expected to be absolute
    706 	 * pathnames, anything else will be AF_INET or AF_INET6.
    707 	 */
    708 	port = 0;
    709 	if (*addrstr != '/') {
    710 		p = strrchr(addrstr, '.');
    711 		if (p == NULL)
    712 			goto out;
    713 		portlo = (unsigned)atoi(p + 1);
    714 		*p = '\0';
    715 
    716 		p = strrchr(addrstr, '.');
    717 		if (p == NULL)
    718 			goto out;
    719 		porthi = (unsigned)atoi(p + 1);
    720 		*p = '\0';
    721 		port = (porthi << 8) | portlo;
    722 	}
    723 
    724 	ret = malloc(sizeof(*ret));
    725 	if (ret == NULL)
    726 		goto out;
    727 
    728 	switch (af) {
    729 	case AF_INET:
    730 		sinp = malloc(sizeof(*sinp));
    731 		if (sinp == NULL)
    732 			goto out;
    733 		memset(sinp, 0, sizeof *sinp);
    734 		sinp->sin_family = AF_INET;
    735 		sinp->sin_port = htons(port);
    736 		if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) {
    737 			free(sinp);
    738 			free(ret);
    739 			ret = NULL;
    740 			goto out;
    741 		}
    742 		sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp;
    743 		ret->buf = sinp;
    744 		break;
    745 #ifdef INET6
    746 	case AF_INET6:
    747 		sin6 = malloc(sizeof(*sin6));
    748 		if (sin6 == NULL)
    749 			goto out;
    750 		memset(sin6, 0, sizeof *sin6);
    751 		sin6->sin6_family = AF_INET6;
    752 		sin6->sin6_port = htons(port);
    753 		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
    754 			free(sin6);
    755 			free(ret);
    756 			ret = NULL;
    757 			goto out;
    758 		}
    759 		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
    760 		ret->buf = sin6;
    761 		break;
    762 #endif
    763 	case AF_LOCAL:
    764 		sun = malloc(sizeof(*sun));
    765 		if (sun == NULL)
    766 			goto out;
    767 		memset(sun, 0, sizeof *sun);
    768 		sun->sun_family = AF_LOCAL;
    769 		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
    770 		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
    771 		ret->buf = sun;
    772 		break;
    773 	default:
    774 		break;
    775 	}
    776 out:
    777 	free(addrstr);
    778 	return ret;
    779 }
    780 
    781 int
    782 __rpc_seman2socktype(int semantics)
    783 {
    784 	switch (semantics) {
    785 	case NC_TPI_CLTS:
    786 		return SOCK_DGRAM;
    787 	case NC_TPI_COTS_ORD:
    788 		return SOCK_STREAM;
    789 	case NC_TPI_RAW:
    790 		return SOCK_RAW;
    791 	default:
    792 		break;
    793 	}
    794 
    795 	return -1;
    796 }
    797 
    798 int
    799 __rpc_socktype2seman(int socktype)
    800 {
    801 	switch (socktype) {
    802 	case SOCK_DGRAM:
    803 		return NC_TPI_CLTS;
    804 	case SOCK_STREAM:
    805 		return NC_TPI_COTS_ORD;
    806 	case SOCK_RAW:
    807 		return NC_TPI_RAW;
    808 	default:
    809 		break;
    810 	}
    811 
    812 	return -1;
    813 }
    814 
    815 /*
    816  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
    817  * Here, we compare the original server address to that of the RPC
    818  * service we just received back from a call to rpcbind on the remote
    819  * machine. If they are both "link local" or "site local", copy
    820  * the scope id of the server address over to the service address.
    821  */
    822 /* ARGSUSED */
    823 int
    824 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
    825 {
    826 #ifdef INET6
    827 	struct sockaddr *sa_new, *sa_svc;
    828 	struct sockaddr_in6 *sin6_new, *sin6_svc;
    829 
    830 	_DIAGASSERT(new != NULL);
    831 	_DIAGASSERT(svc != NULL);
    832 
    833 	sa_svc = (struct sockaddr *)svc->buf;
    834 	sa_new = (struct sockaddr *)new->buf;
    835 
    836 	if (sa_new->sa_family == sa_svc->sa_family &&
    837 	    sa_new->sa_family == AF_INET6) {
    838 		sin6_new = (struct sockaddr_in6 *)new->buf;
    839 		sin6_svc = (struct sockaddr_in6 *)svc->buf;
    840 
    841 		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
    842 		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
    843 		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
    844 		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
    845 			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
    846 		}
    847 	}
    848 #endif
    849 	return 1;
    850 }
    851 
    852 int
    853 __rpc_sockisbound(int fd)
    854 {
    855 	struct sockaddr_storage ss;
    856 	socklen_t slen;
    857 
    858 	slen = sizeof (struct sockaddr_storage);
    859 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
    860 		return 0;
    861 
    862 	switch (ss.ss_family) {
    863 		case AF_INET:
    864 			return (((struct sockaddr_in *)
    865 			    (void *)&ss)->sin_port != 0);
    866 #ifdef INET6
    867 		case AF_INET6:
    868 			return (((struct sockaddr_in6 *)
    869 			    (void *)&ss)->sin6_port != 0);
    870 #endif
    871 		case AF_LOCAL:
    872 			/* XXX check this */
    873 			return (((struct sockaddr_un *)
    874 			    (void *)&ss)->sun_path[0] != '\0');
    875 		default:
    876 			break;
    877 	}
    878 
    879 	return 0;
    880 }
    881 
    882 /*
    883  * For TCP transport, Host Requirements RFCs mandate
    884  * Nagle (RFC-896) processing.  But for RPC, Nagle
    885  * processing adds adds unwanted latency to the last,
    886  * partial TCP segment of each RPC message. See:
    887  *   R. W. Scheifler and J. Gettys, The X Window System,
    888  *   ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69.
    889  * So for TCP transport, disable Nagle via TCP_NODELAY.
    890  * XXX: moral equivalent for non-TCP protocols?
    891  */
    892 int
    893 __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si)
    894 {
    895 	int one = 1;
    896 	if (si->si_proto != IPPROTO_TCP)
    897 		return 0;
    898 	return setsockopt(fd, si->si_proto, TCP_NODELAY, &one, sizeof(one));
    899 }
    900