xref: /netbsd/lib/libc/rpc/rpc_generic.c (revision ddcafdc3)
1*ddcafdc3Schristos /*	$NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $	*/
27df0ccbaSfvdl 
37df0ccbaSfvdl /*
415c1b43eStron  * Copyright (c) 2010, Oracle America, Inc.
57df0ccbaSfvdl  *
615c1b43eStron  * Redistribution and use in source and binary forms, with or without
715c1b43eStron  * modification, are permitted provided that the following conditions are
815c1b43eStron  * met:
97df0ccbaSfvdl  *
1015c1b43eStron  *     * Redistributions of source code must retain the above copyright
1115c1b43eStron  *       notice, this list of conditions and the following disclaimer.
1215c1b43eStron  *     * Redistributions in binary form must reproduce the above
1315c1b43eStron  *       copyright notice, this list of conditions and the following
1415c1b43eStron  *       disclaimer in the documentation and/or other materials
1515c1b43eStron  *       provided with the distribution.
1615c1b43eStron  *     * Neither the name of the "Oracle America, Inc." nor the names of its
1715c1b43eStron  *       contributors may be used to endorse or promote products derived
1815c1b43eStron  *       from this software without specific prior written permission.
197df0ccbaSfvdl  *
2015c1b43eStron  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2115c1b43eStron  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2215c1b43eStron  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2315c1b43eStron  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2415c1b43eStron  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2515c1b43eStron  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2615c1b43eStron  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2715c1b43eStron  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2815c1b43eStron  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2915c1b43eStron  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3015c1b43eStron  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3115c1b43eStron  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
327df0ccbaSfvdl  */
337df0ccbaSfvdl /*
347df0ccbaSfvdl  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
357df0ccbaSfvdl  */
367df0ccbaSfvdl 
377df0ccbaSfvdl /* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
387df0ccbaSfvdl 
397df0ccbaSfvdl /*
407df0ccbaSfvdl  * rpc_generic.c, Miscl routines for RPC.
417df0ccbaSfvdl  *
427df0ccbaSfvdl  */
437df0ccbaSfvdl 
445c945215Sitojun #include <sys/cdefs.h>
455c945215Sitojun #if defined(LIBC_SCCS) && !defined(lint)
46*ddcafdc3Schristos __RCSID("$NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $");
475c945215Sitojun #endif
485c945215Sitojun 
49dbf8a532Skleink #include "namespace.h"
503fdac2b8Sthorpej #include "reentrant.h"
517df0ccbaSfvdl #include <sys/types.h>
527df0ccbaSfvdl #include <sys/param.h>
537df0ccbaSfvdl #include <sys/socket.h>
547df0ccbaSfvdl #include <sys/un.h>
557df0ccbaSfvdl #include <sys/resource.h>
567df0ccbaSfvdl #include <netinet/in.h>
57eadd73deSchristos #include <netinet/tcp.h>
587df0ccbaSfvdl #include <arpa/inet.h>
597df0ccbaSfvdl #include <rpc/rpc.h>
600e8cfd8fSlukem #include <assert.h>
617df0ccbaSfvdl #include <ctype.h>
627df0ccbaSfvdl #include <stdio.h>
637df0ccbaSfvdl #include <netdb.h>
647df0ccbaSfvdl #include <netconfig.h>
65da3e4670Sdholland #include <stdlib.h>
667df0ccbaSfvdl #include <string.h>
67598be7b0Sassar #include <syslog.h>
687df0ccbaSfvdl #include <rpc/nettype.h>
696c0ae2b0Schristos 
706c0ae2b0Schristos #include "svc_fdset.h"
7179d5b270Sfvdl #include "rpc_internal.h"
727df0ccbaSfvdl 
73fd5cb0acSkleink #ifdef __weak_alias
74fd5cb0acSkleink __weak_alias(taddr2uaddr,_taddr2uaddr)
75fd5cb0acSkleink __weak_alias(uaddr2taddr,_uaddr2taddr)
76fd5cb0acSkleink #endif
77fd5cb0acSkleink 
787df0ccbaSfvdl struct handle {
797df0ccbaSfvdl 	NCONF_HANDLE *nhandle;
807df0ccbaSfvdl 	int nflag;		/* Whether NETPATH or NETCONFIG */
817df0ccbaSfvdl 	int nettype;
827df0ccbaSfvdl };
837df0ccbaSfvdl 
84ca797c3cSjdolecek static const struct _rpcnettype {
857df0ccbaSfvdl 	const char *name;
867df0ccbaSfvdl 	const int type;
877df0ccbaSfvdl } _rpctypelist[] = {
887df0ccbaSfvdl 	{ "netpath", _RPC_NETPATH },
897df0ccbaSfvdl 	{ "visible", _RPC_VISIBLE },
907df0ccbaSfvdl 	{ "circuit_v", _RPC_CIRCUIT_V },
917df0ccbaSfvdl 	{ "datagram_v", _RPC_DATAGRAM_V },
927df0ccbaSfvdl 	{ "circuit_n", _RPC_CIRCUIT_N },
937df0ccbaSfvdl 	{ "datagram_n", _RPC_DATAGRAM_N },
947df0ccbaSfvdl 	{ "tcp", _RPC_TCP },
957df0ccbaSfvdl 	{ "udp", _RPC_UDP },
967df0ccbaSfvdl 	{ 0, _RPC_NONE }
977df0ccbaSfvdl };
987df0ccbaSfvdl 
997df0ccbaSfvdl struct netid_af {
1007df0ccbaSfvdl 	const char	*netid;
1017df0ccbaSfvdl 	int		af;
1027df0ccbaSfvdl 	int		protocol;
1037df0ccbaSfvdl };
1047df0ccbaSfvdl 
105ca797c3cSjdolecek static const struct netid_af na_cvt[] = {
1067df0ccbaSfvdl 	{ "udp",  AF_INET,  IPPROTO_UDP },
1077df0ccbaSfvdl 	{ "tcp",  AF_INET,  IPPROTO_TCP },
1087df0ccbaSfvdl #ifdef INET6
1097df0ccbaSfvdl 	{ "udp6", AF_INET6, IPPROTO_UDP },
1107df0ccbaSfvdl 	{ "tcp6", AF_INET6, IPPROTO_TCP },
1117df0ccbaSfvdl #endif
1127df0ccbaSfvdl 	{ "local", AF_LOCAL, 0 }
1137df0ccbaSfvdl };
1147df0ccbaSfvdl 
115deb154d2Schristos #if 0
116c30c4c40Smatt static char *strlocase(char *);
117deb154d2Schristos #endif
118c30c4c40Smatt static int getnettype(const char *);
1197df0ccbaSfvdl 
1207df0ccbaSfvdl /*
1217df0ccbaSfvdl  * Cache the result of getrlimit(), so we don't have to do an
1227df0ccbaSfvdl  * expensive call every time.
1237df0ccbaSfvdl  */
1247df0ccbaSfvdl int
__rpc_dtbsize(void)125c30c4c40Smatt __rpc_dtbsize(void)
1267df0ccbaSfvdl {
1277df0ccbaSfvdl 	static int tbsize;
1287df0ccbaSfvdl 	struct rlimit rl;
1297df0ccbaSfvdl 
1307df0ccbaSfvdl 	if (tbsize) {
1317df0ccbaSfvdl 		return (tbsize);
1327df0ccbaSfvdl 	}
1337df0ccbaSfvdl 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
134deb154d2Schristos 		return (tbsize = (int)rl.rlim_max);
1357df0ccbaSfvdl 	}
1367df0ccbaSfvdl 	/*
1377df0ccbaSfvdl 	 * Something wrong.  I'll try to save face by returning a
1387df0ccbaSfvdl 	 * pessimistic number.
1397df0ccbaSfvdl 	 */
1407df0ccbaSfvdl 	return (32);
1417df0ccbaSfvdl }
1427df0ccbaSfvdl 
1437df0ccbaSfvdl 
1447df0ccbaSfvdl /*
1457df0ccbaSfvdl  * Find the appropriate buffer size
1467df0ccbaSfvdl  */
1477df0ccbaSfvdl u_int
148deb154d2Schristos /*ARGSUSED*/
__rpc_get_t_size(int af,int proto,int size)149c30c4c40Smatt __rpc_get_t_size(
150c30c4c40Smatt 	int af,
151c30c4c40Smatt 	int proto,
152c30c4c40Smatt 	int size)	/* Size requested */
1537df0ccbaSfvdl {
154795dfe88Syamt 	int maxsize, defsize;
1557df0ccbaSfvdl 
156795dfe88Syamt 	maxsize = 256 * 1024;	/* XXX */
1577df0ccbaSfvdl 	switch (proto) {
1587df0ccbaSfvdl 	case IPPROTO_TCP:
159795dfe88Syamt 		defsize = 64 * 1024;	/* XXX */
1607df0ccbaSfvdl 		break;
1617df0ccbaSfvdl 	case IPPROTO_UDP:
162795dfe88Syamt 		defsize = UDPMSGSIZE;
1637df0ccbaSfvdl 		break;
1647df0ccbaSfvdl 	default:
165795dfe88Syamt 		defsize = RPC_MAXDATASIZE;
1667df0ccbaSfvdl 		break;
1677df0ccbaSfvdl 	}
1687df0ccbaSfvdl 	if (size == 0)
169795dfe88Syamt 		return defsize;
1707df0ccbaSfvdl 
1717df0ccbaSfvdl 	/* Check whether the value is within the upper max limit */
1727df0ccbaSfvdl 	return (size > maxsize ? (u_int)maxsize : (u_int)size);
1737df0ccbaSfvdl }
1747df0ccbaSfvdl 
1757df0ccbaSfvdl /*
1767df0ccbaSfvdl  * Find the appropriate address buffer size
1777df0ccbaSfvdl  */
1787df0ccbaSfvdl u_int
__rpc_get_a_size(int af)179c30c4c40Smatt __rpc_get_a_size(int af)
1807df0ccbaSfvdl {
1817df0ccbaSfvdl 	switch (af) {
1827df0ccbaSfvdl 	case AF_INET:
1837df0ccbaSfvdl 		return sizeof (struct sockaddr_in);
1847df0ccbaSfvdl #ifdef INET6
1857df0ccbaSfvdl 	case AF_INET6:
1867df0ccbaSfvdl 		return sizeof (struct sockaddr_in6);
1877df0ccbaSfvdl #endif
1887df0ccbaSfvdl 	case AF_LOCAL:
1897df0ccbaSfvdl 		return sizeof (struct sockaddr_un);
1907df0ccbaSfvdl 	default:
1917df0ccbaSfvdl 		break;
1927df0ccbaSfvdl 	}
1937df0ccbaSfvdl 	return ((u_int)RPC_MAXADDRSIZE);
1947df0ccbaSfvdl }
1957df0ccbaSfvdl 
196deb154d2Schristos #if 0
1977df0ccbaSfvdl static char *
198c30c4c40Smatt strlocase(char *p)
1997df0ccbaSfvdl {
2007df0ccbaSfvdl 	char *t = p;
2017df0ccbaSfvdl 
2020e8cfd8fSlukem 	_DIAGASSERT(p != NULL);
2030e8cfd8fSlukem 
2047df0ccbaSfvdl 	for (; *p; p++)
2057df0ccbaSfvdl 		if (isupper(*p))
2067df0ccbaSfvdl 			*p = tolower(*p);
2077df0ccbaSfvdl 	return (t);
2087df0ccbaSfvdl }
209deb154d2Schristos #endif
2107df0ccbaSfvdl 
2117df0ccbaSfvdl /*
2127df0ccbaSfvdl  * Returns the type of the network as defined in <rpc/nettype.h>
2137df0ccbaSfvdl  * If nettype is NULL, it defaults to NETPATH.
2147df0ccbaSfvdl  */
2157df0ccbaSfvdl static int
getnettype(const char * nettype)216c30c4c40Smatt getnettype(const char *nettype)
2177df0ccbaSfvdl {
2187df0ccbaSfvdl 	int i;
2197df0ccbaSfvdl 
220bc018099Sfvdl 	if ((nettype == NULL) || (nettype[0] == 0)) {
2217df0ccbaSfvdl 		return (_RPC_NETPATH);	/* Default */
2227df0ccbaSfvdl 	}
2237df0ccbaSfvdl 
224deb154d2Schristos #if 0
2257df0ccbaSfvdl 	nettype = strlocase(nettype);
226deb154d2Schristos #endif
2277df0ccbaSfvdl 	for (i = 0; _rpctypelist[i].name; i++)
228deb154d2Schristos 		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
2297df0ccbaSfvdl 			return (_rpctypelist[i].type);
2307df0ccbaSfvdl 		}
2317df0ccbaSfvdl 	return (_rpctypelist[i].type);
2327df0ccbaSfvdl }
2337df0ccbaSfvdl 
2347df0ccbaSfvdl /*
2357df0ccbaSfvdl  * For the given nettype (tcp or udp only), return the first structure found.
2367df0ccbaSfvdl  * This should be freed by calling freenetconfigent()
2377df0ccbaSfvdl  */
2383fdac2b8Sthorpej 
2393fdac2b8Sthorpej #ifdef _REENTRANT
2403fdac2b8Sthorpej static thread_key_t tcp_key, udp_key;
2413fdac2b8Sthorpej static once_t __rpc_getconfigp_once = ONCE_INITIALIZER;
2423fdac2b8Sthorpej 
2433fdac2b8Sthorpej static void
__rpc_getconfigp_setup(void)2443fdac2b8Sthorpej __rpc_getconfigp_setup(void)
2453fdac2b8Sthorpej {
2463fdac2b8Sthorpej 
2473fdac2b8Sthorpej 	thr_keycreate(&tcp_key, free);
2483fdac2b8Sthorpej 	thr_keycreate(&udp_key, free);
2493fdac2b8Sthorpej }
2503fdac2b8Sthorpej #endif
2513fdac2b8Sthorpej 
2527df0ccbaSfvdl struct netconfig *
__rpc_getconfip(const char * nettype)253c30c4c40Smatt __rpc_getconfip(const char *nettype)
2547df0ccbaSfvdl {
2557df0ccbaSfvdl 	char *netid;
256c9cdc302Schristos 	char *netid_tcp = NULL;
257c9cdc302Schristos 	char *netid_udp = NULL;
2587df0ccbaSfvdl 	static char *netid_tcp_main;
2597df0ccbaSfvdl 	static char *netid_udp_main;
2607df0ccbaSfvdl 	struct netconfig *dummy;
2613fdac2b8Sthorpej #ifdef _REENTRANT
2623fdac2b8Sthorpej 	if (__isthreaded == 0) {
2637df0ccbaSfvdl 		netid_udp = netid_udp_main;
2647df0ccbaSfvdl 		netid_tcp = netid_tcp_main;
2657df0ccbaSfvdl 	} else {
2663fdac2b8Sthorpej 		thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup);
2673fdac2b8Sthorpej 		netid_tcp = thr_getspecific(tcp_key);
2683fdac2b8Sthorpej 		netid_udp = thr_getspecific(udp_key);
2697df0ccbaSfvdl 	}
2707df0ccbaSfvdl #else
2717df0ccbaSfvdl 	netid_udp = netid_udp_main;
2727df0ccbaSfvdl 	netid_tcp = netid_tcp_main;
2737df0ccbaSfvdl #endif
2740e8cfd8fSlukem 
2750e8cfd8fSlukem 	_DIAGASSERT(nettype != NULL);
2760e8cfd8fSlukem 
2777df0ccbaSfvdl 	if (!netid_udp && !netid_tcp) {
2787df0ccbaSfvdl 		struct netconfig *nconf;
2797df0ccbaSfvdl 		void *confighandle;
2807df0ccbaSfvdl 
2817df0ccbaSfvdl 		if (!(confighandle = setnetconfig())) {
282598be7b0Sassar 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
2837df0ccbaSfvdl 			return (NULL);
2847df0ccbaSfvdl 		}
285deb154d2Schristos 		while ((nconf = getnetconfig(confighandle)) != NULL) {
2867df0ccbaSfvdl 			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
2877df0ccbaSfvdl 				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
2887df0ccbaSfvdl 					netid_tcp = strdup(nconf->nc_netid);
289c9cdc302Schristos 					if (netid_tcp == NULL)
290c9cdc302Schristos 						return NULL;
2913fdac2b8Sthorpej #ifdef _REENTRANT
2923fdac2b8Sthorpej 					if (__isthreaded == 0)
2937df0ccbaSfvdl 						netid_tcp_main = netid_tcp;
2947df0ccbaSfvdl 					else
2957df0ccbaSfvdl 						thr_setspecific(tcp_key,
2967df0ccbaSfvdl 							(void *) netid_tcp);
2977df0ccbaSfvdl #else
2987df0ccbaSfvdl 					netid_tcp_main = netid_tcp;
2997df0ccbaSfvdl #endif
3007df0ccbaSfvdl 				} else
3017df0ccbaSfvdl 				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
3027df0ccbaSfvdl 					netid_udp = strdup(nconf->nc_netid);
303c9cdc302Schristos 					if (netid_udp == NULL)
304c9cdc302Schristos 						return NULL;
3053fdac2b8Sthorpej #ifdef _REENTRANT
3063fdac2b8Sthorpej 					if (__isthreaded == 0)
3077df0ccbaSfvdl 						netid_udp_main = netid_udp;
3087df0ccbaSfvdl 					else
3097df0ccbaSfvdl 						thr_setspecific(udp_key,
3107df0ccbaSfvdl 							(void *) netid_udp);
3117df0ccbaSfvdl #else
3127df0ccbaSfvdl 					netid_udp_main = netid_udp;
3137df0ccbaSfvdl #endif
3147df0ccbaSfvdl 				}
3157df0ccbaSfvdl 			}
3167df0ccbaSfvdl 		}
3177df0ccbaSfvdl 		endnetconfig(confighandle);
3187df0ccbaSfvdl 	}
3197df0ccbaSfvdl 	if (strcmp(nettype, "udp") == 0)
3207df0ccbaSfvdl 		netid = netid_udp;
3217df0ccbaSfvdl 	else if (strcmp(nettype, "tcp") == 0)
3227df0ccbaSfvdl 		netid = netid_tcp;
3237df0ccbaSfvdl 	else {
324deb154d2Schristos 		return (NULL);
3257df0ccbaSfvdl 	}
326bc018099Sfvdl 	if ((netid == NULL) || (netid[0] == 0)) {
327deb154d2Schristos 		return (NULL);
3287df0ccbaSfvdl 	}
3297df0ccbaSfvdl 	dummy = getnetconfigent(netid);
3307df0ccbaSfvdl 	return (dummy);
3317df0ccbaSfvdl }
3327df0ccbaSfvdl 
3337df0ccbaSfvdl /*
3347df0ccbaSfvdl  * Returns the type of the nettype, which should then be used with
3357df0ccbaSfvdl  * __rpc_getconf().
3367df0ccbaSfvdl  */
3377df0ccbaSfvdl void *
__rpc_setconf(const char * nettype)338c30c4c40Smatt __rpc_setconf(const char *nettype)
3397df0ccbaSfvdl {
3407df0ccbaSfvdl 	struct handle *handle;
3417df0ccbaSfvdl 
3420e8cfd8fSlukem 	/* nettype may be NULL; getnettype() supports that */
3430e8cfd8fSlukem 
344c9cdc302Schristos 	handle = malloc(sizeof(*handle));
3457df0ccbaSfvdl 	if (handle == NULL) {
3467df0ccbaSfvdl 		return (NULL);
3477df0ccbaSfvdl 	}
3487df0ccbaSfvdl 	switch (handle->nettype = getnettype(nettype)) {
3497df0ccbaSfvdl 	case _RPC_NETPATH:
3507df0ccbaSfvdl 	case _RPC_CIRCUIT_N:
3517df0ccbaSfvdl 	case _RPC_DATAGRAM_N:
3527df0ccbaSfvdl 		if (!(handle->nhandle = setnetpath())) {
3537df0ccbaSfvdl 			free(handle);
3547df0ccbaSfvdl 			return (NULL);
3557df0ccbaSfvdl 		}
3567df0ccbaSfvdl 		handle->nflag = TRUE;
3577df0ccbaSfvdl 		break;
3587df0ccbaSfvdl 	case _RPC_VISIBLE:
3597df0ccbaSfvdl 	case _RPC_CIRCUIT_V:
3607df0ccbaSfvdl 	case _RPC_DATAGRAM_V:
3617df0ccbaSfvdl 	case _RPC_TCP:
3627df0ccbaSfvdl 	case _RPC_UDP:
3637df0ccbaSfvdl 		if (!(handle->nhandle = setnetconfig())) {
364598be7b0Sassar 		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
3657df0ccbaSfvdl 			free(handle);
3667df0ccbaSfvdl 			return (NULL);
3677df0ccbaSfvdl 		}
3687df0ccbaSfvdl 		handle->nflag = FALSE;
3697df0ccbaSfvdl 		break;
3707df0ccbaSfvdl 	default:
371cd29290eSchristos 		free(handle);
3727df0ccbaSfvdl 		return (NULL);
3737df0ccbaSfvdl 	}
3747df0ccbaSfvdl 
3757df0ccbaSfvdl 	return (handle);
3767df0ccbaSfvdl }
3777df0ccbaSfvdl 
3787df0ccbaSfvdl /*
3797df0ccbaSfvdl  * Returns the next netconfig struct for the given "net" type.
3807df0ccbaSfvdl  * __rpc_setconf() should have been called previously.
3817df0ccbaSfvdl  */
3827df0ccbaSfvdl struct netconfig *
__rpc_getconf(void * vhandle)383c30c4c40Smatt __rpc_getconf(void *vhandle)
3847df0ccbaSfvdl {
3857df0ccbaSfvdl 	struct handle *handle;
3867df0ccbaSfvdl 	struct netconfig *nconf;
3877df0ccbaSfvdl 
3887df0ccbaSfvdl 	handle = (struct handle *)vhandle;
3897df0ccbaSfvdl 	if (handle == NULL) {
3907df0ccbaSfvdl 		return (NULL);
3917df0ccbaSfvdl 	}
392deb154d2Schristos 	for (;;) {
3937df0ccbaSfvdl 		if (handle->nflag)
3947df0ccbaSfvdl 			nconf = getnetpath(handle->nhandle);
3957df0ccbaSfvdl 		else
3967df0ccbaSfvdl 			nconf = getnetconfig(handle->nhandle);
397deb154d2Schristos 		if (nconf == NULL)
3987df0ccbaSfvdl 			break;
3997df0ccbaSfvdl 		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
4007df0ccbaSfvdl 			(nconf->nc_semantics != NC_TPI_COTS) &&
4017df0ccbaSfvdl 			(nconf->nc_semantics != NC_TPI_COTS_ORD))
4027df0ccbaSfvdl 			continue;
4037df0ccbaSfvdl 		switch (handle->nettype) {
4047df0ccbaSfvdl 		case _RPC_VISIBLE:
4057df0ccbaSfvdl 			if (!(nconf->nc_flag & NC_VISIBLE))
4067df0ccbaSfvdl 				continue;
4077df0ccbaSfvdl 			/* FALLTHROUGH */
4087df0ccbaSfvdl 		case _RPC_NETPATH:	/* Be happy */
4097df0ccbaSfvdl 			break;
4107df0ccbaSfvdl 		case _RPC_CIRCUIT_V:
4117df0ccbaSfvdl 			if (!(nconf->nc_flag & NC_VISIBLE))
4127df0ccbaSfvdl 				continue;
4137df0ccbaSfvdl 			/* FALLTHROUGH */
4147df0ccbaSfvdl 		case _RPC_CIRCUIT_N:
4157df0ccbaSfvdl 			if ((nconf->nc_semantics != NC_TPI_COTS) &&
4167df0ccbaSfvdl 				(nconf->nc_semantics != NC_TPI_COTS_ORD))
4177df0ccbaSfvdl 				continue;
4187df0ccbaSfvdl 			break;
4197df0ccbaSfvdl 		case _RPC_DATAGRAM_V:
4207df0ccbaSfvdl 			if (!(nconf->nc_flag & NC_VISIBLE))
4217df0ccbaSfvdl 				continue;
4227df0ccbaSfvdl 			/* FALLTHROUGH */
4237df0ccbaSfvdl 		case _RPC_DATAGRAM_N:
4247df0ccbaSfvdl 			if (nconf->nc_semantics != NC_TPI_CLTS)
4257df0ccbaSfvdl 				continue;
4267df0ccbaSfvdl 			break;
4277df0ccbaSfvdl 		case _RPC_TCP:
4287df0ccbaSfvdl 			if (((nconf->nc_semantics != NC_TPI_COTS) &&
4297df0ccbaSfvdl 				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
4307df0ccbaSfvdl 				(strcmp(nconf->nc_protofmly, NC_INET)
4317df0ccbaSfvdl #ifdef INET6
4327df0ccbaSfvdl 				 && strcmp(nconf->nc_protofmly, NC_INET6))
4337df0ccbaSfvdl #else
4347df0ccbaSfvdl 				)
4357df0ccbaSfvdl #endif
4367df0ccbaSfvdl 				||
4377df0ccbaSfvdl 				strcmp(nconf->nc_proto, NC_TCP))
4387df0ccbaSfvdl 				continue;
4397df0ccbaSfvdl 			break;
4407df0ccbaSfvdl 		case _RPC_UDP:
4417df0ccbaSfvdl 			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
4427df0ccbaSfvdl 				(strcmp(nconf->nc_protofmly, NC_INET)
4437df0ccbaSfvdl #ifdef INET6
4447df0ccbaSfvdl 				&& strcmp(nconf->nc_protofmly, NC_INET6))
4457df0ccbaSfvdl #else
4467df0ccbaSfvdl 				)
4477df0ccbaSfvdl #endif
4487df0ccbaSfvdl 				||
4497df0ccbaSfvdl 				strcmp(nconf->nc_proto, NC_UDP))
4507df0ccbaSfvdl 				continue;
4517df0ccbaSfvdl 			break;
4527df0ccbaSfvdl 		}
4537df0ccbaSfvdl 		break;
4547df0ccbaSfvdl 	}
4557df0ccbaSfvdl 	return (nconf);
4567df0ccbaSfvdl }
4577df0ccbaSfvdl 
4587df0ccbaSfvdl void
__rpc_endconf(void * vhandle)459c30c4c40Smatt __rpc_endconf(void *vhandle)
4607df0ccbaSfvdl {
4617df0ccbaSfvdl 	struct handle *handle;
4627df0ccbaSfvdl 
4637df0ccbaSfvdl 	handle = (struct handle *) vhandle;
4647df0ccbaSfvdl 	if (handle == NULL) {
4657df0ccbaSfvdl 		return;
4667df0ccbaSfvdl 	}
4677df0ccbaSfvdl 	if (handle->nflag) {
4687df0ccbaSfvdl 		endnetpath(handle->nhandle);
4697df0ccbaSfvdl 	} else {
4707df0ccbaSfvdl 		endnetconfig(handle->nhandle);
4717df0ccbaSfvdl 	}
4727df0ccbaSfvdl 	free(handle);
4737df0ccbaSfvdl }
4747df0ccbaSfvdl 
4757df0ccbaSfvdl /*
4767df0ccbaSfvdl  * Used to ping the NULL procedure for clnt handle.
4777df0ccbaSfvdl  * Returns NULL if fails, else a non-NULL pointer.
4787df0ccbaSfvdl  */
4797df0ccbaSfvdl void *
rpc_nullproc(CLIENT * clnt)480c30c4c40Smatt rpc_nullproc(CLIENT *clnt)
4817df0ccbaSfvdl {
4827df0ccbaSfvdl 	struct timeval TIMEOUT = {25, 0};
4837df0ccbaSfvdl 
484deb154d2Schristos 	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
485deb154d2Schristos 		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
486deb154d2Schristos 		return (NULL);
4877df0ccbaSfvdl 	}
4887df0ccbaSfvdl 	return ((void *) clnt);
4897df0ccbaSfvdl }
4907df0ccbaSfvdl 
4917df0ccbaSfvdl /*
4927df0ccbaSfvdl  * Try all possible transports until
4937df0ccbaSfvdl  * one succeeds in finding the netconf for the given fd.
4947df0ccbaSfvdl  */
4957df0ccbaSfvdl struct netconfig *
__rpcgettp(int fd)496c30c4c40Smatt __rpcgettp(int fd)
4977df0ccbaSfvdl {
4987df0ccbaSfvdl 	const char *netid;
4997df0ccbaSfvdl 	struct __rpc_sockinfo si;
5007df0ccbaSfvdl 
5017df0ccbaSfvdl 	if (!__rpc_fd2sockinfo(fd, &si))
5027df0ccbaSfvdl 		return NULL;
5037df0ccbaSfvdl 
5047df0ccbaSfvdl 	if (!__rpc_sockinfo2netid(&si, &netid))
5057df0ccbaSfvdl 		return NULL;
5067df0ccbaSfvdl 
50703256c6eSchristos 	return getnetconfigent(__UNCONST(netid));
5087df0ccbaSfvdl }
5097df0ccbaSfvdl 
5107df0ccbaSfvdl int
__rpc_fd2sockinfo(int fd,struct __rpc_sockinfo * sip)5117df0ccbaSfvdl __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
5127df0ccbaSfvdl {
5137df0ccbaSfvdl 	socklen_t len;
5147df0ccbaSfvdl 	int type, proto;
5157df0ccbaSfvdl 	struct sockaddr_storage ss;
5167df0ccbaSfvdl 
5170e8cfd8fSlukem 	_DIAGASSERT(sip != NULL);
5180e8cfd8fSlukem 
5197df0ccbaSfvdl 	len = sizeof ss;
520deb154d2Schristos 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
5217df0ccbaSfvdl 		return 0;
5227df0ccbaSfvdl 	sip->si_alen = len;
5237df0ccbaSfvdl 
5247df0ccbaSfvdl 	len = sizeof type;
5257df0ccbaSfvdl 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
5267df0ccbaSfvdl 		return 0;
5277df0ccbaSfvdl 
5287df0ccbaSfvdl 	/* XXX */
5297df0ccbaSfvdl 	if (ss.ss_family != AF_LOCAL) {
5307df0ccbaSfvdl 		if (type == SOCK_STREAM)
5317df0ccbaSfvdl 			proto = IPPROTO_TCP;
5327df0ccbaSfvdl 		else if (type == SOCK_DGRAM)
5337df0ccbaSfvdl 			proto = IPPROTO_UDP;
5347df0ccbaSfvdl 		else
5357df0ccbaSfvdl 			return 0;
5367df0ccbaSfvdl 	} else
5377df0ccbaSfvdl 		proto = 0;
5387df0ccbaSfvdl 
5397df0ccbaSfvdl 	sip->si_af = ss.ss_family;
5407df0ccbaSfvdl 	sip->si_proto = proto;
5417df0ccbaSfvdl 	sip->si_socktype = type;
5427df0ccbaSfvdl 
5437df0ccbaSfvdl 	return 1;
5447df0ccbaSfvdl }
5457df0ccbaSfvdl 
5467df0ccbaSfvdl /*
5477df0ccbaSfvdl  * Linear search, but the number of entries is small.
5487df0ccbaSfvdl  */
5497df0ccbaSfvdl int
__rpc_nconf2sockinfo(const struct netconfig * nconf,struct __rpc_sockinfo * sip)5507df0ccbaSfvdl __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
5517df0ccbaSfvdl {
552d6e3c041Sthorpej 	size_t i;
5537df0ccbaSfvdl 
5540e8cfd8fSlukem 	_DIAGASSERT(nconf != NULL);
5550e8cfd8fSlukem 	_DIAGASSERT(sip != NULL);
5560e8cfd8fSlukem 
5577df0ccbaSfvdl 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
5587df0ccbaSfvdl 		if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
5597df0ccbaSfvdl 			sip->si_af = na_cvt[i].af;
5607df0ccbaSfvdl 			sip->si_proto = na_cvt[i].protocol;
5617df0ccbaSfvdl 			sip->si_socktype =
562deb154d2Schristos 			    __rpc_seman2socktype((int)nconf->nc_semantics);
5637df0ccbaSfvdl 			if (sip->si_socktype == -1)
5647df0ccbaSfvdl 				return 0;
5657df0ccbaSfvdl 			sip->si_alen = __rpc_get_a_size(sip->si_af);
5667df0ccbaSfvdl 			return 1;
5677df0ccbaSfvdl 		}
5687df0ccbaSfvdl 
5697df0ccbaSfvdl 	return 0;
5707df0ccbaSfvdl }
5717df0ccbaSfvdl 
5727df0ccbaSfvdl int
__rpc_nconf2fd(const struct netconfig * nconf)5737df0ccbaSfvdl __rpc_nconf2fd(const struct netconfig *nconf)
5747df0ccbaSfvdl {
5757df0ccbaSfvdl 	struct __rpc_sockinfo si;
5767df0ccbaSfvdl 
5770e8cfd8fSlukem 	_DIAGASSERT(nconf != NULL);
5780e8cfd8fSlukem 
5797df0ccbaSfvdl 	if (!__rpc_nconf2sockinfo(nconf, &si))
5807df0ccbaSfvdl 		return 0;
5817df0ccbaSfvdl 
5827df0ccbaSfvdl 	return socket(si.si_af, si.si_socktype, si.si_proto);
5837df0ccbaSfvdl }
5847df0ccbaSfvdl 
5857df0ccbaSfvdl int
__rpc_sockinfo2netid(struct __rpc_sockinfo * sip,const char ** netid)5867df0ccbaSfvdl __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
5877df0ccbaSfvdl {
588d6e3c041Sthorpej 	size_t i;
5897df0ccbaSfvdl 
5900e8cfd8fSlukem 	_DIAGASSERT(sip != NULL);
5910e8cfd8fSlukem 	/* netid may be NULL */
5920e8cfd8fSlukem 
5937df0ccbaSfvdl 	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
5947df0ccbaSfvdl 		if (na_cvt[i].af == sip->si_af &&
5957df0ccbaSfvdl 		    na_cvt[i].protocol == sip->si_proto) {
5967df0ccbaSfvdl 			if (netid)
5977df0ccbaSfvdl 				*netid = na_cvt[i].netid;
5987df0ccbaSfvdl 			return 1;
5997df0ccbaSfvdl 		}
6007df0ccbaSfvdl 
6017df0ccbaSfvdl 	return 0;
6027df0ccbaSfvdl }
6037df0ccbaSfvdl 
6047df0ccbaSfvdl char *
taddr2uaddr(const struct netconfig * nconf,const struct netbuf * nbuf)6057df0ccbaSfvdl taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
6067df0ccbaSfvdl {
6077df0ccbaSfvdl 	struct __rpc_sockinfo si;
6087df0ccbaSfvdl 
6090e8cfd8fSlukem 	_DIAGASSERT(nconf != NULL);
6100e8cfd8fSlukem 	_DIAGASSERT(nbuf != NULL);
6110e8cfd8fSlukem 
6127df0ccbaSfvdl 	if (!__rpc_nconf2sockinfo(nconf, &si))
6137df0ccbaSfvdl 		return NULL;
6147df0ccbaSfvdl 	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
6157df0ccbaSfvdl }
6167df0ccbaSfvdl 
6177df0ccbaSfvdl struct netbuf *
uaddr2taddr(const struct netconfig * nconf,const char * uaddr)6187df0ccbaSfvdl uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
6197df0ccbaSfvdl {
6207df0ccbaSfvdl 	struct __rpc_sockinfo si;
6217df0ccbaSfvdl 
6220e8cfd8fSlukem 	_DIAGASSERT(nconf != NULL);
6230e8cfd8fSlukem 	_DIAGASSERT(uaddr != NULL);
6240e8cfd8fSlukem 
6257df0ccbaSfvdl 	if (!__rpc_nconf2sockinfo(nconf, &si))
6267df0ccbaSfvdl 		return NULL;
6277df0ccbaSfvdl 	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
6287df0ccbaSfvdl }
6297df0ccbaSfvdl 
6307df0ccbaSfvdl char *
__rpc_taddr2uaddr_af(int af,const struct netbuf * nbuf)6317df0ccbaSfvdl __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
6327df0ccbaSfvdl {
6337df0ccbaSfvdl 	char *ret;
63450f5afd5Slukem 	struct sockaddr_in *sinp;
6357df0ccbaSfvdl 	struct sockaddr_un *sun;
6367df0ccbaSfvdl 	char namebuf[INET_ADDRSTRLEN];
6377df0ccbaSfvdl #ifdef INET6
6387df0ccbaSfvdl 	struct sockaddr_in6 *sin6;
6397df0ccbaSfvdl 	char namebuf6[INET6_ADDRSTRLEN];
6407df0ccbaSfvdl #endif
6417df0ccbaSfvdl 	u_int16_t port;
6427df0ccbaSfvdl 
6430e8cfd8fSlukem 	_DIAGASSERT(nbuf != NULL);
6440e8cfd8fSlukem 
6457df0ccbaSfvdl 	switch (af) {
6467df0ccbaSfvdl 	case AF_INET:
647*ddcafdc3Schristos 		if (nbuf->len < sizeof(*sinp)) {
648*ddcafdc3Schristos 			return NULL;
649*ddcafdc3Schristos 		}
65050f5afd5Slukem 		sinp = nbuf->buf;
651e826745eSchristos 		if (inet_ntop(af, &sinp->sin_addr, namebuf,
652e826745eSchristos 		    (socklen_t)sizeof namebuf) == NULL)
6537df0ccbaSfvdl 			return NULL;
65450f5afd5Slukem 		port = ntohs(sinp->sin_port);
655deb154d2Schristos 		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
656deb154d2Schristos 		    port & 0xff) < 0)
6577df0ccbaSfvdl 			return NULL;
6587df0ccbaSfvdl 		break;
6597df0ccbaSfvdl #ifdef INET6
6607df0ccbaSfvdl 	case AF_INET6:
661*ddcafdc3Schristos 		if (nbuf->len < sizeof(*sin6)) {
662*ddcafdc3Schristos 			return NULL;
663*ddcafdc3Schristos 		}
6647df0ccbaSfvdl 		sin6 = nbuf->buf;
665e826745eSchristos 		if (inet_ntop(af, &sin6->sin6_addr, namebuf6,
666e826745eSchristos 		    (socklen_t)sizeof namebuf6) == NULL)
6677df0ccbaSfvdl 			return NULL;
6687df0ccbaSfvdl 		port = ntohs(sin6->sin6_port);
669deb154d2Schristos 		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
670deb154d2Schristos 		    port & 0xff) < 0)
6717df0ccbaSfvdl 			return NULL;
6727df0ccbaSfvdl 		break;
6737df0ccbaSfvdl #endif
6747df0ccbaSfvdl 	case AF_LOCAL:
6757df0ccbaSfvdl 		sun = nbuf->buf;
6767df0ccbaSfvdl 		sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
6777df0ccbaSfvdl 		ret = strdup(sun->sun_path);
6787df0ccbaSfvdl 		break;
6797df0ccbaSfvdl 	default:
6807df0ccbaSfvdl 		return NULL;
6817df0ccbaSfvdl 	}
6827df0ccbaSfvdl 
6837df0ccbaSfvdl 	return ret;
6847df0ccbaSfvdl }
6857df0ccbaSfvdl 
6867df0ccbaSfvdl struct netbuf *
__rpc_uaddr2taddr_af(int af,const char * uaddr)6877df0ccbaSfvdl __rpc_uaddr2taddr_af(int af, const char *uaddr)
6887df0ccbaSfvdl {
6897df0ccbaSfvdl 	struct netbuf *ret = NULL;
6907df0ccbaSfvdl 	char *addrstr, *p;
6917df0ccbaSfvdl 	unsigned port, portlo, porthi;
692e826745eSchristos 	size_t len;
69350f5afd5Slukem 	struct sockaddr_in *sinp;
6947df0ccbaSfvdl #ifdef INET6
6957df0ccbaSfvdl 	struct sockaddr_in6 *sin6;
6967df0ccbaSfvdl #endif
6977df0ccbaSfvdl 	struct sockaddr_un *sun;
6987df0ccbaSfvdl 
699*ddcafdc3Schristos 	if (uaddr == NULL)
700*ddcafdc3Schristos 		return NULL;
7010e8cfd8fSlukem 
7027df0ccbaSfvdl 	addrstr = strdup(uaddr);
7037df0ccbaSfvdl 	if (addrstr == NULL)
7047df0ccbaSfvdl 		return NULL;
7057df0ccbaSfvdl 
7067df0ccbaSfvdl 	/*
7077df0ccbaSfvdl 	 * AF_LOCAL addresses are expected to be absolute
7087df0ccbaSfvdl 	 * pathnames, anything else will be AF_INET or AF_INET6.
7097df0ccbaSfvdl 	 */
7103af3e6a4Slukem 	port = 0;
7117df0ccbaSfvdl 	if (*addrstr != '/') {
7127df0ccbaSfvdl 		p = strrchr(addrstr, '.');
7137df0ccbaSfvdl 		if (p == NULL)
7147df0ccbaSfvdl 			goto out;
7157df0ccbaSfvdl 		portlo = (unsigned)atoi(p + 1);
7167df0ccbaSfvdl 		*p = '\0';
7177df0ccbaSfvdl 
7187df0ccbaSfvdl 		p = strrchr(addrstr, '.');
7197df0ccbaSfvdl 		if (p == NULL)
7207df0ccbaSfvdl 			goto out;
7217df0ccbaSfvdl 		porthi = (unsigned)atoi(p + 1);
7227df0ccbaSfvdl 		*p = '\0';
7237df0ccbaSfvdl 		port = (porthi << 8) | portlo;
7247df0ccbaSfvdl 	}
7257df0ccbaSfvdl 
726c9cdc302Schristos 	ret = malloc(sizeof(*ret));
7277e4c882aSkristerw 	if (ret == NULL)
7287e4c882aSkristerw 		goto out;
7297df0ccbaSfvdl 
7307df0ccbaSfvdl 	switch (af) {
7317df0ccbaSfvdl 	case AF_INET:
732c9cdc302Schristos 		sinp = malloc(sizeof(*sinp));
73350f5afd5Slukem 		if (sinp == NULL)
7347df0ccbaSfvdl 			goto out;
73550f5afd5Slukem 		memset(sinp, 0, sizeof *sinp);
73650f5afd5Slukem 		sinp->sin_family = AF_INET;
73750f5afd5Slukem 		sinp->sin_port = htons(port);
73850f5afd5Slukem 		if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) {
73950f5afd5Slukem 			free(sinp);
7407df0ccbaSfvdl 			free(ret);
7417df0ccbaSfvdl 			ret = NULL;
7427df0ccbaSfvdl 			goto out;
7437df0ccbaSfvdl 		}
74450f5afd5Slukem 		sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp;
74550f5afd5Slukem 		ret->buf = sinp;
7467df0ccbaSfvdl 		break;
7477df0ccbaSfvdl #ifdef INET6
7487df0ccbaSfvdl 	case AF_INET6:
749c9cdc302Schristos 		sin6 = malloc(sizeof(*sin6));
7507df0ccbaSfvdl 		if (sin6 == NULL)
7517df0ccbaSfvdl 			goto out;
7527df0ccbaSfvdl 		memset(sin6, 0, sizeof *sin6);
7537df0ccbaSfvdl 		sin6->sin6_family = AF_INET6;
7547df0ccbaSfvdl 		sin6->sin6_port = htons(port);
7557df0ccbaSfvdl 		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
7567e4c882aSkristerw 			free(sin6);
7577df0ccbaSfvdl 			free(ret);
7587df0ccbaSfvdl 			ret = NULL;
7597df0ccbaSfvdl 			goto out;
7607df0ccbaSfvdl 		}
7617df0ccbaSfvdl 		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
7627df0ccbaSfvdl 		ret->buf = sin6;
7637df0ccbaSfvdl 		break;
7647df0ccbaSfvdl #endif
7657df0ccbaSfvdl 	case AF_LOCAL:
766c9cdc302Schristos 		sun = malloc(sizeof(*sun));
7677df0ccbaSfvdl 		if (sun == NULL)
7687df0ccbaSfvdl 			goto out;
7697df0ccbaSfvdl 		memset(sun, 0, sizeof *sun);
7707df0ccbaSfvdl 		sun->sun_family = AF_LOCAL;
7717df0ccbaSfvdl 		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
772e826745eSchristos 		len = SUN_LEN(sun);
773e826745eSchristos 		_DIAGASSERT(__type_fit(uint8_t, len));
774e826745eSchristos 		ret->len = ret->maxlen = sun->sun_len = (uint8_t)len;
775e33a1e62Sfvdl 		ret->buf = sun;
776deb154d2Schristos 		break;
7777df0ccbaSfvdl 	default:
7787df0ccbaSfvdl 		break;
7797df0ccbaSfvdl 	}
7807df0ccbaSfvdl out:
7817df0ccbaSfvdl 	free(addrstr);
7827df0ccbaSfvdl 	return ret;
7837df0ccbaSfvdl }
7847df0ccbaSfvdl 
7857df0ccbaSfvdl int
__rpc_seman2socktype(int semantics)7867df0ccbaSfvdl __rpc_seman2socktype(int semantics)
7877df0ccbaSfvdl {
7887df0ccbaSfvdl 	switch (semantics) {
7897df0ccbaSfvdl 	case NC_TPI_CLTS:
7907df0ccbaSfvdl 		return SOCK_DGRAM;
7917df0ccbaSfvdl 	case NC_TPI_COTS_ORD:
7927df0ccbaSfvdl 		return SOCK_STREAM;
7937df0ccbaSfvdl 	case NC_TPI_RAW:
7947df0ccbaSfvdl 		return SOCK_RAW;
7957df0ccbaSfvdl 	default:
7967df0ccbaSfvdl 		break;
7977df0ccbaSfvdl 	}
7987df0ccbaSfvdl 
7997df0ccbaSfvdl 	return -1;
8007df0ccbaSfvdl }
8017df0ccbaSfvdl 
8027df0ccbaSfvdl int
__rpc_socktype2seman(int socktype)8037df0ccbaSfvdl __rpc_socktype2seman(int socktype)
8047df0ccbaSfvdl {
8057df0ccbaSfvdl 	switch (socktype) {
8067df0ccbaSfvdl 	case SOCK_DGRAM:
8077df0ccbaSfvdl 		return NC_TPI_CLTS;
8087df0ccbaSfvdl 	case SOCK_STREAM:
8097df0ccbaSfvdl 		return NC_TPI_COTS_ORD;
8107df0ccbaSfvdl 	case SOCK_RAW:
8117df0ccbaSfvdl 		return NC_TPI_RAW;
8127df0ccbaSfvdl 	default:
8137df0ccbaSfvdl 		break;
8147df0ccbaSfvdl 	}
8157df0ccbaSfvdl 
8167df0ccbaSfvdl 	return -1;
8177df0ccbaSfvdl }
8187df0ccbaSfvdl 
8197df0ccbaSfvdl /*
8207df0ccbaSfvdl  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
8217df0ccbaSfvdl  * Here, we compare the original server address to that of the RPC
8227df0ccbaSfvdl  * service we just received back from a call to rpcbind on the remote
8237df0ccbaSfvdl  * machine. If they are both "link local" or "site local", copy
8247df0ccbaSfvdl  * the scope id of the server address over to the service address.
8257df0ccbaSfvdl  */
826b91c938dSlukem /* ARGSUSED */
8277df0ccbaSfvdl int
__rpc_fixup_addr(struct netbuf * new,const struct netbuf * svc)8287df0ccbaSfvdl __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
8297df0ccbaSfvdl {
8307df0ccbaSfvdl #ifdef INET6
8317df0ccbaSfvdl 	struct sockaddr *sa_new, *sa_svc;
8327df0ccbaSfvdl 	struct sockaddr_in6 *sin6_new, *sin6_svc;
8337df0ccbaSfvdl 
8340e8cfd8fSlukem 	_DIAGASSERT(new != NULL);
8350e8cfd8fSlukem 	_DIAGASSERT(svc != NULL);
8360e8cfd8fSlukem 
8377df0ccbaSfvdl 	sa_svc = (struct sockaddr *)svc->buf;
8387df0ccbaSfvdl 	sa_new = (struct sockaddr *)new->buf;
8397df0ccbaSfvdl 
8407df0ccbaSfvdl 	if (sa_new->sa_family == sa_svc->sa_family &&
8417df0ccbaSfvdl 	    sa_new->sa_family == AF_INET6) {
8427df0ccbaSfvdl 		sin6_new = (struct sockaddr_in6 *)new->buf;
8437df0ccbaSfvdl 		sin6_svc = (struct sockaddr_in6 *)svc->buf;
8447df0ccbaSfvdl 
8457df0ccbaSfvdl 		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
8467df0ccbaSfvdl 		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
8477df0ccbaSfvdl 		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
8487df0ccbaSfvdl 		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
8497df0ccbaSfvdl 			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
8507df0ccbaSfvdl 		}
8517df0ccbaSfvdl 	}
8527df0ccbaSfvdl #endif
8537df0ccbaSfvdl 	return 1;
8547df0ccbaSfvdl }
8557df0ccbaSfvdl 
8567df0ccbaSfvdl int
__rpc_sockisbound(int fd)8577df0ccbaSfvdl __rpc_sockisbound(int fd)
8587df0ccbaSfvdl {
8597df0ccbaSfvdl 	struct sockaddr_storage ss;
8607df0ccbaSfvdl 	socklen_t slen;
8617df0ccbaSfvdl 
8627df0ccbaSfvdl 	slen = sizeof (struct sockaddr_storage);
863deb154d2Schristos 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
8647df0ccbaSfvdl 		return 0;
8657df0ccbaSfvdl 
8667df0ccbaSfvdl 	switch (ss.ss_family) {
8677df0ccbaSfvdl 		case AF_INET:
868deb154d2Schristos 			return (((struct sockaddr_in *)
869deb154d2Schristos 			    (void *)&ss)->sin_port != 0);
8707df0ccbaSfvdl #ifdef INET6
8717df0ccbaSfvdl 		case AF_INET6:
872deb154d2Schristos 			return (((struct sockaddr_in6 *)
873deb154d2Schristos 			    (void *)&ss)->sin6_port != 0);
8747df0ccbaSfvdl #endif
8757df0ccbaSfvdl 		case AF_LOCAL:
8767df0ccbaSfvdl 			/* XXX check this */
877deb154d2Schristos 			return (((struct sockaddr_un *)
878deb154d2Schristos 			    (void *)&ss)->sun_path[0] != '\0');
8797df0ccbaSfvdl 		default:
8807df0ccbaSfvdl 			break;
8817df0ccbaSfvdl 	}
8827df0ccbaSfvdl 
8837df0ccbaSfvdl 	return 0;
8847df0ccbaSfvdl }
885eadd73deSchristos 
886eadd73deSchristos /*
887eadd73deSchristos  * For TCP transport, Host Requirements RFCs mandate
888eadd73deSchristos  * Nagle (RFC-896) processing.  But for RPC, Nagle
889eadd73deSchristos  * processing adds adds unwanted latency to the last,
890eadd73deSchristos  * partial TCP segment of each RPC message. See:
891eadd73deSchristos  *   R. W. Scheifler and J. Gettys, The X Window System,
892eadd73deSchristos  *   ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69.
893eadd73deSchristos  * So for TCP transport, disable Nagle via TCP_NODELAY.
894eadd73deSchristos  * XXX: moral equivalent for non-TCP protocols?
895eadd73deSchristos  */
896eadd73deSchristos int
__rpc_setnodelay(int fd,const struct __rpc_sockinfo * si)897eadd73deSchristos __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si)
898eadd73deSchristos {
899eadd73deSchristos 	int one = 1;
900eadd73deSchristos 	if (si->si_proto != IPPROTO_TCP)
901eadd73deSchristos 		return 0;
902e826745eSchristos 	return setsockopt(fd, si->si_proto, TCP_NODELAY, &one,
903e826745eSchristos 	    (socklen_t)sizeof(one));
904eadd73deSchristos }
905