Remove the static "struct client_connection" mess which is part of
authorJeremy Allison <jra@samba.org>
Fri, 13 Mar 2009 00:59:24 +0000 (17:59 -0700)
committerJeremy Allison <jra@samba.org>
Fri, 13 Mar 2009 00:59:24 +0000 (17:59 -0700)
the problem that stops libsmbclient being thread safe. Subsidiary
DFS connections are now hung off a list inside the cli_state struct.
Much more to do in order to get libsmbclient to thread safety, but
this is a good start.
Jeremy.

source3/client/client.c
source3/include/client.h
source3/include/proto.h
source3/lib/netapi/cm.c
source3/libsmb/clidfs.c
source3/libsmb/clientgen.c
source3/libsmb/clilist.c

index aaa9e35..6491f39 100644 (file)
@@ -1419,7 +1419,7 @@ static bool do_altname(const char *name)
 
 static int cmd_quit(void)
 {
-       cli_cm_shutdown();
+       cli_shutdown(cli);
        exit(0);
        /* NOTREACHED */
        return 0;
@@ -1714,7 +1714,7 @@ static int do_put(const char *rname, const char *lname, bool reput)
        }
 
        if (f == x_stdin) {
-               cli_cm_shutdown();
+               cli_shutdown(cli);
                exit(0);
        }
 
@@ -3815,7 +3815,7 @@ static int cmd_logon(void)
 
 static int cmd_list_connect(void)
 {
-       cli_cm_display();
+       cli_cm_display(cli);
        return 0;
 }
 
@@ -4526,7 +4526,7 @@ static int process(const char *base_directory)
        if (base_directory && *base_directory) {
                rc = do_cd(base_directory);
                if (rc) {
-                       cli_cm_shutdown();
+                       cli_shutdown(cli);
                        return rc;
                }
        }
@@ -4537,7 +4537,7 @@ static int process(const char *base_directory)
                process_stdin();
        }
 
-       cli_cm_shutdown();
+       cli_shutdown(cli);
        return rc;
 }
 
@@ -4568,7 +4568,7 @@ static int do_host_query(const char *query_host)
                /* Workgroups simply don't make sense over anything
                   else but port 139... */
 
-               cli_cm_shutdown();
+               cli_shutdown(cli);
                cli = cli_cm_open(talloc_tos(), NULL,
                                query_host, "IPC$", true, smb_encrypt,
                                max_protocol, 139, name_type);
@@ -4581,7 +4581,7 @@ static int do_host_query(const char *query_host)
 
        list_servers(lp_workgroup());
 
-       cli_cm_shutdown();
+       cli_shutdown(cli);
 
        return(0);
 }
@@ -4609,14 +4609,14 @@ static int do_tar_op(const char *base_directory)
        if (base_directory && *base_directory)  {
                ret = do_cd(base_directory);
                if (ret) {
-                       cli_cm_shutdown();
+                       cli_shutdown(cli);
                        return ret;
                }
        }
 
        ret=process_tar();
 
-       cli_cm_shutdown();
+       cli_shutdown(cli);
 
        return(ret);
 }
@@ -4663,12 +4663,12 @@ static int do_message_op(struct user_auth_info *auth_info)
 
        if (!cli_session_request(cli, &calling, &called)) {
                d_printf("session request failed\n");
-               cli_cm_shutdown();
+               cli_shutdown(cli);
                return 1;
        }
 
        send_message(get_cmdline_auth_info_username(auth_info));
-       cli_cm_shutdown();
+       cli_shutdown(cli);
 
        return 0;
 }
index 646d54a..eae22fd 100644 (file)
@@ -167,6 +167,10 @@ struct smb_trans_enc_state {
 };
 
 struct cli_state {
+       /**
+        * A list of subsidiary connections for DFS.
+        */
+        struct cli_state *prev, *next;
        int port;
        int fd;
        /* Last read or write error. */
@@ -276,6 +280,9 @@ struct cli_state {
         * chained async_req.
         */
        struct cli_request *chain_accumulator;
+
+       /* Where (if anywhere) this is mounted under DFS. */
+       char *dfs_mountpoint;
 };
 
 typedef struct file_info {
index c8a066f..40024c5 100644 (file)
@@ -2355,7 +2355,6 @@ NTSTATUS cli_cm_force_encryption(struct cli_state *c,
                        const char *password,
                        const char *domain,
                        const char *sharename);
-const char *cli_cm_get_mntpoint(struct cli_state *c);
 struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
                                struct cli_state *referring_cli,
                                const char *server,
@@ -2365,8 +2364,7 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
                                int max_protocol,
                                int port,
                                int name_type);
-void cli_cm_shutdown(void);
-void cli_cm_display(void);
+void cli_cm_display(const struct cli_state *c);
 void cli_cm_set_credentials(struct user_auth_info *auth_info);
 void cli_cm_set_port(int port_number);
 void cli_cm_set_dest_name_type(int type);
index 233255f..43ebed6 100644 (file)
@@ -73,19 +73,10 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx,
 /********************************************************************
 ********************************************************************/
 
-WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
-{
-       cli_cm_shutdown();
-
-       return WERR_OK;
-}
-
-/********************************************************************
-********************************************************************/
-
 struct client_pipe_connection {
        struct client_pipe_connection *prev, *next;
        struct rpc_pipe_client *pipe;
+       struct cli_state *cli;
 };
 
 static struct client_pipe_connection *pipe_connections;
@@ -93,6 +84,20 @@ static struct client_pipe_connection *pipe_connections;
 /********************************************************************
 ********************************************************************/
 
+WERROR libnetapi_shutdown_cm(struct libnetapi_ctx *ctx)
+{
+       struct client_pipe_connection *p;
+
+       for (p = pipe_connections; p; p = p->next) {
+               cli_shutdown(p->cli);
+       }
+
+       return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
 static NTSTATUS pipe_cm_find(struct cli_state *cli,
                             const struct ndr_syntax_id *interface,
                             struct rpc_pipe_client **presult)
@@ -138,6 +143,7 @@ static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx,
                return status;
        }
 
+       p->cli = cli;
        DLIST_ADD(pipe_connections, p);
 
        *presult = p->pipe;
@@ -193,5 +199,3 @@ WERROR libnetapi_open_pipe(struct libnetapi_ctx *ctx,
 
        return WERR_OK;
 }
-
-
index 1153d8d..8544d55 100644 (file)
@@ -3,7 +3,7 @@
    client connect/disconnect routines
    Copyright (C) Andrew Tridgell                  1994-1998
    Copyright (C) Gerald (Jerry) Carter            2004
-   Copyright (C) Jeremy Allison                   2007
+   Copyright (C) Jeremy Allison                   2007-2009
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    as a separator when looking at the pathname part.... JRA.
 ********************************************************************/
 
-struct client_connection {
-       struct client_connection *prev, *next;
-       struct cli_state *cli;
-       char *mount;
-};
-
 static struct cm_cred_struct {
        char *username;
        char *password;
@@ -49,8 +43,6 @@ static struct cm_cred_struct {
 
 static void cm_set_password(const char *newpass);
 
-static struct client_connection *connections;
-
 static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
                                struct cli_state *cli,
                                const char *sharename,
@@ -96,7 +88,7 @@ NTSTATUS cli_cm_force_encryption(struct cli_state *c,
 
        return status;
 }
-       
+
 /********************************************************************
  Return a connection to a server.
 ********************************************************************/
@@ -301,52 +293,20 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
 /****************************************************************************
 ****************************************************************************/
 
-static void cli_cm_set_mntpoint(struct cli_state *c, const char *mnt)
-{
-       struct client_connection *p;
-       int i;
-
-       for (p=connections,i=0; p; p=p->next,i++) {
-               if (strequal(p->cli->desthost, c->desthost) &&
-                               strequal(p->cli->share, c->share)) {
-                       break;
-               }
-       }
-
-       if (p) {
-               char *name = clean_name(NULL, mnt);
-               if (!name) {
-                       return;
-               }
-               TALLOC_FREE(p->mount);
-               p->mount = talloc_strdup(p, name);
-               TALLOC_FREE(name);
-       }
-}
-
-/****************************************************************************
-****************************************************************************/
-
-const char *cli_cm_get_mntpoint(struct cli_state *c)
+static void cli_set_mntpoint(struct cli_state *cli, const char *mnt)
 {
-       struct client_connection *p;
-       int i;
-
-       for (p=connections,i=0; p; p=p->next,i++) {
-               if (strequal(p->cli->desthost, c->desthost) &&
-                               strequal(p->cli->share, c->share)) {
-                       break;
-               }
-       }
-
-       if (p) {
-               return p->mount;
+       char *name = clean_name(NULL, mnt);
+       if (!name) {
+               return;
        }
-       return NULL;
+       TALLOC_FREE(cli->dfs_mountpoint);
+       cli->dfs_mountpoint = talloc_strdup(cli, name);
+       TALLOC_FREE(name);
 }
 
 /********************************************************************
- Add a new connection to the list
+ Add a new connection to the list.
+ referring_cli == NULL means a new initial connection.
 ********************************************************************/
 
 static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
@@ -359,53 +319,62 @@ static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
                                        int port,
                                        int name_type)
 {
-       struct client_connection *node;
-
-       /* NB This must be the null context here... JRA. */
-       node = TALLOC_ZERO_ARRAY(NULL, struct client_connection, 1);
-       if (!node) {
-               return NULL;
-       }
+       struct cli_state *cli;
 
-       node->cli = do_connect(ctx, server, share,
+       cli = do_connect(ctx, server, share,
                                show_hdr, force_encrypt, max_protocol,
                                port, name_type);
 
-       if ( !node->cli ) {
-               TALLOC_FREE( node );
+       if (!cli ) {
                return NULL;
        }
 
-       DLIST_ADD( connections, node );
-
-       cli_cm_set_mntpoint(node->cli, "");
+       /* Enter into the list. */
+       if (referring_cli) {
+               DLIST_ADD_END(referring_cli, cli, struct cli_state *);
+       }
 
        if (referring_cli && referring_cli->posix_capabilities) {
                uint16 major, minor;
                uint32 caplow, caphigh;
-               if (cli_unix_extensions_version(node->cli, &major,
+               if (cli_unix_extensions_version(cli, &major,
                                        &minor, &caplow, &caphigh)) {
-                       cli_set_unix_extensions_capabilities(node->cli,
+                       cli_set_unix_extensions_capabilities(cli,
                                        major, minor,
                                        caplow, caphigh);
                }
        }
 
-       return node->cli;
+       return cli;
 }
 
 /********************************************************************
- Return a connection to a server.
+ Return a connection to a server on a particular share.
 ********************************************************************/
 
-static struct cli_state *cli_cm_find(const char *server, const char *share)
+static struct cli_state *cli_cm_find(struct cli_state *cli,
+                               const char *server,
+                               const char *share)
 {
-       struct client_connection *p;
+       struct cli_state *p;
 
-       for (p=connections; p; p=p->next) {
-               if ( strequal(server, p->cli->desthost) &&
-                               strequal(share,p->cli->share)) {
-                       return p->cli;
+       if (cli == NULL) {
+               return NULL;
+       }
+
+       /* Search to the start of the list. */
+       for (p = cli; p; p = p->prev) {
+               if (strequal(server, p->desthost) &&
+                               strequal(share,p->share)) {
+                       return p;
+               }
+       }
+
+       /* Search to the end of the list. */
+       for (p = cli->next; p; p = p->next) {
+               if (strequal(server, p->desthost) &&
+                               strequal(share,p->share)) {
+                       return p;
                }
        }
 
@@ -413,8 +382,7 @@ static struct cli_state *cli_cm_find(const char *server, const char *share)
 }
 
 /****************************************************************************
- Open a client connection to a \\server\share.  Set's the current *cli
- global variable as a side-effect (but only if the connection is successful).
+ Open a client connection to a \\server\share.
 ****************************************************************************/
 
 struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
@@ -427,50 +395,28 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
                                int port,
                                int name_type)
 {
-       struct cli_state *c;
+       /* Try to reuse an existing connection in this list. */
+       struct cli_state *c = cli_cm_find(referring_cli, server, share);
 
-       /* try to reuse an existing connection */
+       if (c) {
+               return c;
+       }
 
-       c = cli_cm_find(server, share);
-       if (!c) {
-               c = cli_cm_connect(ctx, referring_cli,
+       return cli_cm_connect(ctx, referring_cli,
                                server, share, show_hdr, force_encrypt,
                                max_protocol, port, name_type);
-       }
-
-       return c;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-void cli_cm_shutdown(void)
-{
-       struct client_connection *p, *x;
-
-       for (p=connections; p;) {
-               cli_shutdown(p->cli);
-               x = p;
-               p = p->next;
-
-               TALLOC_FREE(x);
-       }
-
-       connections = NULL;
-       return;
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-void cli_cm_display(void)
+void cli_cm_display(const struct cli_state *cli)
 {
-       struct client_connection *p;
        int i;
 
-       for ( p=connections,i=0; p; p=p->next,i++ ) {
+       for (i=0; cli; cli = cli->next,i++ ) {
                d_printf("%d:\tserver=%s, share=%s\n",
-                       i, p->cli->desthost, p->cli->share );
+                       i, cli->desthost, cli->share );
        }
 }
 
@@ -998,7 +944,7 @@ bool cli_resolve_path(TALLOC_CTX *ctx,
                return false;
        }
 
-       cli_cm_set_mntpoint(*targetcli, newmount);
+       cli_set_mntpoint(*targetcli, newmount);
 
        /* Check for another dfs referral, note that we are not
           checking for loops here. */
index 2983f77..7c42da4 100644 (file)
@@ -425,7 +425,7 @@ void cli_init_creds(struct cli_state *cli, const char *username, const char *dom
 }
 
 /****************************************************************************
- Initialise a client structure. Always returns a malloc'ed struct.
+ Initialise a client structure. Always returns a talloc'ed struct.
  Set the signing state (used from the command line).
 ****************************************************************************/
 
@@ -446,6 +446,11 @@ struct cli_state *cli_initialise_ex(int signing_state)
                return NULL;
        }
 
+       cli->dfs_mountpoint = talloc_strdup(cli, "");
+       if (!cli->dfs_mountpoint) {
+               TALLOC_FREE(cli);
+               return NULL;
+       }
        cli->port = 0;
        cli->fd = -1;
        cli->cnum = -1;
@@ -550,6 +555,27 @@ void cli_nt_pipes_close(struct cli_state *cli)
 
 void cli_shutdown(struct cli_state *cli)
 {
+       if (cli->prev == NULL) {
+               /*
+                * Possible head of a DFS list,
+                * shutdown all subsidiary DFS
+                * connections.
+                */
+               struct cli_state *p, *next;
+
+               for (p = cli->next; p; p = next) {
+                       next = p->next;
+                       cli_shutdown(p);
+               }
+       } else {
+               /*
+                * We're a subsidiary connection.
+                * Just remove ourselves from the
+                * DFS list.
+                */
+               DLIST_REMOVE(cli->prev, cli);
+       }
+
        cli_nt_pipes_close(cli);
 
        /*
index e604725..a84a647 100644 (file)
@@ -244,7 +244,6 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
        unsigned int param_len, data_len;
        uint16 setup;
        char *param;
-       const char *mnt;
        uint32 resume_key = 0;
        TALLOC_CTX *frame = talloc_stackframe();
        DATA_BLOB last_name_raw = data_blob(NULL, 0);
@@ -457,8 +456,6 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                First = False;
        }
 
-       mnt = cli_cm_get_mntpoint( cli );
-
         /* see if the server disconnected or the connection otherwise failed */
         if (cli_is_error(cli)) {
                 total_received = -1;
@@ -479,7 +476,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                                        info_level));
                                break;
                        }
-                        fn(mnt,&finfo, Mask, state);
+                        fn(cli->dfs_mountpoint, &finfo, Mask, state);
                 }
         }