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