Add async smbecho client support
authorVolker Lendecke <vl@samba.org>
Wed, 27 Aug 2008 17:30:57 +0000 (19:30 +0200)
committerVolker Lendecke <vl@samba.org>
Thu, 28 Aug 2008 16:16:00 +0000 (18:16 +0200)
(This used to be commit c1d645fbe39433541d8bfe6b818c855cee318dc5)

source3/client/client.c
source3/include/async_smb.h
source3/include/proto.h
source3/libsmb/clientgen.c
source3/torture/torture.c

index 18b286324b62bb1d503207589bc0c9fc42f0d2c2..1c0dff92c158da97c205b77427d3aba12ed7a225 100644 (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)));
        }
 }
 
index 6a09bb6001ef292bff36127c8ea7f2b1f4bf1f26..ed42baef0d6394f532df2e6e80ebb7b16994c919 100644 (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;
 
        /**
index f21cc2b17f0554f39c0388150c2f02b7f816e475..abfc79024ad98923f90686e027f11f22191c5286 100644 (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  */
 
index 2c0950de03a63b60d1439475d7e90bca9cc5a8db..239ba470a9649055cd90c9660e77d98a5263baaa 100644 (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.
+ */
+
+static void cli_echo_recv_helper(struct async_req *req)
+{
+       struct cli_request *cli_req;
+       uint8_t wct;
+       uint16_t *vwv;
+       uint16_t num_bytes;
+       uint8_t *bytes;
+       NTSTATUS status;
+
+       status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+       if (!NT_STATUS_IS_OK(status)) {
+               async_req_error(req, status);
+               return;
+       }
+
+       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;
 
-bool cli_echo(struct cli_state *cli, uint16 num_echos,
-             unsigned char *data, size_t length)
+       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)
 {
-       char *p;
-       int i;
+       uint16_t vwv[1];
+       uint8_t *data_copy;
+       struct async_req *result;
+       struct cli_request *req;
 
-       SMB_ASSERT(length < 1024);
+       SSVAL(vwv, 0, num_echos);
 
-       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;
+       data_copy = (uint8_t *)talloc_memdup(mem_ctx, data.data, data.length);
+       if (data_copy == NULL) {
+               return NULL;
+       }
 
-       cli_setup_bcc(cli, p);
+       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);
 
-       cli_send_smb(cli);
+       client_set_trans_sign_state_on(cli, req->mid);
 
-       for (i=0; i<num_echos; i++) {
-               if (!cli_receive_smb(cli)) {
-                       return false;
-               }
+       req->data.echo.num_echos = num_echos;
+       req->data.echo.data.data = talloc_move(req, &data_copy);
+       req->data.echo.data.length = data.length;
 
-               if (cli_is_error(cli)) {
-                       return false;
-               }
+       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 true;
+       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;
 }
index d159ffbac35c42701e4772323d85b0af80757c63..d8942e42b9b1b82cc6f5d973208a3cb228ec8b7b 100644 (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},