PORTMAP: Rename pmap3_getaddr_result to pmap3_string_result
[deb_libnfs.git] / lib / libnfs.c
index bb89d4a8c10bb34fd541801af242d7d3704ce1f6..30c375715f180ae46ccf4167963bfe7b4b41822b 100644 (file)
@@ -73,6 +73,7 @@
 #include "libnfs-raw.h"
 #include "libnfs-raw-mount.h"
 #include "libnfs-raw-nfs.h"
+#include "libnfs-raw-portmap.h"
 #include "libnfs-private.h"
 
 struct nfsdir {
@@ -394,6 +395,30 @@ void free_rpc_cb_data(struct rpc_cb_data *data)
        free(data);
 }
 
+static void rpc_connect_program_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, status, NULL, data->private_data);
+       free_rpc_cb_data(data);
+}
+
 static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
@@ -414,6 +439,25 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
+       switch (data->program) {
+       case MOUNT_PROGRAM:
+               if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       case NFS_PROGRAM:
+               if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       }
+
        data->cb(rpc, status, NULL, data->private_data);
        free_rpc_cb_data(data);
 }
@@ -421,7 +465,9 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
 static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
-       uint32_t rpc_port;
+       struct pmap3_string_result *gar;
+       uint32_t rpc_port = 0;
+       unsigned char *ptr;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -436,7 +482,29 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       rpc_port = *(uint32_t *)command_data;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               rpc_port = *(uint32_t *)command_data;
+               break;
+       case AF_INET6:
+               /* ouch. portmapper and ipv6 are not great */
+               gar = command_data;
+               if (gar->addr == NULL) {
+                       break;
+               }
+               ptr = strrchr(gar->addr, '.');
+               if (ptr == NULL) {
+                       break;
+               }
+               rpc_port = atoi(ptr + 1);
+               *ptr = 0;
+               ptr = strrchr(gar->addr, '.');
+               if (ptr == NULL) {
+                       break;
+               }
+               rpc_port += 256 * atoi(ptr + 1);
+               break;
+       }
        if (rpc_port == 0) {
                rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
                data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
@@ -455,6 +523,7 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
 static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
+       struct pmap3_mapping map;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -469,10 +538,26 @@ static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
-               data->cb(rpc, status, command_data, data->private_data);
-               free_rpc_cb_data(data);
-               return;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
+       case AF_INET6:
+               map.prog=data->program;
+               map.vers=data->version;
+               map.netid="";
+               map.addr="";
+               map.owner="";
+               if (rpc_pmap3_getaddr_async(rpc, &map, rpc_connect_program_3_cb, private_data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
        }
 }
 
@@ -496,14 +581,25 @@ static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
-               data->cb(rpc, status, command_data, data->private_data);
-               free_rpc_cb_data(data);
-               return;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
+       case AF_INET6:
+               if (rpc_pmap3_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
        }
 }
 
-int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data)
+int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data)
 {
        struct rpc_cb_data *data;
 
@@ -627,36 +723,6 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
-
-static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_nfs3_null_async(rpc, nfs_mount_8_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
 static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
@@ -695,11 +761,13 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da
        memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len);
 
        rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, 2049, nfs_mount_7_cb, data) != 0) {
+
+       if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_8_cb, data) != 0) {
                data->cb(-ENOMEM, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
        }
+
        /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
        rpc_set_autoreconnect(rpc);
 }
@@ -730,123 +798,6 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
-static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_mount3_null_async(rpc, nfs_mount_5_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available on %s", nfs->server);
-               data->cb(-ENOENT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, mount_port, nfs_mount_4_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
-static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, nfs_mount_3_cb, private_data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, nfs_mount_2_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
 /*
  * Async call for mounting an nfs share and geting the root filehandle
  */
@@ -875,7 +826,7 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp
        data->cb           = cb;
        data->private_data = private_data;
 
-       if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) {
+       if (rpc_connect_program_async(nfs->rpc, server, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_5_cb, data) != 0) {
                rpc_set_error(nfs->rpc, "Failed to start connection");
                free_nfs_cb_data(data);
                return -1;
@@ -4317,91 +4268,6 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command
        }
 }
 
-static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available");
-               data->cb(rpc, -ENOENT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, mount_export_3_cb, private_data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
 int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
 {
        struct mount_cb_data *data;
@@ -4420,7 +4286,8 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c
                free_mount_cb_data(data);
                return -1;
        }
-       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+       if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) {
+               rpc_set_error(rpc, "Failed to start connection");
                free_mount_cb_data(data);
                return -1;
        }