r17930: Merge noinclude branch:
[bbaumbach/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_wait.c
index 5815b8eddead4cd9d34b56981965b9e26a854b82..41c5f4742e58ba8933093592f427e1c9f961647f 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "include/includes.h"
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/util/dlinklist.h"
 #include "vfs_posix.h"
+#include "smbd/service_stream.h"
+#include "lib/messaging/irpc.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 ntvfs_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 ntvfs_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, 
-                              servid_t src, DATA_BLOB *data)
+static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uint32_t msg_type, 
+                              uint32_t src, DATA_BLOB *data)
 {
        struct pvfs_wait *pwait = private;
+       struct ntvfs_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, void *private)
 {
-       struct pvfs_wait *pwait = te->private;
-       pwait->handler(pwait->private, True);
+       struct pvfs_wait *pwait = talloc_get_type(private, struct pvfs_wait);
+       struct ntvfs_request *req = pwait->req;
+
+       pwait->reason = PVFS_WAIT_TIMEOUT;
+
+       talloc_increase_ref_count(req);
+       ntvfs_async_setup(pwait->req, pwait);
+       talloc_free(req);
 }
 
 
 /*
   destroy a pending wait
  */
-static int pvfs_wait_destructor(void *ptr)
+static int pvfs_wait_destructor(struct pvfs_wait *pwait)
 {
-       struct pvfs_wait *pwait = ptr;
-       messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait);
-       event_remove_timed(pwait->ev, pwait->te);
+       if (pwait->msg_type != -1) {
+               messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait);
+       }
+       DLIST_REMOVE(pwait->pvfs->wait_list, pwait);
        return 0;
 }
 
@@ -82,47 +117,75 @@ static int pvfs_wait_destructor(void *ptr)
 
   the return value is a handle. To stop waiting talloc_free this
   handle.
+
+  if msg_type == -1 then no message is registered, and it is assumed
+  that the caller handles any messaging setup needed
 */
 void *pvfs_wait_message(struct pvfs_state *pvfs, 
-                       struct smbsrv_request *req, 
+                       struct ntvfs_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;
        struct pvfs_wait *pwait;
 
-       pwait = talloc_p(req, struct pvfs_wait);
+       pwait = talloc(pvfs, struct pvfs_wait);
        if (pwait == NULL) {
                return NULL;
        }
 
        pwait->private = private;
        pwait->handler = fn;
-       pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging_ctx;
-       pwait->ev = req->tcon->smb_conn->connection->event.ctx;
+       pwait->msg_ctx = pvfs->ntvfs->ctx->msg_ctx;
+       pwait->ev = pvfs->ntvfs->ctx->event_ctx;
        pwait->msg_type = msg_type;
+       pwait->req = talloc_reference(pwait, req);
+       pwait->pvfs = pvfs;
 
-       /* setup a timer */
-       te.next_event = end_time;
-       te.handler = pvfs_wait_timeout;
-       te.private = pwait;
-       pwait->te = event_add_timed(pwait->ev, &te);
+       if (!timeval_is_zero(&end_time)) {
+               /* setup a timer */
+               event_add_timed(pwait->ev, pwait, end_time, pvfs_wait_timeout, pwait);
+       }
 
        /* register with the messaging subsystem for this message
           type */
-       messaging_register(pwait->msg_ctx,
-                          pwait,
-                          msg_type,
-                          pvfs_wait_dispatch);
+       if (msg_type != -1) {
+               messaging_register(pwait->msg_ctx,
+                                  pwait,
+                                  msg_type,
+                                  pvfs_wait_dispatch);
+       }
 
        /* 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);
 
        return pwait;
 }
+
+
+/*
+  cancel an outstanding async request
+*/
+NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_wait *pwait;
+
+       for (pwait=pvfs->wait_list;pwait;pwait=pwait->next) {
+               if (pwait->req == req) {
+                       /* trigger a cancel on the request */
+                       pwait->reason = PVFS_WAIT_CANCEL;
+                       ntvfs_async_setup(pwait->req, pwait);
+                       return NT_STATUS_OK;
+               }
+       }
+
+       return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
+}