summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2009-03-10 10:56:33 +0100
committerStefan Metzmacher <metze@samba.org>2009-03-10 11:03:15 +0100
commit7fc8086e11497c96be72859a510f72cb3c4104d5 (patch)
tree2a712d0b8962e7a106baaa7af6f4636fce2ea597
parent143b222546f5b6bd6af000426465aa7466ae2ba3 (diff)
downloadsamba-7fc8086e11497c96be72859a510f72cb3c4104d5.tar.gz
samba-7fc8086e11497c96be72859a510f72cb3c4104d5.tar.bz2
samba-7fc8086e11497c96be72859a510f72cb3c4104d5.zip
s3:libsmb: fix a lot of cli_push() bugs
There were the following problems: 1.) if window_size was a multiple of the chunk_size, we silently dropped the last truncated chunk. 2.) if window_size was 0 pushed only the first chunk to the server and silently dropped the rest. 3.) we had only transferred state->num_reqs writes, even if there would be more data to send. metze
-rw-r--r--source3/libsmb/clireadwrite.c202
1 files changed, 107 insertions, 95 deletions
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index 9d17ff86a5..764ef631f2 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -915,9 +915,15 @@ static NTSTATUS cli_writeall_recv(struct async_req *req)
return async_req_simple_recv_ntstatus(req);
}
-struct cli_push_state {
- struct async_req *req;
+struct cli_push_write_state {
+ struct async_req *req;/* This is the main request! Not the subreq */
+ uint32_t idx;
+ off_t ofs;
+ uint8_t *buf;
+ size_t size;
+};
+struct cli_push_state {
struct event_context *ev;
struct cli_state *cli;
uint16_t fnum;
@@ -928,24 +934,72 @@ struct cli_push_state {
size_t (*source)(uint8_t *buf, size_t n, void *priv);
void *priv;
- size_t chunk_size;
-
- size_t sent;
bool eof;
+ size_t chunk_size;
+ off_t next_offset;
+
/*
* Outstanding requests
*/
- int num_reqs;
- struct async_req **reqs;
-
- int pending;
-
- uint8_t *buf;
+ uint32_t pending;
+ uint32_t num_reqs;
+ struct cli_push_write_state **reqs;
};
static void cli_push_written(struct async_req *req);
+static bool cli_push_write_setup(struct async_req *req,
+ struct cli_push_state *state,
+ uint32_t idx)
+{
+ struct cli_push_write_state *substate;
+ struct async_req *subreq;
+
+ substate = talloc(state->reqs, struct cli_push_write_state);
+ if (!substate) {
+ return false;
+ }
+ substate->req = req;
+ substate->idx = idx;
+ substate->ofs = state->next_offset;
+ substate->buf = talloc_array(substate, uint8_t, state->chunk_size);
+ if (!substate->buf) {
+ talloc_free(substate);
+ return false;
+ }
+ substate->size = state->source(substate->buf,
+ state->chunk_size,
+ state->priv);
+ if (substate->size < state->chunk_size) {
+ state->eof = true;
+ }
+ if (substate->size == 0) {
+ /* nothing to send */
+ talloc_free(substate);
+ return true;
+ }
+
+ subreq = cli_writeall_send(substate,
+ state->ev, state->cli,
+ state->fnum, state->mode,
+ substate->buf,
+ substate->ofs,
+ substate->size);
+ if (!subreq) {
+ talloc_free(substate);
+ return false;
+ }
+ subreq->async.fn = cli_push_written;
+ subreq->async.priv = substate;
+
+ state->reqs[idx] = substate;
+ state->pending += 1;
+ state->next_offset += substate->size;
+
+ return true;
+}
+
struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
struct cli_state *cli,
uint16_t fnum, uint16_t mode,
@@ -954,16 +1008,14 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
void *priv),
void *priv)
{
- struct async_req *result;
+ struct async_req *req;
struct cli_push_state *state;
- int i;
+ uint32_t i;
- if (!async_req_setup(mem_ctx, &result, &state,
+ if (!async_req_setup(mem_ctx, &req, &state,
struct cli_push_state)) {
return NULL;
}
- state->req = result;
-
state->cli = cli;
state->ev = ev;
state->fnum = fnum;
@@ -972,124 +1024,84 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
state->source = source;
state->priv = priv;
state->eof = false;
- state->sent = 0;
state->pending = 0;
+ state->next_offset = start_offset;
state->chunk_size = cli_write_max_bufsize(cli, mode);
- state->num_reqs = MAX(window_size/state->chunk_size, 1);
+ if (window_size == 0) {
+ window_size = cli->max_mux * state->chunk_size;
+ }
+ state->num_reqs = window_size/state->chunk_size;
+ if ((window_size % state->chunk_size) > 0) {
+ state->num_reqs += 1;
+ }
state->num_reqs = MIN(state->num_reqs, cli->max_mux);
+ state->num_reqs = MAX(state->num_reqs, 1);
- state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *,
+ state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_push_write_state *,
state->num_reqs);
if (state->reqs == NULL) {
goto failed;
}
- state->buf = TALLOC_ARRAY(
- state, uint8_t, state->chunk_size * state->num_reqs);
- if (state->buf == NULL) {
- goto failed;
- }
-
for (i=0; i<state->num_reqs; i++) {
- size_t to_write;
- uint8_t *buf = state->buf + i*state->chunk_size;
-
- to_write = state->source(buf, state->chunk_size, state->priv);
- if (to_write == 0) {
- state->eof = true;
- break;
- }
-
- state->reqs[i] = cli_writeall_send(
- state->reqs, state->ev, state->cli, state->fnum,
- state->mode, buf, state->start_offset + state->sent,
- to_write);
- if (state->reqs[i] == NULL) {
+ if (!cli_push_write_setup(req, state, i)) {
goto failed;
}
- state->reqs[i]->async.fn = cli_push_written;
- state->reqs[i]->async.priv = state;
-
- state->sent += to_write;
- state->pending += 1;
+ if (state->eof) {
+ state->num_reqs = i+1;
+ break;
+ }
}
- if (i == 0) {
- if (!async_post_ntstatus(result, ev, NT_STATUS_OK)) {
+ if (state->pending == 0) {
+ if (!async_post_ntstatus(req, ev, NT_STATUS_OK)) {
goto failed;
}
- return result;
+ return req;
}
- return result;
+ return req;
failed:
- TALLOC_FREE(result);
+ TALLOC_FREE(req);
return NULL;
}
-static void cli_push_written(struct async_req *req)
+static void cli_push_written(struct async_req *subreq)
{
+ struct cli_push_write_state *substate = talloc_get_type_abort(
+ subreq->async.priv, struct cli_push_write_state);
+ struct async_req *req = substate->req;
struct cli_push_state *state = talloc_get_type_abort(
- req->async.priv, struct cli_push_state);
+ req->private_data, struct cli_push_state);
NTSTATUS status;
- int i;
- uint8_t *buf;
- size_t to_write;
-
- for (i=0; i<state->num_reqs; i++) {
- if (state->reqs[i] == req) {
- break;
- }
- }
-
- if (i == state->num_reqs) {
- async_req_nterror(state->req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- status = cli_writeall_recv(req);
- TALLOC_FREE(state->reqs[i]);
- req = NULL;
- if (!NT_STATUS_IS_OK(status)) {
- async_req_nterror(state->req, status);
- return;
- }
+ uint32_t idx = substate->idx;
+ state->reqs[idx] = NULL;
state->pending -= 1;
- if (state->pending == 0) {
- async_req_done(state->req);
- return;
- }
- if (state->eof) {
+ status = cli_writeall_recv(subreq);
+ TALLOC_FREE(subreq);
+ TALLOC_FREE(substate);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_nterror(req, status);
return;
}
- buf = state->buf + i * state->chunk_size;
-
- to_write = state->source(buf, state->chunk_size, state->priv);
- if (to_write == 0) {
- state->eof = true;
- return;
+ if (!state->eof) {
+ if (!cli_push_write_setup(req, state, idx)) {
+ async_req_nomem(NULL, req);
+ return;
+ }
}
- state->reqs[i] = cli_writeall_send(
- state->reqs, state->ev, state->cli, state->fnum,
- state->mode, buf, state->start_offset + state->sent, to_write);
- if (state->reqs[i] == NULL) {
- async_req_nterror(state->req, NT_STATUS_NO_MEMORY);
+ if (state->pending == 0) {
+ async_req_done(req);
return;
}
-
- state->reqs[i]->async.fn = cli_push_written;
- state->reqs[i]->async.priv = state;
-
- state->sent += to_write;
- state->pending += 1;
}
NTSTATUS cli_push_recv(struct async_req *req)