1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-24 02:04:21 +03:00

libcli/raw: make multi fragmented nttrans requests possible

metze
(This used to be commit a6aa055097313975299f214d8ebe8d45aa51d10a)
This commit is contained in:
Stefan Metzmacher 2008-07-07 15:04:59 +02:00
parent 1bc344cf52
commit efaf4cedb2

View File

@ -537,6 +537,10 @@ _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
}
struct smb_raw_nttrans_recv_state {
uint32_t params_total;
uint32_t data_total;
uint32_t params_left;
uint32_t data_left;
bool got_first;
uint32_t recvd_data;
uint32_t recvd_param;
@ -569,6 +573,9 @@ failed:
return smbcli_request_destroy(req);
}
static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req,
struct smb_raw_nttrans_recv_state *state);
/*
* This helper returns SMBCLI_REQUEST_RECV until all data has arrived
*/
@ -599,6 +606,10 @@ static enum smbcli_request_state smb_raw_nttrans_recv_helper(struct smbcli_reque
goto failed;
}
if (state->params_left > 0 || state->data_left > 0) {
return smb_raw_nttrans_ship_rest(req, state);
}
/* this is the first packet of the response */
SMBCLI_CHECK_MIN_WCT(req, 18);
@ -716,7 +727,12 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
{
struct smbcli_request *req;
struct smb_raw_nttrans_recv_state *state;
uint8_t *outdata, *outparam;
uint32_t ofs;
size_t space_left;
DATA_BLOB params_chunk;
uint32_t params_ofs;
DATA_BLOB data_chunk;
uint32_t data_ofs;
int align = 0;
/* only align if there are parameters or data */
@ -725,10 +741,7 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
}
req = smbcli_request_setup(tree, SMBnttrans,
19 + parms->in.setup_count,
align +
parms->in.params.length +
parms->in.data.length);
19 + parms->in.setup_count, align);
if (!req) {
return NULL;
}
@ -740,33 +753,81 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
}
/* fill in SMB parameters */
outparam = req->out.data + align;
outdata = outparam + parms->in.params.length;
if (align != 0) {
memset(req->out.data, 0, align);
}
ofs = PTR_DIFF(req->out.data,req->out.hdr)+align;
/* see how much bytes of the params block we can ship in the first request */
space_left = raw_trans_space_left(req);
params_chunk.length = MIN(parms->in.params.length, space_left);
params_chunk.data = parms->in.params.data;
params_ofs = ofs;
state->params_left = parms->in.params.length - params_chunk.length;
if (state->params_left > 0) {
/* we copy the whole params block, if needed we can optimize that latter */
state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length);
if (!state->io.in.params.data) {
smbcli_request_destroy(req);
return NULL;
}
memcpy(state->io.in.params.data,
parms->in.params.data,
parms->in.params.length);
}
/* see how much bytes of the data block we can ship in the first request */
space_left -= params_chunk.length;
#if TORTURE_TRANS_DATA
if (space_left > 1) {
space_left /= 2;
}
#endif
data_chunk.length = MIN(parms->in.data.length, space_left);
data_chunk.data = parms->in.data.data;
data_ofs = params_ofs + params_chunk.length;
state->data_left = parms->in.data.length - data_chunk.length;
if (state->data_left > 0) {
/* we copy the whole params block, if needed we can optimize that latter */
state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length);
if (!state->io.in.data.data) {
smbcli_request_destroy(req);
return NULL;
}
memcpy(state->io.in.data.data,
parms->in.data.data,
parms->in.data.length);
}
state->params_total = parms->in.params.length;
state->data_total = parms->in.data.length;
SCVAL(req->out.vwv, 0, parms->in.max_setup);
SSVAL(req->out.vwv, 1, 0); /* reserved */
SIVAL(req->out.vwv, 3, parms->in.params.length);
SIVAL(req->out.vwv, 7, parms->in.data.length);
SIVAL(req->out.vwv, 11, parms->in.max_param);
SIVAL(req->out.vwv, 15, parms->in.max_data);
SIVAL(req->out.vwv, 19, parms->in.params.length);
SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
SIVAL(req->out.vwv, 27, parms->in.data.length);
SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
SIVAL(req->out.vwv, 19, params_chunk.length);
SIVAL(req->out.vwv, 23, params_ofs);
SIVAL(req->out.vwv, 27, data_chunk.length);
SIVAL(req->out.vwv, 31, data_ofs);
SCVAL(req->out.vwv, 35, parms->in.setup_count);
SSVAL(req->out.vwv, 36, parms->in.function);
memcpy(req->out.vwv + VWV(19), parms->in.setup,
sizeof(uint16_t) * parms->in.setup_count);
if (parms->in.params.length) {
memcpy(outparam, parms->in.params.data, parms->in.params.length);
}
if (parms->in.data.length) {
memcpy(outdata, parms->in.data.data, parms->in.data.length);
}
smbcli_req_append_blob(req, &params_chunk);
smbcli_req_append_blob(req, &data_chunk);
/* add the helper which will check that all multi-part replies are
in before an async client callack will be issued */
@ -781,6 +842,106 @@ struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
return req;
}
static enum smbcli_request_state smb_raw_nttrans_ship_next(struct smbcli_request *req,
struct smb_raw_nttrans_recv_state *state)
{
struct smbcli_request *req2;
size_t space_left;
DATA_BLOB params_chunk;
uint32_t ofs;
uint32_t params_ofs = 0;
uint32_t params_disp = 0;
DATA_BLOB data_chunk;
uint32_t data_ofs = 0;
uint32_t data_disp = 0;
req2 = smbcli_request_setup(req->tree, SMBnttranss, 18, 0);
if (!req2) {
goto nomem;
}
req2->mid = req->mid;
SSVAL(req2->out.hdr, HDR_MID, req2->mid);
ofs = PTR_DIFF(req2->out.data,req2->out.hdr);
/* see how much bytes of the params block we can ship in the first request */
space_left = raw_trans_space_left(req2);
params_disp = state->io.in.params.length - state->params_left;
params_chunk.length = MIN(state->params_left, space_left);
params_chunk.data = state->io.in.params.data + params_disp;
params_ofs = ofs;
state->params_left -= params_chunk.length;
/* see how much bytes of the data block we can ship in the first request */
space_left -= params_chunk.length;
#if TORTURE_TRANS_DATA
if (space_left > 1) {
space_left /= 2;
}
#endif
data_disp = state->io.in.data.length - state->data_left;
data_chunk.length = MIN(state->data_left, space_left);
data_chunk.data = state->io.in.data.data + data_disp;
data_ofs = params_ofs+params_chunk.length;
state->data_left -= data_chunk.length;
SSVAL(req2->out.vwv,0, 0); /* reserved */
SCVAL(req2->out.vwv,2, 0); /* reserved */
SIVAL(req2->out.vwv,3, state->params_total);
SIVAL(req2->out.vwv,7, state->data_total);
SIVAL(req2->out.vwv,11, params_chunk.length);
SIVAL(req2->out.vwv,15, params_ofs);
SIVAL(req2->out.vwv,19, params_disp);
SIVAL(req2->out.vwv,23, data_chunk.length);
SIVAL(req2->out.vwv,27, data_ofs);
SIVAL(req2->out.vwv,31, data_disp);
SCVAL(req2->out.vwv,35, 0); /* reserved */
smbcli_req_append_blob(req2, &params_chunk);
smbcli_req_append_blob(req2, &data_chunk);
/*
* it's a one way request but we need
* the seq_num, so we destroy req2 by hand
*/
if (!smbcli_request_send(req2)) {
goto failed;
}
req->seq_num = req2->seq_num;
smbcli_request_destroy(req2);
return SMBCLI_REQUEST_RECV;
nomem:
req->status = NT_STATUS_NO_MEMORY;
failed:
if (req2) {
req->status = smbcli_request_destroy(req2);
}
return SMBCLI_REQUEST_ERROR;
}
static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req,
struct smb_raw_nttrans_recv_state *state)
{
enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR;
while (state->params_left > 0 || state->data_left > 0) {
ret = smb_raw_nttrans_ship_next(req, state);
if (ret != SMBCLI_REQUEST_RECV) {
break;
}
}
return ret;
}
/****************************************************************************
receive a SMB nttrans response allocating the necessary memory