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

Add async smbecho client support

This commit is contained in:
Volker Lendecke 2008-08-27 19:30:57 +02:00
parent cb2e338eb3
commit c1d645fbe3
5 changed files with 192 additions and 38 deletions

View File

@ -943,6 +943,7 @@ static int cmd_echo(void)
TALLOC_CTX *ctx = talloc_tos();
char *num;
char *data;
NTSTATUS status;
if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
|| !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
@ -950,9 +951,10 @@ static int cmd_echo(void)
return 1;
}
if (!cli_echo(cli, atoi(num), (uint8 *)data, strlen(data))) {
d_printf("echo failed: %s\n",
nt_errstr(cli_get_nt_error(cli)));
status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
if (!NT_STATUS_IS_OK(status)) {
d_printf("echo failed: %s\n", nt_errstr(status));
return 1;
}
@ -4417,7 +4419,7 @@ static void readline_callback(void)
{
unsigned char garbage[16];
memset(garbage, 0xf0, sizeof(garbage));
cli_echo(cli, 1, garbage, sizeof(garbage));
cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
}
}

View File

@ -90,6 +90,10 @@ struct cli_request {
ssize_t received;
uint8_t *rcvbuf;
} read;
struct {
DATA_BLOB data;
uint16_t num_echos;
} echo;
} data;
/**

View File

@ -4338,8 +4338,11 @@ void cli_sockopt(struct cli_state *cli, const char *options);
uint16 cli_setpid(struct cli_state *cli, uint16 pid);
bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive);
bool cli_send_keepalive(struct cli_state *cli);
bool cli_echo(struct cli_state *cli, uint16 num_echos,
unsigned char *data, size_t length);
struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
struct cli_state *cli, uint16_t num_echos,
DATA_BLOB data);
NTSTATUS cli_echo_recv(struct async_req *req);
NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data);
/* The following definitions come from libsmb/clierror.c */

View File

@ -637,41 +637,153 @@ bool cli_send_keepalive(struct cli_state *cli)
return true;
}
/****************************************************************************
Send/receive a SMBecho command: ping the server
****************************************************************************/
/**
* @brief: Collect a echo reply
* @param[in] req The corresponding async request
*
* There might be more than one echo reply. This helper pulls the reply out of
* the data stream. If all expected replies have arrived, declare the
* async_req done.
*/
bool cli_echo(struct cli_state *cli, uint16 num_echos,
unsigned char *data, size_t length)
static void cli_echo_recv_helper(struct async_req *req)
{
char *p;
int i;
struct cli_request *cli_req;
uint8_t wct;
uint16_t *vwv;
uint16_t num_bytes;
uint8_t *bytes;
NTSTATUS status;
SMB_ASSERT(length < 1024);
memset(cli->outbuf,'\0',smb_size);
cli_set_message(cli->outbuf,1,length,true);
SCVAL(cli->outbuf,smb_com,SMBecho);
SSVAL(cli->outbuf,smb_tid,65535);
SSVAL(cli->outbuf,smb_vwv0,num_echos);
cli_setup_packet(cli);
p = smb_buf(cli->outbuf);
memcpy(p, data, length);
p += length;
cli_setup_bcc(cli, p);
cli_send_smb(cli);
for (i=0; i<num_echos; i++) {
if (!cli_receive_smb(cli)) {
return false;
}
if (cli_is_error(cli)) {
return false;
}
status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
if (!NT_STATUS_IS_OK(status)) {
async_req_error(req, status);
return;
}
return true;
cli_req = cli_request_get(req);
if ((num_bytes != cli_req->data.echo.data.length)
|| (memcmp(cli_req->data.echo.data.data, bytes,
num_bytes) != 0)) {
async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
cli_req->data.echo.num_echos -= 1;
if (cli_req->data.echo.num_echos == 0) {
client_set_trans_sign_state_off(cli_req->cli, cli_req->mid);
async_req_done(req);
return;
}
return;
}
/**
* @brief Send SMBEcho requests
* @param[in] mem_ctx The memory context to put the async_req on
* @param[in] ev The event context that will call us back
* @param[in] cli The connection to send the echo to
* @param[in] num_echos How many times do we want to get the reply?
* @param[in] data The data we want to get back
* @retval The async request
*/
struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
struct cli_state *cli, uint16_t num_echos,
DATA_BLOB data)
{
uint16_t vwv[1];
uint8_t *data_copy;
struct async_req *result;
struct cli_request *req;
SSVAL(vwv, 0, num_echos);
data_copy = (uint8_t *)talloc_memdup(mem_ctx, data.data, data.length);
if (data_copy == NULL) {
return NULL;
}
result = cli_request_send(mem_ctx, ev, cli, SMBecho, 0, 1, vwv,
data.length, data.data);
if (result == NULL) {
TALLOC_FREE(data_copy);
return NULL;
}
req = cli_request_get(result);
client_set_trans_sign_state_on(cli, req->mid);
req->data.echo.num_echos = num_echos;
req->data.echo.data.data = talloc_move(req, &data_copy);
req->data.echo.data.length = data.length;
req->recv_helper.fn = cli_echo_recv_helper;
return result;
}
/**
* Get the result out from an echo request
* @param[in] req The async_req from cli_echo_send
* @retval Did the server reply correctly?
*/
NTSTATUS cli_echo_recv(struct async_req *req)
{
SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
if (req->state == ASYNC_REQ_ERROR) {
return req->status;
}
return NT_STATUS_OK;
}
/**
* @brief Send/Receive SMBEcho requests
* @param[in] mem_ctx The memory context to put the async_req on
* @param[in] ev The event context that will call us back
* @param[in] cli The connection to send the echo to
* @param[in] num_echos How many times do we want to get the reply?
* @param[in] data The data we want to get back
* @retval Did the server reply correctly?
*/
NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
{
TALLOC_CTX *frame = talloc_stackframe();
struct event_context *ev;
struct async_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
if (cli->fd_event != NULL) {
/*
* Can't use sync call while an async call is in flight
*/
cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
goto fail;
}
ev = event_context_init(frame);
if (ev == NULL) {
goto fail;
}
req = cli_echo_send(frame, ev, cli, num_echos, data);
if (req == NULL) {
goto fail;
}
while (req->state < ASYNC_REQ_DONE) {
event_loop_once(ev);
}
status = cli_echo_recv(req);
fail:
TALLOC_FREE(frame);
return status;
}

View File

@ -4976,6 +4976,38 @@ static bool run_chain1(int dummy)
return True;
}
static bool run_cli_echo(int dummy)
{
struct cli_state *cli;
struct event_context *ev = event_context_init(NULL);
struct async_req *req;
NTSTATUS status;
printf("starting chain1 test\n");
if (!torture_open_connection(&cli, 0)) {
return false;
}
cli_sockopt(cli, sockops);
req = cli_echo_send(ev, ev, cli, 5, data_blob_const("hello", 5));
if (req == NULL) {
d_printf("cli_echo_send failed\n");
return false;
}
while (req->state < ASYNC_REQ_DONE) {
event_loop_once(ev);
}
status = cli_echo_recv(req);
d_printf("cli_echo returned %s\n", nt_errstr(status));
TALLOC_FREE(req);
torture_close_connection(cli);
return NT_STATUS_IS_OK(status);
}
static bool run_local_substitute(int dummy)
{
bool ok = true;
@ -5474,6 +5506,7 @@ static struct {
{ "EATEST", run_eatest, 0},
{ "SESSSETUP_BENCH", run_sesssetup_bench, 0},
{ "CHAIN1", run_chain1, 0},
{ "CLI_ECHO", run_cli_echo, 0},
{ "LOCAL-SUBSTITUTE", run_local_substitute, 0},
{ "LOCAL-GENCACHE", run_local_gencache, 0},
{ "LOCAL-RBTREE", run_local_rbtree, 0},