Home | History | Annotate | Line # | Download | only in rpc
rpc_generic.c revision 1.4
      1 /*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink 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 "namespace.h"
     43 #include <sys/types.h>
     44 #include <sys/param.h>
     45 #include <sys/socket.h>
     46 #include <sys/un.h>
     47 #include <sys/resource.h>
     48 #include <netinet/in.h>
     49 #include <arpa/inet.h>
     50 #include <rpc/rpc.h>
     51 #include <ctype.h>
     52 #include <stdio.h>
     53 #include <netdb.h>
     54 #include <netconfig.h>
     55 #include <malloc.h>
     56 #include <string.h>
     57 #include <syslog.h>
     58 #include <rpc/nettype.h>
     59 #include "rpc_com.h"
     60 
     61 struct handle {
     62 	NCONF_HANDLE *nhandle;
     63 	int nflag;		/* Whether NETPATH or NETCONFIG */
     64 	int nettype;
     65 };
     66 
     67 struct _rpcnettype {
     68 	const char *name;
     69 	const int type;
     70 } _rpctypelist[] = {
     71 	{ "netpath", _RPC_NETPATH },
     72 	{ "visible", _RPC_VISIBLE },
     73 	{ "circuit_v", _RPC_CIRCUIT_V },
     74 	{ "datagram_v", _RPC_DATAGRAM_V },
     75 	{ "circuit_n", _RPC_CIRCUIT_N },
     76 	{ "datagram_n", _RPC_DATAGRAM_N },
     77 	{ "tcp", _RPC_TCP },
     78 	{ "udp", _RPC_UDP },
     79 	{ 0, _RPC_NONE }
     80 };
     81 
     82 struct netid_af {
     83 	const char	*netid;
     84 	int		af;
     85 	int		protocol;
     86 };
     87 
     88 static struct netid_af na_cvt[] = {
     89 	{ "udp",  AF_INET,  IPPROTO_UDP },
     90 	{ "tcp",  AF_INET,  IPPROTO_TCP },
     91 #ifdef INET6
     92 	{ "udp6", AF_INET6, IPPROTO_UDP },
     93 	{ "tcp6", AF_INET6, IPPROTO_TCP },
     94 #endif
     95 	{ "local", AF_LOCAL, 0 }
     96 };
     97 
     98 #if 0
     99 static char *strlocase __P((char *));
    100 #endif
    101 static int getnettype __P((const char *));
    102 
    103 /*
    104  * Cache the result of getrlimit(), so we don't have to do an
    105  * expensive call every time.
    106  */
    107 int
    108 __rpc_dtbsize()
    109 {
    110 	static int tbsize;
    111 	struct rlimit rl;
    112 
    113 	if (tbsize) {
    114 		return (tbsize);
    115 	}
    116 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
    117 		return (tbsize = (int)rl.rlim_max);
    118 	}
    119 	/*
    120 	 * Something wrong.  I'll try to save face by returning a
    121 	 * pessimistic number.
    122 	 */
    123 	return (32);
    124 }
    125 
    126 
    127 /*
    128  * Find the appropriate buffer size
    129  */
    130 u_int
    131 /*ARGSUSED*/
    132 __rpc_get_t_size(af, proto, size)
    133 	int af, proto;
    134 	int size;	/* Size requested */
    135 {
    136 	int maxsize;
    137 
    138 	switch (proto) {
    139 	case IPPROTO_TCP:
    140 		maxsize = 65536;	/* XXX */
    141 		break;
    142 	case IPPROTO_UDP:
    143 		maxsize = 8192;		/* XXX */
    144 		break;
    145 	default:
    146 		maxsize = RPC_MAXDATASIZE;
    147 		break;
    148 	}
    149 	if (size == 0)
    150 		return maxsize;
    151 
    152 	/* Check whether the value is within the upper max limit */
    153 	return (size > maxsize ? (u_int)maxsize : (u_int)size);
    154 }
    155 
    156 /*
    157  * Find the appropriate address buffer size
    158  */
    159 u_int
    160 __rpc_get_a_size(af)
    161 	int af;
    162 {
    163 	switch (af) {
    164 	case AF_INET:
    165 		return sizeof (struct sockaddr_in);
    166 #ifdef INET6
    167 	case AF_INET6:
    168 		return sizeof (struct sockaddr_in6);
    169 #endif
    170 	case AF_LOCAL:
    171 		return sizeof (struct sockaddr_un);
    172 	default:
    173 		break;
    174 	}
    175 	return ((u_int)RPC_MAXADDRSIZE);
    176 }
    177 
    178 #if 0
    179 static char *
    180 strlocase(p)
    181 	char *p;
    182 {
    183 	char *t = p;
    184 
    185 	for (; *p; p++)
    186 		if (isupper(*p))
    187 			*p = tolower(*p);
    188 	return (t);
    189 }
    190 #endif
    191 
    192 /*
    193  * Returns the type of the network as defined in <rpc/nettype.h>
    194  * If nettype is NULL, it defaults to NETPATH.
    195  */
    196 static int
    197 getnettype(nettype)
    198 	const char *nettype;
    199 {
    200 	int i;
    201 
    202 	if ((nettype == NULL) || (nettype[0] == NULL)) {
    203 		return (_RPC_NETPATH);	/* Default */
    204 	}
    205 
    206 #if 0
    207 	nettype = strlocase(nettype);
    208 #endif
    209 	for (i = 0; _rpctypelist[i].name; i++)
    210 		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
    211 			return (_rpctypelist[i].type);
    212 		}
    213 	return (_rpctypelist[i].type);
    214 }
    215 
    216 /*
    217  * For the given nettype (tcp or udp only), return the first structure found.
    218  * This should be freed by calling freenetconfigent()
    219  */
    220 struct netconfig *
    221 __rpc_getconfip(nettype)
    222 	const char *nettype;
    223 {
    224 	char *netid;
    225 	char *netid_tcp = (char *) NULL;
    226 	char *netid_udp = (char *) NULL;
    227 	static char *netid_tcp_main;
    228 	static char *netid_udp_main;
    229 	struct netconfig *dummy;
    230 #ifdef __REENT
    231 	int main_thread;
    232 	static thread_key_t tcp_key, udp_key;
    233 	extern mutex_t tsd_lock;
    234 
    235 	if ((main_thread = _thr_main())) {
    236 		netid_udp = netid_udp_main;
    237 		netid_tcp = netid_tcp_main;
    238 	} else {
    239 		if (tcp_key == 0) {
    240 			mutex_lock(&tsd_lock);
    241 			if (tcp_key == 0)
    242 				thr_keycreate(&tcp_key, free);
    243 			mutex_unlock(&tsd_lock);
    244 		}
    245 		thr_getspecific(tcp_key, (void **) &netid_tcp);
    246 		if (udp_key == 0) {
    247 			mutex_lock(&tsd_lock);
    248 			if (udp_key == 0)
    249 				thr_keycreate(&udp_key, free);
    250 			mutex_unlock(&tsd_lock);
    251 		}
    252 		thr_getspecific(udp_key, (void **) &netid_udp);
    253 	}
    254 #else
    255 	netid_udp = netid_udp_main;
    256 	netid_tcp = netid_tcp_main;
    257 #endif
    258 	if (!netid_udp && !netid_tcp) {
    259 		struct netconfig *nconf;
    260 		void *confighandle;
    261 
    262 		if (!(confighandle = setnetconfig())) {
    263 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
    264 			return (NULL);
    265 		}
    266 		while ((nconf = getnetconfig(confighandle)) != NULL) {
    267 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
    268 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
    269 					netid_tcp = strdup(nconf->nc_netid);
    270 #ifdef __REENT
    271 					if (main_thread)
    272 						netid_tcp_main = netid_tcp;
    273 					else
    274 						thr_setspecific(tcp_key,
    275 							(void *) netid_tcp);
    276 #else
    277 					netid_tcp_main = netid_tcp;
    278 #endif
    279 				} else
    280 				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
    281 					netid_udp = strdup(nconf->nc_netid);
    282 #ifdef __REENT
    283 					if (main_thread)
    284 						netid_udp_main = netid_udp;
    285 					else
    286 						thr_setspecific(udp_key,
    287 							(void *) netid_udp);
    288 #else
    289 					netid_udp_main = netid_udp;
    290 #endif
    291 				}
    292 			}
    293 		}
    294 		endnetconfig(confighandle);
    295 	}
    296 	if (strcmp(nettype, "udp") == 0)
    297 		netid = netid_udp;
    298 	else if (strcmp(nettype, "tcp") == 0)
    299 		netid = netid_tcp;
    300 	else {
    301 		return (NULL);
    302 	}
    303 	if ((netid == NULL) || (netid[0] == NULL)) {
    304 		return (NULL);
    305 	}
    306 	dummy = getnetconfigent(netid);
    307 	return (dummy);
    308 }
    309 
    310 /*
    311  * Returns the type of the nettype, which should then be used with
    312  * __rpc_getconf().
    313  */
    314 void *
    315 __rpc_setconf(nettype)
    316 	const char *nettype;
    317 {
    318 	struct handle *handle;
    319 
    320 	handle = (struct handle *) malloc(sizeof (struct handle));
    321 	if (handle == NULL) {
    322 		return (NULL);
    323 	}
    324 	switch (handle->nettype = getnettype(nettype)) {
    325 	case _RPC_NETPATH:
    326 	case _RPC_CIRCUIT_N:
    327 	case _RPC_DATAGRAM_N:
    328 		if (!(handle->nhandle = setnetpath())) {
    329 			free(handle);
    330 			return (NULL);
    331 		}
    332 		handle->nflag = TRUE;
    333 		break;
    334 	case _RPC_VISIBLE:
    335 	case _RPC_CIRCUIT_V:
    336 	case _RPC_DATAGRAM_V:
    337 	case _RPC_TCP:
    338 	case _RPC_UDP:
    339 		if (!(handle->nhandle = setnetconfig())) {
    340 		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
    341 			free(handle);
    342 			return (NULL);
    343 		}
    344 		handle->nflag = FALSE;
    345 		break;
    346 	default:
    347 		return (NULL);
    348 	}
    349 
    350 	return (handle);
    351 }
    352 
    353 /*
    354  * Returns the next netconfig struct for the given "net" type.
    355  * __rpc_setconf() should have been called previously.
    356  */
    357 struct netconfig *
    358 __rpc_getconf(vhandle)
    359 	void *vhandle;
    360 {
    361 	struct handle *handle;
    362 	struct netconfig *nconf;
    363 
    364 	handle = (struct handle *)vhandle;
    365 	if (handle == NULL) {
    366 		return (NULL);
    367 	}
    368 	for (;;) {
    369 		if (handle->nflag)
    370 			nconf = getnetpath(handle->nhandle);
    371 		else
    372 			nconf = getnetconfig(handle->nhandle);
    373 		if (nconf == NULL)
    374 			break;
    375 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
    376 			(nconf->nc_semantics != NC_TPI_COTS) &&
    377 			(nconf->nc_semantics != NC_TPI_COTS_ORD))
    378 			continue;
    379 		switch (handle->nettype) {
    380 		case _RPC_VISIBLE:
    381 			if (!(nconf->nc_flag & NC_VISIBLE))
    382 				continue;
    383 			/* FALLTHROUGH */
    384 		case _RPC_NETPATH:	/* Be happy */
    385 			break;
    386 		case _RPC_CIRCUIT_V:
    387 			if (!(nconf->nc_flag & NC_VISIBLE))
    388 				continue;
    389 			/* FALLTHROUGH */
    390 		case _RPC_CIRCUIT_N:
    391 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
    392 				(nconf->nc_semantics != NC_TPI_COTS_ORD))
    393 				continue;
    394 			break;
    395 		case _RPC_DATAGRAM_V:
    396 			if (!(nconf->nc_flag & NC_VISIBLE))
    397 				continue;
    398 			/* FALLTHROUGH */
    399 		case _RPC_DATAGRAM_N:
    400 			if (nconf->nc_semantics != NC_TPI_CLTS)
    401 				continue;
    402 			break;
    403 		case _RPC_TCP:
    404 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
    405 				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
    406 				(strcmp(nconf->nc_protofmly, NC_INET)
    407 #ifdef INET6
    408 				 && strcmp(nconf->nc_protofmly, NC_INET6))
    409 #else
    410 				)
    411 #endif
    412 				||
    413 				strcmp(nconf->nc_proto, NC_TCP))
    414 				continue;
    415 			break;
    416 		case _RPC_UDP:
    417 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
    418 				(strcmp(nconf->nc_protofmly, NC_INET)
    419 #ifdef INET6
    420 				&& strcmp(nconf->nc_protofmly, NC_INET6))
    421 #else
    422 				)
    423 #endif
    424 				||
    425 				strcmp(nconf->nc_proto, NC_UDP))
    426 				continue;
    427 			break;
    428 		}
    429 		break;
    430 	}
    431 	return (nconf);
    432 }
    433 
    434 void
    435 __rpc_endconf(vhandle)
    436 	void * vhandle;
    437 {
    438 	struct handle *handle;
    439 
    440 	handle = (struct handle *) vhandle;
    441 	if (handle == NULL) {
    442 		return;
    443 	}
    444 	if (handle->nflag) {
    445 		endnetpath(handle->nhandle);
    446 	} else {
    447 		endnetconfig(handle->nhandle);
    448 	}
    449 	free(handle);
    450 }
    451 
    452 /*
    453  * Used to ping the NULL procedure for clnt handle.
    454  * Returns NULL if fails, else a non-NULL pointer.
    455  */
    456 void *
    457 rpc_nullproc(clnt)
    458 	CLIENT *clnt;
    459 {
    460 	struct timeval TIMEOUT = {25, 0};
    461 
    462 	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
    463 		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
    464 		return (NULL);
    465 	}
    466 	return ((void *) clnt);
    467 }
    468 
    469 /*
    470  * Try all possible transports until
    471  * one succeeds in finding the netconf for the given fd.
    472  */
    473 struct netconfig *
    474 __rpcgettp(fd)
    475 	int fd;
    476 {
    477 	const char *netid;
    478 	struct __rpc_sockinfo si;
    479 
    480 	if (!__rpc_fd2sockinfo(fd, &si))
    481 		return NULL;
    482 
    483 	if (!__rpc_sockinfo2netid(&si, &netid))
    484 		return NULL;
    485 
    486 	/*LINTED const castaway*/
    487 	return getnetconfigent((char *)netid);
    488 }
    489 
    490 int
    491 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
    492 {
    493 	socklen_t len;
    494 	int type, proto;
    495 	struct sockaddr_storage ss;
    496 
    497 	len = sizeof ss;
    498 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
    499 		return 0;
    500 	sip->si_alen = len;
    501 
    502 	len = sizeof type;
    503 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
    504 		return 0;
    505 
    506 	/* XXX */
    507 	if (ss.ss_family != AF_LOCAL) {
    508 		if (type == SOCK_STREAM)
    509 			proto = IPPROTO_TCP;
    510 		else if (type == SOCK_DGRAM)
    511 			proto = IPPROTO_UDP;
    512 		else
    513 			return 0;
    514 	} else
    515 		proto = 0;
    516 
    517 	sip->si_af = ss.ss_family;
    518 	sip->si_proto = proto;
    519 	sip->si_socktype = type;
    520 
    521 	return 1;
    522 }
    523 
    524 /*
    525  * Linear search, but the number of entries is small.
    526  */
    527 int
    528 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
    529 {
    530 	int i;
    531 
    532 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    533 		if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
    534 			sip->si_af = na_cvt[i].af;
    535 			sip->si_proto = na_cvt[i].protocol;
    536 			sip->si_socktype =
    537 			    __rpc_seman2socktype((int)nconf->nc_semantics);
    538 			if (sip->si_socktype == -1)
    539 				return 0;
    540 			sip->si_alen = __rpc_get_a_size(sip->si_af);
    541 			return 1;
    542 		}
    543 
    544 	return 0;
    545 }
    546 
    547 int
    548 __rpc_nconf2fd(const struct netconfig *nconf)
    549 {
    550 	struct __rpc_sockinfo si;
    551 
    552 	if (!__rpc_nconf2sockinfo(nconf, &si))
    553 		return 0;
    554 
    555 	return socket(si.si_af, si.si_socktype, si.si_proto);
    556 }
    557 
    558 int
    559 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
    560 {
    561 	int i;
    562 
    563 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
    564 		if (na_cvt[i].af == sip->si_af &&
    565 		    na_cvt[i].protocol == sip->si_proto) {
    566 			if (netid)
    567 				*netid = na_cvt[i].netid;
    568 			return 1;
    569 		}
    570 
    571 	return 0;
    572 }
    573 
    574 char *
    575 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
    576 {
    577 	struct __rpc_sockinfo si;
    578 
    579 	if (!__rpc_nconf2sockinfo(nconf, &si))
    580 		return NULL;
    581 	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
    582 }
    583 
    584 struct netbuf *
    585 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
    586 {
    587 	struct __rpc_sockinfo si;
    588 
    589 	if (!__rpc_nconf2sockinfo(nconf, &si))
    590 		return NULL;
    591 	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
    592 }
    593 
    594 char *
    595 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
    596 {
    597 	char *ret;
    598 	struct sockaddr_in *sin;
    599 	struct sockaddr_un *sun;
    600 	char namebuf[INET_ADDRSTRLEN];
    601 #ifdef INET6
    602 	struct sockaddr_in6 *sin6;
    603 	char namebuf6[INET6_ADDRSTRLEN];
    604 #endif
    605 	u_int16_t port;
    606 
    607 	switch (af) {
    608 	case AF_INET:
    609 		sin = nbuf->buf;
    610 		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
    611 		    == NULL)
    612 			return NULL;
    613 		port = ntohs(sin->sin_port);
    614 		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
    615 		    port & 0xff) < 0)
    616 			return NULL;
    617 		break;
    618 #ifdef INET6
    619 	case AF_INET6:
    620 		sin6 = nbuf->buf;
    621 		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
    622 		    == NULL)
    623 			return NULL;
    624 		port = ntohs(sin6->sin6_port);
    625 		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
    626 		    port & 0xff) < 0)
    627 			return NULL;
    628 		break;
    629 #endif
    630 	case AF_LOCAL:
    631 		sun = nbuf->buf;
    632 		sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
    633 		ret = strdup(sun->sun_path);
    634 		break;
    635 	default:
    636 		return NULL;
    637 	}
    638 
    639 	return ret;
    640 }
    641 
    642 struct netbuf *
    643 __rpc_uaddr2taddr_af(int af, const char *uaddr)
    644 {
    645 	struct netbuf *ret = NULL;
    646 	char *addrstr, *p;
    647 	unsigned port, portlo, porthi;
    648 	struct sockaddr_in *sin;
    649 #ifdef INET6
    650 	struct sockaddr_in6 *sin6;
    651 #endif
    652 	struct sockaddr_un *sun;
    653 
    654 	addrstr = strdup(uaddr);
    655 	if (addrstr == NULL)
    656 		return NULL;
    657 
    658 	/*
    659 	 * AF_LOCAL addresses are expected to be absolute
    660 	 * pathnames, anything else will be AF_INET or AF_INET6.
    661 	 */
    662 	if (*addrstr != '/') {
    663 		p = strrchr(addrstr, '.');
    664 		if (p == NULL)
    665 			goto out;
    666 		portlo = (unsigned)atoi(p + 1);
    667 		*p = '\0';
    668 
    669 		p = strrchr(addrstr, '.');
    670 		if (p == NULL)
    671 			goto out;
    672 		porthi = (unsigned)atoi(p + 1);
    673 		*p = '\0';
    674 		port = (porthi << 8) | portlo;
    675 	}
    676 
    677 	ret = (struct netbuf *)malloc(sizeof *ret);
    678 
    679 	switch (af) {
    680 	case AF_INET:
    681 		sin = (struct sockaddr_in *)malloc(sizeof *sin);
    682 		if (sin == NULL)
    683 			goto out;
    684 		memset(sin, 0, sizeof *sin);
    685 		sin->sin_family = AF_INET;
    686 		sin->sin_port = htons(port);
    687 		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
    688 			free(sin);
    689 			free(ret);
    690 			ret = NULL;
    691 			goto out;
    692 		}
    693 		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
    694 		ret->buf = sin;
    695 		break;
    696 #ifdef INET6
    697 	case AF_INET6:
    698 		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
    699 		if (sin6 == NULL)
    700 			goto out;
    701 		memset(sin6, 0, sizeof *sin6);
    702 		sin6->sin6_family = AF_INET6;
    703 		sin6->sin6_port = htons(port);
    704 		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
    705 			free(sin);
    706 			free(ret);
    707 			ret = NULL;
    708 			goto out;
    709 		}
    710 		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
    711 		ret->buf = sin6;
    712 		break;
    713 #endif
    714 	case AF_LOCAL:
    715 		sun = (struct sockaddr_un *)malloc(sizeof *sun);
    716 		if (sun == NULL)
    717 			goto out;
    718 		memset(sun, 0, sizeof *sun);
    719 		sun->sun_family = AF_LOCAL;
    720 		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
    721 		break;
    722 	default:
    723 		break;
    724 	}
    725 out:
    726 	free(addrstr);
    727 	return ret;
    728 }
    729 
    730 int
    731 __rpc_seman2socktype(int semantics)
    732 {
    733 	switch (semantics) {
    734 	case NC_TPI_CLTS:
    735 		return SOCK_DGRAM;
    736 	case NC_TPI_COTS_ORD:
    737 		return SOCK_STREAM;
    738 	case NC_TPI_RAW:
    739 		return SOCK_RAW;
    740 	default:
    741 		break;
    742 	}
    743 
    744 	return -1;
    745 }
    746 
    747 int
    748 __rpc_socktype2seman(int socktype)
    749 {
    750 	switch (socktype) {
    751 	case SOCK_DGRAM:
    752 		return NC_TPI_CLTS;
    753 	case SOCK_STREAM:
    754 		return NC_TPI_COTS_ORD;
    755 	case SOCK_RAW:
    756 		return NC_TPI_RAW;
    757 	default:
    758 		break;
    759 	}
    760 
    761 	return -1;
    762 }
    763 
    764 /*
    765  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
    766  * Here, we compare the original server address to that of the RPC
    767  * service we just received back from a call to rpcbind on the remote
    768  * machine. If they are both "link local" or "site local", copy
    769  * the scope id of the server address over to the service address.
    770  */
    771 int
    772 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
    773 {
    774 #ifdef INET6
    775 	struct sockaddr *sa_new, *sa_svc;
    776 	struct sockaddr_in6 *sin6_new, *sin6_svc;
    777 
    778 	sa_svc = (struct sockaddr *)svc->buf;
    779 	sa_new = (struct sockaddr *)new->buf;
    780 
    781 	if (sa_new->sa_family == sa_svc->sa_family &&
    782 	    sa_new->sa_family == AF_INET6) {
    783 		sin6_new = (struct sockaddr_in6 *)new->buf;
    784 		sin6_svc = (struct sockaddr_in6 *)svc->buf;
    785 
    786 		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
    787 		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
    788 		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
    789 		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
    790 			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
    791 		}
    792 	}
    793 #endif
    794 	return 1;
    795 }
    796 
    797 int
    798 __rpc_sockisbound(int fd)
    799 {
    800 	struct sockaddr_storage ss;
    801 	socklen_t slen;
    802 
    803 	slen = sizeof (struct sockaddr_storage);
    804 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
    805 		return 0;
    806 
    807 	switch (ss.ss_family) {
    808 		case AF_INET:
    809 			return (((struct sockaddr_in *)
    810 			    (void *)&ss)->sin_port != 0);
    811 #ifdef INET6
    812 		case AF_INET6:
    813 			return (((struct sockaddr_in6 *)
    814 			    (void *)&ss)->sin6_port != 0);
    815 #endif
    816 		case AF_LOCAL:
    817 			/* XXX check this */
    818 			return (((struct sockaddr_un *)
    819 			    (void *)&ss)->sun_path[0] != '\0');
    820 		default:
    821 			break;
    822 	}
    823 
    824 	return 0;
    825 }
    826