2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
28 * @(#)rpc_generic.c 1.17 94/04/24 SMI
29 * $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $
30 * $FreeBSD: src/lib/libc/rpc/rpc_generic.c,v 1.14 2007/09/20 22:35:24 matteo Exp $
33 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
37 * rpc_generic.c, Misc routines for RPC.
41 #include "namespace.h"
42 #include "reentrant.h"
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
48 #include <sys/resource.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
56 #include <netconfig.h>
60 #include <rpc/nettype.h>
61 #include "un-namespace.h"
66 NCONF_HANDLE
*nhandle
;
67 int nflag
; /* Whether NETPATH or NETCONFIG */
71 static const struct _rpcnettype
{
75 { "netpath", _RPC_NETPATH
},
76 { "visible", _RPC_VISIBLE
},
77 { "circuit_v", _RPC_CIRCUIT_V
},
78 { "datagram_v", _RPC_DATAGRAM_V
},
79 { "circuit_n", _RPC_CIRCUIT_N
},
80 { "datagram_n", _RPC_DATAGRAM_N
},
92 static const struct netid_af na_cvt
[] = {
93 { "udp", AF_INET
, IPPROTO_UDP
},
94 { "tcp", AF_INET
, IPPROTO_TCP
},
96 { "udp6", AF_INET6
, IPPROTO_UDP
},
97 { "tcp6", AF_INET6
, IPPROTO_TCP
},
99 { "local", AF_LOCAL
, 0 }
103 static char *strlocase(char *);
105 static int getnettype(const char *);
108 * Cache the result of getrlimit(), so we don't have to do an
109 * expensive call every time.
120 if (getrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
121 return (tbsize
= (int)rl
.rlim_max
);
124 * Something wrong. I'll try to save face by returning a
125 * pessimistic number.
132 * Find the appropriate buffer size
136 __rpc_get_t_size(int af
, int proto
,
137 int size
) /* Size requested */
139 int maxsize
, defsize
;
141 maxsize
= 256 * 1024; /* XXX */
144 defsize
= 64 * 1024; /* XXX */
147 defsize
= UDPMSGSIZE
;
150 defsize
= RPC_MAXDATASIZE
;
156 /* Check whether the value is within the upper max limit */
157 return (size
> maxsize
? (u_int
)maxsize
: (u_int
)size
);
161 * Find the appropriate address buffer size
164 __rpc_get_a_size(int af
)
168 return sizeof (struct sockaddr_in
);
171 return sizeof (struct sockaddr_in6
);
174 return sizeof (struct sockaddr_un
);
178 return ((u_int
)RPC_MAXADDRSIZE
);
195 * Returns the type of the network as defined in <rpc/nettype.h>
196 * If nettype is NULL, it defaults to NETPATH.
199 getnettype(const char *nettype
)
203 if ((nettype
== NULL
) || (nettype
[0] == 0)) {
204 return (_RPC_NETPATH
); /* Default */
208 nettype
= strlocase(nettype
);
210 for (i
= 0; _rpctypelist
[i
].name
; i
++)
211 if (strcasecmp(nettype
, _rpctypelist
[i
].name
) == 0) {
212 return (_rpctypelist
[i
].type
);
214 return (_rpctypelist
[i
].type
);
218 * For the given nettype (tcp or udp only), return the first structure found.
219 * This should be freed by calling freenetconfigent()
222 __rpc_getconfip(const char *nettype
)
225 char *netid_tcp
= NULL
;
226 char *netid_udp
= NULL
;
227 static char *netid_tcp_main
;
228 static char *netid_udp_main
;
229 struct netconfig
*dummy
;
231 static thread_key_t tcp_key
, udp_key
;
233 if ((main_thread
= thr_main())) {
234 netid_udp
= netid_udp_main
;
235 netid_tcp
= netid_tcp_main
;
238 mutex_lock(&tsd_lock
);
240 thr_keycreate(&tcp_key
, free
);
241 mutex_unlock(&tsd_lock
);
243 netid_tcp
= (char *)thr_getspecific(tcp_key
);
245 mutex_lock(&tsd_lock
);
247 thr_keycreate(&udp_key
, free
);
248 mutex_unlock(&tsd_lock
);
250 netid_udp
= (char *)thr_getspecific(udp_key
);
252 if (!netid_udp
&& !netid_tcp
) {
253 struct netconfig
*nconf
;
256 if (!(confighandle
= setnetconfig())) {
257 syslog (LOG_ERR
, "rpc: failed to open " NETCONFIG
);
260 while ((nconf
= getnetconfig(confighandle
)) != NULL
) {
261 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) {
262 if (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) {
263 netid_tcp
= strdup(nconf
->nc_netid
);
265 netid_tcp_main
= netid_tcp
;
267 thr_setspecific(tcp_key
,
270 if (strcmp(nconf
->nc_proto
, NC_UDP
) == 0) {
271 netid_udp
= strdup(nconf
->nc_netid
);
273 netid_udp_main
= netid_udp
;
275 thr_setspecific(udp_key
,
280 endnetconfig(confighandle
);
282 if (strcmp(nettype
, "udp") == 0)
284 else if (strcmp(nettype
, "tcp") == 0)
289 if ((netid
== NULL
) || (netid
[0] == 0)) {
292 dummy
= getnetconfigent(netid
);
297 * Returns the type of the nettype, which should then be used with
301 __rpc_setconf(const char *nettype
)
303 struct handle
*handle
;
305 handle
= (struct handle
*) malloc(sizeof (struct handle
));
306 if (handle
== NULL
) {
309 switch (handle
->nettype
= getnettype(nettype
)) {
312 case _RPC_DATAGRAM_N
:
313 if (!(handle
->nhandle
= setnetpath()))
315 handle
->nflag
= TRUE
;
319 case _RPC_DATAGRAM_V
:
322 if (!(handle
->nhandle
= setnetconfig())) {
323 syslog (LOG_ERR
, "rpc: failed to open " NETCONFIG
);
326 handle
->nflag
= FALSE
;
340 * Returns the next netconfig struct for the given "net" type.
341 * __rpc_setconf() should have been called previously.
344 __rpc_getconf(void *vhandle
)
346 struct handle
*handle
;
347 struct netconfig
*nconf
;
349 handle
= (struct handle
*)vhandle
;
350 if (handle
== NULL
) {
355 nconf
= getnetpath(handle
->nhandle
);
357 nconf
= getnetconfig(handle
->nhandle
);
360 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) &&
361 (nconf
->nc_semantics
!= NC_TPI_COTS
) &&
362 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
364 switch (handle
->nettype
) {
366 if (!(nconf
->nc_flag
& NC_VISIBLE
))
369 case _RPC_NETPATH
: /* Be happy */
372 if (!(nconf
->nc_flag
& NC_VISIBLE
))
376 if ((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
377 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
380 case _RPC_DATAGRAM_V
:
381 if (!(nconf
->nc_flag
& NC_VISIBLE
))
384 case _RPC_DATAGRAM_N
:
385 if (nconf
->nc_semantics
!= NC_TPI_CLTS
)
389 if (((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
390 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
)) ||
391 (strcmp(nconf
->nc_protofmly
, NC_INET
)
393 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
398 strcmp(nconf
->nc_proto
, NC_TCP
))
402 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) ||
403 (strcmp(nconf
->nc_protofmly
, NC_INET
)
405 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
410 strcmp(nconf
->nc_proto
, NC_UDP
))
420 __rpc_endconf(void *vhandle
)
422 struct handle
*handle
;
424 handle
= (struct handle
*) vhandle
;
425 if (handle
== NULL
) {
429 endnetpath(handle
->nhandle
);
431 endnetconfig(handle
->nhandle
);
437 * Used to ping the NULL procedure for clnt handle.
438 * Returns NULL if fails, else a non-NULL pointer.
441 rpc_nullproc(CLIENT
*clnt
)
443 struct timeval TIMEOUT
= {25, 0};
445 if (clnt_call(clnt
, NULLPROC
, (xdrproc_t
) xdr_void
, NULL
,
446 (xdrproc_t
) xdr_void
, NULL
, TIMEOUT
) != RPC_SUCCESS
) {
449 return ((void *) clnt
);
453 * Try all possible transports until
454 * one succeeds in finding the netconf for the given fd.
460 struct __rpc_sockinfo si
;
462 if (!__rpc_fd2sockinfo(fd
, &si
))
465 if (!__rpc_sockinfo2netid(&si
, &netid
))
468 /*LINTED const castaway*/
469 return getnetconfigent((char *)netid
);
473 __rpc_fd2sockinfo(int fd
, struct __rpc_sockinfo
*sip
)
477 struct sockaddr_storage ss
;
480 if (_getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &len
) < 0)
485 if (_getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &type
, &len
) < 0)
489 if (ss
.ss_family
!= AF_LOCAL
) {
490 if (type
== SOCK_STREAM
)
492 else if (type
== SOCK_DGRAM
)
499 sip
->si_af
= ss
.ss_family
;
500 sip
->si_proto
= proto
;
501 sip
->si_socktype
= type
;
507 * Linear search, but the number of entries is small.
510 __rpc_nconf2sockinfo(const struct netconfig
*nconf
, struct __rpc_sockinfo
*sip
)
514 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++)
515 if (strcmp(na_cvt
[i
].netid
, nconf
->nc_netid
) == 0 || (
516 strcmp(nconf
->nc_netid
, "unix") == 0 &&
517 strcmp(na_cvt
[i
].netid
, "local") == 0)) {
518 sip
->si_af
= na_cvt
[i
].af
;
519 sip
->si_proto
= na_cvt
[i
].protocol
;
521 __rpc_seman2socktype((int)nconf
->nc_semantics
);
522 if (sip
->si_socktype
== -1)
524 sip
->si_alen
= __rpc_get_a_size(sip
->si_af
);
532 __rpc_nconf2fd(const struct netconfig
*nconf
)
534 struct __rpc_sockinfo si
;
536 if (!__rpc_nconf2sockinfo(nconf
, &si
))
539 return _socket(si
.si_af
, si
.si_socktype
, si
.si_proto
);
543 __rpc_sockinfo2netid(struct __rpc_sockinfo
*sip
, const char **netid
)
546 struct netconfig
*nconf
;
548 nconf
= getnetconfigent("local");
550 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++) {
551 if (na_cvt
[i
].af
== sip
->si_af
&&
552 na_cvt
[i
].protocol
== sip
->si_proto
) {
553 if (strcmp(na_cvt
[i
].netid
, "local") == 0 && nconf
== NULL
) {
558 *netid
= na_cvt
[i
].netid
;
561 freenetconfigent(nconf
);
566 freenetconfigent(nconf
);
572 taddr2uaddr(const struct netconfig
*nconf
, const struct netbuf
*nbuf
)
574 struct __rpc_sockinfo si
;
576 if (!__rpc_nconf2sockinfo(nconf
, &si
))
578 return __rpc_taddr2uaddr_af(si
.si_af
, nbuf
);
582 uaddr2taddr(const struct netconfig
*nconf
, const char *uaddr
)
584 struct __rpc_sockinfo si
;
586 if (!__rpc_nconf2sockinfo(nconf
, &si
))
588 return __rpc_uaddr2taddr_af(si
.si_af
, uaddr
);
592 __rpc_taddr2uaddr_af(int af
, const struct netbuf
*nbuf
)
595 struct sockaddr_in
*sin
;
596 struct sockaddr_un
*sun
;
597 char namebuf
[INET_ADDRSTRLEN
];
599 struct sockaddr_in6
*sin6
;
600 char namebuf6
[INET6_ADDRSTRLEN
];
607 if (inet_ntop(af
, &sin
->sin_addr
, namebuf
, sizeof namebuf
)
610 port
= ntohs(sin
->sin_port
);
611 if (asprintf(&ret
, "%s.%u.%u", namebuf
, ((u_int32_t
)port
) >> 8,
618 if (inet_ntop(af
, &sin6
->sin6_addr
, namebuf6
, sizeof namebuf6
)
621 port
= ntohs(sin6
->sin6_port
);
622 if (asprintf(&ret
, "%s.%u.%u", namebuf6
, ((u_int32_t
)port
) >> 8,
629 if (asprintf(&ret
, "%.*s", (int)(sun
->sun_len
-
630 offsetof(struct sockaddr_un
, sun_path
)),
642 __rpc_uaddr2taddr_af(int af
, const char *uaddr
)
644 struct netbuf
*ret
= NULL
;
646 unsigned port
, portlo
, porthi
;
647 struct sockaddr_in
*sin
;
649 struct sockaddr_in6
*sin6
;
651 struct sockaddr_un
*sun
;
655 addrstr
= strdup(uaddr
);
660 * AF_LOCAL addresses are expected to be absolute
661 * pathnames, anything else will be AF_INET or AF_INET6.
663 if (*addrstr
!= '/') {
664 p
= strrchr(addrstr
, '.');
667 portlo
= (unsigned)atoi(p
+ 1);
670 p
= strrchr(addrstr
, '.');
673 porthi
= (unsigned)atoi(p
+ 1);
675 port
= (porthi
<< 8) | portlo
;
678 ret
= (struct netbuf
*)malloc(sizeof *ret
);
684 sin
= (struct sockaddr_in
*)malloc(sizeof *sin
);
687 memset(sin
, 0, sizeof *sin
);
688 sin
->sin_family
= AF_INET
;
689 sin
->sin_port
= htons(port
);
690 if (inet_pton(AF_INET
, addrstr
, &sin
->sin_addr
) <= 0) {
696 sin
->sin_len
= ret
->maxlen
= ret
->len
= sizeof *sin
;
701 sin6
= (struct sockaddr_in6
*)malloc(sizeof *sin6
);
704 memset(sin6
, 0, sizeof *sin6
);
705 sin6
->sin6_family
= AF_INET6
;
706 sin6
->sin6_port
= htons(port
);
707 if (inet_pton(AF_INET6
, addrstr
, &sin6
->sin6_addr
) <= 0) {
713 sin6
->sin6_len
= ret
->maxlen
= ret
->len
= sizeof *sin6
;
718 sun
= (struct sockaddr_un
*)malloc(sizeof *sun
);
721 memset(sun
, 0, sizeof *sun
);
722 sun
->sun_family
= AF_LOCAL
;
723 strncpy(sun
->sun_path
, addrstr
, sizeof(sun
->sun_path
) - 1);
724 ret
->len
= ret
->maxlen
= sun
->sun_len
= SUN_LEN(sun
);
736 __rpc_seman2socktype(int semantics
)
741 case NC_TPI_COTS_ORD
:
753 __rpc_socktype2seman(int socktype
)
759 return NC_TPI_COTS_ORD
;
770 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
771 * Here, we compare the original server address to that of the RPC
772 * service we just received back from a call to rpcbind on the remote
773 * machine. If they are both "link local" or "site local", copy
774 * the scope id of the server address over to the service address.
777 __rpc_fixup_addr(struct netbuf
*new, const struct netbuf
*svc
)
780 struct sockaddr
*sa_new
, *sa_svc
;
781 struct sockaddr_in6
*sin6_new
, *sin6_svc
;
783 sa_svc
= (struct sockaddr
*)svc
->buf
;
784 sa_new
= (struct sockaddr
*)new->buf
;
786 if (sa_new
->sa_family
== sa_svc
->sa_family
&&
787 sa_new
->sa_family
== AF_INET6
) {
788 sin6_new
= (struct sockaddr_in6
*)new->buf
;
789 sin6_svc
= (struct sockaddr_in6
*)svc
->buf
;
791 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new
->sin6_addr
) &&
792 IN6_IS_ADDR_LINKLOCAL(&sin6_svc
->sin6_addr
)) ||
793 (IN6_IS_ADDR_SITELOCAL(&sin6_new
->sin6_addr
) &&
794 IN6_IS_ADDR_SITELOCAL(&sin6_svc
->sin6_addr
))) {
795 sin6_new
->sin6_scope_id
= sin6_svc
->sin6_scope_id
;
803 __rpc_sockisbound(int fd
)
805 struct sockaddr_storage ss
;
808 slen
= sizeof (struct sockaddr_storage
);
809 if (_getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0)
812 switch (ss
.ss_family
) {
814 return (((struct sockaddr_in
*)
815 (void *)&ss
)->sin_port
!= 0);
818 return (((struct sockaddr_in6
*)
819 (void *)&ss
)->sin6_port
!= 0);
823 return (((struct sockaddr_un
*)
824 (void *)&ss
)->sun_path
[0] != '\0');