[MSAFD] Add some parameter checks on send/recv based on wine tests. CORE-12104
[reactos.git] / reactos / dll / win32 / msafd / misc / sndrcv.c
index e53db68..e94ab2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS Ancillary Function Driver DLL
- * FILE:        misc/sndrcv.c
+ * FILE:        dll/win32/msafd/misc/sndrcv.c
  * PURPOSE:     Send/receive routines
  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
  *              Alex Ionescu (alex@relsoft.net)
@@ -12,6 +12,9 @@
 
 #include <msafd.h>
 
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(msafd);
+
 INT
 WSPAPI
 WSPAsyncSelect(IN  SOCKET Handle,
@@ -43,10 +46,10 @@ WSPAsyncSelect(IN  SOCKET Handle,
     /* Change the Socket to Non Blocking */
     BlockMode = TRUE;
     SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL);
-    Socket->SharedData.NonBlocking = TRUE;
+    Socket->SharedData->NonBlocking = TRUE;
 
     /* Deactive WSPEventSelect */
-    if (Socket->SharedData.AsyncEvents)
+    if (Socket->SharedData->AsyncEvents)
     {
         if (WSPEventSelect(Handle, NULL, 0, lpErrno) == SOCKET_ERROR)
         {
@@ -62,14 +65,14 @@ WSPAsyncSelect(IN  SOCKET Handle,
     SockGetAsyncSelectHelperAfdHandle();
 
     /* Store Socket Data */
-    Socket->SharedData.hWnd = hWnd;
-    Socket->SharedData.wMsg = wMsg;
-    Socket->SharedData.AsyncEvents = lEvent;
-    Socket->SharedData.AsyncDisabledEvents = 0;
-    Socket->SharedData.SequenceNumber++;
+    Socket->SharedData->hWnd = hWnd;
+    Socket->SharedData->wMsg = wMsg;
+    Socket->SharedData->AsyncEvents = lEvent;
+    Socket->SharedData->AsyncDisabledEvents = 0;
+    Socket->SharedData->SequenceNumber++;
 
     /* Return if there are no more Events */
-    if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0)
+    if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0)
     {
         HeapFree(GetProcessHeap(), 0, AsyncData);
         return 0;
@@ -77,7 +80,7 @@ WSPAsyncSelect(IN  SOCKET Handle,
 
     /* Set up the Async Data */
     AsyncData->ParentSocket = Socket;
-    AsyncData->SequenceNumber = Socket->SharedData.SequenceNumber;
+    AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber;
 
     /* Begin Async Select by using I/O Completion */
     NtSetIoCompletion(SockAsyncCompletionPort,
@@ -91,6 +94,92 @@ WSPAsyncSelect(IN  SOCKET Handle,
 }
 
 
+BOOL
+WSPAPI
+WSPGetOverlappedResult(
+    IN  SOCKET Handle,
+    IN  LPWSAOVERLAPPED lpOverlapped,
+    OUT LPDWORD lpdwBytes,
+    IN  BOOL fWait,
+    OUT LPDWORD lpdwFlags,
+    OUT LPINT lpErrno)
+{
+    PIO_STATUS_BLOCK        IOSB;
+    NTSTATUS                Status;
+    PSOCKET_INFORMATION     Socket;
+
+    TRACE("Called (%x)\n", Handle);
+
+    /* Get the Socket Structure associate to this Socket*/
+    Socket = GetSocketStructure(Handle);
+    if (!Socket)
+    {
+        if(lpErrno)
+            *lpErrno = WSAENOTSOCK;
+        return FALSE;
+    }
+    if (!lpOverlapped || !lpdwBytes || !lpdwFlags)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return FALSE;
+    }
+    IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
+    if (!IOSB)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return FALSE;
+    }
+    Status = IOSB->Status;
+
+    /* Wait for completition of overlapped */
+    if (Status == STATUS_PENDING)
+    {
+        /* It's up to the protocol to time out recv.  We must wait
+        * until the protocol decides it's had enough.
+        */
+        if (fWait)
+        {
+            WaitForSingleObject(lpOverlapped->hEvent, INFINITE);
+            Status = IOSB->Status;
+        }
+    }
+
+    TRACE("Status %x Information %d\n", Status, IOSB->Information);
+
+    if (Status != STATUS_PENDING)
+    {
+        *lpdwFlags = 0;
+
+        *lpdwBytes = IOSB->Information;
+
+        /* Re-enable Async Event */
+        SockReenableAsyncSelectEvent(Socket, FD_OOB);
+        SockReenableAsyncSelectEvent(Socket, FD_WRITE);
+        SockReenableAsyncSelectEvent(Socket, FD_READ);
+    }
+
+    return Status == STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+AfdAPC(PVOID ApcContext,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       ULONG Reserved)
+{
+    PAFDAPCCONTEXT Context = ApcContext;
+
+    /* Re-enable Async Event */
+    SockReenableAsyncSelectEvent(Context->lpSocket, FD_OOB);
+    SockReenableAsyncSelectEvent(Context->lpSocket, FD_READ);
+    SockReenableAsyncSelectEvent(Context->lpSocket, FD_WRITE);
+
+    Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0);
+    HeapFree(GlobalHeap, 0, ApcContext);
+}
+
 int
 WSPAPI
 WSPRecv(SOCKET Handle,
@@ -108,19 +197,26 @@ WSPRecv(SOCKET Handle,
     AFD_RECV_INFO           RecvInfo;
     NTSTATUS                Status;
     PVOID                   APCContext;
-    PVOID                   APCFunction;
+    PIO_APC_ROUTINE         APCFunction;
     HANDLE                  Event = NULL;
     HANDLE                  SockEvent;
     PSOCKET_INFORMATION     Socket;
 
-    AFD_DbgPrint(MID_TRACE,("Called (%x)\n", Handle));
+    TRACE("Called (%x)\n", Handle);
 
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        if (lpErrno)
+            *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!lpNumberOfBytesRead && !lpOverlapped)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return SOCKET_ERROR;
     }
 
     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
@@ -133,7 +229,7 @@ WSPRecv(SOCKET Handle,
     RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
     RecvInfo.BufferCount = dwBufferCount;
     RecvInfo.TdiFlags = 0;
-    RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
+    RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
 
     /* Set the TDI Flags */
     if (*ReceiveFlags == 0)
@@ -170,6 +266,12 @@ WSPRecv(SOCKET Handle,
     }
     else
     {
+        /* Overlapped request for non overlapped opened socket */
+        if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
+        {
+            TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
+            return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead);
+        }
         if (lpCompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
@@ -180,8 +282,16 @@ WSPRecv(SOCKET Handle,
         else
         {
             /* Using Overlapped Structure and a Completition Routine, so use an APC */
-            APCFunction = NULL; // should be a private io completition function inside us
-            APCContext = lpCompletionRoutine;
+            APCFunction = &AfdAPC; // should be a private io completition function inside us
+            APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
+            if (!APCContext)
+            {
+                ERR("Not enough memory for APC Context\n");
+                return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead);
+            }
+            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
+            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
+            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
             RecvInfo.AfdFlags |= AFD_SKIP_FIO;
         }
 
@@ -193,15 +303,15 @@ WSPRecv(SOCKET Handle,
 
     /* Send IOCTL */
     Status = NtDeviceIoControlFile((HANDLE)Handle,
-        Event,
-        APCFunction,
-        APCContext,
-        IOSB,
-        IOCTL_AFD_RECV,
-        &RecvInfo,
-        sizeof(RecvInfo),
-        NULL,
-        0);
+                                   Event,
+                                   APCFunction,
+                                   APCContext,
+                                   IOSB,
+                                   IOCTL_AFD_RECV,
+                                   &RecvInfo,
+                                   sizeof(RecvInfo),
+                                   NULL,
+                                   0);
 
     /* Wait for completition of not overlapped */
     if (Status == STATUS_PENDING && lpOverlapped == NULL)
@@ -215,7 +325,13 @@ WSPRecv(SOCKET Handle,
 
     NtClose( SockEvent );
 
-    AFD_DbgPrint(MID_TRACE,("Status %x Information %d\n", Status, IOSB->Information));
+    TRACE("Status %x Information %d\n", Status, IOSB->Information);
+
+    if (Status == STATUS_PENDING)
+    {
+        TRACE("Leaving (Pending)\n");
+        return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
+    }
 
     /* Return the Flags */
     *ReceiveFlags = 0;
@@ -243,6 +359,12 @@ WSPRecv(SOCKET Handle,
         SockReenableAsyncSelectEvent(Socket, FD_READ);
     }
 
+    if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
+    {
+        lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
+        HeapFree(GlobalHeap, 0, (PVOID)APCContext);
+    }
+
     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
 }
 
@@ -274,11 +396,18 @@ WSPRecvFrom(SOCKET Handle,
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        if (lpErrno)
+            *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!lpNumberOfBytesRead && !lpOverlapped)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return SOCKET_ERROR;
     }
 
-    if (!(Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS))
+    if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
     {
         /* Call WSPRecv for a non-datagram socket */
         return WSPRecv(Handle,
@@ -292,6 +421,17 @@ WSPRecvFrom(SOCKET Handle,
                        lpErrno);
     }
 
+    /* Bind us First */
+    if (Socket->SharedData->State == SocketOpen)
+    {
+        Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
+            SocketAddress,
+            SocketAddressLength);
+        /* Bind it */
+        if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR)
+            return SOCKET_ERROR;
+    }
+
     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
                             NULL, 1, FALSE );
 
@@ -302,7 +442,7 @@ WSPRecvFrom(SOCKET Handle,
     RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
     RecvInfo.BufferCount = dwBufferCount;
     RecvInfo.TdiFlags = 0;
-    RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
+    RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
     RecvInfo.AddressLength = SocketAddressLength;
     RecvInfo.Address = SocketAddress;
 
@@ -341,6 +481,12 @@ WSPRecvFrom(SOCKET Handle,
     }
     else
     {
+        /* Overlapped request for non overlapped opened socket */
+        if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
+        {
+            TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
+            return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead);
+        }
         if (lpCompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
@@ -351,8 +497,16 @@ WSPRecvFrom(SOCKET Handle,
         else
         {
             /* Using Overlapped Structure and a Completition Routine, so use an APC */
-            APCFunction = NULL; // should be a private io completition function inside us
-            APCContext = lpCompletionRoutine;
+            APCFunction = &AfdAPC; // should be a private io completition function inside us
+            APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
+            if (!APCContext)
+            {
+                ERR("Not enough memory for APC Context\n");
+                return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead);
+            }
+            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
+            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
+            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
             RecvInfo.AfdFlags |= AFD_SKIP_FIO;
         }
 
@@ -383,12 +537,19 @@ WSPRecvFrom(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    if (Status == STATUS_PENDING)
+    {
+        TRACE("Leaving (Pending)\n");
+        return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
+    }
+
     /* Return the Flags */
     *ReceiveFlags = 0;
 
     switch (Status)
     {
-        case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB;
+        case STATUS_RECEIVE_EXPEDITED:
+            *ReceiveFlags = MSG_OOB;
             break;
         case STATUS_RECEIVE_PARTIAL_EXPEDITED:
             *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
@@ -408,6 +569,12 @@ WSPRecvFrom(SOCKET Handle,
         SockReenableAsyncSelectEvent(Socket, FD_READ);
     }
 
+    if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
+    {
+        lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
+        HeapFree(GlobalHeap, 0, (PVOID)APCContext);
+    }
+
     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
 }
 
@@ -438,8 +605,15 @@ WSPSend(SOCKET Handle,
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        if (lpErrno)
+            *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!lpNumberOfBytesSent && !lpOverlapped)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return SOCKET_ERROR;
     }
 
     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
@@ -448,13 +622,13 @@ WSPSend(SOCKET Handle,
     if( !NT_SUCCESS(Status) )
         return -1;
 
-    AFD_DbgPrint(MID_TRACE,("Called\n"));
+    TRACE("Called\n");
 
     /* Set up the Send Structure */
     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
     SendInfo.BufferCount = dwBufferCount;
     SendInfo.TdiFlags = 0;
-    SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
+    SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
 
     /* Set the TDI Flags */
     if (iFlags)
@@ -480,6 +654,12 @@ WSPSend(SOCKET Handle,
     }
     else
     {
+        /* Overlapped request for non overlapped opened socket */
+        if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
+        {
+            TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
+            return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
+        }
         if (lpCompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
@@ -490,8 +670,16 @@ WSPSend(SOCKET Handle,
         else
         {
             /* Using Overlapped Structure and a Completition Routine, so use an APC */
-            APCFunction = NULL; // should be a private io completition function inside us
-            APCContext = lpCompletionRoutine;
+            APCFunction = &AfdAPC; // should be a private io completition function inside us
+            APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
+            if (!APCContext)
+            {
+                ERR("Not enough memory for APC Context\n");
+                return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
+            }
+            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
+            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
+            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
             SendInfo.AfdFlags |= AFD_SKIP_FIO;
         }
 
@@ -524,14 +712,20 @@ WSPSend(SOCKET Handle,
 
     if (Status == STATUS_PENDING)
     {
-        AFD_DbgPrint(MID_TRACE,("Leaving (Pending)\n"));
+        TRACE("Leaving (Pending)\n");
         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
     }
 
     /* Re-enable Async Event */
     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
 
-    AFD_DbgPrint(MID_TRACE,("Leaving (Success, %d)\n", IOSB->Information));
+    TRACE("Leaving (Success, %d)\n", IOSB->Information);
+
+    if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
+    {
+        lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
+        HeapFree(GlobalHeap, 0, (PVOID)APCContext);
+    }
 
     return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
 }
@@ -567,11 +761,18 @@ WSPSendTo(SOCKET Handle,
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        if (lpErrno)
+            *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!lpNumberOfBytesSent && !lpOverlapped)
+    {
+        if (lpErrno)
+            *lpErrno = WSAEFAULT;
+        return SOCKET_ERROR;
     }
 
-    if (!(Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS))
+    if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
     {
         /* Use WSPSend for connection-oriented sockets */
         return WSPSend(Handle,
@@ -586,7 +787,7 @@ WSPSendTo(SOCKET Handle,
     }
 
     /* Bind us First */
-    if (Socket->SharedData.State == SocketOpen)
+    if (Socket->SharedData->State == SocketOpen)
     {
         /* Get the Wildcard Address */
         BindAddressLength = Socket->HelperData->MaxWSAddressLength;
@@ -636,7 +837,7 @@ WSPSendTo(SOCKET Handle,
 
     /* Set up Structure */
     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
-    SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
+    SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
     SendInfo.BufferCount = dwBufferCount;
     SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
     SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
@@ -652,6 +853,12 @@ WSPSendTo(SOCKET Handle,
     }
     else
     {
+        /* Overlapped request for non overlapped opened socket */
+        if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
+        {
+            TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
+            return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
+        }
         if (lpCompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
@@ -662,9 +869,16 @@ WSPSendTo(SOCKET Handle,
         else
         {
             /* Using Overlapped Structure and a Completition Routine, so use an APC */
-            /* Should be a private io completition function inside us */
-            APCFunction = NULL;
-            APCContext = lpCompletionRoutine;
+            APCFunction = &AfdAPC; // should be a private io completition function inside us
+            APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
+            if (!APCContext)
+            {
+                ERR("Not enough memory for APC Context\n");
+                return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
+            }
+            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
+            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
+            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
             SendInfo.AfdFlags |= AFD_SKIP_FIO;
         }
 
@@ -699,8 +913,20 @@ WSPSendTo(SOCKET Handle,
         HeapFree(GlobalHeap, 0, BindAddress);
     }
 
+    if (Status == STATUS_PENDING)
+    {
+        TRACE("Leaving (Pending)\n");
+        return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
+    }
+
     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
 
+    if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
+    {
+        lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
+        HeapFree(GlobalHeap, 0, (PVOID)APCContext);
+    }
+
     return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
 }
 
@@ -710,7 +936,7 @@ WSPRecvDisconnect(IN  SOCKET s,
                   OUT LPWSABUF lpInboundDisconnectData,
                   OUT LPINT lpErrno)
 {
-    UNIMPLEMENTED
+    UNIMPLEMENTED;
     return 0;
 }
 
@@ -722,7 +948,7 @@ WSPSendDisconnect(IN  SOCKET s,
                   IN  LPWSABUF lpOutboundDisconnectData,
                   OUT LPINT lpErrno)
 {
-    UNIMPLEMENTED
+    UNIMPLEMENTED;
     return 0;
 }