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:
parent
e0bda61112
commit
83fbe080e7
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user