Home | History | Annotate | Line # | Download | only in rpc
rpc_generic.c revision 1.25
      1 /*	$NetBSD: rpc_generic.c,v 1.25 2012/03/13 21:13:44 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.25 2012/03/13 21:13:44 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 = NULL;
    256 	char *netid_udp = NULL;
    257 	static char *netid_tcp_main;
    258 	static char *netid_udp_main;
    259 	struct netconfig *dummy;
    260 #ifdef _REENTRANT
    261 	if (__isthreaded == 0) {
    262 		netid_udp = netid_udp_main;
    263 		netid_tcp = netid_tcp_main;
    264 	} else {
    265 		thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup);
    266 		netid_tcp = thr_getspecific(tcp_key);
    267 		netid_udp = thr_getspecific(udp_key);
    268 	}
    269 #else
    270 	netid_udp = netid_udp_main;
    271 	netid_tcp = netid_tcp_main;
    272 #endif
    273 
    274 	_DIAGASSERT(nettype != NULL);
    275 
    276 	if (!netid_udp && !netid_tcp) {
    277 		struct netconfig *nconf;
    278 		void *confighandle;
    279 
    280 		if (!(confighandle = setnetconfig())) {
    281 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
    282 			return (NULL);
    283 		}
    284 		while ((nconf = getnetconfig(confighandle)) != NULL) {
    285 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
    286 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
    287 					netid_tcp = strdup(nconf->nc_netid);
    288 					if (netid_tcp == NULL)
    289 						return NULL;
    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 					if (netid_udp == NULL)
    303 						return NULL;
    304 #ifdef _REENTRANT
    305 					if (__isthreaded == 0)
    306 						netid_udp_main = netid_udp;
    307 					else
    308 						thr_setspecific(udp_key,
    309 							(void *) netid_udp);
    310 #else
    311 					netid_udp_main = netid_udp;
    312 #endif
    313 				}
    314 			}
    315 		}
    316 		endnetconfig(confighandle);
    317 	}
    318 	if (strcmp(nettype, "udp") == 0)
    319 		netid = netid_udp;
    320 	else if (strcmp(nettype, "tcp") == 0)
    321 		netid = netid_tcp;
    322 	else {
    323 		return (NULL);
    324 	}
    325 	if ((netid == NULL) || (netid[0] == 0)) {
    326 		return (NULL);
    327 	}
    328 	dummy = getnetconfigent(netid);
    329 	return (dummy);
    330 }
    331 
    332 /*
    333  * Returns the type of the nettype, which should then be used with
    334  * __rpc_getconf().
    335  */
    336 void *
    337 __rpc_setconf(nettype)
    338 	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(vhandle)
    384 	void *vhandle;
    385 {
    386 	struct handle *handle;
    387 	struct netconfig *nconf;
    388 
    389 	handle = (struct handle *)vhandle;
    390 	if (handle == NULL) {
    391 		return (NULL);
    392 	}
    393 	for (;;) {
    394 		if (handle->nflag)
    395 			nconf = getnetpath(handle->nhandle);
    396 		else
    397 			nconf = getnetconfig(handle->nhandle);
    398 		if (nconf == NULL)
    399 			break;
    400 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
    401 			(nconf->nc_semantics != NC_TPI_COTS) &&
    402 			(nconf->nc_semantics != NC_TPI_COTS_ORD))
    403 			continue;
    404 		switch (handle->nettype) {
    405 		case _RPC_VISIBLE:
    406 			if (!(nconf->nc_flag & NC_VISIBLE))
    407 				continue;
    408 			/* FALLTHROUGH */
    409 		case _RPC_NETPATH:	/* Be happy */
    410 			break;
    411 		case _RPC_CIRCUIT_V:
    412 			if (!(nconf->nc_flag & NC_VISIBLE))
    413 				continue;
    414 			/* FALLTHROUGH */
    415 		case _RPC_CIRCUIT_N:
    416 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
    417 				(nconf->nc_semantics != NC_TPI_COTS_ORD))
    418 				continue;
    419 			break;
    420 		case _RPC_DATAGRAM_V:
    421 			if (!(nconf->nc_flag & NC_VISIBLE))
    422 				continue;
    423 			/* FALLTHROUGH */
    424 		case _RPC_DATAGRAM_N:
    425 			if (nconf->nc_semantics != NC_TPI_CLTS)
    426 				continue;
    427 			break;
    428 		case _RPC_TCP:
    429 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
    430 				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
    431 				(strcmp(nconf->nc_protofmly, NC_INET)
    432 #ifdef INET6
    433 				 && strcmp(nconf->nc_protofmly, NC_INET6))
    434 #else
    435 				)
    436 #endif
    437 				||
    438 				strcmp(nconf->nc_proto, NC_TCP))
    439 				continue;
    440 			break;
    441 		case _RPC_UDP:
    442 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
    443 				(strcmp(nconf->nc_protofmly, NC_INET)
    444 #ifdef INET6
    445 				&& strcmp(nconf->nc_protofmly, NC_INET6))
    446 #else
    447 				)
    448 #endif
    449 				||
    450 				strcmp(nconf->nc_proto, NC_UDP))
    451 				continue;
    452 			break;
    453 		}
    454 		break;
    455 	}
    456 	return (nconf);
    457 }
    458 
    459 void
    460 __rpc_endconf(vhandle)
    461 	void * vhandle;
    462 {
    463 	struct handle *handle;
    464 
    465 	handle = (struct handle *) vhandle;
    466 	if (handle == NULL) {
    467 		return;
    468 	}
    469 	if (handle->nflag) {
    470 		endnetpath(handle->nhandle);
    471 	} else {
    472 		endnetconfig(handle->nhandle);
    473 	}
    474 	free(handle);
    475 }
    476 
    477 /*
    478  * Used to ping the NULL procedure for clnt handle.
    479  * Returns NULL if fails, else a non-NULL pointer.
    480  */
    481 void *
    482 rpc_nullproc(clnt)
    483 	CLIENT *clnt;
    484 {
    485 	struct timeval TIMEOUT = {25, 0};
    486 
    487 	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
    488 		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
    489 		return (NULL);
    490 	}
    491 	return ((void *) clnt);
    492 }
    493 
    494 /*
    495  * Try all possible transports until
    496  * one succeeds in finding the netconf for the given fd.
    497  */
    498 struct netconfig *
    499 __rpcgettp(fd)
    500 	int fd;
    501 {
    502 	const char *netid;
    503 	struct __rpc_sockinfo si;
    504 
    505 	if (!__rpc_fd2sockinfo(fd, &si))
    506 		return NULL;
    507 
    508 	if (!__rpc_sockinfo2netid(&si, &netid))
    509 		return NULL;
    510 
    511 	return getnetconfigent(__UNCONST(netid));
    512 }
    513 
    514 int
    515 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
    516 {
    517 	socklen_t len;
    518 	int type, proto;
    519 	struct sockaddr_storage ss;
    520 
    521 	_DIAGASSERT(sip != NULL);
    522 
    523 	len = sizeof ss;
    524 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
    525 		return 0;
    526 	sip->si_alen = len;
    527 
    528 	len = sizeof type;
    529 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
    530 		return 0;
    531 
    532 	/* XXX */
    533 	if (ss.ss_family != AF_LOCAL) {
    534 		if (type == SOCK_STREAM)
    535 			proto = IPPROTO_TCP;
    536 		else if (type == SOCK_DGRAM)
    537 			proto = IPPROTO_UDP;
    538 		else
    539 			return 0;
    540 	} else
    541 		proto = 0;
    542 
    543 	sip->si_af = ss.ss_family;
    544 	sip->si_proto = proto;
    545 	sip->si_socktype = type;
    546 
    547 	return 1;
    548 }
    549 
    550 /*
    551  * Linear search, but the number of entries is small.
    552  */
    553 int
    554 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
    555 {
    556 	size_t i;
    557 
    558 	_DIAGASSERT(nconf != NULL);
    559 	_DIAGASSERT(sip != NULL);
    560 
    561 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    562 		if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
    563 			sip->si_af = na_cvt[i].af;
    564 			sip->si_proto = na_cvt[i].protocol;
    565 			sip->si_socktype =
    566 			    __rpc_seman2socktype((int)nconf->nc_semantics);
    567 			if (sip->si_socktype == -1)
    568 				return 0;
    569 			sip->si_alen = __rpc_get_a_size(sip->si_af);
    570 			return 1;
    571 		}
    572 
    573 	return 0;
    574 }
    575 
    576 int
    577 __rpc_nconf2fd(const struct netconfig *nconf)
    578 {
    579 	struct __rpc_sockinfo si;
    580 
    581 	_DIAGASSERT(nconf != NULL);
    582 
    583 	if (!__rpc_nconf2sockinfo(nconf, &si))
    584 		return 0;
    585 
    586 	return socket(si.si_af, si.si_socktype, si.si_proto);
    587 }
    588 
    589 int
    590 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
    591 {
    592 	size_t i;
    593 
    594 	_DIAGASSERT(sip != NULL);
    595 	/* netid may be NULL */
    596 
    597 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    598 		if (na_cvt[i].af == sip->si_af &&
    599 		    na_cvt[i].protocol == sip->si_proto) {
    600 			if (netid)
    601 				*netid = na_cvt[i].netid;
    602 			return 1;
    603 		}
    604 
    605 	return 0;
    606 }
    607 
    608 char *
    609 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
    610 {
    611 	struct __rpc_sockinfo si;
    612 
    613 	_DIAGASSERT(nconf != NULL);
    614 	_DIAGASSERT(nbuf != NULL);
    615 
    616 	if (!__rpc_nconf2sockinfo(nconf, &si))
    617 		return NULL;
    618 	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
    619 }
    620 
    621 struct netbuf *
    622 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
    623 {
    624 	struct __rpc_sockinfo si;
    625 
    626 	_DIAGASSERT(nconf != NULL);
    627 	_DIAGASSERT(uaddr != NULL);
    628 
    629 	if (!__rpc_nconf2sockinfo(nconf, &si))
    630 		return NULL;
    631 	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
    632 }
    633 
    634 char *
    635 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
    636 {
    637 	char *ret;
    638 	struct sockaddr_in *sinp;
    639 	struct sockaddr_un *sun;
    640 	char namebuf[INET_ADDRSTRLEN];
    641 #ifdef INET6
    642 	struct sockaddr_in6 *sin6;
    643 	char namebuf6[INET6_ADDRSTRLEN];
    644 #endif
    645 	u_int16_t port;
    646 
    647 	_DIAGASSERT(nbuf != NULL);
    648 
    649 	switch (af) {
    650 	case AF_INET:
    651 		sinp = nbuf->buf;
    652 		if (inet_ntop(af, &sinp->sin_addr, namebuf,
    653 		    (socklen_t)sizeof namebuf) == NULL)
    654 			return NULL;
    655 		port = ntohs(sinp->sin_port);
    656 		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
    657 		    port & 0xff) < 0)
    658 			return NULL;
    659 		break;
    660 #ifdef INET6
    661 	case AF_INET6:
    662 		sin6 = nbuf->buf;
    663 		if (inet_ntop(af, &sin6->sin6_addr, namebuf6,
    664 		    (socklen_t)sizeof namebuf6) == NULL)
    665 			return NULL;
    666 		port = ntohs(sin6->sin6_port);
    667 		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
    668 		    port & 0xff) < 0)
    669 			return NULL;
    670 		break;
    671 #endif
    672 	case AF_LOCAL:
    673 		sun = nbuf->buf;
    674 		sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
    675 		ret = strdup(sun->sun_path);
    676 		break;
    677 	default:
    678 		return NULL;
    679 	}
    680 
    681 	return ret;
    682 }
    683 
    684 struct netbuf *
    685 __rpc_uaddr2taddr_af(int af, const char *uaddr)
    686 {
    687 	struct netbuf *ret = NULL;
    688 	char *addrstr, *p;
    689 	unsigned port, portlo, porthi;
    690 	size_t len;
    691 	struct sockaddr_in *sinp;
    692 #ifdef INET6
    693 	struct sockaddr_in6 *sin6;
    694 #endif
    695 	struct sockaddr_un *sun;
    696 
    697 	_DIAGASSERT(uaddr != NULL);
    698 
    699 	addrstr = strdup(uaddr);
    700 	if (addrstr == NULL)
    701 		return NULL;
    702 
    703 	/*
    704 	 * AF_LOCAL addresses are expected to be absolute
    705 	 * pathnames, anything else will be AF_INET or AF_INET6.
    706 	 */
    707 	port = 0;
    708 	if (*addrstr != '/') {
    709 		p = strrchr(addrstr, '.');
    710 		if (p == NULL)
    711 			goto out;
    712 		portlo = (unsigned)atoi(p + 1);
    713 		*p = '\0';
    714 
    715 		p = strrchr(addrstr, '.');
    716 		if (p == NULL)
    717 			goto out;
    718 		porthi = (unsigned)atoi(p + 1);
    719 		*p = '\0';
    720 		port = (porthi << 8) | portlo;
    721 	}
    722 
    723 	ret = malloc(sizeof(*ret));
    724 	if (ret == NULL)
    725 		goto out;
    726 
    727 	switch (af) {
    728 	case AF_INET:
    729 		sinp = malloc(sizeof(*sinp));
    730 		if (sinp == NULL)
    731 			goto out;
    732 		memset(sinp, 0, sizeof *sinp);
    733 		sinp->sin_family = AF_INET;
    734 		sinp->sin_port = htons(port);
    735 		if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) {
    736 			free(sinp);
    737 			free(ret);
    738 			ret = NULL;
    739 			goto out;
    740 		}
    741 		sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp;
    742 		ret->buf = sinp;
    743 		break;
    744 #ifdef INET6
    745 	case AF_INET6:
    746 		sin6 = malloc(sizeof(*sin6));
    747 		if (sin6 == NULL)
    748 			goto out;
    749 		memset(sin6, 0, sizeof *sin6);
    750 		sin6->sin6_family = AF_INET6;
    751 		sin6->sin6_port = htons(port);
    752 		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
    753 			free(sin6);
    754 			free(ret);
    755 			ret = NULL;
    756 			goto out;
    757 		}
    758 		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
    759 		ret->buf = sin6;
    760 		break;
    761 #endif
    762 	case AF_LOCAL:
    763 		sun = malloc(sizeof(*sun));
    764 		if (sun == NULL)
    765 			goto out;
    766 		memset(sun, 0, sizeof *sun);
    767 		sun->sun_family = AF_LOCAL;
    768 		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
    769 		len = SUN_LEN(sun);
    770 		_DIAGASSERT(__type_fit(uint8_t, len));
    771 		ret->len = ret->maxlen = sun->sun_len = (uint8_t)len;
    772 		ret->buf = sun;
    773 		break;
    774 	default:
    775 		break;
    776 	}
    777 out:
    778 	free(addrstr);
    779 	return ret;
    780 }
    781 
    782 int
    783 __rpc_seman2socktype(int semantics)
    784 {
    785 	switch (semantics) {
    786 	case NC_TPI_CLTS:
    787 		return SOCK_DGRAM;
    788 	case NC_TPI_COTS_ORD:
    789 		return SOCK_STREAM;
    790 	case NC_TPI_RAW:
    791 		return SOCK_RAW;
    792 	default:
    793 		break;
    794 	}
    795 
    796 	return -1;
    797 }
    798 
    799 int
    800 __rpc_socktype2seman(int socktype)
    801 {
    802 	switch (socktype) {
    803 	case SOCK_DGRAM:
    804 		return NC_TPI_CLTS;
    805 	case SOCK_STREAM:
    806 		return NC_TPI_COTS_ORD;
    807 	case SOCK_RAW:
    808 		return NC_TPI_RAW;
    809 	default:
    810 		break;
    811 	}
    812 
    813 	return -1;
    814 }
    815 
    816 /*
    817  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
    818  * Here, we compare the original server address to that of the RPC
    819  * service we just received back from a call to rpcbind on the remote
    820  * machine. If they are both "link local" or "site local", copy
    821  * the scope id of the server address over to the service address.
    822  */
    823 /* ARGSUSED */
    824 int
    825 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
    826 {
    827 #ifdef INET6
    828 	struct sockaddr *sa_new, *sa_svc;
    829 	struct sockaddr_in6 *sin6_new, *sin6_svc;
    830 
    831 	_DIAGASSERT(new != NULL);
    832 	_DIAGASSERT(svc != NULL);
    833 
    834 	sa_svc = (struct sockaddr *)svc->buf;
    835 	sa_new = (struct sockaddr *)new->buf;
    836 
    837 	if (sa_new->sa_family == sa_svc->sa_family &&
    838 	    sa_new->sa_family == AF_INET6) {
    839 		sin6_new = (struct sockaddr_in6 *)new->buf;
    840 		sin6_svc = (struct sockaddr_in6 *)svc->buf;
    841 
    842 		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
    843 		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
    844 		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
    845 		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
    846 			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
    847 		}
    848 	}
    849 #endif
    850 	return 1;
    851 }
    852 
    853 int
    854 __rpc_sockisbound(int fd)
    855 {
    856 	struct sockaddr_storage ss;
    857 	socklen_t slen;
    858 
    859 	slen = sizeof (struct sockaddr_storage);
    860 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
    861 		return 0;
    862 
    863 	switch (ss.ss_family) {
    864 		case AF_INET:
    865 			return (((struct sockaddr_in *)
    866 			    (void *)&ss)->sin_port != 0);
    867 #ifdef INET6
    868 		case AF_INET6:
    869 			return (((struct sockaddr_in6 *)
    870 			    (void *)&ss)->sin6_port != 0);
    871 #endif
    872 		case AF_LOCAL:
    873 			/* XXX check this */
    874 			return (((struct sockaddr_un *)
    875 			    (void *)&ss)->sun_path[0] != '\0');
    876 		default:
    877 			break;
    878 	}
    879 
    880 	return 0;
    881 }
    882 
    883 /*
    884  * For TCP transport, Host Requirements RFCs mandate
    885  * Nagle (RFC-896) processing.  But for RPC, Nagle
    886  * processing adds adds unwanted latency to the last,
    887  * partial TCP segment of each RPC message. See:
    888  *   R. W. Scheifler and J. Gettys, The X Window System,
    889  *   ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69.
    890  * So for TCP transport, disable Nagle via TCP_NODELAY.
    891  * XXX: moral equivalent for non-TCP protocols?
    892  */
    893 int
    894 __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si)
    895 {
    896 	int one = 1;
    897 	if (si->si_proto != IPPROTO_TCP)
    898 		return 0;
    899 	return setsockopt(fd, si->si_proto, TCP_NODELAY, &one,
    900 	    (socklen_t)sizeof(one));
    901 }
    902