s3: Fix async smb handling
authorVolker Lendecke <vl@samba.org>
Tue, 26 Jul 2011 17:44:51 +0000 (19:44 +0200)
committerVolker Lendecke <vlendec@samba.org>
Tue, 26 Jul 2011 22:47:45 +0000 (00:47 +0200)
In cli_echo with more than one response we ended up with more than one read_smb
request. One from the call to cli_smb_req_set_pending called from
cli_smb_received. The other one from cli_smb_received itself. I don't really
see another way to deal with this than to hold the read_smb request in the
cli_state.

Metze, please check!

Volker

source3/include/client.h
source3/libsmb/async_smb.c

index 34d99d4c085b4cbfa7c399b46b5b09f527bd3ddd..c4f011dfe7dd1ec73d40ccfbc475179f266c909c 100644 (file)
@@ -124,6 +124,7 @@ struct cli_state {
                struct sockaddr_storage local_ss;
                struct sockaddr_storage remote_ss;
                const char *remote_name;
+               struct tevent_req *read_smb_req;
                struct tevent_queue *outgoing;
                struct tevent_req **pending;
        } conn;
index 87614bd3265381ab818aa030aa71c4a1ccfb9ac1..ecc77803b0487b581bf0a8cc07bfcb43c900e5b8 100644 (file)
@@ -139,6 +139,7 @@ void cli_smb_req_unset_pending(struct tevent_req *req)
                 * delete the socket read fde.
                 */
                TALLOC_FREE(cli->conn.pending);
+               cli->conn.read_smb_req = NULL;
                return;
        }
 
@@ -193,7 +194,6 @@ bool cli_smb_req_set_pending(struct tevent_req *req)
        struct cli_state *cli;
        struct tevent_req **pending;
        int num_pending;
-       struct tevent_req *subreq;
 
        cli = state->cli;
        num_pending = talloc_array_length(cli->conn.pending);
@@ -207,7 +207,7 @@ bool cli_smb_req_set_pending(struct tevent_req *req)
        cli->conn.pending = pending;
        talloc_set_destructor(req, cli_smb_req_destructor);
 
-       if (num_pending > 0) {
+       if (cli->conn.read_smb_req != NULL) {
                return true;
        }
 
@@ -215,12 +215,13 @@ bool cli_smb_req_set_pending(struct tevent_req *req)
         * We're the first ones, add the read_smb request that waits for the
         * answer from the server
         */
-       subreq = read_smb_send(cli->conn.pending, state->ev, cli->conn.fd);
-       if (subreq == NULL) {
+       cli->conn.read_smb_req = read_smb_send(cli->conn.pending, state->ev,
+                                              cli->conn.fd);
+       if (cli->conn.read_smb_req == NULL) {
                cli_smb_req_unset_pending(req);
                return false;
        }
-       tevent_req_set_callback(subreq, cli_smb_received, cli);
+       tevent_req_set_callback(cli->conn.read_smb_req, cli_smb_received, cli);
        return true;
 }
 
@@ -531,8 +532,16 @@ static void cli_smb_received(struct tevent_req *subreq)
        uint16_t mid;
        bool oplock_break;
 
+       if (subreq != cli->conn.read_smb_req) {
+               DEBUG(1, ("Internal error: cli_smb_received called with "
+                         "unexpected subreq\n"));
+               status = NT_STATUS_INTERNAL_ERROR;
+               goto fail;
+       }
+
        received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
        TALLOC_FREE(subreq);
+       cli->conn.read_smb_req = NULL;
        if (received == -1) {
                cli_state_disconnect(cli);
                status = map_nt_error_from_unix(err);
@@ -642,19 +651,22 @@ static void cli_smb_received(struct tevent_req *subreq)
                TALLOC_FREE(chain);
        }
  done:
-       if (talloc_array_length(cli->conn.pending) > 0) {
+       if ((talloc_array_length(cli->conn.pending) > 0) &&
+           (cli->conn.read_smb_req == NULL)) {
                /*
                 * Set up another read request for the other pending cli_smb
                 * requests
                 */
                state = tevent_req_data(cli->conn.pending[0],
                                        struct cli_smb_state);
-               subreq = read_smb_send(cli->conn.pending, state->ev, cli->conn.fd);
-               if (subreq == NULL) {
+               cli->conn.read_smb_req = read_smb_send(
+                       cli->conn.pending, state->ev, cli->conn.fd);
+               if (cli->conn.read_smb_req == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto fail;
                }
-               tevent_req_set_callback(subreq, cli_smb_received, cli);
+               tevent_req_set_callback(cli->conn.read_smb_req,
+                                       cli_smb_received, cli);
        }
        return;
  fail: