- better support for non-blocking COMM and socket read/writes:
  + added necessary semantics to fd flags
  + no longer uses fd type (but fd flags) read/write semantic behavior
- fixed socket code to use the proper manifest constants
- fixes for kernel32.GetOverlappedResult without hEvent set
- in ntdll.Nt{Read|Write}File
  + always reset the event
  + added support for longlong offsets
  + better object disposal in error handling code paths

diff --git a/dlls/kernel/file.c b/dlls/kernel/file.c
index 44176b3..fefe715 100644
--- a/dlls/kernel/file.c
+++ b/dlls/kernel/file.c
@@ -497,56 +497,64 @@
 BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped,
                                 LPDWORD lpTransferred, BOOL bWait)
 {
-    DWORD r;
+    DWORD r = WAIT_OBJECT_0;
 
-    TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait);
+    TRACE( "(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait );
 
-    if (lpOverlapped==NULL)
+    if ( lpOverlapped == NULL )
     {
         ERR("lpOverlapped was null\n");
         return FALSE;
     }
-    if (!lpOverlapped->hEvent)
-    {
-        ERR("lpOverlapped->hEvent was null\n");
-        return FALSE;
-    }
-
     if ( bWait )
     {
-        do {
-            TRACE("waiting on %p\n",lpOverlapped);
-            r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
-            TRACE("wait on %p returned %ld\n",lpOverlapped,r);
-        } while (r==STATUS_USER_APC);
+        if ( lpOverlapped->hEvent )
+        {
+            do
+            {
+                TRACE( "waiting on %p\n", lpOverlapped );
+                r = WaitForSingleObjectEx( lpOverlapped->hEvent, INFINITE, TRUE );
+                TRACE( "wait on %p returned %ld\n", lpOverlapped, r );
+            } while ( r == WAIT_IO_COMPLETION );
+        }
+        else
+        {
+            /* busy loop */
+            while ( (volatile DWORD)lpOverlapped->Internal == STATUS_PENDING )
+                Sleep( 10 );
+        }
     }
     else if ( lpOverlapped->Internal == STATUS_PENDING )
     {
         /* Wait in order to give APCs a chance to run. */
         /* This is cheating, so we must set the event again in case of success -
            it may be a non-manual reset event. */
-        do {
-            TRACE("waiting on %p\n",lpOverlapped);
-            r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE);
-            TRACE("wait on %p returned %ld\n",lpOverlapped,r);
-        } while (r==STATUS_USER_APC);
-        if ( r == WAIT_OBJECT_0 )
-            NtSetEvent ( lpOverlapped->hEvent, NULL );
+        do
+        {
+            TRACE( "waiting on %p\n", lpOverlapped );
+            r = WaitForSingleObjectEx( lpOverlapped->hEvent, 0, TRUE );
+            TRACE( "wait on %p returned %ld\n", lpOverlapped, r );
+        } while ( r == WAIT_IO_COMPLETION );
+        if ( r == WAIT_OBJECT_0 && lpOverlapped->hEvent )
+            NtSetEvent( lpOverlapped->hEvent, NULL );
     }
-
-    if(lpTransferred)
-        *lpTransferred = lpOverlapped->InternalHigh;
+    if ( r == WAIT_FAILED )
+    {
+        ERR("wait operation failed\n");
+        return FALSE;
+    }
+    if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh;
 
     switch ( lpOverlapped->Internal )
     {
     case STATUS_SUCCESS:
         return TRUE;
     case STATUS_PENDING:
-        SetLastError ( ERROR_IO_INCOMPLETE );
-        if ( bWait ) ERR ("PENDING status after waiting!\n");
+        SetLastError( ERROR_IO_INCOMPLETE );
+        if ( bWait ) ERR("PENDING status after waiting!\n");
         return FALSE;
     default:
-        SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
+        SetLastError( RtlNtStatusToDosError( lpOverlapped->Internal ) );
         return FALSE;
     }
 }
@@ -640,7 +648,6 @@
     return (HFILE)create_file_OF( path, mode & ~OF_CREATE );
 }
 
-
 /***********************************************************************
  *           _lread   (KERNEL32.@)
  */
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 0d4bdec..4d253fc 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -247,13 +247,13 @@
     void*                            apc_user;
     char                             *buffer;
     unsigned int                     count;
-    unsigned long                    offset;
-    enum fd_type                     fd_type;
+    off_t                            offset;
+    BOOL                             avail_mode;
 } async_fileio;
 
 static DWORD fileio_get_async_count(const struct async_private *ovp)
 {
-    async_fileio *fileio = (async_fileio*) ovp;
+    const async_fileio *fileio = (const async_fileio*) ovp;
 
     if (fileio->count < fileio->async.iosb->Information)
     	return 0;
@@ -334,7 +334,7 @@
 
     /* check to see if the data is ready (non-blocking) */
 
-    if ( fileio->fd_type == FD_TYPE_SOCKET )
+    if ( fileio->avail_mode )
         result = read(ovp->fd, &fileio->buffer[already], fileio->count - already);
     else
     {
@@ -363,14 +363,15 @@
         return;
     }
 
+    TRACE("status before: %s\n", (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending");
     io_status->Information += result;
-    if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
+    if (io_status->Information >= fileio->count || fileio->avail_mode )
         io_status->u.Status = STATUS_SUCCESS;
     else
         io_status->u.Status = STATUS_PENDING;
 
-    TRACE("read %d more bytes %ld/%d so far\n",
-          result, io_status->Information, fileio->count);
+    TRACE("read %d more bytes %ld/%d so far (%s)\n",
+          result, io_status->Information, fileio->count, (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending");
 }
 
 
@@ -402,13 +403,12 @@
                            PLARGE_INTEGER offset, PULONG key)
 {
     int unix_handle, flags;
-    enum fd_type type;
 
     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
 
     io_status->Information = 0;
-    io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &type, &flags );
+    io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, NULL, &flags );
     if (io_status->u.Status) return io_status->u.Status;
 
     if (flags & FD_FLAG_RECV_SHUTDOWN)
@@ -442,6 +442,7 @@
         if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio))))
         {
             wine_server_release_fd( hFile, unix_handle );
+            if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
             return STATUS_NO_MEMORY;
         }
         ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops );
@@ -456,18 +457,24 @@
             ovp->offset = 0;
         else
         {
-            ovp->offset = offset->u.LowPart;
-            if (offset->u.HighPart) FIXME("NIY-high part\n");
+            ovp->offset = offset->QuadPart;
+            if (offset->u.HighPart && ovp->offset == offset->u.LowPart)
+                FIXME("High part of offset is lost\n");
         } 
         ovp->apc = apc;
         ovp->apc_user = apc_user;
         ovp->buffer = buffer;
-        ovp->fd_type = type;
+        ovp->avail_mode = (flags & FD_FLAG_AVAILABLE);
+        NtResetEvent(hEvent, NULL);
 
-        io_status->Information = 0;
         ret = register_new_async(&ovp->async);
         if (ret != STATUS_SUCCESS)
+        {
+            wine_server_release_fd( hFile, unix_handle );
+            if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent);
+            RtlFreeHeap(GetProcessHeap(), 0, ovp);
             return ret;
+        }
         if (flags & FD_FLAG_TIMEOUT)
         {
             NtWaitForSingleObject(hEvent, TRUE, NULL);
@@ -480,6 +487,15 @@
             /* let some APC be run, this will read some already pending data */
             timeout.u.LowPart = timeout.u.HighPart = 0;
             NtDelayExecution( TRUE, &timeout );
+            /* if we only have to read the available data, and none is available,
+             * simply cancel the request. If data was available, it has been read
+             * while in by previous call (NtDelayExecution)
+             */
+            if ((flags & FD_FLAG_AVAILABLE) && io_status->u.Status == STATUS_PENDING)
+            {
+                io_status->u.Status = STATUS_SUCCESS;
+                register_old_async(&ovp->async);
+            }
         }
         return io_status->u.Status;
     }
@@ -526,7 +542,7 @@
 
     /* write some data (non-blocking) */
 
-    if ( fileio->fd_type == FD_TYPE_SOCKET )
+    if ( fileio->avail_mode )
         result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
     else
     {
@@ -583,16 +599,12 @@
                             PLARGE_INTEGER offset, PULONG key)
 {
     int unix_handle, flags;
-    enum fd_type type;
 
     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
 
-    TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
-          hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
-
     io_status->Information = 0;
-    io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &type, &flags );
+    io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, NULL, &flags );
     if (io_status->u.Status) return io_status->u.Status;
 
     if (flags & FD_FLAG_SEND_SHUTDOWN)
@@ -620,15 +632,17 @@
         ovp->async.iosb = io_status;
         ovp->count = length;
         if (offset) {
-            ovp->offset = offset->u.LowPart;
-            if (offset->u.HighPart) FIXME("NIY-high part\n");
+            ovp->offset = offset->QuadPart;
+            if (offset->u.HighPart && ovp->offset == offset->u.LowPart)
+                FIXME("High part of offset is lost\n");
         } else {
             ovp->offset = 0;
         }
         ovp->apc = apc;
         ovp->apc_user = apc_user;
         ovp->buffer = (void*)buffer;
-        ovp->fd_type = type;
+        ovp->avail_mode = (flags & FD_FLAG_AVAILABLE);
+        NtResetEvent(hEvent, NULL);
 
         io_status->Information = 0;
         ret = register_new_async(&ovp->async);
diff --git a/include/async.h b/include/async.h
index 4bc7191..eae7ee7 100644
--- a/include/async.h
+++ b/include/async.h
@@ -111,8 +111,10 @@
     return ret;
 }
 
-#define register_old_async(ovp) \
-    __register_async(ovp, ovp->iosb->u.Status);
+inline static NTSTATUS register_old_async( async_private *ovp )
+{
+    return __register_async(ovp, ovp->iosb->u.Status);
+}
 
 inline static NTSTATUS register_new_async( async_private *ovp )
 {
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 76fa6be..40810a9 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -805,6 +805,8 @@
 #define FD_FLAG_TIMEOUT            0x02
 #define FD_FLAG_RECV_SHUTDOWN      0x04
 #define FD_FLAG_SEND_SHUTDOWN      0x08
+#define FD_FLAG_AVAILABLE          0x10 /* in overlap read/write operation,
+                                         * only handle available data (don't wait) */
 
 
 
@@ -3647,6 +3649,6 @@
     struct set_global_windows_reply set_global_windows_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 147
+#define SERVER_PROTOCOL_VERSION 148
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index a2864be..3859533 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -612,10 +612,12 @@
     FD_TYPE_DEFAULT,
     FD_TYPE_SOCKET
 };
-#define FD_FLAG_OVERLAPPED         0x01
-#define FD_FLAG_TIMEOUT            0x02
+#define FD_FLAG_OVERLAPPED         0x01 /* fd opened in overlapped mode */
+#define FD_FLAG_TIMEOUT            0x02 /* read/write is synchronous */
 #define FD_FLAG_RECV_SHUTDOWN      0x04
 #define FD_FLAG_SEND_SHUTDOWN      0x08
+#define FD_FLAG_AVAILABLE          0x10 /* in overlap read/write operation, 
+                                         * only handle available data (don't wait) */
 
 
 /* Flush a file buffers */
diff --git a/server/serial.c b/server/serial.c
index 5dd55d7..de0e373 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -209,9 +209,12 @@
     *flags = 0;
     if (!(serial->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
         *flags |= FD_FLAG_OVERLAPPED;
-    else if(!((serial->readinterval == MAXDWORD) &&
-              (serial->readmult == 0) && (serial->readconst == 0)) )
+    else if (!(serial->readinterval == MAXDWORD &&
+               serial->readmult == 0 && serial->readconst == 0))
         *flags |= FD_FLAG_TIMEOUT;
+    if (serial->readinterval == MAXDWORD &&     
+        serial->readmult == 0 && serial->readconst == 0)
+        *flags |= FD_FLAG_AVAILABLE;
 
     return FD_TYPE_DEFAULT;
 }
@@ -292,7 +295,7 @@
     else if ( async ) destroy_async ( async );
     else set_error ( STATUS_INVALID_PARAMETER );
 
-    set_fd_events ( fd, serial_get_poll_events( fd ));
+    set_fd_events ( fd, serial_get_poll_events( fd ) );
 }
 
 static int serial_flush( struct fd *fd, struct event **event )
diff --git a/server/sock.c b/server/sock.c
index 2b1a126..059bdba 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -234,7 +234,7 @@
     int i;
     int async_active = 0;
 
-    if ( sock->flags & FD_FLAG_OVERLAPPED )
+    if ( sock->flags & WSA_FLAG_OVERLAPPED )
     {
         if( pollev & (POLLIN|POLLPRI) && IS_READY( sock->read_q ) )
         {
@@ -425,7 +425,7 @@
         sock_reselect( sock );
 
     /* wake up anyone waiting for whatever just happened */
-    if ( sock->pmask & sock->mask || sock->flags & FD_FLAG_OVERLAPPED ) sock_wake_up( sock, event );
+    if ( sock->pmask & sock->mask || sock->flags & WSA_FLAG_OVERLAPPED ) sock_wake_up( sock, event );
 
     /* if anyone is stupid enough to wait on the socket object itself,
      * maybe we should wake them up too, just in case? */
@@ -480,7 +480,7 @@
     struct sock *sock = get_fd_user( fd );
     assert ( sock->obj.ops == &sock_ops );
 
-    *flags = 0;
+    *flags = FD_FLAG_AVAILABLE;
     if (sock->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED;
     if ( sock->type != SOCK_STREAM || sock->state & FD_WINE_CONNECTED )
     {