Convert api_rpc_trans_reply to async np_*
authorVolker Lendecke <vl@samba.org>
Tue, 14 Oct 2008 13:53:35 +0000 (15:53 +0200)
committerVolker Lendecke <vl@samba.org>
Sat, 31 Jan 2009 16:50:18 +0000 (17:50 +0100)
source3/include/smb.h
source3/smbd/ipc.c

index be6ccbf59795d47b2d6e0cfa9fb150462cc3aac1..491dd763ff42619bdb1484015ebfce8217181407 100644 (file)
@@ -624,7 +624,18 @@ struct smb_request {
        uint16_t buflen;
        const uint8_t *buf;
        const uint8 *inbuf;
+
+       /*
+        * Async handling in the main smb processing loop is directed by
+        * outbuf: reply_xxx routines indicate sync behaviour by putting their
+        * reply into "outbuf". If they leave it as NULL, they take of it
+        * themselves, possibly later.
+        *
+        * If async handling is wanted, the reply_xxx routine must make sure
+        * that it talloc_move()s the smb_req somewhere else.
+        */
        uint8 *outbuf;
+
        size_t unread_bytes;
        bool encrypted;
        connection_struct *conn;
@@ -638,6 +649,11 @@ struct smb_request {
         * Here we collect the outbufs from the chain handlers
         */
        uint8_t *chain_outbuf;
+
+       /*
+        * state information for async smb handling
+        */
+       void *async_priv;
 };
 
 /* Defines for the sent_oplock_break field above. */
index 7c150561b150fbb55b94115c395d44d9117cad69..9c7528dfa7af34af545921f5f6b740fa9d8d65f7 100644 (file)
@@ -204,40 +204,137 @@ void send_trans_reply(connection_struct *conn,
  Start the first part of an RPC reply which began with an SMBtrans request.
 ****************************************************************************/
 
-static void api_rpc_trans_reply(connection_struct *conn,
-                               struct smb_request *req,
-                               files_struct *fsp,
-                               int max_trans_reply)
+struct dcerpc_cmd_state {
+       struct fake_file_handle *handle;
+       uint8_t *data;
+       size_t num_data;
+       size_t max_read;
+};
+
+static void api_dcerpc_cmd_write_done(struct async_req *subreq);
+static void api_dcerpc_cmd_read_done(struct async_req *subreq);
+
+static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
+                          files_struct *fsp, uint8_t *data, size_t length,
+                          size_t max_read)
 {
-       bool is_data_outstanding;
-       uint8_t *rdata = SMB_MALLOC_ARRAY(uint8_t, max_trans_reply);
-       ssize_t data_len;
-       NTSTATUS status;
+       struct async_req *subreq;
+       struct dcerpc_cmd_state *state;
+
+       if (!fsp_is_np(fsp)) {
+               api_no_reply(conn, req);
+               return;
+       }
 
-       if(rdata == NULL) {
-               DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+       state = talloc(req, struct dcerpc_cmd_state);
+       if (state == NULL) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
+       req->async_priv = state;
 
-       if (!fsp_is_np(fsp)) {
-               SAFE_FREE(rdata);
-               api_no_reply(conn,req);
+       state->handle = fsp->fake_file_handle;
+
+       /*
+        * This memdup severely sucks. But doing it properly essentially means
+        * to rewrite lanman.c, something which I don't really want to do now.
+        */
+       state->data = (uint8_t *)talloc_memdup(state, data, length);
+       if (state->data == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
+       state->num_data = length;
+       state->max_read = max_read;
+
+       subreq = np_write_send(state, smbd_event_context(), state->handle,
+                              state->data, length);
+       if (subreq == NULL) {
+               TALLOC_FREE(state);
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+       subreq->async.fn = api_dcerpc_cmd_write_done;
+       subreq->async.priv = talloc_move(conn, &req);
+}
+
+static void api_dcerpc_cmd_write_done(struct async_req *subreq)
+{
+       struct smb_request *req = talloc_get_type_abort(
+               subreq->async.priv, struct smb_request);
+       struct dcerpc_cmd_state *state = talloc_get_type_abort(
+               req->async_priv, struct dcerpc_cmd_state);
+       NTSTATUS status;
+       ssize_t nwritten = -1;
+
+       status = np_write_recv(subreq, &nwritten);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status) || (nwritten != state->num_data)) {
+               DEBUG(10, ("Could not write to pipe: %s (%d/%d)\n",
+                          nt_errstr(status), (int)state->num_data,
+                          (int)nwritten));
+               reply_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
+               goto send;
+       }
+
+       state->data = TALLOC_REALLOC_ARRAY(state, state->data, uint8_t,
+                                          state->max_read);
+       if (state->data == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto send;
+       }
+
+       subreq = np_read_send(req->conn, smbd_event_context(),
+                             state->handle, state->data, state->max_read);
+       if (subreq == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto send;
+       }
+
+       subreq->async.fn = api_dcerpc_cmd_read_done;
+       subreq->async.priv = req;
+       return;
+
+ send:
+       if (!srv_send_smb(
+                   smbd_server_fd(), (char *)req->outbuf,
+                   IS_CONN_ENCRYPTED(req->conn) || req->encrypted)) {
+               exit_server_cleanly("construct_reply: srv_send_smb failed.");
+       }
+       TALLOC_FREE(req);
+}
+
+static void api_dcerpc_cmd_read_done(struct async_req *subreq)
+{
+       struct smb_request *req = talloc_get_type_abort(
+               subreq->async.priv, struct smb_request);
+       struct dcerpc_cmd_state *state = talloc_get_type_abort(
+               req->async_priv, struct dcerpc_cmd_state);
+       NTSTATUS status;
+       ssize_t nread;
+       bool is_data_outstanding;
+
+       status = np_read_recv(subreq, &nread, &is_data_outstanding);
+       TALLOC_FREE(subreq);
 
-       status = np_read(fsp->fake_file_handle, rdata, max_trans_reply,
-                        &data_len, &is_data_outstanding);
        if (!NT_STATUS_IS_OK(status)) {
-               SAFE_FREE(rdata);
-               api_no_reply(conn,req);
+               DEBUG(10, ("Could not read from to pipe: %s\n",
+                          nt_errstr(status)));
+               reply_nterror(req, status);
+
+               if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+                                 IS_CONN_ENCRYPTED(req->conn)
+                                 ||req->encrypted)) {
+                       exit_server_cleanly("construct_reply: srv_send_smb "
+                                           "failed.");
+               }
+               TALLOC_FREE(req);
                return;
        }
 
-       send_trans_reply(conn, req, NULL, 0, (char *)rdata, data_len,
+       send_trans_reply(req->conn, req, NULL, 0, (char *)state->data, nread,
                         is_data_outstanding);
-       SAFE_FREE(rdata);
-       return;
+       TALLOC_FREE(req);
 }
 
 /****************************************************************************
@@ -310,7 +407,6 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
        struct files_struct *fsp;
        int pnum;
        int subcommand;
-       NTSTATUS status;
 
        DEBUG(5,("api_fd_reply\n"));
 
@@ -360,14 +456,8 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
        switch (subcommand) {
        case TRANSACT_DCERPCCMD: {
                /* dce/rpc command */
-               ssize_t nwritten;
-               status = np_write(fsp->fake_file_handle, data, tdscnt,
-                                 &nwritten);
-               if (!NT_STATUS_IS_OK(status)) {
-                       api_no_reply(conn, req);
-                       return;
-               }
-               api_rpc_trans_reply(conn, req, fsp, mdrcnt);
+               api_dcerpc_cmd(conn, req, fsp, (uint8_t *)data, tdscnt,
+                              mdrcnt);
                break;
        }
        case TRANSACT_WAITNAMEDPIPEHANDLESTATE: