r3544: fixed some #include lines to make them more consistent
[jra/samba/.git] / source4 / ntvfs / posix / pvfs_wait.c
index 5815b8eddead4cd9d34b56981965b9e26a854b82..a226918877a00f8b248f13fe20303a0803ff211e 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "include/includes.h"
+#include "includes.h"
+#include "events.h"
+#include "dlinklist.h"
 #include "vfs_posix.h"
 
 /* the context for a single wait instance */
 struct pvfs_wait {
-       void (*handler)(void *, BOOL);
+       struct pvfs_wait *next, *prev;
+       struct pvfs_state *pvfs;
+       void (*handler)(void *, enum pvfs_wait_notice);
        void *private;
        struct timed_event *te;
        int msg_type;
-       void *msg_ctx;
+       struct messaging_context *msg_ctx;
        struct event_context *ev;
+       struct smbsrv_request *req;
+       enum pvfs_wait_notice reason;
 };
 
+/*
+  called from the ntvfs layer when we have requested setup of an async
+  call.  this ensures that async calls runs with the right state of
+  previous ntvfs handlers in the chain (such as security context)
+*/
+NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs,
+                         struct smbsrv_request *req, void *private)
+{
+       struct pvfs_wait *pwait = private;
+       pwait->handler(pwait->private, pwait->reason);
+       return NT_STATUS_OK;
+}
 
 /*
   receive a completion message for a wait
 */
-static void pvfs_wait_dispatch(void *msg_ctx, void *private, uint32_t msg_type, 
+static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uint32_t msg_type, 
                               servid_t src, DATA_BLOB *data)
 {
        struct pvfs_wait *pwait = private;
+       struct smbsrv_request *req;
 
-       /* we need to check that this one is for us. This sender sends
-          the private pointer as the body of the message. This might
-          seem a little unusual, but as the pointer is guaranteed
-          unique for this server, it is a good token */
+       /* we need to check that this one is for us. See
+          messaging_send_ptr() for the other side of this.
+        */
        if (data->length != sizeof(void *) ||
            *(void **)data->data != pwait->private) {
                return;
        }
-
-       pwait->handler(pwait->private, False);
+       pwait->reason = PVFS_WAIT_EVENT;
+       req = pwait->req;
+
+       /* the extra reference here is to ensure that the req
+          structure is not destroyed when the async request reply is
+          sent, which would cause problems with the other ntvfs
+          modules above us */
+       talloc_increase_ref_count(req);
+       ntvfs_async_setup(pwait->req, pwait);
+       talloc_free(req);
 }
 
 
 /*
   receive a timeout on a message wait
 */
-static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, time_t t)
+static void pvfs_wait_timeout(struct event_context *ev, 
+                             struct timed_event *te, struct timeval t)
 {
        struct pvfs_wait *pwait = te->private;
-       pwait->handler(pwait->private, True);
+       struct smbsrv_request *req = pwait->req;
+
+       pwait->reason = PVFS_WAIT_TIMEOUT;
+
+       talloc_increase_ref_count(req);
+       ntvfs_async_setup(pwait->req, pwait);
+       talloc_free(req);
 }
 
 
@@ -73,6 +106,7 @@ static int pvfs_wait_destructor(void *ptr)
        struct pvfs_wait *pwait = ptr;
        messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait);
        event_remove_timed(pwait->ev, pwait->te);
+       DLIST_REMOVE(pwait->pvfs->wait_list, pwait);
        return 0;
 }
 
@@ -83,11 +117,11 @@ static int pvfs_wait_destructor(void *ptr)
   the return value is a handle. To stop waiting talloc_free this
   handle.
 */
-void *pvfs_wait_message(struct pvfs_state *pvfs, 
+ void *pvfs_wait_message(struct pvfs_state *pvfs, 
                        struct smbsrv_request *req, 
                        int msg_type, 
-                       time_t end_time,
-                       void (*fn)(void *, BOOL),
+                       struct timeval end_time,
+                       void (*fn)(void *, enum pvfs_wait_notice),
                        void *private)
 {
        struct timed_event te;
@@ -103,6 +137,8 @@ void *pvfs_wait_message(struct pvfs_state *pvfs,
        pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging_ctx;
        pwait->ev = req->tcon->smb_conn->connection->event.ctx;
        pwait->msg_type = msg_type;
+       pwait->req = req;
+       pwait->pvfs = pvfs;
 
        /* setup a timer */
        te.next_event = end_time;
@@ -119,10 +155,37 @@ void *pvfs_wait_message(struct pvfs_state *pvfs,
 
        /* tell the main smb server layer that we will be replying 
           asynchronously */
-       req->control_flags |= REQ_CONTROL_ASYNC;
+       req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+
+       DLIST_ADD(pvfs->wait_list, pwait);
 
        /* make sure we cleanup the timer and message handler */
        talloc_set_destructor(pwait, pvfs_wait_destructor);
 
+       /* make sure that on a disconnect the request is not destroyed
+          before pvfs */
+       talloc_steal(pvfs, req);
+
        return pwait;
 }
+
+
+/*
+  cancel an outstanding async request
+*/
+NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_wait *pwait;
+       for (pwait=pvfs->wait_list;pwait;pwait=pwait->next) {
+               if (SVAL(req->in.hdr, HDR_MID) == SVAL(pwait->req->in.hdr, HDR_MID) &&
+                   req->smbpid == pwait->req->smbpid) {
+                       /* trigger a cancel on the request */
+                       pwait->reason = PVFS_WAIT_CANCEL;
+                       ntvfs_async_setup(pwait->req, pwait);
+                       return NT_STATUS_OK;
+               }
+       }
+
+       return NT_STATUS_UNSUCCESSFUL;
+}