2 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
32 //#include <sys/cdefs.h>
35 * rpc_generic.c, Miscl routines for RPC.
39 //#include <pthread.h>
40 #include <reentrant.h>
41 #include <sys/types.h>
42 //#include <sys/param.h>
43 //#include <sys/socket.h>
44 //#include <sys/time.h>
46 //#include <sys/resource.h>
47 //#include <netinet/in.h>
48 //#include <arpa/inet.h>
54 #include <netconfig.h>
58 #include <rpc/nettype.h>
62 NCONF_HANDLE
*nhandle
;
63 int nflag
; /* Whether NETPATH or NETCONFIG */
67 static const struct _rpcnettype
{
71 { "netpath", _RPC_NETPATH
},
72 { "visible", _RPC_VISIBLE
},
73 { "circuit_v", _RPC_CIRCUIT_V
},
74 { "datagram_v", _RPC_DATAGRAM_V
},
75 { "circuit_n", _RPC_CIRCUIT_N
},
76 { "datagram_n", _RPC_DATAGRAM_N
},
88 static const struct netid_af na_cvt
[] = {
89 { "udp", AF_INET
, IPPROTO_UDP
},
90 { "tcp", AF_INET
, IPPROTO_TCP
},
92 { "udp6", AF_INET6
, IPPROTO_UDP
},
93 { "tcp6", AF_INET6
, IPPROTO_TCP
},
96 { "local", AF_LOCAL
, 0 }
101 static char *strlocase(char *);
103 static int getnettype(const char *);
106 * Cache the result of getrlimit(), so we don't have to do an
107 * expensive call every time.
113 return (WINSOCK_HANDLE_HASH_SIZE
);
122 if (getrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
123 return (tbsize
= (int)rl
.rlim_max
);
126 * Something wrong. I'll try to save face by returning a
127 * pessimistic number.
135 * Find the appropriate buffer size
139 __rpc_get_t_size(af
, proto
, size
)
141 int size
; /* Size requested */
143 int maxsize
, defsize
;
145 maxsize
= 256 * 1024; /* XXX */
148 defsize
= 1024 * 1024; /* XXX */
151 defsize
= UDPMSGSIZE
;
154 defsize
= RPC_MAXDATASIZE
;
160 /* cbodley- give us the size we ask for, or we'll get fragmented! */
163 /* Check whether the value is within the upper max limit */
164 return (size
> maxsize
? (u_int
)maxsize
: (u_int
)size
);
169 * Find the appropriate address buffer size
177 return sizeof (struct sockaddr_in
);
180 return sizeof (struct sockaddr_in6
);
184 return sizeof (struct sockaddr_un
);
189 return ((u_int
)RPC_MAXADDRSIZE
);
207 * Returns the type of the network as defined in <rpc/nettype.h>
208 * If nettype is NULL, it defaults to NETPATH.
216 if ((nettype
== NULL
) || (nettype
[0] == 0)) {
217 return (_RPC_NETPATH
); /* Default */
221 nettype
= strlocase(nettype
);
223 for (i
= 0; _rpctypelist
[i
].name
; i
++)
224 if (strcasecmp(nettype
, _rpctypelist
[i
].name
) == 0) {
225 return (_rpctypelist
[i
].type
);
227 return (_rpctypelist
[i
].type
);
231 * For the given nettype (tcp or udp only), return the first structure found.
232 * This should be freed by calling freenetconfigent()
235 __rpc_getconfip(nettype
)
239 char *netid_tcp
= (char *) NULL
;
240 char *netid_udp
= (char *) NULL
;
241 struct netconfig
*dummy
;
242 extern thread_key_t tcp_key
, udp_key
;
243 extern mutex_t tsd_lock
;
246 mutex_lock(&tsd_lock
);
248 tcp_key
= TlsAlloc(); //thr_keycreate(&tcp_key, free);
249 mutex_unlock(&tsd_lock
);
251 netid_tcp
= (char *)thr_getspecific(tcp_key
);
253 mutex_lock(&tsd_lock
);
255 udp_key
= TlsAlloc(); //thr_keycreate(&udp_key, free);
256 mutex_unlock(&tsd_lock
);
258 netid_udp
= (char *)thr_getspecific(udp_key
);
259 if (!netid_udp
&& !netid_tcp
) {
260 struct netconfig
*nconf
;
263 if (!(confighandle
= setnetconfig())) {
264 //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
267 while ((nconf
= getnetconfig(confighandle
)) != NULL
) {
268 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
269 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) {
270 if (strcmp(nconf
->nc_proto
, NC_TCP
) == 0 &&
272 netid_tcp
= strdup(nconf
->nc_netid
);
273 thr_setspecific(tcp_key
,
276 if (strcmp(nconf
->nc_proto
, NC_UDP
) == 0 &&
278 netid_udp
= strdup(nconf
->nc_netid
);
279 thr_setspecific(udp_key
,
284 endnetconfig(confighandle
);
286 if (strcmp(nettype
, "udp") == 0)
288 else if (strcmp(nettype
, "tcp") == 0)
293 if ((netid
== NULL
) || (netid
[0] == 0)) {
296 dummy
= getnetconfigent(netid
);
301 * Returns the type of the nettype, which should then be used with
305 __rpc_setconf(nettype
)
308 struct handle
*handle
;
310 handle
= (struct handle
*) malloc(sizeof (struct handle
));
311 if (handle
== NULL
) {
314 switch (handle
->nettype
= getnettype(nettype
)) {
317 case _RPC_DATAGRAM_N
:
318 if (!(handle
->nhandle
= setnetpath())) {
322 handle
->nflag
= TRUE
;
326 case _RPC_DATAGRAM_V
:
329 if (!(handle
->nhandle
= setnetconfig())) {
330 //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
334 handle
->nflag
= FALSE
;
344 * Returns the next netconfig struct for the given "net" type.
345 * __rpc_setconf() should have been called previously.
348 __rpc_getconf(vhandle
)
351 struct handle
*handle
;
352 struct netconfig
*nconf
;
354 handle
= (struct handle
*)vhandle
;
355 if (handle
== NULL
) {
360 nconf
= getnetpath(handle
->nhandle
);
362 nconf
= getnetconfig(handle
->nhandle
);
365 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) &&
366 (nconf
->nc_semantics
!= NC_TPI_COTS
) &&
367 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
369 switch (handle
->nettype
) {
371 if (!(nconf
->nc_flag
& NC_VISIBLE
))
374 case _RPC_NETPATH
: /* Be happy */
377 if (!(nconf
->nc_flag
& NC_VISIBLE
))
381 if ((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
382 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
385 case _RPC_DATAGRAM_V
:
386 if (!(nconf
->nc_flag
& NC_VISIBLE
))
389 case _RPC_DATAGRAM_N
:
390 if (nconf
->nc_semantics
!= NC_TPI_CLTS
)
394 if (((nconf
->nc_semantics
!= NC_TPI_COTS
) &&
395 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
)) ||
396 (strcmp(nconf
->nc_protofmly
, NC_INET
)
398 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
403 strcmp(nconf
->nc_proto
, NC_TCP
))
407 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) ||
408 (strcmp(nconf
->nc_protofmly
, NC_INET
)
410 && strcmp(nconf
->nc_protofmly
, NC_INET6
))
415 strcmp(nconf
->nc_proto
, NC_UDP
))
425 __rpc_endconf(vhandle
)
428 struct handle
*handle
;
430 handle
= (struct handle
*) vhandle
;
431 if (handle
== NULL
) {
435 endnetpath(handle
->nhandle
);
437 endnetconfig(handle
->nhandle
);
443 * Used to ping the NULL procedure for clnt handle.
444 * Returns NULL if fails, else a non-NULL pointer.
450 struct timeval TIMEOUT
= {25, 0};
452 if (clnt_call(clnt
, NULLPROC
, (xdrproc_t
) xdr_void
, NULL
,
453 (xdrproc_t
) xdr_void
, NULL
, TIMEOUT
) != RPC_SUCCESS
) {
456 return ((void *) clnt
);
460 * Try all possible transports until
461 * one succeeds in finding the netconf for the given fd.
468 struct __rpc_sockinfo si
;
470 if (!__rpc_fd2sockinfo(fd
, &si
))
473 if (!__rpc_sockinfo2netid(&si
, &netid
))
476 /*LINTED const castaway*/
477 return getnetconfigent((char *)netid
);
481 __rpc_fd2sockinfo(SOCKET fd
, struct __rpc_sockinfo
*sip
)
485 struct sockaddr_storage ss
;
488 WSAPROTOCOL_INFO proto_info
;
489 int proto_info_size
= sizeof(proto_info
);
490 if (getsockopt(fd
, SOL_SOCKET
, SO_PROTOCOL_INFO
, (char *)&proto_info
, &proto_info_size
) == SOCKET_ERROR
) {
491 int err
= WSAGetLastError();
494 len
= proto_info
.iMaxSockAddr
;
495 ss
.ss_family
= (ADDRESS_FAMILY
)proto_info
.iAddressFamily
;
498 if (getsockname(fd
, (struct sockaddr
*)&ss
, &len
) == SOCKET_ERROR
) {
505 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, (char *)&type
, &len
) == SOCKET_ERROR
) {
506 int err
= WSAGetLastError();
512 if (ss
.ss_family
!= AF_LOCAL
) {
514 if (type
== SOCK_STREAM
)
516 else if (type
== SOCK_DGRAM
)
525 sip
->si_af
= ss
.ss_family
;
526 sip
->si_proto
= proto
;
527 sip
->si_socktype
= type
;
533 * Linear search, but the number of entries is small.
536 __rpc_nconf2sockinfo(const struct netconfig
*nconf
, struct __rpc_sockinfo
*sip
)
540 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++)
541 if (strcmp(na_cvt
[i
].netid
, nconf
->nc_netid
) == 0 || (
542 strcmp(nconf
->nc_netid
, "unix") == 0 &&
543 strcmp(na_cvt
[i
].netid
, "local") == 0)) {
544 sip
->si_af
= na_cvt
[i
].af
;
545 sip
->si_proto
= na_cvt
[i
].protocol
;
547 __rpc_seman2socktype((int)nconf
->nc_semantics
);
548 if (sip
->si_socktype
== -1)
550 sip
->si_alen
= __rpc_get_a_size(sip
->si_af
);
558 __rpc_nconf2fd(const struct netconfig
*nconf
)
560 struct __rpc_sockinfo si
;
563 if (!__rpc_nconf2sockinfo(nconf
, &si
))
566 if ((fd
= socket(si
.si_af
, si
.si_socktype
, si
.si_proto
)) != INVALID_SOCKET
&&
567 si
.si_af
== AF_INET6
) {
570 setsockopt(fd
, SOL_IPV6
, IPV6_V6ONLY
, (const char *)&val
, sizeof(val
));
576 __rpc_sockinfo2netid(struct __rpc_sockinfo
*sip
, const char **netid
)
579 struct netconfig
*nconf
;
581 nconf
= getnetconfigent("local");
583 for (i
= 0; i
< (sizeof na_cvt
) / (sizeof (struct netid_af
)); i
++) {
584 if (na_cvt
[i
].af
== sip
->si_af
&&
585 na_cvt
[i
].protocol
== sip
->si_proto
) {
586 if (strcmp(na_cvt
[i
].netid
, "local") == 0 && nconf
== NULL
) {
591 *netid
= na_cvt
[i
].netid
;
594 freenetconfigent(nconf
);
599 freenetconfigent(nconf
);
605 taddr2uaddr(const struct netconfig
*nconf
, const struct netbuf
*nbuf
)
607 struct __rpc_sockinfo si
;
609 if (!__rpc_nconf2sockinfo(nconf
, &si
))
611 return __rpc_taddr2uaddr_af(si
.si_af
, nbuf
);
615 uaddr2taddr(const struct netconfig
*nconf
, const char *uaddr
)
617 struct __rpc_sockinfo si
;
619 if (!__rpc_nconf2sockinfo(nconf
, &si
))
621 return __rpc_uaddr2taddr_af(si
.si_af
, uaddr
);
624 void freeuaddr(char *uaddr
)
629 void freenetbuf(struct netbuf
*nbuf
)
640 inet_ntop(INT af
, PVOID src
, PSTR dst
, size_t cnt
)
646 memcpy(&in
.s_addr
, src
, sizeof(in
.s_addr
));
647 text_addr
= inet_ntoa(in
);
648 if (text_addr
&& dst
) {
649 strncpy(dst
, text_addr
, cnt
);
659 __rpc_taddr2uaddr_af(int af
, const struct netbuf
*nbuf
)
662 struct sockaddr_in
*sin
;
664 struct sockaddr_un
*sun
;
666 char namebuf
[INET_ADDRSTRLEN
];
668 struct sockaddr_in6
*sin6
;
669 char namebuf6
[INET6_ADDRSTRLEN
];
679 if (inet_ntop(af
, &sin
->sin_addr
, namebuf
, sizeof namebuf
)
682 port
= ntohs(sin
->sin_port
);
683 if (asprintf(&ret
, "%s.%u.%u", namebuf
, ((u_int32_t
)port
) >> 8,
690 if (inet_ntop(af
, &sin6
->sin6_addr
, namebuf6
, sizeof namebuf6
)
693 port
= ntohs(sin6
->sin6_port
);
694 if (asprintf(&ret
, "%s.%u.%u", namebuf6
, ((u_int32_t
)port
) >> 8,
702 /* if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
703 offsetof(struct sockaddr_un, sun_path)),
704 sun->sun_path) < 0)*/
705 if (asprintf(&ret
, "%.*s", (int)(sizeof(*sun
) -
706 offsetof(struct sockaddr_un
, sun_path
)),
720 __rpc_uaddr2taddr_af(int af
, const char *uaddr
)
722 struct netbuf
*ret
= NULL
;
724 unsigned short port
, portlo
, porthi
;
725 struct sockaddr_in
*sin
;
727 struct sockaddr_in6
*sin6
;
730 struct sockaddr_un
*sun
;
735 addrstr
= strdup(uaddr
);
740 * AF_LOCAL addresses are expected to be absolute
741 * pathnames, anything else will be AF_INET or AF_INET6.
743 if (*addrstr
!= '/') {
744 p
= strrchr(addrstr
, '.');
747 portlo
= (unsigned)atoi(p
+ 1);
750 p
= strrchr(addrstr
, '.');
753 porthi
= (unsigned)atoi(p
+ 1);
755 port
= (porthi
<< 8) | portlo
;
758 ret
= (struct netbuf
*)malloc(sizeof *ret
);
764 sin
= (struct sockaddr_in
*)malloc(sizeof *sin
);
767 memset(sin
, 0, sizeof *sin
);
768 sin
->sin_family
= AF_INET
;
769 sin
->sin_port
= htons(port
);
771 if (inet_pton(AF_INET
, addrstr
, &sin
->sin_addr
) <= 0) {
773 sin
->sin_addr
.S_un
.S_addr
= inet_addr(addrstr
);
774 if (sin
->sin_addr
.S_un
.S_addr
== INADDR_NONE
) {
781 ret
->maxlen
= ret
->len
= sizeof *sin
;
786 sin6
= (struct sockaddr_in6
*)malloc(sizeof *sin6
);
789 memset(sin6
, 0, sizeof *sin6
);
790 sin6
->sin6_family
= AF_INET6
;
791 sin6
->sin6_port
= htons(port
);
792 if (inet_pton(AF_INET6
, addrstr
, &sin6
->sin6_addr
) <= 0) {
798 ret
->maxlen
= ret
->len
= sizeof *sin6
;
804 sun
= (struct sockaddr_un
*)malloc(sizeof *sun
);
807 memset(sun
, 0, sizeof *sun
);
808 sun
->sun_family
= AF_LOCAL
;
809 strncpy(sun
->sun_path
, addrstr
, sizeof(sun
->sun_path
) - 1);
810 ret
->len
= SUN_LEN(sun
);
811 ret
->maxlen
= sizeof(struct sockaddr_un
);
824 __rpc_seman2socktype(int semantics
)
829 case NC_TPI_COTS_ORD
:
841 __rpc_socktype2seman(int socktype
)
847 return NC_TPI_COTS_ORD
;
858 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
859 * Here, we compare the original server address to that of the RPC
860 * service we just received back from a call to rpcbind on the remote
861 * machine. If they are both "link local" or "site local", copy
862 * the scope id of the server address over to the service address.
865 __rpc_fixup_addr(struct netbuf
*new, const struct netbuf
*svc
)
868 struct sockaddr
*sa_new
, *sa_svc
;
869 struct sockaddr_in6
*sin6_new
, *sin6_svc
;
871 sa_svc
= (struct sockaddr
*)svc
->buf
;
872 sa_new
= (struct sockaddr
*)new->buf
;
874 if (sa_new
->sa_family
== sa_svc
->sa_family
&&
875 sa_new
->sa_family
== AF_INET6
) {
876 sin6_new
= (struct sockaddr_in6
*)new->buf
;
877 sin6_svc
= (struct sockaddr_in6
*)svc
->buf
;
879 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new
->sin6_addr
) &&
880 IN6_IS_ADDR_LINKLOCAL(&sin6_svc
->sin6_addr
)) ||
881 (IN6_IS_ADDR_SITELOCAL(&sin6_new
->sin6_addr
) &&
882 IN6_IS_ADDR_SITELOCAL(&sin6_svc
->sin6_addr
))) {
883 sin6_new
->sin6_scope_id
= sin6_svc
->sin6_scope_id
;
891 __rpc_sockisbound(SOCKET fd
)
893 struct sockaddr_storage ss
;
895 struct sockaddr_in sin
;
896 struct sockaddr_in6 sin6
;
898 struct sockaddr_un usin
;
903 slen
= sizeof (struct sockaddr_storage
);
904 if (getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) == SOCKET_ERROR
)
907 switch (ss
.ss_family
) {
909 memcpy(&u_addr
.sin
, &ss
, sizeof(u_addr
.sin
));
910 return (u_addr
.sin
.sin_port
!= 0);
913 memcpy(&u_addr
.sin6
, &ss
, sizeof(u_addr
.sin6
));
914 return (u_addr
.sin6
.sin6_port
!= 0);
919 memcpy(&u_addr
.usin
, &ss
, sizeof(u_addr
.usin
));
920 return (u_addr
.usin
.sun_path
[0] != 0);
930 * Helper function to set up a netbuf
933 __rpc_set_netbuf(struct netbuf
*nb
, const void *ptr
, size_t len
)
935 if (nb
->len
!= len
) {
937 mem_free(nb
->buf
, nb
->len
);
938 nb
->buf
= mem_alloc(len
);
942 nb
->maxlen
= nb
->len
= len
;
944 memcpy(nb
->buf
, ptr
, len
);