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

Activate code to enable chained requests

Add the CHAIN1 torture test
This commit is contained in:
Volker Lendecke 2008-08-25 15:59:36 +02:00
parent b4c539ba04
commit 82992d74a9
4 changed files with 133 additions and 179 deletions

View File

@ -22,6 +22,13 @@
#include "includes.h"
/**
* struct cli_request is the state holder for an async client request we sent
* to the server. It can consist of more than one struct async_req that we
* have to server if the application did a cli_chain_cork() and
* cli_chain_uncork()
*/
struct cli_request {
/**
* "prev" and "next" form the doubly linked list in
@ -30,9 +37,15 @@ struct cli_request {
struct cli_request *prev, *next;
/**
* "our" struct async_req;
* num_async: How many chained requests do we serve?
*/
struct async_req *async;
int num_async;
/**
* async: This is the list of chained requests that were queued up by
* cli_request_chain before we sent out this request
*/
struct async_req **async;
/**
* The client connection for this request
@ -92,6 +105,10 @@ struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
uint8_t wct, const uint16_t *vwv,
uint16_t num_bytes, const uint8_t *bytes);
bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
size_t size_hint);
void cli_chain_uncork(struct cli_state *cli);
/*
* Convenience function to get the SMB part out of an async_req
*/

View File

@ -208,7 +208,8 @@ struct cli_state {
* fd_event is around while we have async requests outstanding or are
* building a chained request.
*
* (fd_event!=NULL) && (outstanding_request!=NULL)
* (fd_event!=NULL) &&
* ((outstanding_request!=NULL)||(chain_accumulator!=NULL))
*
* should always be true, as well as the reverse: If both cli_request
* pointers are NULL, no fd_event is around.
@ -220,6 +221,11 @@ struct cli_state {
* A linked list of requests that are waiting for a reply
*/
struct cli_request *outstanding_requests;
/**
* The place to build up the list of chained requests.
*/
struct cli_request *chain_accumulator;
};
typedef struct file_info {

View File

@ -135,8 +135,6 @@ static int cli_request_destructor(struct cli_request *req)
return 0;
}
#if 0
/**
* Is the SMB command able to hold an AND_X successor
* @param[in] cmd The SMB command in question
@ -667,176 +665,6 @@ NTSTATUS cli_pull_reply(struct async_req *req,
return NT_STATUS_OK;
}
#endif
/*
* Create a fresh async smb request
*/
static struct async_req *cli_request_new(TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct cli_state *cli,
uint8_t num_words, size_t num_bytes,
struct cli_request **preq)
{
struct async_req *result;
struct cli_request *cli_req;
size_t bufsize = smb_size + num_words * 2 + num_bytes;
result = async_req_new(mem_ctx, ev);
if (result == NULL) {
return NULL;
}
cli_req = (struct cli_request *)talloc_size(
result, sizeof(*cli_req) + bufsize);
if (cli_req == NULL) {
TALLOC_FREE(result);
return NULL;
}
talloc_set_name_const(cli_req, "struct cli_request");
result->private_data = cli_req;
result->print = cli_request_print;
cli_req->async = result;
cli_req->cli = cli;
cli_req->outbuf = ((char *)cli_req + sizeof(*cli_req));
cli_req->sent = 0;
cli_req->mid = cli_new_mid(cli);
cli_req->inbuf = NULL;
cli_req->enc_state = NULL;
SCVAL(cli_req->outbuf, smb_wct, num_words);
SSVAL(cli_req->outbuf, smb_vwv + num_words * 2, num_bytes);
DLIST_ADD_END(cli->outstanding_requests, cli_req,
struct cli_request *);
talloc_set_destructor(cli_req, cli_request_destructor);
DEBUG(10, ("cli_request_new: mid=%d\n", cli_req->mid));
*preq = cli_req;
return result;
}
/*
* Ship a new smb request to the server
*/
struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct cli_state *cli,
uint8_t smb_command,
uint8_t additional_flags,
uint8_t wct, const uint16_t *vwv,
uint16_t num_bytes, const uint8_t *bytes)
{
struct async_req *result;
struct cli_request *req;
if (cli->fd_event == NULL) {
SMB_ASSERT(cli->outstanding_requests == NULL);
cli->fd_event = event_add_fd(ev, cli, cli->fd,
EVENT_FD_READ,
cli_state_handler, cli);
if (cli->fd_event == NULL) {
return NULL;
}
}
result = cli_request_new(mem_ctx, ev, cli, wct, num_bytes, &req);
if (result == NULL) {
DEBUG(0, ("cli_request_new failed\n"));
TALLOC_FREE(cli->fd_event);
return NULL;
}
cli_set_message(req->outbuf, wct, num_bytes, false);
SCVAL(req->outbuf, smb_com, smb_command);
SSVAL(req->outbuf, smb_tid, cli->cnum);
cli_setup_packet_buf(cli, req->outbuf);
memcpy(req->outbuf + smb_vwv0, vwv, sizeof(uint16_t) * wct);
memcpy(smb_buf(req->outbuf), bytes, num_bytes);
SSVAL(req->outbuf, smb_mid, req->mid);
SCVAL(cli->outbuf, smb_flg,
CVAL(cli->outbuf,smb_flg) | additional_flags);
cli_calculate_sign_mac(cli, req->outbuf);
if (cli_encryption_on(cli)) {
NTSTATUS status;
char *enc_buf;
status = cli_encrypt_message(cli, req->outbuf, &enc_buf);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Error in encrypting client message. "
"Error %s\n", nt_errstr(status)));
TALLOC_FREE(req);
return NULL;
}
req->outbuf = enc_buf;
req->enc_state = cli->trans_enc_state;
}
event_fd_set_writeable(cli->fd_event);
return result;
}
/**
* @brief Pull reply data out of a request
* @param[in] req The request that we just received a reply for
* @param[out] pwct How many words did the server send?
* @param[out] pvwv The words themselves
* @param[out] pnum_bytes How many bytes did the server send?
* @param[out] pbytes The bytes themselves
* @retval Was the reply formally correct?
*/
NTSTATUS cli_pull_reply(struct async_req *req,
uint8_t *pwct, uint16_t **pvwv,
uint16_t *pnum_bytes, uint8_t **pbytes)
{
struct cli_request *cli_req = cli_request_get(req);
uint8_t wct, cmd;
uint16_t num_bytes;
size_t wct_ofs, bytes_offset;
NTSTATUS status;
status = cli_pull_error(cli_req->inbuf);
if (NT_STATUS_IS_ERR(status)) {
cli_set_error(cli_req->cli, status);
return status;
}
cmd = CVAL(cli_req->inbuf, smb_com);
wct_ofs = smb_wct;
wct = CVAL(cli_req->inbuf, wct_ofs);
bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
num_bytes = SVAL(cli_req->inbuf, bytes_offset);
/*
* wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
* is a 16-bit value. So bytes_offset being size_t should be far from
* wrapping.
*/
if ((bytes_offset + 2 > talloc_get_size(cli_req->inbuf))
|| (bytes_offset > 0xffff)) {
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
*pwct = wct;
*pvwv = (uint16_t *)(cli_req->inbuf + wct_ofs + 1);
*pnum_bytes = num_bytes;
*pbytes = (uint8_t *)cli_req->inbuf + bytes_offset + 2;
return NT_STATUS_OK;
}
/**
* Convenience function to get the SMB part out of an async_req
* @param[in] req The request to look at
@ -862,8 +690,11 @@ static void handle_incoming_pdu(struct cli_state *cli)
uint16_t mid;
size_t raw_pdu_len, buf_len, pdu_len, rest_len;
char *pdu;
int i;
NTSTATUS status;
int num_async;
/*
* The encrypted PDU len might differ from the unencrypted one
*/
@ -976,7 +807,24 @@ static void handle_incoming_pdu(struct cli_state *cli)
req->inbuf = talloc_move(req, &pdu);
async_req_done(req->async);
/*
* Freeing the last async_req will free the req (see
* cli_async_req_destructor). So make a copy of req->num_async, we
* can't reference it in the last round.
*/
num_async = req->num_async;
for (i=0; i<num_async; i++) {
/**
* A request might have been talloc_free()'ed before we arrive
* here. It will have removed itself from req->async via its
* destructor cli_async_req_destructor().
*/
if (req->async[i] != NULL) {
async_req_done(req->async[i]);
}
}
return;
invalidate_requests:
@ -985,7 +833,7 @@ static void handle_incoming_pdu(struct cli_state *cli)
nt_errstr(status)));
for (req = cli->outstanding_requests; req; req = req->next) {
async_req_error(req->async, status);
async_req_error(req->async[0], status);
}
return;
}
@ -1101,8 +949,11 @@ static void cli_state_handler(struct event_context *event_ctx,
sock_error:
for (req = cli->outstanding_requests; req; req = req->next) {
req->async->state = ASYNC_REQ_ERROR;
req->async->status = map_nt_error_from_unix(errno);
int i;
for (i=0; i<req->num_async; i++) {
req->async[i]->state = ASYNC_REQ_ERROR;
req->async[i]->status = map_nt_error_from_unix(errno);
}
}
TALLOC_FREE(cli->fd_event);
close(cli->fd);

View File

@ -4897,6 +4897,85 @@ static bool subst_test(const char *str, const char *user, const char *domain,
return result;
}
static void chain1_open_completion(struct async_req *req)
{
int fnum;
NTSTATUS status;
status = cli_open_recv(req, &fnum);
TALLOC_FREE(req);
d_printf("cli_open_recv returned %s: %d\n",
nt_errstr(status),
NT_STATUS_IS_OK(status) ? fnum : -1);
}
static void chain1_read_completion(struct async_req *req)
{
NTSTATUS status;
ssize_t received;
uint8_t *rcvbuf;
status = cli_read_andx_recv(req, &received, &rcvbuf);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(req);
d_printf("cli_read_andx_recv returned %s\n",
nt_errstr(status));
return;
}
d_printf("got %d bytes: %.*s\n", (int)received, (int)received,
(char *)rcvbuf);
TALLOC_FREE(req);
}
static void chain1_close_completion(struct async_req *req)
{
NTSTATUS status;
status = cli_close_recv(req);
*((bool *)(req->async.priv)) = true;
TALLOC_FREE(req);
d_printf("cli_close returned %s\n", nt_errstr(status));
}
static bool run_chain1(int dummy)
{
struct cli_state *cli1;
struct event_context *evt = event_context_init(NULL);
struct async_req *reqs[4];
bool done = false;
printf("starting chain1 test\n");
if (!torture_open_connection(&cli1, 0)) {
return False;
}
cli_sockopt(cli1, sockops);
cli_chain_cork(cli1, evt, 0);
reqs[0] = cli_open_send(talloc_tos(), evt, cli1, "\\test",
O_CREAT|O_RDWR, 0);
reqs[0]->async.fn = chain1_open_completion;
reqs[1] = cli_read_andx_send(talloc_tos(), evt, cli1, 0, 0, 10);
reqs[1]->async.fn = chain1_read_completion;
reqs[2] = cli_read_andx_send(talloc_tos(), evt, cli1, 0, 1, 10);
reqs[2]->async.fn = chain1_read_completion;
reqs[3] = cli_close_send(talloc_tos(), evt, cli1, 0);
reqs[3]->async.fn = chain1_close_completion;
reqs[3]->async.priv = (void *)&done;
cli_chain_uncork(cli1);
while (!done) {
event_loop_once(evt);
}
torture_close_connection(cli1);
return True;
}
static bool run_local_substitute(int dummy)
{
bool ok = true;
@ -5394,6 +5473,7 @@ static struct {
{"FDSESS", run_fdsesstest, 0},
{ "EATEST", run_eatest, 0},
{ "SESSSETUP_BENCH", run_sesssetup_bench, 0},
{ "CHAIN1", run_chain1, 0},
{ "LOCAL-SUBSTITUTE", run_local_substitute, 0},
{ "LOCAL-GENCACHE", run_local_gencache, 0},
{ "LOCAL-RBTREE", run_local_rbtree, 0},