summaryrefslogtreecommitdiff
path: root/source3/libsmb/cli_np_tstream.c
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2010-09-04 11:01:55 +0200
committerStefan Metzmacher <metze@samba.org>2010-12-15 15:26:05 +0100
commit0df669e14111de741ded8445a2acc00a51a50413 (patch)
tree155c516345e09af9ef4632de11bd5cb535bd1f28 /source3/libsmb/cli_np_tstream.c
parente08c324fc5ed9d7d4970fc7a7b6b13bff38ace59 (diff)
downloadsamba-0df669e14111de741ded8445a2acc00a51a50413.tar.gz
samba-0df669e14111de741ded8445a2acc00a51a50413.tar.bz2
samba-0df669e14111de741ded8445a2acc00a51a50413.zip
s3:libsmb: add tstream_cli_np_use_trans() and the needed logic
tstream_cli_np_use_trans() defers the next tstream_writev to the next tstream_readv and send both as an SMBtrans request. metze
Diffstat (limited to 'source3/libsmb/cli_np_tstream.c')
-rw-r--r--source3/libsmb/cli_np_tstream.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c
index aa5806bba8..a46b511905 100644
--- a/source3/libsmb/cli_np_tstream.c
+++ b/source3/libsmb/cli_np_tstream.c
@@ -37,6 +37,12 @@ struct tstream_cli_np {
uint16_t fnum;
struct {
+ bool active;
+ struct tevent_req *write_req;
+ uint16_t setup[2];
+ } trans;
+
+ struct {
off_t ofs;
size_t left;
uint8_t buf[TSTREAM_CLI_NP_BUF_SIZE];
@@ -173,6 +179,11 @@ NTSTATUS _tstream_cli_np_open_recv(struct tevent_req *req,
talloc_set_destructor(cli_nps, tstream_cli_np_destructor);
+ cli_nps->trans.active = false;
+ cli_nps->trans.write_req = NULL;
+ SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
+ SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
+
*_stream = stream;
tevent_req_received(req);
return NT_STATUS_OK;
@@ -204,6 +215,24 @@ bool tstream_is_cli_np(struct tstream_context *stream)
return true;
}
+NTSTATUS tstream_cli_np_use_trans(struct tstream_context *stream)
+{
+ struct tstream_cli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_cli_np);
+
+ if (cli_nps->trans.write_req) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cli_nps->trans.active) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ cli_nps->trans.active = true;
+
+ return NT_STATUS_OK;
+}
+
struct tstream_cli_np_writev_state {
struct tstream_context *stream;
struct tevent_context *ev;
@@ -219,6 +248,17 @@ struct tstream_cli_np_writev_state {
} error;
};
+static int tstream_cli_np_writev_state_destructor(struct tstream_cli_np_writev_state *state)
+{
+ struct tstream_cli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_cli_np);
+
+ cli_nps->trans.write_req = NULL;
+
+ return 0;
+}
+
static void tstream_cli_np_writev_write_next(struct tevent_req *req);
static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
@@ -241,6 +281,8 @@ static struct tevent_req *tstream_cli_np_writev_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->ret = 0;
+ talloc_set_destructor(state, tstream_cli_np_writev_state_destructor);
+
if (!cli_state_is_connected(cli_nps->cli)) {
tevent_req_error(req, ENOTCONN);
return tevent_req_post(req, ev);
@@ -308,6 +350,12 @@ static void tstream_cli_np_writev_write_next(struct tevent_req *req)
return;
}
+ if (cli_nps->trans.active && state->count == 0) {
+ cli_nps->trans.active = false;
+ cli_nps->trans.write_req = req;
+ return;
+ }
+
subreq = cli_write_andx_send(state, state->ev, cli_nps->cli,
cli_nps->fnum,
8, /* 8 means message mode. */
@@ -432,6 +480,10 @@ struct tstream_cli_np_readv_state {
int ret;
struct {
+ struct tevent_immediate *im;
+ } trans;
+
+ struct {
int val;
const char *location;
} error;
@@ -482,6 +534,7 @@ static struct tevent_req *tstream_cli_np_readv_send(TALLOC_CTX *mem_ctx,
return req;
}
+static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq);
static void tstream_cli_np_readv_read_done(struct tevent_req *subreq);
static void tstream_cli_np_readv_read_next(struct tevent_req *req)
@@ -523,6 +576,32 @@ static void tstream_cli_np_readv_read_next(struct tevent_req *req)
return;
}
+ if (cli_nps->trans.write_req) {
+ state->trans.im = tevent_create_immediate(state);
+ if (tevent_req_nomem(state->trans.im, req)) {
+ return;
+ }
+
+ subreq = cli_trans_send(state, state->ev,
+ cli_nps->cli,
+ SMBtrans,
+ "\\PIPE\\",
+ 0, 0, 0,
+ cli_nps->trans.setup, 2,
+ 0,
+ NULL, 0, 0,
+ cli_nps->write.buf,
+ cli_nps->write.ofs,
+ TSTREAM_CLI_NP_BUF_SIZE);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_cli_np_readv_trans_done,
+ req);
+ return;
+ }
+
subreq = cli_read_andx_send(state, state->ev, cli_nps->cli,
cli_nps->fnum, 0, TSTREAM_CLI_NP_BUF_SIZE);
if (tevent_req_nomem(subreq, req)) {
@@ -536,6 +615,70 @@ static void tstream_cli_np_readv_read_next(struct tevent_req *req)
static void tstream_cli_np_readv_disconnect_now(struct tevent_req *req,
int error,
const char *location);
+static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_cli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_cli_np_readv_state);
+ struct tstream_cli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_cli_np);
+ uint8_t *rcvbuf;
+ uint32_t received;
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
+ NULL, 0, NULL,
+ &rcvbuf, 0, &received);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received > TSTREAM_CLI_NP_BUF_SIZE) {
+ tstream_cli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received == 0) {
+ tstream_cli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ cli_nps->read.ofs = 0;
+ cli_nps->read.left = received;
+ memcpy(cli_nps->read.buf, rcvbuf, received);
+ TALLOC_FREE(rcvbuf);
+
+ if (cli_nps->trans.write_req == NULL) {
+ tstream_cli_np_readv_read_next(req);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_cli_np_readv_trans_next, req);
+
+ tevent_req_done(cli_nps->trans.write_req);
+}
+
+static void tstream_cli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+
+ tstream_cli_np_readv_read_next(req);
+}
static void tstream_cli_np_readv_read_done(struct tevent_req *subreq)
{
@@ -649,11 +792,49 @@ static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq)
tstream_cli_np_readv_error(req);
}
+static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
static void tstream_cli_np_readv_error(struct tevent_req *req)
{
struct tstream_cli_np_readv_state *state =
tevent_req_data(req,
struct tstream_cli_np_readv_state);
+ struct tstream_cli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_cli_np);
+
+ if (cli_nps->trans.write_req == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ if (state->trans.im == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_cli_np_readv_error_trigger, req);
+
+ /* return the original error for writev */
+ _tevent_req_error(cli_nps->trans.write_req,
+ state->error.val, state->error.location);
+}
+
+static void tstream_cli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_cli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_cli_np_readv_state);
/* return the original error */
_tevent_req_error(req, state->error.val, state->error.location);