Add smb_composite_connectmulti: Send out multiple SYN packets at once, use the
authorvlendec <vlendec@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Sun, 2 Oct 2005 10:02:35 +0000 (10:02 +0000)
committervlendec <vlendec@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Sun, 2 Oct 2005 10:02:35 +0000 (10:02 +0000)
first one that replies correctly.

Add a talloc context to smb_composite_connect()

Volker

git-svn-id: svn+ssh://svn.samba.org/data/svn/samba/branches/SAMBA_4_0@10677 0c0555d6-39d7-0310-84fc-f1cc0bd64818

source/include/structs.h
source/libcli/config.mk
source/libcli/smb_composite/connect.c
source/libcli/smb_composite/connect_multi.c [new file with mode: 0644]
source/libcli/smb_composite/fetchfile.c
source/libcli/smb_composite/fsinfo.c
source/libcli/smb_composite/smb_composite.h
source/ntvfs/cifs/vfs_cifs.c
source/winbind/wb_samba3_cmd.c

index ea904207530f914d1d057a10c92dd9480abe2634..cc9f4992bd5359beb55e201dbb4180313fe4d9c4 100644 (file)
@@ -217,6 +217,7 @@ struct monitor_msg;
 struct smb_composite_loadfile;
 struct smb_composite_savefile;
 struct smb_composite_connect;
+struct smb_composite_connectmulti;
 struct smb_composite_sesssetup;
 struct smb_composite_fetchfile;
 struct smb_composite_appendacl;
index 62530ed64b8340fa13063af78878b637f9643b80..8b3920719421187b16d10b8c21bec7494ef5e06c 100644 (file)
@@ -20,6 +20,7 @@ ADD_OBJ_FILES = \
        libcli/smb_composite/loadfile.o \
        libcli/smb_composite/savefile.o \
        libcli/smb_composite/connect.o \
+       libcli/smb_composite/connect_multi.o \
        libcli/smb_composite/sesssetup.o \
        libcli/smb_composite/fetchfile.o \
        libcli/smb_composite/appendacl.o \
index 56d9d988c36a4c977627773e6d349221f4a61cce..53cc8a9ac0df47788b0f27eaee796b0f9592bde3 100644 (file)
@@ -25,6 +25,7 @@
 #include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
 #include "libcli/smb_composite/smb_composite.h"
+#include "lib/events/events.h"
 
 /* the stages of this call */
 enum connect_stage {CONNECT_RESOLVE, 
@@ -39,6 +40,7 @@ struct connect_state {
        struct smbcli_socket *sock;
        struct smbcli_transport *transport;
        struct smbcli_session *session;
+       struct smb_composite_connectmulti *conn;
        struct smb_composite_connect *io;
        union smb_tcon *io_tcon;
        struct smb_composite_sesssetup *io_setup;
@@ -213,9 +215,11 @@ static NTSTATUS connect_socket(struct composite_context *c,
        NTSTATUS status;
        struct nbt_name calling, called;
 
-       status = smbcli_sock_connect_recv(state->creq);
+       status = smb_composite_connectmulti_recv(state->creq, state);
        NT_STATUS_NOT_OK_RETURN(status);
 
+       state->sock = state->conn->out.socket;
+
        /* the socket is up - we can initialise the smbcli transport layer */
        state->transport = smbcli_transport_init(state->sock, state, True);
        NT_STATUS_HAVE_NO_MEMORY(state->transport);
@@ -254,11 +258,33 @@ static NTSTATUS connect_resolve(struct composite_context *c,
        struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
        NTSTATUS status;
        const char *address;
+       struct smb_composite_connectmulti *conn;
 
        status = resolve_name_recv(state->creq, state, &address);
        NT_STATUS_NOT_OK_RETURN(status);
 
-       state->creq = smbcli_sock_connect_send(state->sock, address, state->io->in.port, io->in.dest_host);
+       conn = talloc(state, struct smb_composite_connectmulti);
+       NT_STATUS_HAVE_NO_MEMORY(conn);
+       state->conn = conn;
+       conn->in.num_dests = 1;
+
+       conn->in.addresses = talloc_array(state->conn, const char *, 1);
+       NT_STATUS_HAVE_NO_MEMORY(conn->in.addresses);
+       conn->in.addresses[0] = address;
+
+       conn->in.hostnames = talloc_array(state->conn, const char *, 1);
+       NT_STATUS_HAVE_NO_MEMORY(conn->in.hostnames);
+       conn->in.hostnames[0] = state->io->in.dest_host;
+       
+       conn->in.ports = NULL;
+       if (state->io->in.port != 0) {
+               conn->in.ports = talloc_array(state->conn, int, 1);
+               NT_STATUS_HAVE_NO_MEMORY(conn->in.ports);
+               conn->in.ports[0] = state->io->in.port;
+       }
+
+       state->creq = smb_composite_connectmulti_send(conn, state,
+                                                     c->event_ctx);
        NT_STATUS_HAVE_NO_MEMORY(state->creq);
 
        state->stage = CONNECT_SOCKET;
@@ -332,25 +358,27 @@ static void composite_handler(struct composite_context *creq)
   a function to establish a smbcli_tree from scratch
 */
 struct composite_context *smb_composite_connect_send(struct smb_composite_connect *io,
-                                                   struct event_context *event_ctx)
+                                                    TALLOC_CTX *mem_ctx,
+                                                    struct event_context *event_ctx)
 {
        struct composite_context *c;
        struct connect_state *state;
        struct nbt_name name;
 
-       c = talloc_zero(NULL, struct composite_context);
+       c = talloc_zero(mem_ctx, struct composite_context);
        if (c == NULL) goto failed;
 
        state = talloc(c, struct connect_state);
        if (state == NULL) goto failed;
 
-       state->sock = smbcli_sock_init(state, event_ctx);
-       if (state->sock == NULL) goto failed;
+       if (event_ctx == NULL) {
+               event_ctx = event_context_init(mem_ctx);
+       }
 
        state->io = io;
 
        c->state = COMPOSITE_STATE_IN_PROGRESS;
-       c->event_ctx = talloc_reference(c, state->sock->event.ctx);
+       c->event_ctx = talloc_reference(c, event_ctx);
        c->private_data = state;
 
        state->stage = CONNECT_RESOLVE;
@@ -391,6 +419,6 @@ NTSTATUS smb_composite_connect_recv(struct composite_context *c, TALLOC_CTX *mem
 NTSTATUS smb_composite_connect(struct smb_composite_connect *io, TALLOC_CTX *mem_ctx,
                               struct event_context *ev)
 {
-       struct composite_context *c = smb_composite_connect_send(io, ev);
+       struct composite_context *c = smb_composite_connect_send(io, mem_ctx, ev);
        return smb_composite_connect_recv(c, mem_ctx);
 }
diff --git a/source/libcli/smb_composite/connect_multi.c b/source/libcli/smb_composite/connect_multi.c
new file mode 100644 (file)
index 0000000..a539ba4
--- /dev/null
@@ -0,0 +1,188 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Volker Lendecke
+   
+   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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+  a composite API to fire connect calls to multiple targets, picking the first
+  one.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+
+struct connectmulti_state {
+       struct smb_composite_connectmulti *io;
+       struct composite_context *creq;
+       struct smbcli_socket *result;
+       int num_socks, socks_left;
+       struct smbcli_socket **socks;
+       struct composite_context **creqs;
+};
+
+static void connect_receive(struct composite_context *c)
+
+{
+       struct connectmulti_state *state =
+               talloc_get_type(c->async.private_data,
+                               struct connectmulti_state);
+       int i;
+
+       for (i=0; i<state->num_socks; i++) {
+               if (state->creqs[i] == c) {
+                       break;
+               }
+       }
+
+       if (i == state->num_socks) {
+               c->status = NT_STATUS_INTERNAL_ERROR;
+               c->state = COMPOSITE_STATE_ERROR;
+               if (state->creq->async.fn != NULL) {
+                       state->creq->async.fn(state->creq);
+               }
+               return;
+       }
+
+       state->creq->status = smbcli_sock_connect_recv(c);
+       if (!NT_STATUS_IS_OK(state->creq->status)) {
+               talloc_free(state->socks[i]);
+               state->socks[i] = NULL;
+               state->creqs[i] = NULL;
+               state->socks_left -= 1;
+               if (state->socks_left == 0) {
+                       state->creq->state = COMPOSITE_STATE_ERROR;
+                       if (state->creq->async.fn != NULL) {
+                               state->creq->async.fn(state->creq);
+                       }
+               }
+               return;
+       }
+
+       state->result = talloc_steal(state, state->socks[i]);
+       talloc_free(state->socks);
+
+       state->creq->state = COMPOSITE_STATE_DONE;
+       if (state->creq->async.fn != NULL) {
+               state->creq->async.fn(state->creq);
+       }
+}
+
+struct composite_context *smb_composite_connectmulti_send(struct smb_composite_connectmulti *io,
+                                                         TALLOC_CTX *mem_ctx,
+                                                         struct event_context *event_ctx)
+{
+       struct composite_context *c;
+       struct connectmulti_state *state;
+       int num_socks = io->in.num_dests;
+       const char **hostnames = io->in.hostnames;
+       const char **addresses = io->in.addresses;
+       int *ports = io->in.ports;
+       int i;
+
+       c = talloc_zero(mem_ctx, struct composite_context);
+       if (c == NULL) goto failed;
+
+       state = talloc(c, struct connectmulti_state);
+       if (state == NULL) goto failed;
+
+       c->state = COMPOSITE_STATE_IN_PROGRESS;
+       c->event_ctx = talloc_reference(c, event_ctx);
+       c->private_data = state;
+
+       if (ports == NULL) {
+               int j, nports;
+               const char **smb_ports = lp_smb_ports();
+
+               for (nports=0; smb_ports[nports]; nports++) /* noop */;
+
+               num_socks *= nports;
+               hostnames = talloc_array(state, const char *, num_socks);
+               if (hostnames == NULL) goto failed;
+               addresses = talloc_array(state, const char *, num_socks);
+               if (addresses == NULL) goto failed;
+               ports = talloc_array(state, int, num_socks);
+               if (ports == NULL) goto failed;
+
+               for (i=0; i<io->in.num_dests; i++) {
+                       for (j=0; j<nports; j++) {
+                               hostnames[i*nports+j] = io->in.hostnames[i];
+                               addresses[i*nports+j] = io->in.addresses[i];
+                               ports[i*nports+j] = atoi(smb_ports[j]);
+                       }
+               }
+       }
+
+       state->io = io;
+       state->creq = c;
+       state->num_socks = num_socks;
+       state->socks_left = num_socks;
+       state->socks = talloc_array(state, struct smbcli_socket *, num_socks);
+       state->creqs = talloc_array(state, struct composite_context *,
+                                   num_socks);
+       if ((state->socks == NULL) || (state->creqs == NULL)) goto failed;
+
+       for (i=0; i<num_socks; i++) {
+               state->socks[i] = smbcli_sock_init(state->socks, event_ctx);
+               if (state->socks[i] == NULL) goto failed;
+
+               /* If the event_ctx we got given is NULL, the first socket
+                * creates one and all others need to refer to it. */
+               event_ctx = state->socks[i]->event.ctx;
+
+               state->creqs[i] = smbcli_sock_connect_send(state->socks[i],
+                                                          addresses[i],
+                                                          ports[i],
+                                                          hostnames[i]);
+               if (state->creqs[i] == NULL) goto failed;
+               state->creqs[i]->async.fn = connect_receive;
+               state->creqs[i]->async.private_data = state;
+       }
+
+       return c;
+
+ failed:
+       talloc_free(c);
+       return NULL;
+}
+
+NTSTATUS smb_composite_connectmulti_recv(struct composite_context *c,
+                                        TALLOC_CTX *mem_ctx)
+{
+       NTSTATUS status;
+       status = composite_wait(c);
+
+       if (NT_STATUS_IS_OK(status)) {
+               struct connectmulti_state *state =
+                       talloc_get_type(c->private_data,
+                                       struct connectmulti_state);
+               state->io->out.socket = talloc_steal(mem_ctx, state->result);
+       }
+
+       talloc_free(c);
+       return status;
+}
+
+NTSTATUS smb_composite_connectmulti(struct smb_composite_connectmulti *io,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct event_context *ev)
+{
+       struct composite_context *c =
+               smb_composite_connectmulti_send(io, mem_ctx, ev);
+       return smb_composite_connectmulti_recv(c, mem_ctx);
+}
index 9e88fb669db086979954bf759c138631041cb7b1..8aa91bf3a91747526967983cdf899adb15a5e823 100644 (file)
@@ -146,7 +146,7 @@ struct composite_context *smb_composite_fetchfile_send(struct smb_composite_fetc
        state->connect->in.credentials  = io->in.credentials;
        state->connect->in.workgroup    = io->in.workgroup;
 
-       state->creq = smb_composite_connect_send(state->connect, event_ctx);
+       state->creq = smb_composite_connect_send(state->connect, state, event_ctx);
        if (state->creq == NULL) goto failed;
 
        state->creq->async.private_data = c;
index e870225906502e6b62b3f9ece216b7330ddc5ab6..fa9f18d132c653ea510d772b3a40889f3f904027 100644 (file)
@@ -156,7 +156,8 @@ struct composite_context *smb_composite_fsinfo_send(struct smbcli_tree *tree,
        c->event_ctx = talloc_reference(c,  tree->session->transport->socket->event.ctx);
        c->private_data = state;
 
-       state->creq = smb_composite_connect_send(state->connect, c->event_ctx);
+       state->creq = smb_composite_connect_send(state->connect, state,
+                                                c->event_ctx);
 
        if (state->creq == NULL) goto failed;
   
index 08031c2f4b02fadc74c64a9628c9481cc8a5fc03..ec3a7af22df9545c0ec9548dc9d7c7c4c7b0ff7c 100644 (file)
@@ -150,3 +150,21 @@ struct smb_composite_appendacl {
                struct security_descriptor *sd;
        } out;
 };
+
+/*
+  a composite API to fire connect() calls to multiple targets, picking the
+  first one.
+*/
+
+struct smb_composite_connectmulti {
+       struct {
+               int num_dests;
+               const char **hostnames;
+               const char **addresses;
+               int *ports;     /* Either NULL for lp_smb_ports() per
+                                * destination or a list of explicit ports */
+       } in;
+       struct {
+               struct smbcli_socket *socket;
+       } out;
+};
index 789f24259a4ec3b87387c04bfee10d37c9a6d097..0ad04254159d8ec6dd5f10f630751377f0ac7e7f 100644 (file)
@@ -134,7 +134,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
        io.in.service = remote_share;
        io.in.service_type = "?????";
        
-       creq = smb_composite_connect_send(&io, tcon->smb_conn->connection->event.ctx);
+       creq = smb_composite_connect_send(&io, private, tcon->smb_conn->connection->event.ctx);
        status = smb_composite_connect_recv(creq, private);
        NT_STATUS_NOT_OK_RETURN(status);
 
index a1593ef8bdef4624c771023e58c38346d54f45ca..7b3cd79cf4b68be260b85a4d2e2693eb9bc39126 100644 (file)
@@ -164,7 +164,8 @@ static void wbsrv_samba3_check_machacc_receive_dcs(struct composite_context *act
        cli_credentials_set_conf(state->conn->in.credentials);
        cli_credentials_set_anonymous(state->conn->in.credentials);
 
-       ctx = smb_composite_connect_send(state->conn, s3call->call->event_ctx);
+       ctx = smb_composite_connect_send(state->conn, state,
+                                        s3call->call->event_ctx);
        if (ctx == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto done;