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