1 /* $NetBSD: rpc_generic.c,v 1.29 2013/04/05 03:17:38 dholland Exp $ */
4 * Copyright (c) 2010, Oracle America, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of the "Oracle America, Inc." nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
37 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
40 * rpc_generic.c, Miscl routines for RPC.
44 #include <sys/cdefs.h>
45 #if defined(LIBC_SCCS) && !defined(lint)
46 __RCSID("$NetBSD: rpc_generic.c,v 1.29 2013/04/05 03:17:38 dholland Exp $");
49 #include "namespace.h"
50 #include "reentrant.h"
51 #include <sys/types.h>
52 #include <sys/param.h>
53 #include <sys/socket.h>
55 #include <sys/resource.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58 #include <arpa/inet.h>
64 #include <netconfig.h>
68 #include <rpc/nettype.h>
70 #include "svc_fdset.h"
71 #include "rpc_internal.h"
74 __weak_alias(taddr2uaddr
,_taddr2uaddr
)
75 __weak_alias(uaddr2taddr
,_uaddr2taddr
)
79 NCONF_HANDLE
*nhandle
;
80 int nflag
; /* Whether NETPATH or NETCONFIG */
84 static const struct _rpcnettype
{
88 { "netpath", _RPC_NETPATH
},
89 { "visible", _RPC_VISIBLE
},
90 { "circuit_v", _RPC_CIRCUIT_V
},
91 { "datagram_v", _RPC_DATAGRAM_V
},
92 { "circuit_n", _RPC_CIRCUIT_N
},
93 { "datagram_n", _RPC_DATAGRAM_N
},
105 static const struct netid_af na_cvt
[] = {
106 { "udp", AF_INET
, IPPROTO_UDP
},
107 { "tcp", AF_INET
, IPPROTO_TCP
},
109 { "udp6", AF_INET6
, IPPROTO_UDP
},
110 { "tcp6", AF_INET6
, IPPROTO_TCP
},
112 { "local", AF_LOCAL
, 0 }
116 static char *strlocase(char *);
118 static int getnettype(const char *);
121 * Cache the result of getrlimit(), so we don't have to do an
122 * expensive call every time.
133 if (getrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
134 return (tbsize
= (int)rl
.rlim_max
);
137 * Something wrong. I'll try to save face by returning a
138 * pessimistic number.
145 * Find the appropriate buffer size
152 int size
) /* Size requested */
154 int maxsize
, defsize
;
156 maxsize
= 256 * 1024; /* XXX */
159 defsize
= 64 * 1024; /* XXX */
162 defsize
= UDPMSGSIZE
;
165 defsize
= RPC_MAXDATASIZE
;
171 /* Check whether the value is within the upper max limit */
172 return (size
> maxsize
? (u_int
)maxsize
: (u_int
)size
);
176 * Find the appropriate address buffer size
179 __rpc_get_a_size(int af
)
183 return sizeof (struct sockaddr_in
);
186 return sizeof (struct sockaddr_in6
);
189 return sizeof (struct sockaddr_un
);
193 return ((u_int
)RPC_MAXADDRSIZE
);
202 _DIAGASSERT(p
!= NULL
);
212 * Returns the type of the network as defined in <rpc/nettype.h>
213 * If nettype is NULL, it defaults to NETPATH.
216 getnettype(const char *nettype
)
220 if ((nettype
== NULL
) || (nettype
[0] == 0)) {
221 return (_RPC_NETPATH
); /* Default */
225 nettype
= strlocase(nettype
);
227 for (i
= 0; _rpctypelist
[i
].name
; i
++)
228 if (strcasecmp(nettype
, _rpctypelist
[i
].name
) == 0) {
229 return (_rpctypelist
[i
].type
);
231 return (_rpctypelist
[i
].type
);
235 * For the given nettype (tcp or udp only), return the first structure found.
236 * This should be freed by calling freenetconfigent()
240 static thread_key_t tcp_key
, udp_key
;
241 static once_t __rpc_getconfigp_once
= ONCE_INITIALIZER
;
244 __rpc_getconfigp_setup(void)
247 thr_keycreate(&tcp_key
, free
);
248 thr_keycreate(&udp_key
, free
);
253 __rpc_getconfip(const char *nettype
)
256 char *netid_tcp
= NULL
;
257 char *netid_udp
= NULL
;
258 static char *netid_tcp_main
;
259 static char *netid_udp_main
;
260 struct netconfig
*dummy
;
262 if (__isthreaded
== 0) {
263 netid_udp
= netid_udp_main
;
264 netid_tcp
= netid_tcp_main
;
266 thr_once(&__rpc_getconfigp_once
, __rpc_getconfigp_setup
);
267 netid_tcp
= thr_getspecific(tcp_key
);
268 netid_udp
= thr_getspecific(udp_key
);
271 netid_udp
= netid_udp_main
;
272 netid_tcp
= netid_tcp_main
;
275 _DIAGASSERT(nettype
!= NULL
);
277 if (!netid_udp
&& !netid_tcp
) {
278 struct netconfig
*nconf
;
281 if (!(confighandle
= setnetconfig())) {
282 syslog (LOG_ERR
, "rpc: failed to open " NETCONFIG
);
285 while ((nconf
= getnetconfig(confighandle
)) != NULL
) {
286 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) {
287 if (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) {
288 netid_tcp
= strdup(nconf
->nc_netid
);
289 if (netid_tcp
== NULL
)
292 if (__isthreaded
== 0)
293 netid_tcp_main
= netid_tcp
;
295 thr_setspecific(tcp_key
,
298 netid_tcp_main
= netid_tcp
;
301 if (strcmp(nconf
->nc_proto
, NC_UDP
) == 0) {
302 netid_udp
= strdup(nconf
->nc_netid
);
303 if (netid_udp
== NULL
)
306 if (__isthreaded
== 0)
307 netid_udp_main
= netid_udp
;
309 thr_setspecific(udp_key
,
312 netid_udp_main
= netid_udp
;
317 endnetconfig(confighandle
);
319 if (strcmp(nettype
, "udp") == 0)
321 else if (strcmp(nettype
, "tcp") == 0)
326 if ((netid
== NULL
) || (netid
[0] == 0)) {
329 dummy
= getnetconfigent(netid
);
334 * Returns the type of the nettype, which should then be used with
338 __rpc_setconf(const char *nettype
)
340 struct handle
*handle
;
342 /* nettype may be NULL; getnettype() supports that */
344 handle
= malloc(sizeof(*handle
));
345 if (handle
== NULL
) {
348 switch (handle
->nettype
= getnettype(nettype
)) {
351 case _RPC_DATAGRAM_N
:
352 if (!(handle
->nhandle
= setnetpath())) {
356 handle
->nflag
= TRUE
;
360 case _RPC_DATAGRAM_V
:
363 if (!(handle
->nhandle
= setnetconfig())) {
364 syslog (LOG_ERR
, "rpc: failed to open " NETCONFIG
);
368 handle
->nflag
= FALSE
;
379 * Returns the next netconfig struct for the given "net" type.
380 * __rpc_setconf() should have been called previously.
383 __rpc_getconf(void *vhandle
)
385 struct handle
*handle
;
386 struct netconfig
*nconf
;
388 handle
= (struct handle
*)vhandle
;
389 if (handle
== NULL
) {
394 nconf
= getnetpath(handle
->nhandle
);
396 nconf
= getnetconfig(handle
->nhandle
);
399 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) &&
400 (nconf
->nc_semantics
!= NC_TPI_COTS
) &&
401 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
403 switch (handle
->nettype
) {
405 if (!(nconf
->nc_flag
& NC_VISIBLE
))
408 case _RPC_NETPATH
: /* Be happy */
411 if (!(nconf
->nc_flag
& NC_VISIBLE
))
415 if ((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
416 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
419 case _RPC_DATAGRAM_V
:
420 if (!(nconf
->nc_flag
& NC_VISIBLE
))
423 case _RPC_DATAGRAM_N
:
424 if (nconf
->nc_semantics
!= NC_TPI_CLTS
)
428 if (((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
429 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
)) ||
430 (strcmp(nconf
->nc_protofmly
, NC_INET
)
432 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
437 strcmp(nconf
->nc_proto
, NC_TCP
))
441 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) ||
442 (strcmp(nconf
->nc_protofmly
, NC_INET
)
444 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
449 strcmp(nconf
->nc_proto
, NC_UDP
))
459 __rpc_endconf(void *vhandle
)
461 struct handle
*handle
;
463 handle
= (struct handle
*) vhandle
;
464 if (handle
== NULL
) {
468 endnetpath(handle
->nhandle
);
470 endnetconfig(handle
->nhandle
);
476 * Used to ping the NULL procedure for clnt handle.
477 * Returns NULL if fails, else a non-NULL pointer.
480 rpc_nullproc(CLIENT
*clnt
)
482 struct timeval TIMEOUT
= {25, 0};
484 if (clnt_call(clnt
, NULLPROC
, (xdrproc_t
) xdr_void
, NULL
,
485 (xdrproc_t
) xdr_void
, NULL
, TIMEOUT
) != RPC_SUCCESS
) {
488 return ((void *) clnt
);
492 * Try all possible transports until
493 * one succeeds in finding the netconf for the given fd.
499 struct __rpc_sockinfo si
;
501 if (!__rpc_fd2sockinfo(fd
, &si
))
504 if (!__rpc_sockinfo2netid(&si
, &netid
))
507 return getnetconfigent(__UNCONST(netid
));
511 __rpc_fd2sockinfo(int fd
, struct __rpc_sockinfo
*sip
)
515 struct sockaddr_storage ss
;
517 _DIAGASSERT(sip
!= NULL
);
520 if (getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &len
) < 0)
525 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &type
, &len
) < 0)
529 if (ss
.ss_family
!= AF_LOCAL
) {
530 if (type
== SOCK_STREAM
)
532 else if (type
== SOCK_DGRAM
)
539 sip
->si_af
= ss
.ss_family
;
540 sip
->si_proto
= proto
;
541 sip
->si_socktype
= type
;
547 * Linear search, but the number of entries is small.
550 __rpc_nconf2sockinfo(const struct netconfig
*nconf
, struct __rpc_sockinfo
*sip
)
554 _DIAGASSERT(nconf
!= NULL
);
555 _DIAGASSERT(sip
!= NULL
);
557 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++)
558 if (!strcmp(na_cvt
[i
].netid
, nconf
->nc_netid
)) {
559 sip
->si_af
= na_cvt
[i
].af
;
560 sip
->si_proto
= na_cvt
[i
].protocol
;
562 __rpc_seman2socktype((int)nconf
->nc_semantics
);
563 if (sip
->si_socktype
== -1)
565 sip
->si_alen
= __rpc_get_a_size(sip
->si_af
);
573 __rpc_nconf2fd(const struct netconfig
*nconf
)
575 struct __rpc_sockinfo si
;
577 _DIAGASSERT(nconf
!= NULL
);
579 if (!__rpc_nconf2sockinfo(nconf
, &si
))
582 return socket(si
.si_af
, si
.si_socktype
, si
.si_proto
);
586 __rpc_sockinfo2netid(struct __rpc_sockinfo
*sip
, const char **netid
)
590 _DIAGASSERT(sip
!= NULL
);
591 /* netid may be NULL */
593 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++)
594 if (na_cvt
[i
].af
== sip
->si_af
&&
595 na_cvt
[i
].protocol
== sip
->si_proto
) {
597 *netid
= na_cvt
[i
].netid
;
605 taddr2uaddr(const struct netconfig
*nconf
, const struct netbuf
*nbuf
)
607 struct __rpc_sockinfo si
;
609 _DIAGASSERT(nconf
!= NULL
);
610 _DIAGASSERT(nbuf
!= NULL
);
612 if (!__rpc_nconf2sockinfo(nconf
, &si
))
614 return __rpc_taddr2uaddr_af(si
.si_af
, nbuf
);
618 uaddr2taddr(const struct netconfig
*nconf
, const char *uaddr
)
620 struct __rpc_sockinfo si
;
622 _DIAGASSERT(nconf
!= NULL
);
623 _DIAGASSERT(uaddr
!= NULL
);
625 if (!__rpc_nconf2sockinfo(nconf
, &si
))
627 return __rpc_uaddr2taddr_af(si
.si_af
, uaddr
);
631 __rpc_taddr2uaddr_af(int af
, const struct netbuf
*nbuf
)
634 struct sockaddr_in
*sinp
;
635 struct sockaddr_un
*sun
;
636 char namebuf
[INET_ADDRSTRLEN
];
638 struct sockaddr_in6
*sin6
;
639 char namebuf6
[INET6_ADDRSTRLEN
];
643 _DIAGASSERT(nbuf
!= NULL
);
648 if (inet_ntop(af
, &sinp
->sin_addr
, namebuf
,
649 (socklen_t
)sizeof namebuf
) == NULL
)
651 port
= ntohs(sinp
->sin_port
);
652 if (asprintf(&ret
, "%s.%u.%u", namebuf
, ((u_int32_t
)port
) >> 8,
659 if (inet_ntop(af
, &sin6
->sin6_addr
, namebuf6
,
660 (socklen_t
)sizeof namebuf6
) == NULL
)
662 port
= ntohs(sin6
->sin6_port
);
663 if (asprintf(&ret
, "%s.%u.%u", namebuf6
, ((u_int32_t
)port
) >> 8,
670 sun
->sun_path
[sizeof(sun
->sun_path
) - 1] = '\0'; /* safety */
671 ret
= strdup(sun
->sun_path
);
681 __rpc_uaddr2taddr_af(int af
, const char *uaddr
)
683 struct netbuf
*ret
= NULL
;
685 unsigned port
, portlo
, porthi
;
687 struct sockaddr_in
*sinp
;
689 struct sockaddr_in6
*sin6
;
691 struct sockaddr_un
*sun
;
693 _DIAGASSERT(uaddr
!= NULL
);
695 addrstr
= strdup(uaddr
);
700 * AF_LOCAL addresses are expected to be absolute
701 * pathnames, anything else will be AF_INET or AF_INET6.
704 if (*addrstr
!= '/') {
705 p
= strrchr(addrstr
, '.');
708 portlo
= (unsigned)atoi(p
+ 1);
711 p
= strrchr(addrstr
, '.');
714 porthi
= (unsigned)atoi(p
+ 1);
716 port
= (porthi
<< 8) | portlo
;
719 ret
= malloc(sizeof(*ret
));
725 sinp
= malloc(sizeof(*sinp
));
728 memset(sinp
, 0, sizeof *sinp
);
729 sinp
->sin_family
= AF_INET
;
730 sinp
->sin_port
= htons(port
);
731 if (inet_pton(AF_INET
, addrstr
, &sinp
->sin_addr
) <= 0) {
737 sinp
->sin_len
= ret
->maxlen
= ret
->len
= sizeof *sinp
;
742 sin6
= malloc(sizeof(*sin6
));
745 memset(sin6
, 0, sizeof *sin6
);
746 sin6
->sin6_family
= AF_INET6
;
747 sin6
->sin6_port
= htons(port
);
748 if (inet_pton(AF_INET6
, addrstr
, &sin6
->sin6_addr
) <= 0) {
754 sin6
->sin6_len
= ret
->maxlen
= ret
->len
= sizeof *sin6
;
759 sun
= malloc(sizeof(*sun
));
762 memset(sun
, 0, sizeof *sun
);
763 sun
->sun_family
= AF_LOCAL
;
764 strncpy(sun
->sun_path
, addrstr
, sizeof(sun
->sun_path
) - 1);
766 _DIAGASSERT(__type_fit(uint8_t, len
));
767 ret
->len
= ret
->maxlen
= sun
->sun_len
= (uint8_t)len
;
779 __rpc_seman2socktype(int semantics
)
784 case NC_TPI_COTS_ORD
:
796 __rpc_socktype2seman(int socktype
)
802 return NC_TPI_COTS_ORD
;
813 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
814 * Here, we compare the original server address to that of the RPC
815 * service we just received back from a call to rpcbind on the remote
816 * machine. If they are both "link local" or "site local", copy
817 * the scope id of the server address over to the service address.
821 __rpc_fixup_addr(struct netbuf
*new, const struct netbuf
*svc
)
824 struct sockaddr
*sa_new
, *sa_svc
;
825 struct sockaddr_in6
*sin6_new
, *sin6_svc
;
827 _DIAGASSERT(new != NULL
);
828 _DIAGASSERT(svc
!= NULL
);
830 sa_svc
= (struct sockaddr
*)svc
->buf
;
831 sa_new
= (struct sockaddr
*)new->buf
;
833 if (sa_new
->sa_family
== sa_svc
->sa_family
&&
834 sa_new
->sa_family
== AF_INET6
) {
835 sin6_new
= (struct sockaddr_in6
*)new->buf
;
836 sin6_svc
= (struct sockaddr_in6
*)svc
->buf
;
838 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new
->sin6_addr
) &&
839 IN6_IS_ADDR_LINKLOCAL(&sin6_svc
->sin6_addr
)) ||
840 (IN6_IS_ADDR_SITELOCAL(&sin6_new
->sin6_addr
) &&
841 IN6_IS_ADDR_SITELOCAL(&sin6_svc
->sin6_addr
))) {
842 sin6_new
->sin6_scope_id
= sin6_svc
->sin6_scope_id
;
850 __rpc_sockisbound(int fd
)
852 struct sockaddr_storage ss
;
855 slen
= sizeof (struct sockaddr_storage
);
856 if (getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0)
859 switch (ss
.ss_family
) {
861 return (((struct sockaddr_in
*)
862 (void *)&ss
)->sin_port
!= 0);
865 return (((struct sockaddr_in6
*)
866 (void *)&ss
)->sin6_port
!= 0);
870 return (((struct sockaddr_un
*)
871 (void *)&ss
)->sun_path
[0] != '\0');
880 * For TCP transport, Host Requirements RFCs mandate
881 * Nagle (RFC-896) processing. But for RPC, Nagle
882 * processing adds adds unwanted latency to the last,
883 * partial TCP segment of each RPC message. See:
884 * R. W. Scheifler and J. Gettys, The X Window System,
885 * ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69.
886 * So for TCP transport, disable Nagle via TCP_NODELAY.
887 * XXX: moral equivalent for non-TCP protocols?
890 __rpc_setnodelay(int fd
, const struct __rpc_sockinfo
*si
)
893 if (si
->si_proto
!= IPPROTO_TCP
)
895 return setsockopt(fd
, si
->si_proto
, TCP_NODELAY
, &one
,
896 (socklen_t
)sizeof(one
));