]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/network.c
libnfs.a: move mnt_{open, close}clnt calls to utils/mount/network.c
[nfs-utils.git] / utils / mount / network.c
index 12fc7620877b11eb6d8e84e042302a445b42f465..08b1f99f458f0baa894c98fc82bb152f2a69b028 100644 (file)
@@ -38,7 +38,6 @@
 #include "xcommon.h"
 #include "mount.h"
 #include "nls.h"
-#include "nfsumount.h"
 #include "nfs_mount.h"
 #include "mount_constants.h"
 #include "network.h"
@@ -122,42 +121,66 @@ int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
 }
 
 /*
- * getport() is very similar to pmap_getport() with
- * the exception this version uses a non-reserve ports
- * instead of reserve ports since reserve ports
- * are not needed for pmap requests.
+ * getport() is very similar to pmap_getport() with the exception that
+ * this version tries to use an ephemeral port, since reserved ports are
+ * not needed for GETPORT queries.  This conserves the very limited
+ * reserved port space, which helps reduce failed socket binds
+ * during mount storms.
+ *
+ * A side effect of calling this function is that rpccreateerr is set.
  */
-unsigned short getport(struct sockaddr_in *saddr, unsigned long prog,
-                       unsigned long vers, unsigned int prot)
+static unsigned short getport(struct sockaddr_in *saddr,
+                               unsigned long program,
+                               unsigned long version,
+                               unsigned int proto)
 {
        unsigned short port = 0;
        int socket;
        CLIENT *clnt = NULL;
-       struct pmap parms;
        enum clnt_stat stat;
 
-       saddr->sin_port = htons (PMAPPORT);
-       socket = get_socket(saddr, prot, FALSE, FALSE);
+       saddr->sin_port = htons(PMAPPORT);
+
+       /*
+        * Try to get a socket with a non-privileged port.
+        * clnt*create() will create one anyway if this
+        * fails.
+        */
+       socket = get_socket(saddr, proto, FALSE, FALSE);
+       if (socket == RPC_ANYSOCK) {
+               if (proto == IPPROTO_TCP && errno == ETIMEDOUT) {
+                       /*
+                        * TCP SYN timed out, so exit now.
+                        */
+                       rpc_createerr.cf_stat = RPC_TIMEDOUT;
+               }
+               return 0;
+       }
 
-       switch (prot) {
+       switch (proto) {
        case IPPROTO_UDP:
                clnt = clntudp_bufcreate(saddr,
-                                        PMAPPROG, PMAPVERS, TIMEOUT, &socket,
-                                        UDPMSGSIZE, UDPMSGSIZE);
+                                        PMAPPROG, PMAPVERS,
+                                        RETRY_TIMEOUT, &socket,
+                                        RPCSMALLMSGSIZE,
+                                        RPCSMALLMSGSIZE);
                break;
        case IPPROTO_TCP:
-               clnt = clnttcp_create(saddr,
-                       PMAPPROG, PMAPVERS, &socket, 50, 500);
+               clnt = clnttcp_create(saddr, PMAPPROG, PMAPVERS, &socket,
+                                     RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
                break;
        }
        if (clnt != NULL) {
-               parms.pm_prog = prog;
-               parms.pm_vers = vers;
-               parms.pm_prot = prot;
-               parms.pm_port = 0;    /* not needed or used */
-
-               stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap,
-                       (caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT);
+               struct pmap parms = {
+                       .pm_prog        = program,
+                       .pm_vers        = version,
+                       .pm_prot        = proto,
+               };
+
+               stat = clnt_call(clnt, PMAPPROC_GETPORT,
+                                (xdrproc_t)xdr_pmap, (caddr_t)&parms,
+                                (xdrproc_t)xdr_u_short, (caddr_t)&port,
+                                TIMEOUT);
                if (stat) {
                        clnt_geterr(clnt, &rpc_createerr.cf_error);
                        rpc_createerr.cf_stat = stat;
@@ -406,3 +429,50 @@ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
                return 1;
        return 0;
 }
+
+CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
+{
+       struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
+       struct pmap *mnt_pmap = &mnt_server->pmap;
+       CLIENT *clnt = NULL;
+
+       mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
+       *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE, FALSE);
+       if (*msock == RPC_ANYSOCK) {
+               if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
+                       /*
+                        * Probably in-use by a TIME_WAIT connection,
+                        * It is worth waiting a while and trying again.
+                        */
+                       rpc_createerr.cf_stat = RPC_TIMEDOUT;
+               return NULL;
+       }
+
+       switch (mnt_pmap->pm_prot) {
+       case IPPROTO_UDP:
+               clnt = clntudp_bufcreate(mnt_saddr,
+                                        mnt_pmap->pm_prog, mnt_pmap->pm_vers,
+                                        RETRY_TIMEOUT, msock,
+                                        MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
+               break;
+       case IPPROTO_TCP:
+               clnt = clnttcp_create(mnt_saddr,
+                                     mnt_pmap->pm_prog, mnt_pmap->pm_vers,
+                                     msock,
+                                     MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
+               break;
+       }
+       if (clnt) {
+               /* try to mount hostname:dirname */
+               clnt->cl_auth = authunix_create_default();
+               return clnt;
+       }
+       return NULL;
+}
+
+void mnt_closeclnt(CLIENT *clnt, int msock)
+{
+       auth_destroy(clnt->cl_auth);
+       clnt_destroy(clnt);
+       close(msock);
+}