]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/network.c
mount.nfs: Create a new API to find out client's address
[nfs-utils.git] / utils / mount / network.c
index 5a56c23ce20f9b9ca6333d9f1e08f837a8d18925..16b802de56acddac4727a5195eb1c53345aa9786 100644 (file)
@@ -303,14 +303,16 @@ static unsigned short getport(struct sockaddr_in *saddr,
                                unsigned long version,
                                unsigned int proto)
 {
+       struct sockaddr_in bind_saddr;
        unsigned short port = 0;
        int socket;
        CLIENT *clnt = NULL;
        enum clnt_stat stat;
+       bind_saddr = *saddr;
+       bind_saddr.sin_port = htons(PMAPPORT);
 
-       saddr->sin_port = htons(PMAPPORT);
-
-       socket = get_socket(saddr, proto, PMAP_TIMEOUT, FALSE, FALSE);
+       socket = get_socket(&bind_saddr, proto, PMAP_TIMEOUT, FALSE, FALSE);
        if (socket == RPC_ANYSOCK) {
                if (proto == IPPROTO_TCP &&
                    rpc_createerr.cf_error.re_errno == ETIMEDOUT)
@@ -320,14 +322,16 @@ static unsigned short getport(struct sockaddr_in *saddr,
 
        switch (proto) {
        case IPPROTO_UDP:
-               clnt = clntudp_bufcreate(saddr,
+               clnt = clntudp_bufcreate(&bind_saddr,
                                         PMAPPROG, PMAPVERS,
                                         RETRY_TIMEOUT, &socket,
                                         RPCSMALLMSGSIZE,
                                         RPCSMALLMSGSIZE);
                break;
        case IPPROTO_TCP:
-               clnt = clnttcp_create(saddr, PMAPPROG, PMAPVERS, &socket,
+               clnt = clnttcp_create(&bind_saddr,
+                                     PMAPPROG, PMAPVERS,
+                                     &socket,
                                      RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
                break;
        }
@@ -388,7 +392,7 @@ static int probe_port(clnt_addr_t *server, const unsigned long *versions,
                                                inet_ntoa(saddr->sin_addr),
                                                prog, *p_vers,
                                                *p_prot == IPPROTO_UDP ?
-                                                       "udp" : "tcp",
+                                                       _("UDP") : _("TCP"),
                                                p_port);
                                 }
                                if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
@@ -638,10 +642,23 @@ void mnt_closeclnt(CLIENT *clnt, int msock)
 }
 
 /*
+ * clnt_ping - send an RPC ping to the remote RPC service endpoint
+ * @saddr: server's address
+ * @prog: target RPC program number
+ * @vers: target RPC version number
+ * @prot: target RPC protocol
+ * @caddr: filled in with our network address
+ *
  * Sigh... getport() doesn't actually check the version number.
  * In order to make sure that the server actually supports the service
  * we're requesting, we open and RPC client, and fire off a NULL
  * RPC call.
+ *
+ * caddr is the network address that the server will use to call us back.
+ * On multi-homed clients, this address depends on which NIC we use to
+ * route requests to the server.
+ *
+ * Returns one if successful, otherwise zero.
  */
 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
                const unsigned long vers, const unsigned int prot,
@@ -711,3 +728,36 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
        else
                return 0;
 }
+
+/*
+ * get_client_address - acquire our local network address
+ * @saddr: server's address
+ * @caddr: filled in with our network address
+ *
+ * Discover a network address that the server will use to call us back.
+ * On multi-homed clients, this address depends on which NIC we use to
+ * route requests to the server.
+ *
+ * Use a connected datagram socket so as not to leave a socket in TIME_WAIT.
+ *
+ * Returns one if successful, otherwise zero.
+ */
+int get_client_address(struct sockaddr_in *saddr, struct sockaddr_in *caddr)
+{
+       socklen_t len = sizeof(*caddr);
+       int socket, err;
+
+       socket = get_socket(saddr, IPPROTO_UDP, CONNECT_TIMEOUT, FALSE, TRUE);
+       if (socket == RPC_ANYSOCK)
+               return 0;
+
+       err = getsockname(socket, caddr, &len);
+       close(socket);
+
+       if (err && verbose) {
+               nfs_error(_("%s: getsockname failed: %s"),
+                               progname, strerror(errno));
+               return 0;
+       }
+       return 1;
+}