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