1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

r2103: in the conversion to async rpc I simplified the smb backend to only

use readx/writex instead of the more efficient SMBtrans calls. This
patch restores the efficiency by using SMBtrans when possible.
This commit is contained in:
Andrew Tridgell 2004-08-30 05:35:30 +00:00 committed by Gerald (Jerry) Carter
parent e0bda61112
commit 83fbe080e7
4 changed files with 153 additions and 46 deletions

View 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;
}

View 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 *);

View 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;
}

View 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;
}