Track waiting requests in a hash table, by xid
[deb_libnfs.git] / lib / libnfs.c
index d4a3f6cc2f483365bb74a9547fa19c669398abc2..9053ab1884992ff7b01287d8c5ac655c90e4fc6e 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 {
@@ -464,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);
 
@@ -479,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);
@@ -498,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);
 
@@ -512,10 +538,26 @@ static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       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;
+       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;
        }
 }
 
@@ -539,10 +581,21 @@ static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       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;
+       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;
        }
 }
 
@@ -941,7 +994,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
 
        /* /$ -> \0 */
        len = strlen(path);
-       if (len >= 1) {
+       if (len > 1) {
                if (path[len - 1] == '/') {
                        path[len - 1] = '\0';
                        len--;
@@ -2741,46 +2794,48 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
        /* steal the dirhandle */
        nfsdir->current = nfsdir->entries;
 
-       rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
-       rdpe_cb_data->getattrcount = 0;
-       rdpe_cb_data->status = RPC_STATUS_SUCCESS;
-       rdpe_cb_data->data = data;
-       for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
-               struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
-               LOOKUP3args args;
-
-               rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
-               rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
-               rdpe_lookup_cb_data->nfsdirent = nfsdirent;
-
-               memset(&args, 0, sizeof(LOOKUP3args));
-               args.what.dir = data->fh;
-               args.what.name = nfsdirent->name;
-
-               if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
-                       rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
-
-                       /* if we have already commands in flight, we cant just stop, we have to wait for the
-                        * commands in flight to complete
-                        */
-                       if (rdpe_cb_data->getattrcount > 0) {
+       if (nfsdir->entries) {
+               rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
+               rdpe_cb_data->getattrcount = 0;
+               rdpe_cb_data->status = RPC_STATUS_SUCCESS;
+               rdpe_cb_data->data = data;
+               for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
+                       struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
+                       LOOKUP3args args;
+
+                       rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
+                       rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
+                       rdpe_lookup_cb_data->nfsdirent = nfsdirent;
+
+                       memset(&args, 0, sizeof(LOOKUP3args));
+                       args.what.dir = data->fh;
+                       args.what.name = nfsdirent->name;
+
+                       if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
+                               rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
+
+                               /* if we have already commands in flight, we cant just stop, we have to wait for the
+                                * commands in flight to complete
+                                */
+                               if (rdpe_cb_data->getattrcount > 0) {
+                                       nfs_free_nfsdir(nfsdir);
+                                       data->continue_data = NULL;
+                                       free_nfs_cb_data(data);
+                                       rdpe_cb_data->status = RPC_STATUS_ERROR;
+                                       free(rdpe_lookup_cb_data);
+                                       return;
+                               }
+
+                               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                                nfs_free_nfsdir(nfsdir);
                                data->continue_data = NULL;
                                free_nfs_cb_data(data);
-                               rdpe_cb_data->status = RPC_STATUS_ERROR;
                                free(rdpe_lookup_cb_data);
+                               free(rdpe_cb_data);
                                return;
                        }
-
-                       data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
-                       nfs_free_nfsdir(nfsdir);
-                       data->continue_data = NULL;
-                       free_nfs_cb_data(data);
-                       free(rdpe_lookup_cb_data);
-                       free(rdpe_cb_data);
-                       return;
+                       rdpe_cb_data->getattrcount++;
                }
-               rdpe_cb_data->getattrcount++;
        }
 }
 
@@ -4215,91 +4270,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_pmap2_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_pmap2_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;
@@ -4318,7 +4288,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;
        }