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:
parent
cb2e338eb3
commit
c1d645fbe3
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,10 @@ struct cli_request {
|
||||
ssize_t received;
|
||||
uint8_t *rcvbuf;
|
||||
} read;
|
||||
struct {
|
||||
DATA_BLOB data;
|
||||
uint16_t num_echos;
|
||||
} echo;
|
||||
} data;
|
||||
|
||||
/**
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user