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