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