- got rid of include/async.h
- fixed some overlapped issues in socket handling
- moved kernel32.CancelIo implementation to ntdll

diff --git a/server/fd.c b/server/fd.c
index e29c6cf..f43c4a9 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -980,6 +980,89 @@
 
 
 /****************************************************************/
+/* asynchronous operations support */
+
+struct async
+{
+    struct fd           *fd;
+    struct thread       *thread;
+    void                *apc;
+    void                *user;
+    void                *sb;
+    struct timeval       when;
+    struct timeout_user *timeout;
+    struct async        *next;
+    struct async       **head;
+};
+
+/* cb for timeout on an async request */
+static void async_callback(void *private)
+{
+    struct async *async = (struct async *)private;
+
+    /* fprintf(stderr, "async timeout out %p\n", async); */
+    async->timeout = NULL;
+    async_terminate( async, STATUS_TIMEOUT );
+}
+
+/* create an async on a given queue of a fd */
+struct async *create_async(struct fd *fd, struct thread *thread,
+                           int timeout, struct async **head, 
+                           void *io_apc, void *io_user, void* io_sb)
+{
+    struct async *async = mem_alloc( sizeof(struct async) );
+    struct async **p;
+
+    if (!async) return NULL;
+
+    async->fd = fd;
+    async->thread = (struct thread *)grab_object(thread);
+    async->apc = io_apc;
+    async->user = io_user;
+    async->sb = io_sb;
+    async->head = head;
+    async->next = NULL;
+
+    for (p = head; *p; p = &(*p)->next);
+    *p = async;
+
+    if (timeout)
+    {
+        gettimeofday( &async->when, 0 );
+        add_timeout( &async->when, timeout );
+        async->timeout = add_timeout_user( &async->when, async_callback, async );
+    }
+    else async->timeout = NULL;
+
+    return async;
+}
+
+/* notifies client thread of new status of its async request */
+/* destroys the server side of it */
+void async_terminate( struct async *async, int status )
+{
+    struct async** p;
+
+    thread_queue_apc( async->thread, NULL, async->apc, APC_ASYNC_IO,
+                      1, async->user, async->sb, (void *)status );
+
+    if (async->timeout) remove_timeout_user( async->timeout );
+    async->timeout = NULL;
+
+    for (p = async->head; *p; p = &(*p)->next)
+    {
+        if (*p == async)
+        {
+            *p = async->next;
+            break;
+        }
+    }
+
+    release_object( async->thread );
+    free( async );
+}
+
+/****************************************************************/
 /* file descriptor functions */
 
 static void fd_dump( struct object *obj, int verbose )
@@ -1309,7 +1392,14 @@
 }
 
 /* default queue_async() routine */
-void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count )
+void no_queue_async( struct fd *fd, void* apc, void* user, void* io_sb, 
+                     int type, int count)
+{
+    set_error( STATUS_OBJECT_TYPE_MISMATCH );
+}
+
+/* default cancel_async() routine */
+void no_cancel_async( struct fd *fd )
 {
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
 }
@@ -1338,7 +1428,7 @@
     if (fd)
     {
         fd->fd_ops->flush( fd, &event );
-        if( event )
+        if ( event )
         {
             reply->event = alloc_handle( current->process, event, SYNCHRONIZE, 0 );
         }
@@ -1372,26 +1462,41 @@
 {
     struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
 
-/*
- * The queue_async method must do the following:
- *
- * 1. Get the async_queue for the request of given type.
- * 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found).
- * 3. If status is STATUS_PENDING:
- *      a) If no async request found in step 2 (new request): call create_async() to initialize one.
- *      b) Set request's status to STATUS_PENDING.
- *      c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue.
- *    Otherwise:
- *      If the async request was found in step 2, destroy it by calling destroy_async().
- * 4. Carry out any operations necessary to adjust the object's poll events
- *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
- *
- * See also the implementations in file.c, serial.c, and sock.c.
-*/
+    /*
+     * The queue_async method must do the following:
+     *
+     * 1. Get the async_queue for the request of given type.
+     * 2. Create a new asynchronous request for the selected queue
+     * 3. Carry out any operations necessary to adjust the object's poll events
+     *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
+     * 4. When the async request is triggered, then send back (with a proper APC)
+     *    the trigger (STATUS_ALERTED) to the thread that posted the request. 
+     *    async_destroy() is to be called: it will both notify the sender about
+     *    the trigger and destroy the request by itself
+     * See also the implementations in file.c, serial.c, and sock.c.
+     */
 
     if (fd)
     {
-        fd->fd_ops->queue_async( fd, req->overlapped, req->status, req->type, req->count );
+        fd->fd_ops->queue_async( fd, req->io_apc, req->io_user, req->io_sb, 
+                                 req->type, req->count );
         release_object( fd );
     }
 }
+
+/* cancels all async I/O */
+DECL_HANDLER(cancel_async)
+{
+    struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+    if (fd)
+    {
+        /* Note: we don't kill the queued APC_ASYNC_IO on this thread because
+         * NtCancelIoFile() will force the pending APC to be run. Since, 
+         * Windows only guarantees that the current thread will have no async 
+         * operation on the current fd when NtCancelIoFile returns, this shall
+         * do the work.
+         */
+        fd->fd_ops->cancel_async( fd );
+        release_object( fd );
+    }        
+}