r2103: in the conversion to async rpc I simplified the smb backend to only
authorAndrew Tridgell <tridge@samba.org>
Mon, 30 Aug 2004 05:35:30 +0000 (05:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:58:25 +0000 (12:58 -0500)
use readx/writex instead of the more efficient SMBtrans calls. This
patch restores the efficiency by using SMBtrans when possible.

source/librpc/rpc/dcerpc.c
source/librpc/rpc/dcerpc.h
source/librpc/rpc/dcerpc_smb.c
source/librpc/rpc/dcerpc_tcp.c

index 1a8fe7373a8654c7afa5a45383aa03d339c4a89c..61e5c1c8b21bad219cf2d1ba622e11e86b235e79 100644 (file)
@@ -352,7 +352,7 @@ static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
 }
 
 /*
-  perform a synchronous request - used for the bind code
+  perform a single pdu synchronous request - used for the bind code
   this cannot be mixed with normal async requests
 */
 static NTSTATUS full_request(struct dcerpc_pipe *p, 
@@ -373,13 +373,11 @@ static NTSTATUS full_request(struct dcerpc_pipe *p,
        p->transport.recv_data = full_request_recv;
        p->full_request_private = state;
 
-       status = p->transport.send_request(p, request_blob);
+       status = p->transport.send_request(p, request_blob, True);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       p->transport.send_read(p);
-
        while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
                struct event_context *ctx = p->transport.event_context(p);
                event_loop_once(ctx);
@@ -563,7 +561,7 @@ NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
        }
 
        /* send it on its way */
-       status = p->transport.send_request(p, &blob);
+       status = p->transport.send_request(p, &blob, False);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -757,7 +755,7 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
                        return req;
                }
                
-               req->status = p->transport.send_request(p, &blob);
+               req->status = p->transport.send_request(p, &blob, False);
                if (!NT_STATUS_IS_OK(req->status)) {
                        req->state = RPC_REQUEST_DONE;
                        return req;
@@ -783,8 +781,8 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
                return req;
        }
 
-       /* send the pdu */
-       req->status = p->transport.send_request(p, &blob);
+       /* send the final pdu */
+       req->status = p->transport.send_request(p, &blob, True);
 
        if (!NT_STATUS_IS_OK(req->status)) {
                req->state = RPC_REQUEST_DONE;
@@ -792,8 +790,6 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
 
        DLIST_ADD(p->pending, req);
 
-       p->transport.send_read(p);
-
        return req;
 }
 
index 2dce5df92a457a74997d820c0ffd785bf56464ba..91899a9fec4dd240d7e7435bd36c844899bea4f1 100644 (file)
@@ -52,7 +52,7 @@ struct dcerpc_pipe {
                const char *(*peer_name)(struct dcerpc_pipe *);
 
                /* send a request to the server */
-               NTSTATUS (*send_request)(struct dcerpc_pipe *, DATA_BLOB *);
+               NTSTATUS (*send_request)(struct dcerpc_pipe *, DATA_BLOB *, BOOL trigger_read);
 
                /* send a read request to the server */
                NTSTATUS (*send_read)(struct dcerpc_pipe *);
index fffc94540345ad565facadca91be0789e6435804..3f936407a673e8b06355fdfd4961a1d4a432e1d7 100644 (file)
@@ -65,14 +65,8 @@ static void smb_read_callback(struct smbcli_request *req)
        smb = state->p->transport.private;
        io = state->io;
 
-       if (!NT_STATUS_IS_OK(req->status)) {
-               pipe_dead(state->p, req->status);
-               talloc_free(state);
-               return;
-       }
-
        status = smb_raw_read_recv(state->req, io);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (NT_STATUS_IS_ERR(status)) {
                pipe_dead(state->p, status);
                talloc_free(state);
                return;
@@ -89,6 +83,7 @@ static void smb_read_callback(struct smbcli_request *req)
        }
 
        frag_length = dcerpc_get_frag_length(&state->data);
+
        if (frag_length <= state->received) {
                state->data.length = state->received;
                state->p->transport.recv_data(state->p, &state->data, NT_STATUS_OK);
@@ -99,25 +94,27 @@ static void smb_read_callback(struct smbcli_request *req)
        /* initiate another read request, as we only got part of a fragment */
        state->data.data = talloc_realloc(state->data.data, frag_length);
 
-       io->readx.in.mincnt = frag_length - state->received;
+       io->readx.in.mincnt = MIN(state->p->srv_max_xmit_frag, 
+                                 frag_length - state->received);
        io->readx.in.maxcnt = io->readx.in.mincnt;
        io->readx.out.data = state->data.data + state->received;
 
-       req = smb_raw_read_send(smb->tree, io);
-       if (req == NULL) {
+       state->req = smb_raw_read_send(smb->tree, io);
+       if (state->req == NULL) {
                pipe_dead(state->p, NT_STATUS_NO_MEMORY);
                talloc_free(state);
                return;
        }
 
-       req->async.fn = smb_read_callback;
-       req->async.private = state;
+       state->req->async.fn = smb_read_callback;
+       state->req->async.private = state;
 }
 
 /*
-  trigger a read request from the server
+  trigger a read request from the server, possibly with some initial
+  data in the read buffer
 */
-static NTSTATUS send_read_request(struct dcerpc_pipe *p)
+static NTSTATUS send_read_request_continue(struct dcerpc_pipe *p, DATA_BLOB *blob)
 {
        struct smb_private *smb = p->transport.private;
        union smb_read *io;
@@ -130,18 +127,31 @@ static NTSTATUS send_read_request(struct dcerpc_pipe *p)
        }
 
        state->p = p;
-       state->received = 0;
-       state->data = data_blob_talloc(state, NULL, 0x2000);
+       if (blob == NULL) {
+               state->received = 0;
+               state->data = data_blob_talloc(state, NULL, 0x2000);
+       } else {
+               uint32_t frag_length = blob->length>=16?
+                       dcerpc_get_frag_length(blob):0x2000;
+               state->received = blob->length;
+               state->data = data_blob_talloc(state, NULL, frag_length);
+               if (!state->data.data) {
+                       talloc_free(state);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               memcpy(state->data.data, blob->data, blob->length);
+       }
+
        state->io = talloc_p(state, union smb_read);
 
        io = state->io;
        io->generic.level = RAW_READ_READX;
        io->readx.in.fnum = smb->fnum;
-       io->readx.in.mincnt = state->data.length;
-       io->readx.in.maxcnt = state->data.length;
+       io->readx.in.mincnt = state->data.length - state->received;
+       io->readx.in.maxcnt = io->readx.in.mincnt;
        io->readx.in.offset = 0;
        io->readx.in.remaining = 0;
-       io->readx.out.data = state->data.data;
+       io->readx.out.data = state->data.data + state->received;
        req = smb_raw_read_send(smb->tree, io);
        if (req == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -156,6 +166,96 @@ static NTSTATUS send_read_request(struct dcerpc_pipe *p)
 }
 
 
+/*
+  trigger a read request from the server
+*/
+static NTSTATUS send_read_request(struct dcerpc_pipe *p)
+{
+       return send_read_request_continue(p, NULL);
+}
+
+/* 
+   this holds the state of an in-flight trans call
+*/
+struct smb_trans_state {
+       struct dcerpc_pipe *p;
+       struct smbcli_request *req;
+       struct smb_trans2 *trans;
+};
+
+/*
+  called when a trans request has completed
+*/
+static void smb_trans_callback(struct smbcli_request *req)
+{
+       struct smb_trans_state *state = req->async.private;
+       struct dcerpc_pipe *p = state->p;
+       NTSTATUS status;
+
+       status = smb_raw_trans_recv(req, state, state->trans);
+
+       if (NT_STATUS_IS_ERR(status)) {
+               pipe_dead(p, status);
+               return;
+       }
+
+       if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+               p->transport.recv_data(p, &state->trans->out.data, NT_STATUS_OK);
+               talloc_free(state);
+               return;
+       }
+
+       /* there is more to receive - setup a readx */
+       send_read_request_continue(p, &state->trans->out.data);
+       talloc_free(state);
+}
+
+/*
+  send a SMBtrans style request
+*/
+static NTSTATUS smb_send_trans_request(struct dcerpc_pipe *p, DATA_BLOB *blob)
+{
+        struct smb_private *smb = p->transport.private;
+        struct smb_trans2 *trans;
+        uint16 setup[2];
+       struct smb_trans_state *state;
+
+       state = talloc_p(smb, struct smb_trans_state);
+       if (state == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       state->p = p;
+       state->trans = talloc_p(state, struct smb_trans2);
+       trans = state->trans;
+
+        trans->in.data = *blob;
+        trans->in.params = data_blob(NULL, 0);
+        
+        setup[0] = TRANSACT_DCERPCCMD;
+        setup[1] = smb->fnum;
+
+        trans->in.max_param = 0;
+        trans->in.max_data = 0x8000;
+        trans->in.max_setup = 0;
+        trans->in.setup_count = 2;
+        trans->in.flags = 0;
+        trans->in.timeout = 0;
+        trans->in.setup = setup;
+        trans->in.trans_name = "\\PIPE\\";
+
+        state->req = smb_raw_trans_send(smb->tree, trans);
+       if (state->req == NULL) {
+               talloc_free(state);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       state->req->async.fn = smb_trans_callback;
+       state->req->async.private = state;
+
+        return NT_STATUS_OK;
+}
+
 /*
   called when a write request has completed
 */
@@ -174,12 +274,16 @@ static void smb_write_callback(struct smbcli_request *req)
 /* 
    send a packet to the server
 */
-static NTSTATUS smb_send_request(struct dcerpc_pipe *p, DATA_BLOB *blob)
+static NTSTATUS smb_send_request(struct dcerpc_pipe *p, DATA_BLOB *blob, BOOL trigger_read)
 {
        struct smb_private *smb = p->transport.private;
        union smb_write io;
        struct smbcli_request *req;
 
+       if (trigger_read) {
+               return smb_send_trans_request(p, blob);
+       }
+
        io.generic.level = RAW_WRITE_WRITEX;
        io.writex.in.fnum = smb->fnum;
        io.writex.in.offset = 0;
@@ -196,6 +300,10 @@ static NTSTATUS smb_send_request(struct dcerpc_pipe *p, DATA_BLOB *blob)
        req->async.fn = smb_write_callback;
        req->async.private = p;
 
+       if (trigger_read) {
+               send_read_request(p);
+       }
+
        return NT_STATUS_OK;
 }
 
index 7cf7cc98bb7e96e1b570761e6f27fff81005e8e3..35928cc1c4ce981042d4397a5a0ecf84d2e062b5 100644 (file)
@@ -198,11 +198,24 @@ static void tcp_io_handler(struct event_context *ev, struct fd_event *fde,
        }
 }
 
+/* 
+   initiate a read request 
+*/
+static NTSTATUS tcp_send_read(struct dcerpc_pipe *p)
+{
+       struct tcp_private *tcp = p->transport.private;
+
+       tcp->recv.pending_count++;
+       if (tcp->recv.pending_count == 1) {
+               tcp->fde->flags |= EVENT_FD_READ;
+       }
+       return NT_STATUS_OK;
+}
+
 /* 
    send an initial pdu in a multi-pdu sequence
 */
-static NTSTATUS tcp_send_request(struct dcerpc_pipe *p, 
-                                DATA_BLOB *data)
+static NTSTATUS tcp_send_request(struct dcerpc_pipe *p, DATA_BLOB *data, BOOL trigger_read)
 {
        struct tcp_private *tcp = p->transport.private;
        struct tcp_blob *blob;
@@ -222,20 +235,10 @@ static NTSTATUS tcp_send_request(struct dcerpc_pipe *p,
 
        tcp->fde->flags |= EVENT_FD_WRITE;
 
-       return NT_STATUS_OK;
-}
-
-/* 
-   initiate a read request 
-*/
-static NTSTATUS tcp_send_read(struct dcerpc_pipe *p)
-{
-       struct tcp_private *tcp = p->transport.private;
-
-       tcp->recv.pending_count++;
-       if (tcp->recv.pending_count == 1) {
-               tcp->fde->flags |= EVENT_FD_READ;
+       if (trigger_read) {
+               tcp_send_read(p);
        }
+
        return NT_STATUS_OK;
 }