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