2 * Provide a variety of APIs that query an rpcbind daemon to
3 * discover RPC service ports and allowed protocol version
6 * Copyright (C) 2008 Oracle Corporation. All rights reserved.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 021110-1307, USA.
29 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
38 #include <arpa/inet.h>
41 #include <rpc/pmap_prot.h>
43 #ifdef HAVE_TIRPC_NETCONFIG_H
44 #include <tirpc/netconfig.h>
45 #include <tirpc/rpc/rpcb_prot.h>
51 * Try a local socket first to access the local rpcbind daemon
53 * Rpcbind's local socket service does not seem to be working.
54 * Disable this logic for now.
58 #else /* HAVE_XDR_RPCB */
60 #endif /* HAVE_XDR_RPCB */
63 const static rpcvers_t default_rpcb_version = RPCBVERS_4;
65 const static rpcvers_t default_rpcb_version = PMAPVERS;
68 static const char *nfs_gp_rpcb_pgmtbl[] = {
77 * Discover the port number that should be used to contact an
78 * rpcbind service. This will detect if the port has a local
79 * value that may have been set in /etc/services.
81 * NB: s_port is already in network byte order.
83 * Returns network byte-order port number of rpcbind service
86 static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
88 struct protoent *proto;
90 proto = getprotobynumber((int)protocol);
92 struct servent *entry;
94 entry = getservbyname("rpcbind", proto->p_name);
96 return (in_port_t)entry->s_port;
98 entry = getservbyname("portmapper", proto->p_name);
100 return (in_port_t)entry->s_port;
102 entry = getservbyname("sunrpc", proto->p_name);
104 return (in_port_t)entry->s_port;
106 return htons((uint16_t)PMAPPORT);
110 * Plant port number in @sap. @port is already in network byte order.
112 static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
114 struct sockaddr_in *sin = (struct sockaddr_in *)sap;
115 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
117 switch (sap->sa_family) {
119 sin->sin_port = port;
122 sin6->sin6_port = port;
125 fprintf(stderr, "%s: unrecognized address family\n",
131 * Set up an RPC client for communicating with an rpcbind daemon at
132 * @sap over @transport with protocol version @version.
134 * Returns a pointer to a prepared RPC client if successful, and
135 * @timeout is initialized; caller must destroy a non-NULL returned RPC
136 * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to
139 static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap,
140 const socklen_t salen,
141 const unsigned short transport,
142 const rpcvers_t version,
143 struct timeval *timeout)
145 struct sockaddr_storage address;
146 struct sockaddr *saddr = (struct sockaddr *)&address;
147 rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, nfs_gp_rpcb_pgmtbl);
149 memcpy(saddr, sap, (size_t)salen);
150 nfs_gp_set_port(saddr, nfs_gp_get_rpcb_port(transport));
152 return nfs_get_rpcclient(saddr, salen, transport, rpcb_prog,
157 * One of the arguments passed when querying remote rpcbind services
158 * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
159 * field used in legacy PMAP_GETPORT calls.
161 * RFC 1833 says netids are not standard but rather defined on the local
162 * host. There are, however, standard definitions for nc_protofmly and
163 * nc_proto that can be used to derive a netid string on the local host,
164 * based on the contents of /etc/netconfig.
166 * Walk through the local netconfig database and grab the netid of the
167 * first entry that matches @family and @protocol and whose netid string
168 * fits in the provided buffer.
170 * Returns a '\0'-terminated string if successful; otherwise NULL.
171 * rpc_createerr.cf_stat is set to reflect the error.
175 static char *nfs_gp_get_netid(const sa_family_t family,
176 const unsigned short protocol)
178 char *nc_protofmly, *nc_proto, *nc_netid;
179 struct netconfig *nconf;
180 struct protoent *proto;
186 nc_protofmly = NC_INET;
189 nc_protofmly = NC_INET6;
195 proto = getprotobynumber(protocol);
198 nc_proto = proto->p_name;
200 handle = setnetconfig();
201 while ((nconf = getnetconfig(handle)) != NULL) {
203 if (nconf->nc_protofmly != NULL &&
204 strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
206 if (nconf->nc_proto != NULL &&
207 strcmp(nconf->nc_proto, nc_proto) != 0)
210 nc_netid = strdup(nconf->nc_netid);
211 endnetconfig(handle);
214 endnetconfig(handle);
217 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
221 #endif /* HAVE_XDR_RPCB */
224 * Extract a port number from a universal address, and terminate the
225 * string in @addrstr just after the address part.
227 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
230 static int nfs_gp_universal_porthelper(char *addrstr)
233 unsigned long portlo, porthi;
236 p = strrchr(addrstr, '.');
239 portlo = strtoul(p + 1, &endptr, 10);
240 if (*endptr != '\0' || portlo > 255)
244 p = strrchr(addrstr, '.');
247 porthi = strtoul(p + 1, &endptr, 10);
248 if (*endptr != '\0' || porthi > 255)
251 port = (porthi << 8) | portlo;
258 * nfs_universal2port - extract port number from a "universal address"
259 * @uaddr: '\0'-terminated C string containing a universal address
261 * Universal addresses (defined in RFC 1833) are used when calling an
262 * rpcbind daemon via protocol versions 3 or 4..
264 * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0)
267 int nfs_universal2port(const char *uaddr)
272 addrstr = strdup(uaddr);
273 if (addrstr != NULL) {
274 port = nfs_gp_universal_porthelper(addrstr);
281 * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
282 * @sap: pointer to a socket address
283 * @salen: length of socket address
285 * Universal addresses (defined in RFC 1833) are used when calling an
286 * rpcbind daemon via protocol versions 3 or 4..
288 * Returns a '\0'-terminated string if successful; caller must free
289 * the returned string. Otherwise NULL is returned and
290 * rpc_createerr.cf_stat is set to reflect the error.
293 #ifdef HAVE_GETNAMEINFO
295 char *nfs_sockaddr2universal(const struct sockaddr *sap,
296 const socklen_t salen)
298 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
299 char buf[NI_MAXHOST];
302 switch (sap->sa_family) {
304 return strndup(sun->sun_path, sizeof(sun->sun_path));
306 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
307 NULL, 0, NI_NUMERICHOST) != 0)
309 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
312 if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
313 NULL, 0, NI_NUMERICHOST) != 0)
315 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
321 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
322 (unsigned)(port >> 8), (unsigned)(port & 0xff));
327 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
331 #else /* HAVE_GETNAMEINFO */
333 char *nfs_sockaddr2universal(const struct sockaddr *sap,
334 const socklen_t salen)
336 struct sockaddr_un *sun = (struct sockaddr_un *)sap;
337 char buf[NI_MAXHOST];
341 switch (sap->sa_family) {
343 return strndup(sun->sun_path, sizeof(sun->sun_path));
345 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
346 if (addr != NULL && strlen(addr) > sizeof(buf))
349 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
355 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
356 (unsigned)(port >> 8), (unsigned)(port & 0xff));
361 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
365 #endif /* HAVE_GETNAMEINFO */
368 * Send a NULL request to the indicated RPC service.
370 * Returns 1 if the service responded; otherwise 0;
372 static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
374 enum clnt_stat status;
376 status = CLNT_CALL(client, NULLPROC,
377 (xdrproc_t)xdr_void, NULL,
378 (xdrproc_t)xdr_void, NULL,
381 return (int)(status == RPC_SUCCESS);
387 * Initialize the rpcb argument for a GETADDR request.
389 * The rpcbind daemon ignores the parms.r_owner field in GETADDR
390 * requests, but we plant an eye-catcher to help distinguish these
391 * requests in network traces.
393 * Returns 1 if successful, and caller must free strings pointed
394 * to by r_netid and r_addr; otherwise 0.
396 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
397 const socklen_t salen,
398 const rpcprog_t program,
399 const rpcvers_t version,
400 const unsigned short protocol,
405 netid = nfs_gp_get_netid(sap->sa_family, protocol);
409 addr = nfs_sockaddr2universal(sap, salen);
415 memset(parms, 0, sizeof(*parms));
416 parms->r_prog = program;
417 parms->r_vers = version;
418 parms->r_netid = netid;
419 parms->r_addr = addr;
420 parms->r_owner = "nfs-utils"; /* eye-catcher */
425 static void nfs_gp_free_rpcb_parms(struct rpcb *parms)
427 free(parms->r_netid);
432 * Try rpcbind GETADDR via version 4. If that fails, try same
433 * request via version 3.
435 * Returns non-zero port number on success; otherwise returns
436 * zero. rpccreateerr is set to reflect the nature of the error.
438 static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
440 struct timeval timeout)
442 rpcvers_t rpcb_version;
443 struct rpc_err rpcerr;
446 for (rpcb_version = RPCBVERS_4;
447 rpcb_version >= RPCBVERS_3;
449 enum clnt_stat status;
452 CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version);
453 status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
454 (xdrproc_t)xdr_rpcb, (void *)parms,
455 (xdrproc_t)xdr_wrapstring, (void *)&uaddr,
460 if ((uaddr == NULL) || (uaddr[0] == '\0')) {
461 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
465 port = nfs_universal2port(uaddr);
466 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
468 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
471 return (unsigned short)port;
472 case RPC_PROGVERSMISMATCH:
473 clnt_geterr(client, &rpcerr);
474 if (rpcerr.re_vers.low > RPCBVERS4)
477 case RPC_PROCUNAVAIL:
478 case RPC_PROGUNAVAIL:
481 /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
482 rpc_createerr.cf_stat = status;
483 clnt_geterr(client, &rpc_createerr.cf_error);
490 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
491 clnt_geterr(client, &rpc_createerr.cf_error);
496 #endif /* HAVE_XDR_RPCB */
499 * Try GETPORT request via rpcbind version 2.
501 * Returns non-zero port number on success; otherwise returns
502 * zero. rpccreateerr is set to reflect the nature of the error.
504 static unsigned long nfs_gp_pmap_getport(CLIENT *client,
506 struct timeval timeout)
508 enum clnt_stat status;
511 status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
512 (xdrproc_t)xdr_pmap, (void *)parms,
513 (xdrproc_t)xdr_u_long, (void *)&port,
516 if (status != RPC_SUCCESS) {
517 rpc_createerr.cf_stat = status;
518 clnt_geterr(client, &rpc_createerr.cf_error);
520 } else if (port == 0)
521 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
528 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
529 const struct sockaddr *sap,
530 const socklen_t salen,
531 const rpcprog_t program,
532 const rpcvers_t version,
533 const unsigned short protocol,
534 struct timeval timeout)
536 unsigned short port = 0;
539 if (nfs_gp_init_rpcb_parms(sap, salen, program,
540 version, protocol, &parms) != 0) {
541 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
542 nfs_gp_free_rpcb_parms(&parms);
548 #endif /* HAVE_XDR_RPCB */
550 static unsigned long nfs_gp_getport_pmap(CLIENT *client,
551 const rpcprog_t program,
552 const rpcvers_t version,
553 const unsigned short protocol,
554 struct timeval timeout)
556 struct pmap parms = {
561 rpcvers_t pmap_version = PMAPVERS;
563 CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version);
564 return nfs_gp_pmap_getport(client, &parms, timeout);
568 * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET
569 * request via rpcbind v2.
571 * Returns non-zero port number on success; otherwise returns
572 * zero. rpccreateerr is set to reflect the nature of the error.
574 static unsigned short nfs_gp_getport(CLIENT *client,
575 const struct sockaddr *sap,
576 const socklen_t salen,
577 const rpcprog_t program,
578 const rpcvers_t version,
579 const unsigned short protocol,
580 struct timeval timeout)
582 switch (sap->sa_family) {
585 return nfs_gp_getport_rpcb(client, sap, salen, program,
586 version, protocol, timeout);
587 #endif /* HAVE_XDR_RPCB */
589 return nfs_gp_getport_pmap(client, program, version,
593 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
598 * nfs_rcp_ping - Determine if RPC service is responding to requests
599 * @sap: pointer to address of server to query (port is already filled in)
600 * @salen: length of server address
601 * @program: requested RPC program number
602 * @version: requested RPC version number
603 * @protocol: requested IPPROTO_ value of transport protocol
604 * @timeout: pointer to request timeout (NULL means use default timeout)
606 * Returns 1 if the remote service responded without an error; otherwise
609 int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
610 const rpcprog_t program, const rpcvers_t version,
611 const unsigned short protocol, const struct timeval *timeout)
614 struct timeval tout = { -1, 0 };
620 client = nfs_get_rpcclient(sap, salen, protocol, program, version, &tout);
621 if (client != NULL) {
622 result = nfs_gp_ping(client, tout);
623 CLNT_DESTROY(client);
630 * nfs_getport - query server's rpcbind to get port number for an RPC service
631 * @sap: pointer to address of server to query
632 * @salen: length of server's address
633 * @program: requested RPC program number
634 * @version: requested RPC version number
635 * @protocol: IPPROTO_ value of requested transport protocol
637 * Uses any acceptable rpcbind version to discover the port number for the
638 * RPC service described by the given [program, version, transport] tuple.
639 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
640 * AF_INET6 server addresses.
642 * Returns a positive integer representing the port number of the RPC
643 * service advertised by the server (in host byte order), or zero if the
644 * service is not advertised or there was some problem querying the server's
645 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
648 * There are a variety of ways to choose which transport and rpcbind versions
649 * to use. We chose to conserve local resources and try to avoid incurring
653 * To provide rudimentary support for traversing firewalls, query the remote
654 * using the same transport as the requested service. This provides some
655 * guarantee that the requested transport is available between this client
656 * and the server, and if the caller specifically requests TCP, for example,
657 * this may be becuase a firewall is in place that blocks UDP traffic. We
658 * could try both, but that could involve a lengthy timeout in several cases,
659 * and would often consume an extra ephemeral port.
662 * To avoid using up too many ephemeral ports, AF_INET queries use tried-and-
663 * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use
664 * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol
665 * versions can adequately detect if a remote RPC service does not support
666 * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the
667 * overall number of consumed ephemeral ports low.
669 unsigned short nfs_getport(const struct sockaddr *sap,
670 const socklen_t salen,
671 const rpcprog_t program,
672 const rpcvers_t version,
673 const unsigned short protocol)
675 struct timeval timeout = { -1, 0 };
676 unsigned short port = 0;
679 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
680 default_rpcb_version, &timeout);
681 if (client != NULL) {
682 port = nfs_gp_getport(client, sap, salen, program,
683 version, protocol, timeout);
684 CLNT_DESTROY(client);
691 * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result
692 * @sap: IN: pointer to address of server to query;
693 * OUT: pointer to updated address
694 * @salen: length of server's address
695 * @program: requested RPC program number
696 * @version: requested RPC version number
697 * @protocol: IPPROTO_ value of requested transport protocol
699 * Uses any acceptable rpcbind version to discover the port number for the
700 * RPC service described by the given [program, version, transport] tuple.
701 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
702 * AF_INET6 server addresses.
704 * Returns a 1 and sets the port number in the passed-in server address
705 * if both the query and the ping were successful; otherwise zero.
706 * rpccreateerr is set to reflect the underlying cause of the error.
708 int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
709 const rpcprog_t program, const rpcvers_t version,
710 const unsigned short protocol)
712 struct timeval timeout = { -1, 0 };
713 unsigned short port = 0;
717 client = nfs_gp_get_rpcbclient(sap, salen, protocol,
718 default_rpcb_version, &timeout);
719 if (client != NULL) {
720 port = nfs_gp_getport(client, sap, salen, program,
721 version, protocol, timeout);
722 CLNT_DESTROY(client);
727 struct sockaddr_storage address;
728 struct sockaddr *saddr = (struct sockaddr *)&address;
730 memcpy(saddr, sap, (size_t)salen);
731 nfs_gp_set_port(saddr, htons(port));
733 client = nfs_get_rpcclient(saddr, salen, protocol,
734 program, version, &timeout);
735 if (client != NULL) {
736 result = nfs_gp_ping(client, timeout);
737 CLNT_DESTROY(client);
742 nfs_gp_set_port(sap, htons(port));
748 * nfs_getlocalport - query local rpcbind to get port number for an RPC service
749 * @program: requested RPC program number
750 * @version: requested RPC version number
751 * @protocol: IPPROTO_ value of requested transport protocol
753 * Uses any acceptable rpcbind version to discover the port number for the
754 * RPC service described by the given [program, version, transport] tuple.
755 * Uses a quick timeout and an ephemeral source port. Supports AF_INET and
756 * AF_INET6 local addresses.
758 * Returns a positive integer representing the port number of the RPC
759 * service advertised by the server (in host byte order), or zero if the
760 * service is not advertised or there was some problem querying the server's
761 * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of
764 * Try an AF_LOCAL connection first. The rpcbind daemon implementation should
765 * listen on AF_LOCAL.
767 * If that doesn't work (for example, if portmapper is running, or rpcbind
768 * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
769 * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
772 * getaddrinfo(3) generates a usable loopback address. RFC 3484 requires that
773 * the results are sorted so that the first result has the best likelihood of
774 * working, so we try just that first result. If IPv6 is all that is
775 * available, we are sure to generate an AF_INET6 loopback address and use
776 * rpcbindv4/v3 GETADDR. AF_INET6 requests go via rpcbind v4/3 in order to
777 * detect if the requested RPC service supports AF_INET6 or not.
779 unsigned short nfs_getlocalport(const rpcprot_t program,
780 const rpcvers_t version,
781 const unsigned short protocol)
783 struct addrinfo *gai_results;
784 struct addrinfo gai_hint = {
785 .ai_flags = AI_ADDRCONFIG,
787 unsigned short port = 0;
791 const struct sockaddr_un sun = {
792 .sun_family = AF_LOCAL,
793 .sun_path = _PATH_RPCBINDSOCK,
795 const struct sockaddr *sap = (struct sockaddr *)&sun;
796 const socklen_t salen = SUN_LEN(&sun);
798 struct timeval timeout = { -1, 0 };
800 client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
801 if (client != NULL) {
804 if (nfs_gp_init_rpcb_parms(sap, salen, program, version,
805 protocol, &parms) != 0) {
806 port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
807 nfs_gp_free_rpcb_parms(&parms);
809 CLNT_DESTROY(client);
811 #endif /* NFS_GP_LOCAL */
814 error = getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results);
816 port = nfs_getport(gai_results->ai_addr,
817 gai_results->ai_addrlen,
818 program, version, protocol);
819 freeaddrinfo(gai_results);
821 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
828 * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3
829 * @sap: pointer to address of server to query
830 * @salen: length of server address
831 * @transport: transport protocol to use for the query
832 * @addr: pointer to r_addr address
833 * @addrlen: length of address
834 * @program: requested RPC program number
835 * @version: requested RPC version number
836 * @protocol: requested IPPROTO_ value of transport protocol
837 * @timeout: pointer to request timeout (NULL means use default timeout)
839 * Returns a positive integer representing the port number of the RPC
840 * service advertised by the server (in host byte order), or zero if the
841 * service is not advertised or there was some problem querying the
842 * server's rpcbind daemon. rpccreateerr is set to reflect the
843 * underlying cause of the error.
845 * This function provides similar functionality to nfs_pmap_getport(),
846 * but performs the rpcbind lookup via rpcbind version 4. If the server
847 * doesn't support rpcbind version 4, it will retry with version 3.
848 * The GETADDR procedure is exactly the same in these two versions of
849 * the rpcbind protocol, so the socket, RPC client, and arguments are
850 * re-used when retrying, saving ephemeral port space.
852 * These RPC procedures take a universal address as an argument, so the
853 * query will fail if the remote rpcbind daemon doesn't find an entry
854 * with a matching address. A matching address includes an ANYADDR
855 * address of the same address family. In this way an RPC server can
856 * advertise via rpcbind that it does not support AF_INET6.
860 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
861 const socklen_t salen,
862 const unsigned short transport,
863 const struct sockaddr *addr,
864 const socklen_t addrlen,
865 const rpcprog_t program,
866 const rpcvers_t version,
867 const unsigned short protocol,
868 const struct timeval *timeout)
872 struct timeval tout = { -1, 0 };
873 unsigned short port = 0;
878 client = nfs_gp_get_rpcbclient(sap, salen, transport, RPCBVERS_4, &tout);
879 if (client != NULL) {
880 if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version,
881 protocol, &parms) != 0) {
882 port = nfs_gp_rpcb_getaddr(client, &parms, tout);
883 nfs_gp_free_rpcb_parms(&parms);
885 CLNT_DESTROY(client);
891 #else /* HAVE_XDR_RPCB */
893 unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
894 const socklen_t salen,
895 const unsigned short transport,
896 const struct sockaddr *addr,
897 const socklen_t addrlen,
898 const rpcprog_t program,
899 const rpcvers_t version,
900 const unsigned short protocol,
901 const struct timeval *timeout)
903 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
907 #endif /* HAVE_XDR_RPCB */
910 * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2)
911 * @sin: pointer to AF_INET address of server to query
912 * @transport: transport protocol to use for the query
913 * @program: requested RPC program number
914 * @version: requested RPC version number
915 * @protocol: requested IPPROTO_ value of transport protocol
916 * @timeout: pointer to request timeout (NULL means use default timeout)
918 * Returns a positive integer representing the port number of the RPC service
919 * advertised by the server (in host byte order), or zero if the service is
920 * not advertised or there was some problem querying the server's rpcbind
921 * daemon. rpccreateerr is set to reflect the underlying cause of the error.
923 * nfs_pmap_getport() is very similar to pmap_getport(), except that:
925 * 1. This version always tries to use an ephemeral port, since reserved
926 * ports are not needed for GETPORT queries. This conserves the very
927 * limited reserved port space, helping reduce failed socket binds
928 * during mount storms.
930 * 2. This version times out quickly by default. It time-limits the
931 * connect process as well as the actual RPC call, and even allows the
932 * caller to specify the timeout.
934 * 3. This version shares code with the rpcbindv3 and rpcbindv4 query
935 * functions. It can use a TI-RPC generated CLIENT.
937 unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
938 const unsigned short transport,
939 const unsigned long program,
940 const unsigned long version,
941 const unsigned long protocol,
942 const struct timeval *timeout)
945 struct pmap parms = {
950 struct timeval tout = { -1, 0 };
951 unsigned long port = 0;
956 client = nfs_gp_get_rpcbclient((struct sockaddr *)sin,
957 (socklen_t)sizeof(*sin),
958 transport, PMAPVERS, &tout);
959 if (client != NULL) {
960 port = nfs_gp_pmap_getport(client, &parms, tout);
961 CLNT_DESTROY(client);