[MSAFD] Don't update shared state on close if we still have active references to...
[reactos.git] / reactos / dll / win32 / msafd / misc / dllmain.c
index dda602f..747299e 100644 (file)
@@ -79,49 +79,41 @@ WSPSocket(int AddressFamily,
     {
         /* Duplpicating socket from different process */
         if ((HANDLE)lpProtocolInfo->dwServiceFlags3 == INVALID_HANDLE_VALUE)
-            return WSAEINVAL;
+        {
+            Status = WSAEINVAL;
+            goto error;
+        }
         if ((HANDLE)lpProtocolInfo->dwServiceFlags4 == INVALID_HANDLE_VALUE)
-            return WSAEINVAL;
+        {
+            Status = WSAEINVAL;
+            goto error;
+        }
         SharedData = MapViewOfFile((HANDLE)lpProtocolInfo->dwServiceFlags3,
                                    FILE_MAP_ALL_ACCESS,
                                    0,
                                    0,
                                    sizeof(SOCK_SHARED_INFO));
         if (!SharedData)
-            return WSAEINVAL;
+        {
+            Status = WSAEINVAL;
+            goto error;
+        }
         InterlockedIncrement(&SharedData->RefCount);
         AddressFamily = SharedData->AddressFamily;
         SocketType = SharedData->SocketType;
         Protocol = SharedData->Protocol;
     }
 
-    if (lpProtocolInfo)
+    if (AddressFamily == AF_UNSPEC && SocketType == 0 && Protocol == 0)
     {
-        if (lpProtocolInfo->iAddressFamily && AddressFamily <= 0)
-            AddressFamily = lpProtocolInfo->iAddressFamily;
-        if (lpProtocolInfo->iSocketType && SocketType <= 0)
-            SocketType = lpProtocolInfo->iSocketType;
-        if (lpProtocolInfo->iProtocol && Protocol <= 0)
-            Protocol = lpProtocolInfo->iProtocol;
+        Status = WSAEINVAL;
+        goto error;
     }
 
-    /* FIXME: AF_NETDES should be AF_MAX */
-    if (AddressFamily < AF_UNSPEC || AddressFamily > AF_NETDES)
-        return WSAEINVAL;
-
-    if (SocketType < 0 && SocketType > SOCK_SEQPACKET)
-        return WSAEINVAL;
-
-    if (Protocol < 0 && Protocol > IPPROTO_MAX)
-        return WSAEINVAL;
-
-    /* when no protocol and socket type are specified the first entry
-    * from WSAEnumProtocols that has the flag PFL_MATCHES_PROTOCOL_ZERO
-    * is returned */
-    if (SocketType == 0 && Protocol == 0 && lpProtocolInfo && (lpProtocolInfo->dwProviderFlags & PFL_MATCHES_PROTOCOL_ZERO) == 0)
-        return WSAEINVAL;
-
     /* Set the defaults */
+    if (AddressFamily == AF_UNSPEC)
+        AddressFamily = AF_INET;
+
     if (SocketType == 0)
     {
         switch (Protocol)
@@ -137,7 +129,8 @@ WSPSocket(int AddressFamily,
             break;
         default:
             TRACE("Unknown Protocol (%d). We will try SOCK_STREAM.\n", Protocol);
-            return WSAEINVAL;
+            SocketType = SOCK_STREAM;
+            break;
         }
     }
 
@@ -156,13 +149,11 @@ WSPSocket(int AddressFamily,
             break;
         default:
             TRACE("Unknown SocketType (%d). We will try IPPROTO_TCP.\n", SocketType);
-            return WSAEINVAL;
+            Protocol = IPPROTO_TCP;
+            break;
         }
     }
 
-    if (AddressFamily == AF_UNSPEC)
-        return WSAEINVAL;
-
     /* Get Helper Data and Transport */
     Status = SockGetTdiName (&AddressFamily,
                              &SocketType,
@@ -188,7 +179,7 @@ WSPSocket(int AddressFamily,
     Socket = HeapAlloc(GlobalHeap, 0, sizeof(*Socket));
     if (!Socket)
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Status = WSAENOBUFS;
         goto error;
     }
     RtlZeroMemory(Socket, sizeof(*Socket));
@@ -205,7 +196,7 @@ WSPSocket(int AddressFamily,
         Socket->SharedData = HeapAlloc(GlobalHeap, 0, sizeof(*Socket->SharedData));
         if (!Socket->SharedData)
         {
-            Status = STATUS_INSUFFICIENT_RESOURCES;
+            Status = WSAENOBUFS;
             goto error;
         }
         RtlZeroMemory(Socket->SharedData, sizeof(*Socket->SharedData));
@@ -223,6 +214,9 @@ WSPSocket(int AddressFamily,
         Socket->SharedData->ProviderFlags = lpProtocolInfo->dwProviderFlags;
         Socket->SharedData->UseSAN = FALSE;
         Socket->SharedData->NonBlocking = FALSE; /* Sockets start blocking */
+        Socket->SharedData->RecvTimeout = INFINITE;
+        Socket->SharedData->SendTimeout = INFINITE;
+        Socket->SharedData->OobInline = FALSE;
 
         /* Ask alex about this */
         if( Socket->SharedData->SocketType == SOCK_DGRAM ||
@@ -231,7 +225,7 @@ WSPSocket(int AddressFamily,
             TRACE("Connectionless socket\n");
             Socket->SharedData->ServiceFlags1 |= XP1_CONNECTIONLESS;
         }
-        Socket->Handle = -1;
+        Socket->Handle = INVALID_SOCKET;
     }
 
     Socket->HelperContext = HelperDLLContext;
@@ -254,7 +248,7 @@ WSPSocket(int AddressFamily,
     EABuffer = HeapAlloc(GlobalHeap, 0, SizeOfEA);
     if (!EABuffer)
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Status = WSAENOBUFS;
         goto error;
     }
 
@@ -281,6 +275,7 @@ WSPSocket(int AddressFamily,
         if ((SocketType != SOCK_DGRAM) && (SocketType != SOCK_RAW))
         {
             /* Only RAW or UDP can be Connectionless */
+            Status = WSAEINVAL;
             goto error;
         }
         AfdPacket->EndpointFlags |= AFD_ENDPOINT_CONNECTIONLESS;
@@ -293,6 +288,7 @@ WSPSocket(int AddressFamily,
             if ((Socket->SharedData->ServiceFlags1 & XP1_PSEUDO_STREAM) == 0)
             {
                 /* The Provider doesn't actually support Message Oriented Streams */
+                Status = WSAEINVAL;
                 goto error;
             }
         }
@@ -309,6 +305,7 @@ WSPSocket(int AddressFamily,
         if ((Socket->SharedData->ServiceFlags1 & XP1_SUPPORT_MULTIPOINT) == 0)
         {
             /* The Provider doesn't actually support Multipoint */
+            Status = WSAEINVAL;
             goto error;
         }
         AfdPacket->EndpointFlags |= AFD_ENDPOINT_MULTIPOINT;
@@ -319,6 +316,7 @@ WSPSocket(int AddressFamily,
                 || ((dwFlags & WSA_FLAG_MULTIPOINT_C_LEAF) != 0))
             {
                 /* The Provider doesn't support Control Planes, or you already gave a leaf */
+                Status = WSAEINVAL;
                 goto error;
             }
             AfdPacket->EndpointFlags |= AFD_ENDPOINT_C_ROOT;
@@ -330,6 +328,7 @@ WSPSocket(int AddressFamily,
                 || ((dwFlags & WSA_FLAG_MULTIPOINT_D_LEAF) != 0))
             {
                 /* The Provider doesn't support Data Planes, or you already gave a leaf */
+                Status = WSAEINVAL;
                 goto error;
             }
             AfdPacket->EndpointFlags |= AFD_ENDPOINT_D_ROOT;
@@ -364,6 +363,7 @@ WSPSocket(int AddressFamily,
     if (!NT_SUCCESS(Status))
     {
         ERR("Failed to open socket. Status 0x%08x\n", Status);
+        Status = TranslateNtStatusError(Status);
         goto error;
     }
 
@@ -600,6 +600,9 @@ TranslateNtStatusError(NTSTATUS Status)
        case STATUS_ACCESS_DENIED:
           return WSAEACCES;
 
+       case STATUS_NOT_IMPLEMENTED:
+          return WSAEOPNOTSUPP;
+
        default:
           ERR("MSAFD: Unhandled NTSTATUS value: 0x%x\n", Status);
           return WSAENETDOWN;
@@ -628,6 +631,14 @@ WSPCloseSocket(IN SOCKET Handle,
     LONG LingerWait = -1;
     DWORD References;
 
+    /* Get the Socket Structure associate to this Socket*/
+    Socket = GetSocketStructure(Handle);
+    if (!Socket)
+    {
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
+       return SOCKET_ERROR;
+    }
+
     /* Create the Wait Event */
     Status = NtCreateEvent(&SockEvent,
                            EVENT_ALL_ACCESS,
@@ -640,14 +651,6 @@ WSPCloseSocket(IN SOCKET Handle,
         ERR("NtCreateEvent failed: 0x%08x", Status);
         return SOCKET_ERROR;
     }
-    /* Get the Socket Structure associate to this Socket*/
-    Socket = GetSocketStructure(Handle);
-    if (!Socket)
-    {
-       NtClose(SockEvent);
-       if (lpErrno) *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
-    }
 
     if (Socket->HelperEvents & WSH_NOTIFY_CLOSE)
     {
@@ -674,15 +677,16 @@ WSPCloseSocket(IN SOCKET Handle,
         if (lpErrno) *lpErrno = WSAENOTSOCK;
         return SOCKET_ERROR;
     }
-    /* Set the state to close */
-    OldState = Socket->SharedData->State;
-    Socket->SharedData->State = SocketClosed;
 
     /* Decrement reference count on SharedData */
     References = InterlockedDecrement(&Socket->SharedData->RefCount);
     if (References)
         goto ok;
 
+    /* Set the state to close */
+    OldState = Socket->SharedData->State;
+    Socket->SharedData->State = SocketClosed;
+
     /* If SO_LINGER is ON and the Socket is connected, we need to disconnect */
     /* FIXME: Should we do this on Datagram Sockets too? */
     if ((OldState == SocketConnected) && (Socket->SharedData->LingerData.l_onoff))
@@ -721,7 +725,7 @@ WSPCloseSocket(IN SOCKET Handle,
             /*
              * We have to execute a sleep, so it's kind of like
              * a block. If the socket is Nonblock, we cannot
-             * go on since asyncronous operation is expected
+             * go on since asynchronous operation is expected
              * and we cannot offer it
              */
             if (Socket->SharedData->NonBlocking)
@@ -850,11 +854,33 @@ WSPBind(SOCKET Handle,
     SOCKADDR_INFO           SocketInfo;
     HANDLE                  SockEvent;
 
-    /* See below */
-    BindData = HeapAlloc(GlobalHeap, 0, 0xA + SocketAddressLength);
-    if (!BindData)
+    /* Get the Socket Structure associate to this Socket*/
+    Socket = GetSocketStructure(Handle);
+    if (!Socket)
     {
-        return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
+       return SOCKET_ERROR;
+    }
+    if (Socket->SharedData->State != SocketOpen)
+    {
+       if (lpErrno) *lpErrno = WSAEINVAL;
+       return SOCKET_ERROR;
+    }
+    if (!SocketAddress || SocketAddressLength < Socket->SharedData->SizeOfLocalAddress)
+    {
+        if (lpErrno) *lpErrno = WSAEINVAL;
+        return SOCKET_ERROR;
+    }
+
+    /* Get Address Information */
+    Socket->HelperData->WSHGetSockaddrType ((PSOCKADDR)SocketAddress,
+                                            SocketAddressLength,
+                                            &SocketInfo);
+
+    if (SocketInfo.AddressInfo == SockaddrAddressInfoBroadcast && !Socket->SharedData->Broadcast)
+    {
+       if (lpErrno) *lpErrno = WSAEADDRNOTAVAIL;
+       return SOCKET_ERROR;
     }
 
     Status = NtCreateEvent(&SockEvent,
@@ -865,17 +891,14 @@ WSPBind(SOCKET Handle,
 
     if (!NT_SUCCESS(Status))
     {
-        HeapFree(GlobalHeap, 0, BindData);
         return SOCKET_ERROR;
     }
 
-    /* Get the Socket Structure associate to this Socket*/
-    Socket = GetSocketStructure(Handle);
-    if (!Socket)
+    /* See below */
+    BindData = HeapAlloc(GlobalHeap, 0, 0xA + SocketAddressLength);
+    if (!BindData)
     {
-       HeapFree(GlobalHeap, 0, BindData);
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
     }
 
     /* Set up Address in TDI Format */
@@ -886,11 +909,6 @@ WSPBind(SOCKET Handle,
                    SocketAddress->sa_data,
                    SocketAddressLength - sizeof(SocketAddress->sa_family));
 
-    /* Get Address Information */
-    Socket->HelperData->WSHGetSockaddrType ((PSOCKADDR)SocketAddress,
-                                            SocketAddressLength,
-                                            &SocketInfo);
-
     /* Set the Share Type */
     if (Socket->SharedData->ExclusiveAddressUse)
     {
@@ -931,6 +949,7 @@ WSPBind(SOCKET Handle,
     NtClose( SockEvent );
     HeapFree(GlobalHeap, 0, BindData);
 
+    Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
     if (Status != STATUS_SUCCESS)
         return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
 
@@ -972,12 +991,12 @@ WSPListen(SOCKET Handle,
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       *lpErrno = WSAENOTSOCK;
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
        return SOCKET_ERROR;
     }
 
     if (Socket->SharedData->Listening)
-        return 0;
+        return NO_ERROR;
 
     Status = NtCreateEvent(&SockEvent,
                            EVENT_ALL_ACCESS,
@@ -986,7 +1005,7 @@ WSPListen(SOCKET Handle,
                            FALSE);
 
     if( !NT_SUCCESS(Status) )
-        return -1;
+        return SOCKET_ERROR;
 
     /* Set Up Listen Structure */
     ListenData.UseSAN = FALSE;
@@ -1014,6 +1033,7 @@ WSPListen(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
     if (Status != STATUS_SUCCESS)
        return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
 
@@ -1060,13 +1080,34 @@ WSPSelect(IN int nfds,
     PSOCKET_INFORMATION Socket;
     SOCKET              Handle;
     ULONG               Events;
+    fd_set              selectfds;
 
     /* Find out how many sockets we have, and how large the buffer needs
      * to be */
+    FD_ZERO(&selectfds);
+    if (readfds != NULL)
+    {
+        for (i = 0; i < readfds->fd_count; i++)
+        {
+            FD_SET(readfds->fd_array[i], &selectfds);
+        }
+    }
+    if (writefds != NULL)
+    {
+        for (i = 0; i < writefds->fd_count; i++)
+        {
+            FD_SET(writefds->fd_array[i], &selectfds);
+        }
+    }
+    if (exceptfds != NULL)
+    {
+        for (i = 0; i < exceptfds->fd_count; i++)
+        {
+            FD_SET(exceptfds->fd_array[i], &selectfds);
+        }
+    }
 
-    HandleCount = ( readfds ? readfds->fd_count : 0 ) +
-                  ( writefds ? writefds->fd_count : 0 ) +
-                  ( exceptfds ? exceptfds->fd_count : 0 );
+    HandleCount = selectfds.fd_count;
 
     if ( HandleCount == 0 )
     {
@@ -1097,7 +1138,7 @@ WSPSelect(IN int nfds,
         if (Timeout.QuadPart > 0)
         {
             if (lpErrno) *lpErrno = WSAEINVAL;
-                return SOCKET_ERROR;
+            return SOCKET_ERROR;
         }
         TRACE("Timeout: Orig %d.%06d kernel %d\n",
                      timeout->tv_sec, timeout->tv_usec,
@@ -1138,9 +1179,26 @@ WSPSelect(IN int nfds,
     PollInfo->Exclusive = FALSE;
     PollInfo->Timeout = Timeout;
 
+    for (i = 0; i < selectfds.fd_count; i++)
+    {
+        PollInfo->Handles[i].Handle = selectfds.fd_array[i];
+    }
     if (readfds != NULL) {
-        for (i = 0; i < readfds->fd_count; i++, j++)
+        for (i = 0; i < readfds->fd_count; i++)
         {
+            for (j = 0; j < HandleCount; j++)
+            {
+                if (PollInfo->Handles[j].Handle == readfds->fd_array[i])
+                    break;
+            }
+            if (j >= HandleCount)
+            {
+                ERR("Error while counting readfds %ld > %ld\n", j, HandleCount);
+                if (lpErrno) *lpErrno = WSAEFAULT;
+                HeapFree(GlobalHeap, 0, PollBuffer);
+                NtClose(SockEvent);
+                return SOCKET_ERROR;
+            }
             Socket = GetSocketStructure(readfds->fd_array[i]);
             if (!Socket)
             {
@@ -1150,20 +1208,32 @@ WSPSelect(IN int nfds,
                 NtClose(SockEvent);
                 return SOCKET_ERROR;
             }
-            PollInfo->Handles[j].Handle = readfds->fd_array[i];
-            PollInfo->Handles[j].Events = AFD_EVENT_RECEIVE |
-                                          AFD_EVENT_DISCONNECT |
-                                          AFD_EVENT_ABORT |
-                                          AFD_EVENT_CLOSE |
-                                          AFD_EVENT_ACCEPT;
-            if (Socket->SharedData->OobInline != 0)
-                PollInfo->Handles[j].Events |= AFD_EVENT_OOB_RECEIVE;
+            PollInfo->Handles[j].Events |= AFD_EVENT_RECEIVE |
+                                           AFD_EVENT_DISCONNECT |
+                                           AFD_EVENT_ABORT |
+                                           AFD_EVENT_CLOSE |
+                                           AFD_EVENT_ACCEPT;
+            //if (Socket->SharedData->OobInline != 0)
+            //    PollInfo->Handles[j].Events |= AFD_EVENT_OOB_RECEIVE;
         }
     }
     if (writefds != NULL)
     {
-        for (i = 0; i < writefds->fd_count; i++, j++)
+        for (i = 0; i < writefds->fd_count; i++)
         {
+            for (j = 0; j < HandleCount; j++)
+            {
+                if (PollInfo->Handles[j].Handle == writefds->fd_array[i])
+                    break;
+            }
+            if (j >= HandleCount)
+            {
+                ERR("Error while counting writefds %ld > %ld\n", j, HandleCount);
+                if (lpErrno) *lpErrno = WSAEFAULT;
+                HeapFree(GlobalHeap, 0, PollBuffer);
+                NtClose(SockEvent);
+                return SOCKET_ERROR;
+            }
             Socket = GetSocketStructure(writefds->fd_array[i]);
             if (!Socket)
             {
@@ -1174,15 +1244,28 @@ WSPSelect(IN int nfds,
                 return SOCKET_ERROR;
             }
             PollInfo->Handles[j].Handle = writefds->fd_array[i];
-            PollInfo->Handles[j].Events = AFD_EVENT_SEND;
+            PollInfo->Handles[j].Events |= AFD_EVENT_SEND;
             if (Socket->SharedData->NonBlocking != 0)
                 PollInfo->Handles[j].Events |= AFD_EVENT_CONNECT;
         }
     }
     if (exceptfds != NULL)
     {
-        for (i = 0; i < exceptfds->fd_count; i++, j++)
+        for (i = 0; i < exceptfds->fd_count; i++)
         {
+            for (j = 0; j < HandleCount; j++)
+            {
+                if (PollInfo->Handles[j].Handle == exceptfds->fd_array[i])
+                    break;
+            }
+            if (j > HandleCount)
+            {
+                ERR("Error while counting exceptfds %ld > %ld\n", j, HandleCount);
+                if (lpErrno) *lpErrno = WSAEFAULT;
+                HeapFree(GlobalHeap, 0, PollBuffer);
+                NtClose(SockEvent);
+                return SOCKET_ERROR;
+            }
             Socket = GetSocketStructure(exceptfds->fd_array[i]);
             if (!Socket)
             {
@@ -1193,20 +1276,14 @@ WSPSelect(IN int nfds,
                 return SOCKET_ERROR;
             }
             PollInfo->Handles[j].Handle = exceptfds->fd_array[i];
-            PollInfo->Handles[j].Events = 0;
             if (Socket->SharedData->OobInline == 0)
                 PollInfo->Handles[j].Events |= AFD_EVENT_OOB_RECEIVE;
             if (Socket->SharedData->NonBlocking != 0)
                 PollInfo->Handles[j].Events |= AFD_EVENT_CONNECT_FAIL;
-            if (PollInfo->Handles[j].Events == 0)
-            {
-                TRACE("No events can be checked for exceptfds %d. It is nonblocking and OOB line is disabled. Skipping it.", exceptfds->fd_array[i]);
-                j--;
-            }
         }
     }
 
-    PollInfo->HandleCount = j;
+    PollInfo->HandleCount = HandleCount;
     PollBufferSize = FIELD_OFFSET(AFD_POLL_INFO, Handles) + PollInfo->HandleCount * sizeof(AFD_HANDLE);
 
     /* Send IOCTL */
@@ -1223,7 +1300,7 @@ WSPSelect(IN int nfds,
 
     TRACE("DeviceIoControlFile => %x\n", Status);
 
-    /* Wait for Completition */
+    /* Wait for Completion */
     if (Status == STATUS_PENDING)
     {
         WaitForSingleObject(SockEvent, INFINITE);
@@ -1267,6 +1344,10 @@ WSPSelect(IN int nfds,
                     TRACE("Event %x on handle %x\n",
                         Events,
                         Handle);
+                    if ((Events & x) == AFD_EVENT_DISCONNECT || (Events & x) == AFD_EVENT_CLOSE)
+                        Socket->SharedData->SocketLastError = WSAECONNRESET;
+                    if ((Events & x) == AFD_EVENT_ABORT)
+                        Socket->SharedData->SocketLastError = WSAECONNABORTED;
                     if( readfds )
                         FD_SET(Handle, readfds);
                     break;
@@ -1331,6 +1412,21 @@ WSPSelect(IN int nfds,
     return HandleCount;
 }
 
+DWORD
+GetCurrentTimeInSeconds(VOID)
+{
+    SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
+    union
+    {
+        FILETIME ft;
+        ULONGLONG ll;
+    } u1970, Time;
+
+    GetSystemTimeAsFileTime(&Time.ft);
+    SystemTimeToFileTime(&st1970, &u1970.ft);
+    return (DWORD)((Time.ll - u1970.ll) / 10000000ULL);
+}
+
 SOCKET
 WSPAPI
 WSPAccept(SOCKET Handle,
@@ -1361,6 +1457,21 @@ WSPAccept(SOCKET Handle,
     UCHAR                       ReceiveBuffer[0x1A];
     HANDLE                      SockEvent;
 
+    /* Get the Socket Structure associate to this Socket*/
+    Socket = GetSocketStructure(Handle);
+    if (!Socket)
+    {
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
+       return SOCKET_ERROR;
+    }
+    if ((SocketAddress && !SocketAddressLength) ||
+        (SocketAddressLength && !SocketAddress) ||
+        (SocketAddressLength && *SocketAddressLength < sizeof(SOCKADDR)))
+    {
+       if (lpErrno) *lpErrno = WSAEFAULT;
+       return INVALID_SOCKET;
+    }
+
     Status = NtCreateEvent(&SockEvent,
                            EVENT_ALL_ACCESS,
                            NULL,
@@ -1369,22 +1480,12 @@ WSPAccept(SOCKET Handle,
 
     if( !NT_SUCCESS(Status) )
     {
-        MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-        return INVALID_SOCKET;
+        return SOCKET_ERROR;
     }
 
     /* Dynamic Structure...ugh */
     ListenReceiveData = (PAFD_RECEIVED_ACCEPT_DATA)ReceiveBuffer;
 
-    /* Get the Socket Structure associate to this Socket*/
-    Socket = GetSocketStructure(Handle);
-    if (!Socket)
-    {
-       NtClose(SockEvent);
-       *lpErrno = WSAENOTSOCK;
-       return INVALID_SOCKET;
-    }
-
     /* If this is non-blocking, make sure there's something for us to accept */
     FD_ZERO(&ReadSet);
     FD_SET(Socket->Handle, &ReadSet);
@@ -1394,14 +1495,14 @@ WSPAccept(SOCKET Handle,
     if (WSPSelect(0, &ReadSet, NULL, NULL, &Timeout, lpErrno) == SOCKET_ERROR)
     {
         NtClose(SockEvent);
-        return INVALID_SOCKET;
+        return SOCKET_ERROR;
     }
 
     if (ReadSet.fd_array[0] != Socket->Handle)
     {
         NtClose(SockEvent);
-        *lpErrno = WSAEWOULDBLOCK;
-        return INVALID_SOCKET;
+        if (lpErrno) *lpErrno = WSAEWOULDBLOCK;
+        return SOCKET_ERROR;
     }
 
     /* Send IOCTL */
@@ -1426,8 +1527,7 @@ WSPAccept(SOCKET Handle,
     if (!NT_SUCCESS(Status))
     {
         NtClose( SockEvent );
-        MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-        return INVALID_SOCKET;
+        return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
     }
 
     if (lpfnCondition != NULL)
@@ -1460,8 +1560,7 @@ WSPAccept(SOCKET Handle,
             if (!NT_SUCCESS(Status))
             {
                 NtClose( SockEvent );
-                MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-                return INVALID_SOCKET;
+                return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
             }
 
             /* How much data to allocate */
@@ -1473,8 +1572,7 @@ WSPAccept(SOCKET Handle,
                 PendingData = HeapAlloc(GlobalHeap, 0, PendingDataLength);
                 if (!PendingData)
                 {
-                    MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
-                    return INVALID_SOCKET;
+                    return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
                 }
 
                 /* We want the data now */
@@ -1502,8 +1600,7 @@ WSPAccept(SOCKET Handle,
                 if (!NT_SUCCESS(Status))
                 {
                     NtClose( SockEvent );
-                    MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-                    return INVALID_SOCKET;
+                    return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
                 }
             }
         }
@@ -1520,8 +1617,7 @@ WSPAccept(SOCKET Handle,
         RemoteAddress = HeapAlloc(GlobalHeap, 0, sizeof(*RemoteAddress));
         if (!RemoteAddress)
         {
-            MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
-            return INVALID_SOCKET;
+            return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
         }
 
         /* Set up Address in SOCKADDR Format */
@@ -1543,8 +1639,7 @@ WSPAccept(SOCKET Handle,
             /* Allocate Buffer for Callee Data */
             CalleeDataBuffer = HeapAlloc(GlobalHeap, 0, 4096);
             if (!CalleeDataBuffer) {
-                MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
-                return INVALID_SOCKET;
+                return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
             }
             CalleeData.buf = CalleeDataBuffer;
             CalleeData.len = 4096;
@@ -1611,19 +1706,18 @@ WSPAccept(SOCKET Handle,
 
             if (!NT_SUCCESS(Status))
             {
-                MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-                return INVALID_SOCKET;
+                return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
             }
 
             if (CallBack == CF_REJECT )
             {
-                *lpErrno = WSAECONNREFUSED;
-                return INVALID_SOCKET;
+                if (lpErrno) *lpErrno = WSAECONNREFUSED;
+                return SOCKET_ERROR;
             }
             else
             {
-                *lpErrno = WSAECONNREFUSED;
-                return INVALID_SOCKET;
+                if (lpErrno) *lpErrno = WSAECONNREFUSED;
+                return SOCKET_ERROR;
             }
         }
     }
@@ -1637,7 +1731,7 @@ WSPAccept(SOCKET Handle,
                               Socket->SharedData->CreateFlags,
                               lpErrno);
     if (AcceptSocket == INVALID_SOCKET)
-        return INVALID_SOCKET;
+        return SOCKET_ERROR;
 
     /* Set up the Accept Structure */
     AcceptData.ListenHandle = (HANDLE)AcceptSocket;
@@ -1662,12 +1756,12 @@ WSPAccept(SOCKET Handle,
         Status = IOSB.Status;
     }
 
+    Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
     if (!NT_SUCCESS(Status))
     {
         NtClose(SockEvent);
         WSPCloseSocket( AcceptSocket, lpErrno );
-        MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
-        return INVALID_SOCKET;
+        return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
     }
 
     AcceptSocketInfo = GetSocketStructure(AcceptSocket);
@@ -1675,11 +1769,11 @@ WSPAccept(SOCKET Handle,
     {
         NtClose(SockEvent);
         WSPCloseSocket( AcceptSocket, lpErrno );
-        MsafdReturnWithErrno( STATUS_PROTOCOL_NOT_SUPPORTED, lpErrno, 0, NULL );
-        return INVALID_SOCKET;
+        return MsafdReturnWithErrno( STATUS_PROTOCOL_NOT_SUPPORTED, lpErrno, 0, NULL );
     }
 
     AcceptSocketInfo->SharedData->State = SocketConnected;
+    AcceptSocketInfo->SharedData->ConnectTime = GetCurrentTimeInSeconds();
 
     /* Return Address in SOCKADDR FORMAT */
     if( SocketAddress )
@@ -1709,56 +1803,16 @@ WSPAccept(SOCKET Handle,
         if (Status)
         {
             if (lpErrno) *lpErrno = Status;
-            return INVALID_SOCKET;
+            return SOCKET_ERROR;
         }
     }
 
-    *lpErrno = 0;
+    if (lpErrno) *lpErrno = NO_ERROR;
 
     /* Return Socket */
     return AcceptSocket;
 }
 
-VOID
-NTAPI
-AfdConnectAPC(PVOID ApcContext,
-              PIO_STATUS_BLOCK IoStatusBlock,
-              ULONG Reserved)
-{
-    PAFDCONNECTAPCCONTEXT Context = ApcContext;
-
-    if (IoStatusBlock->Status == STATUS_SUCCESS)
-    {
-        Context->lpSocket->SharedData->State = SocketConnected;
-        Context->lpSocket->TdiConnectionHandle = (HANDLE)IoStatusBlock->Information;
-    }
-
-    if (Context->lpConnectInfo) HeapFree(GetProcessHeap(), 0, Context->lpConnectInfo);
-
-    /* Re-enable Async Event */
-    SockReenableAsyncSelectEvent(Context->lpSocket, FD_WRITE);
-
-    /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
-    SockReenableAsyncSelectEvent(Context->lpSocket, FD_CONNECT);
-
-    if (IoStatusBlock->Status == STATUS_SUCCESS && (Context->lpSocket->HelperEvents & WSH_NOTIFY_CONNECT))
-    {
-        Context->lpSocket->HelperData->WSHNotify(Context->lpSocket->HelperContext,
-                                                 Context->lpSocket->Handle,
-                                                 Context->lpSocket->TdiAddressHandle,
-                                                 Context->lpSocket->TdiConnectionHandle,
-                                                 WSH_NOTIFY_CONNECT);
-    }
-    else if (IoStatusBlock->Status != STATUS_SUCCESS && (Context->lpSocket->HelperEvents & WSH_NOTIFY_CONNECT_ERROR))
-    {
-        Context->lpSocket->HelperData->WSHNotify(Context->lpSocket->HelperContext,
-                                                 Context->lpSocket->Handle,
-                                                 Context->lpSocket->TdiAddressHandle,
-                                                 Context->lpSocket->TdiConnectionHandle,
-                                                 WSH_NOTIFY_CONNECT_ERROR);
-    }
-    HeapFree(GlobalHeap, 0, ApcContext);
-}
 int
 WSPAPI
 WSPConnect(SOCKET Handle,
@@ -1781,10 +1835,8 @@ WSPConnect(SOCKET Handle,
     PSOCKADDR               BindAddress;
     HANDLE                  SockEvent;
     int                     SocketDataLength;
-    PVOID                   APCContext = NULL;
-    PVOID                   APCFunction = NULL;
 
-    TRACE("Called\n");
+    TRACE("Called (%lx) %lx:%d\n", Handle, ((const struct sockaddr_in *)SocketAddress)->sin_addr, ((const struct sockaddr_in *)SocketAddress)->sin_port);
 
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
@@ -1801,7 +1853,7 @@ WSPConnect(SOCKET Handle,
                            FALSE);
 
     if (!NT_SUCCESS(Status))
-        return MsafdReturnWithErrno(Status, lpErrno, 0, NULL);
+        return SOCKET_ERROR;
 
     /* Bind us First */
     if (Socket->SharedData->State == SocketOpen)
@@ -1913,22 +1965,14 @@ WSPConnect(SOCKET Handle,
     /* FIXME: Handle Async Connect */
     if (Socket->SharedData->NonBlocking)
     {
-        APCFunction = &AfdConnectAPC; // should be a private io completition function inside us
-        APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDCONNECTAPCCONTEXT));
-        if (!APCContext)
-        {
-            ERR("Not enough memory for APC Context\n");
-            return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
-        }
-        ((PAFDCONNECTAPCCONTEXT)APCContext)->lpConnectInfo = ConnectInfo;
-        ((PAFDCONNECTAPCCONTEXT)APCContext)->lpSocket = Socket;
+        ERR("Async Connect UNIMPLEMENTED!\n");
     }
 
     /* Send IOCTL */
     Status = NtDeviceIoControlFile((HANDLE)Handle,
                                    SockEvent,
-                                   APCFunction,
-                                   APCContext,
+                                   NULL,
+                                   NULL,
                                    &IOSB,
                                    IOCTL_AFD_CONNECT,
                                    ConnectInfo,
@@ -1936,25 +1980,19 @@ WSPConnect(SOCKET Handle,
                                    NULL,
                                    0);
     /* Wait for return */
-    if (Status == STATUS_PENDING && !Socket->SharedData->NonBlocking)
+    if (Status == STATUS_PENDING)
     {
         WaitForSingleObject(SockEvent, INFINITE);
         Status = IOSB.Status;
     }
 
-    if (Status == STATUS_PENDING)
-    {
-        TRACE("Leaving (Pending)\n");
-        return MsafdReturnWithErrno(STATUS_CANT_WAIT, lpErrno, 0, NULL);
-    }
-
-    if (APCContext) HeapFree(GetProcessHeap(), 0, APCContext);
-
+    Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
     if (Status != STATUS_SUCCESS)
         goto notify;
 
     Socket->SharedData->State = SocketConnected;
     Socket->TdiConnectionHandle = (HANDLE)IOSB.Information;
+    Socket->SharedData->ConnectTime = GetCurrentTimeInSeconds();
 
     /* Get any pending connect data */
     if (lpCalleeData != NULL)
@@ -1977,7 +2015,7 @@ WSPConnect(SOCKET Handle,
         }
     }
 
-    TRACE("Ending\n");
+    TRACE("Ending %lx\n", IOSB.Status);
 
 notify:
     if (ConnectInfo) HeapFree(GetProcessHeap(), 0, ConnectInfo);
@@ -2034,26 +2072,25 @@ WSPShutdown(SOCKET Handle,
     NTSTATUS                Status;
     HANDLE                  SockEvent;
 
-    Status = NtCreateEvent(&SockEvent,
-                           EVENT_ALL_ACCESS,
-                           NULL,
-                           1,
-                           FALSE);
-
-    if( !NT_SUCCESS(Status) )
-        return -1;
-
     TRACE("Called\n");
 
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       NtClose(SockEvent);
-       *lpErrno = WSAENOTSOCK;
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
        return SOCKET_ERROR;
     }
 
+    Status = NtCreateEvent(&SockEvent,
+                           EVENT_ALL_ACCESS,
+                           NULL,
+                           1,
+                           FALSE);
+
+    if( !NT_SUCCESS(Status) )
+        return SOCKET_ERROR;
+
     /* Set AFD Disconnect Type */
     switch (HowTo)
     {
@@ -2097,6 +2134,7 @@ WSPShutdown(SOCKET Handle,
 
     NtClose( SockEvent );
 
+    Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
     return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
 }
 
@@ -2110,46 +2148,44 @@ WSPGetSockName(IN SOCKET Handle,
 {
     IO_STATUS_BLOCK         IOSB;
     ULONG                   TdiAddressSize;
-       PTDI_ADDRESS_INFO       TdiAddress;
+    PTDI_ADDRESS_INFO       TdiAddress;
     PTRANSPORT_ADDRESS      SocketAddress;
     PSOCKET_INFORMATION     Socket = NULL;
     NTSTATUS                Status;
     HANDLE                  SockEvent;
 
-    Status = NtCreateEvent(&SockEvent,
-                           EVENT_ALL_ACCESS,
-                           NULL,
-                           1,
-                           FALSE);
-
-    if( !NT_SUCCESS(Status) )
-        return SOCKET_ERROR;
-
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
     if (!Socket)
     {
-       NtClose(SockEvent);
-       *lpErrno = WSAENOTSOCK;
+       if (lpErrno) *lpErrno = WSAENOTSOCK;
        return SOCKET_ERROR;
     }
 
     if (!Name || !NameLength)
     {
-        NtClose(SockEvent);
-        *lpErrno = WSAEFAULT;
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
 
+    Status = NtCreateEvent(&SockEvent,
+                           EVENT_ALL_ACCESS,
+                           NULL,
+                           1,
+                           FALSE);
+
+    if( !NT_SUCCESS(Status) )
+        return SOCKET_ERROR;
+
     /* Allocate a buffer for the address */
     TdiAddressSize =
-               sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfLocalAddress;
+        sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfLocalAddress;
     TdiAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
 
     if ( TdiAddress == NULL )
     {
         NtClose( SockEvent );
-        *lpErrno = WSAENOBUFS;
+        if (lpErrno) *lpErrno = WSAENOBUFS;
         return SOCKET_ERROR;
     }
 
@@ -2194,7 +2230,7 @@ WSPGetSockName(IN SOCKET Handle,
         else
         {
             HeapFree(GlobalHeap, 0, TdiAddress);
-            *lpErrno = WSAEFAULT;
+            if (lpErrno) *lpErrno = WSAEFAULT;
             return SOCKET_ERROR;
         }
     }
@@ -2219,38 +2255,35 @@ WSPGetPeerName(IN SOCKET s,
     NTSTATUS                Status;
     HANDLE                  SockEvent;
 
-    Status = NtCreateEvent(&SockEvent,
-                           EVENT_ALL_ACCESS,
-                           NULL,
-                           1,
-                           FALSE);
-
-    if( !NT_SUCCESS(Status) )
-        return SOCKET_ERROR;
-
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(s);
     if (!Socket)
     {
-       NtClose(SockEvent);
-       *lpErrno = WSAENOTSOCK;
-       return SOCKET_ERROR;
+        if (lpErrno) *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
     }
 
     if (Socket->SharedData->State != SocketConnected)
     {
-        NtClose(SockEvent);
-        *lpErrno = WSAENOTCONN;
+        if (lpErrno) *lpErrno = WSAENOTCONN;
         return SOCKET_ERROR;
     }
 
     if (!Name || !NameLength)
     {
-        NtClose(SockEvent);
-        *lpErrno = WSAEFAULT;
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
 
+    Status = NtCreateEvent(&SockEvent,
+                           EVENT_ALL_ACCESS,
+                           NULL,
+                           1,
+                           FALSE);
+
+    if( !NT_SUCCESS(Status) )
+        return SOCKET_ERROR;
+
     /* Allocate a buffer for the address */
     TdiAddressSize = sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfRemoteAddress;
     SocketAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
@@ -2258,7 +2291,7 @@ WSPGetPeerName(IN SOCKET s,
     if ( SocketAddress == NULL )
     {
         NtClose( SockEvent );
-        *lpErrno = WSAENOBUFS;
+        if (lpErrno) *lpErrno = WSAENOBUFS;
         return SOCKET_ERROR;
     }
 
@@ -2301,7 +2334,7 @@ WSPGetPeerName(IN SOCKET s,
         else
         {
             HeapFree(GlobalHeap, 0, SocketAddress);
-            *lpErrno = WSAEFAULT;
+            if (lpErrno) *lpErrno = WSAEFAULT;
             return SOCKET_ERROR;
         }
     }
@@ -2326,7 +2359,7 @@ WSPIoctl(IN  SOCKET Handle,
          OUT LPINT lpErrno)
 {
     PSOCKET_INFORMATION Socket = NULL;
-    BOOLEAN NeedsCompletion = lpOverlapped != NULL;
+    BOOL NeedsCompletion = lpOverlapped != NULL;
     BOOLEAN NonBlocking;
     INT Errno = NO_ERROR, Ret = SOCKET_ERROR;
     DWORD cbRet = 0;
@@ -2356,6 +2389,22 @@ WSPIoctl(IN  SOCKET Handle,
                 break;
             }
             NonBlocking = *((PULONG)lpvInBuffer) ? TRUE : FALSE;
+            /* Don't allow to go in blocking mode if WSPAsyncSelect or WSPEventSelect is pending */
+            if (!NonBlocking)
+            {
+                /* If there is an WSPAsyncSelect pending, fail with WSAEINVAL */
+                if (Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents))
+                {
+                    Errno = WSAEINVAL;
+                    break;
+                }
+                /* If there is an WSPEventSelect pending, fail with WSAEINVAL */
+                if (Socket->NetworkEvents)
+                {
+                    Errno = WSAEINVAL;
+                    break;
+                }
+            }
             Socket->SharedData->NonBlocking = NonBlocking ? 1 : 0;
             NeedsCompletion = FALSE;
             Errno = SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &NonBlocking, NULL, NULL, lpOverlapped, lpCompletionRoutine);
@@ -2394,9 +2443,16 @@ WSPIoctl(IN  SOCKET Handle,
                 Errno = WSAEINVAL;
                 break;
             }
+            if (Socket->SharedData->SocketType != SOCK_STREAM)
+            {
+                Errno = WSAEINVAL;
+                break;
+            }
 
-            /* FIXME: Return false for now */
-            *(BOOL*)lpvOutBuffer = FALSE;
+            /* FIXME: Return false if OOBINLINE is true for now
+               We should MSG_PEEK|MSG_OOB check with driver
+            */
+            *(BOOL*)lpvOutBuffer = !Socket->SharedData->OobInline;
 
             cbRet = sizeof(BOOL);
             Errno = NO_ERROR;
@@ -2447,7 +2503,7 @@ WSPIoctl(IN  SOCKET Handle,
                                                  &cbRet,
                                                  lpOverlapped,
                                                  lpCompletionRoutine,
-                                                 (LPBOOL)&NeedsCompletion);
+                                                 &NeedsCompletion);
 
             if (Errno == NO_ERROR)
                 Ret = NO_ERROR;
@@ -2490,17 +2546,23 @@ WSPGetSockOpt(IN SOCKET Handle,
     PVOID Buffer;
     INT BufferSize;
     BOOL BoolBuffer;
-    INT IntBuffer;
+    DWORD DwordBuffer;
+    INT Errno;
+
+    TRACE("Called\n");
 
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(Handle);
     if (Socket == NULL)
     {
-        *lpErrno = WSAENOTSOCK;
+        if (lpErrno) *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!OptionLength || !OptionValue)
+    {
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
-
-    TRACE("Called\n");
 
     switch (Level)
     {
@@ -2549,7 +2611,7 @@ WSPGetSockOpt(IN SOCKET Handle,
                 case SO_LINGER:
                     if (Socket->SharedData->SocketType == SOCK_DGRAM)
                     {
-                        *lpErrno = WSAENOPROTOOPT;
+                        if (lpErrno) *lpErrno = WSAENOPROTOOPT;
                         return SOCKET_ERROR;
                     }
                     Buffer = &Socket->SharedData->LingerData;
@@ -2586,13 +2648,16 @@ WSPGetSockOpt(IN SOCKET Handle,
                     break;
 
                 case SO_ERROR:
-                    /* HACK: This needs to be properly tracked */
-                    IntBuffer = 0;
-                    DbgPrint("MSAFD: Hacked SO_ERROR returning error %d\n", IntBuffer);
-
-                    Buffer = &IntBuffer;
+                    Buffer = &Socket->SharedData->SocketLastError;
                     BufferSize = sizeof(INT);
                     break;
+
+                case SO_CONNECT_TIME:
+                    DwordBuffer = GetCurrentTimeInSeconds() - Socket->SharedData->ConnectTime;
+                    Buffer = &DwordBuffer;
+                    BufferSize = sizeof(DWORD);
+                    break;
+
                 case SO_SNDTIMEO:
                     Buffer = &Socket->SharedData->SendTimeout;
                     BufferSize = sizeof(DWORD);
@@ -2612,13 +2677,13 @@ WSPGetSockOpt(IN SOCKET Handle,
 
                 default:
                     DbgPrint("MSAFD: Get unknown optname %x\n", OptionName);
-                    *lpErrno = WSAENOPROTOOPT;
+                    if (lpErrno) *lpErrno = WSAENOPROTOOPT;
                     return SOCKET_ERROR;
             }
 
             if (*OptionLength < BufferSize)
             {
-                *lpErrno = WSAEFAULT;
+                if (lpErrno) *lpErrno = WSAEFAULT;
                 *OptionLength = BufferSize;
                 return SOCKET_ERROR;
             }
@@ -2627,20 +2692,21 @@ WSPGetSockOpt(IN SOCKET Handle,
             return 0;
 
         default:
-            *lpErrno = WSAEINVAL;
+            if (lpErrno) *lpErrno = WSAEINVAL;
             return SOCKET_ERROR;
     }
 
 SendToHelper:
-    *lpErrno = Socket->HelperData->WSHGetSocketInformation(Socket->HelperContext,
-                                                           Handle,
-                                                           Socket->TdiAddressHandle,
-                                                           Socket->TdiConnectionHandle,
-                                                           Level,
-                                                           OptionName,
-                                                           OptionValue,
-                                                           (LPINT)OptionLength);
-    return (*lpErrno == 0) ? 0 : SOCKET_ERROR;
+    Errno = Socket->HelperData->WSHGetSocketInformation(Socket->HelperContext,
+                                                        Handle,
+                                                        Socket->TdiAddressHandle,
+                                                        Socket->TdiConnectionHandle,
+                                                        Level,
+                                                        OptionName,
+                                                        OptionValue,
+                                                        (LPINT)OptionLength);
+    if (lpErrno) *lpErrno = Errno;
+    return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
 }
 
 INT
@@ -2654,12 +2720,18 @@ WSPSetSockOpt(
     OUT LPINT lpErrno)
 {
     PSOCKET_INFORMATION Socket;
+    INT Errno;
 
     /* Get the Socket Structure associate to this Socket*/
     Socket = GetSocketStructure(s);
     if (Socket == NULL)
     {
-        *lpErrno = WSAENOTSOCK;
+        if (lpErrno) *lpErrno = WSAENOTSOCK;
+        return SOCKET_ERROR;
+    }
+    if (!optval)
+    {
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
 
@@ -2672,84 +2744,105 @@ WSPSetSockOpt(
            case SO_BROADCAST:
               if (optlen < sizeof(BOOL))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
               Socket->SharedData->Broadcast = (*optval != 0) ? 1 : 0;
-              return 0;
+              return NO_ERROR;
+
+           case SO_OOBINLINE:
+              if (optlen < sizeof(BOOL))
+              {
+                  if (lpErrno) *lpErrno = WSAEFAULT;
+                  return SOCKET_ERROR;
+              }
+              Socket->SharedData->OobInline = (*optval != 0) ? 1 : 0;
+              return NO_ERROR;
 
            case SO_DONTLINGER:
               if (optlen < sizeof(BOOL))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
               Socket->SharedData->LingerData.l_onoff = (*optval != 0) ? 0 : 1;
-              return 0;
+              return NO_ERROR;
 
            case SO_REUSEADDR:
               if (optlen < sizeof(BOOL))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
               Socket->SharedData->ReuseAddresses = (*optval != 0) ? 1 : 0;
-              return 0;
+              return NO_ERROR;
 
            case SO_EXCLUSIVEADDRUSE:
               if (optlen < sizeof(BOOL))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
               Socket->SharedData->ExclusiveAddressUse = (*optval != 0) ? 1 : 0;
-              return 0;
+              return NO_ERROR;
 
            case SO_LINGER:
               if (optlen < sizeof(struct linger))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
               RtlCopyMemory(&Socket->SharedData->LingerData,
                             optval,
                             sizeof(struct linger));
-              return 0;
+              return NO_ERROR;
 
            case SO_SNDBUF:
               if (optlen < sizeof(DWORD))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
 
               /* TODO: The total per-socket buffer space reserved for sends */
               ERR("Setting send buf to %x is not implemented yet\n", optval);
-              return 0;
+              return NO_ERROR;
+
+           case SO_ERROR:
+              if (optlen < sizeof(INT))
+              {
+                  if (lpErrno) *lpErrno = WSAEFAULT;
+                  return SOCKET_ERROR;
+              }
+
+              RtlCopyMemory(&Socket->SharedData->SocketLastError,
+                            optval,
+                            sizeof(INT));
+              return NO_ERROR;
 
            case SO_SNDTIMEO:
               if (optlen < sizeof(DWORD))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
 
               RtlCopyMemory(&Socket->SharedData->SendTimeout,
                             optval,
                             sizeof(DWORD));
-              return 0;
+              return NO_ERROR;
 
            case SO_RCVTIMEO:
               if (optlen < sizeof(DWORD))
               {
-                  *lpErrno = WSAEFAULT;
+                  if (lpErrno) *lpErrno = WSAEFAULT;
                   return SOCKET_ERROR;
               }
 
               RtlCopyMemory(&Socket->SharedData->RecvTimeout,
                             optval,
                             sizeof(DWORD));
-              return 0;
+              return NO_ERROR;
 
            case SO_KEEPALIVE:
            case SO_DONTROUTE:
@@ -2759,20 +2852,21 @@ WSPSetSockOpt(
            default:
               /* Obviously this is a hack */
               ERR("MSAFD: Set unknown optname %x\n", optname);
-              return 0;
+              return NO_ERROR;
         }
     }
 
 SendToHelper:
-    *lpErrno = Socket->HelperData->WSHSetSocketInformation(Socket->HelperContext,
-                                                           s,
-                                                           Socket->TdiAddressHandle,
-                                                           Socket->TdiConnectionHandle,
-                                                           level,
-                                                           optname,
-                                                           (PCHAR)optval,
-                                                           optlen);
-    return (*lpErrno == 0) ? 0 : SOCKET_ERROR;
+    Errno = Socket->HelperData->WSHSetSocketInformation(Socket->HelperContext,
+                                                        s,
+                                                        Socket->TdiAddressHandle,
+                                                        Socket->TdiConnectionHandle,
+                                                        level,
+                                                        optname,
+                                                        (PCHAR)optval,
+                                                        optlen);
+    if (lpErrno) *lpErrno = Errno;
+    return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
 }
 
 /*
@@ -2866,7 +2960,7 @@ WSPAddressToString(IN LPSOCKADDR lpsaAddress,
 
     if (!lpsaAddress || !lpszAddressString || !lpdwAddressStringLength)
     {
-        *lpErrno = WSAEFAULT;
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
 
@@ -2875,7 +2969,7 @@ WSPAddressToString(IN LPSOCKADDR lpsaAddress,
         case AF_INET:
             if (dwAddressLength < sizeof(SOCKADDR_IN))
             {
-                *lpErrno = WSAEINVAL;
+                if (lpErrno) *lpErrno = WSAEINVAL;
                 return SOCKET_ERROR;
             }
             swprintf(buffer,
@@ -2893,7 +2987,7 @@ WSPAddressToString(IN LPSOCKADDR lpsaAddress,
             }
             break;
         default:
-            *lpErrno = WSAEINVAL;
+            if (lpErrno) *lpErrno = WSAEINVAL;
             return SOCKET_ERROR;
     }
 
@@ -2902,7 +2996,7 @@ WSPAddressToString(IN LPSOCKADDR lpsaAddress,
     if (*lpdwAddressStringLength < size)
     {
         *lpdwAddressStringLength = size;
-        *lpErrno = WSAEFAULT;
+        if (lpErrno) *lpErrno = WSAEFAULT;
         return SOCKET_ERROR;
     }
 
@@ -2920,14 +3014,15 @@ WSPStringToAddress(IN LPWSTR AddressString,
                    IN OUT LPINT lpAddressLength,
                    OUT LPINT lpErrno)
 {
-    int pos = 0;
-    LONG inetaddr = 0;
+    int numdots = 0;
+    USHORT port;
+    LONG inetaddr = 0, ip_part;
     LPWSTR *bp = NULL;
     SOCKADDR_IN *sockaddr;
 
     if (!lpAddressLength || !lpAddress || !AddressString)
     {
-        *lpErrno = WSAEINVAL;
+        if (lpErrno) *lpErrno = WSAEINVAL;
         return SOCKET_ERROR;
     }
 
@@ -2948,51 +3043,78 @@ WSPStringToAddress(IN LPWSTR AddressString,
     {
         if (*lpAddressLength < (INT)sizeof(SOCKADDR_IN))
         {
-            *lpAddressLength = sizeof(SOCKADDR_IN);
-            *lpErrno = WSAEFAULT;
+            if (lpErrno) *lpErrno = WSAEFAULT;
         }
         else
         {
             // translate ip string to ip
 
-            /* rest sockaddr.sin_addr.s_addr
-            for we need to be sure it is zero when we come to while */
-            memset(lpAddress, 0, sizeof(SOCKADDR_IN));
-
-            /* Set right adress family */
-            sockaddr->sin_family = AF_INET;
-
-            /* Get port number */
-            pos = wcscspn(AddressString, L":") + 1;
+            /* Get ip number */
+            bp = &AddressString;
+            inetaddr = 0;
 
-            if (pos < (int)wcslen(AddressString))
+            while (*bp < &AddressString[wcslen(AddressString)])
             {
-                sockaddr->sin_port = wcstol(&AddressString[pos], bp, 10);
+                ip_part = wcstol(*bp, bp, 10);
+                /* ip part number should be in range 0-255 */
+                if (ip_part < 0 || ip_part > 255)
+                {
+                    if (lpErrno) *lpErrno = WSAEINVAL;
+                    return SOCKET_ERROR;
+                }
+                inetaddr = (inetaddr << 8) + ip_part;
+                /* we end on string end or port separator */
+                if ((*bp)[0] == 0 || (*bp)[0] == L':')
+                    break;
+                /* ip parts are dot separated. verify it */
+                if ((*bp)[0] != L'.')
+                {
+                    if (lpErrno) *lpErrno = WSAEINVAL;
+                    return SOCKET_ERROR;
+                }
+                /* count the dots */
+                numdots++;
+                /* move over the dot to next ip part */
+                (*bp)++;
             }
-            else
+            
+            /* check dots count */
+            if (numdots != 3)
             {
-                sockaddr->sin_port = 0;
+                if (lpErrno) *lpErrno = WSAEINVAL;
+                return SOCKET_ERROR;
             }
 
-            /* Get ip number */
-            pos = 0;
-            inetaddr = 0;
-
-            while (pos < (int)wcslen(AddressString))
+            /* Get port number */
+            if ((*bp)[0] == L':')
             {
-                inetaddr = (inetaddr << 8) +
-                           ((UCHAR)wcstol(&AddressString[pos], bp, 10));
-
-                pos += wcscspn(&AddressString[pos], L".") + 1;
+                /* move over the column to port part */
+                (*bp)++;
+                /* next char should be numeric */
+                if ((*bp)[0] < L'0' || (*bp)[0] > L'9')
+                {
+                    if (lpErrno) *lpErrno = WSAEINVAL;
+                    return SOCKET_ERROR;
+                }
+                port = wcstol(*bp, bp, 10);
+            }
+            else
+            {
+                port = 0;
             }
 
-            *lpErrno = 0;
+            if (lpErrno) *lpErrno = NO_ERROR;
+            /* rest sockaddr.sin_addr.s_addr
+            for we need to be sure it is zero when we come to while */
+            *lpAddressLength = sizeof(*sockaddr);
+            memset(lpAddress, 0, sizeof(*sockaddr));
+            sockaddr->sin_family = AF_INET;
             sockaddr->sin_addr.s_addr = inetaddr;
-
+            sockaddr->sin_port = port;
         }
     }
 
-    if (!*lpErrno)
+    if (lpErrno && !*lpErrno)
     {
         return 0;
     }
@@ -3013,7 +3135,8 @@ WSPCleanup(OUT LPINT lpErrno)
 
 {
     TRACE("Leaving.\n");
-    *lpErrno = NO_ERROR;
+
+    if (lpErrno) *lpErrno = NO_ERROR;
 
     return 0;
 }
@@ -3043,7 +3166,7 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
     IO_STATUS_BLOCK     DummyIOSB;
     AFD_INFO            InfoData;
     NTSTATUS            Status;
-    PVOID               APCContext;
+    PAFDAPCCONTEXT      APCContext;
     PIO_APC_ROUTINE     APCFunction;
     HANDLE              Event = NULL;
     HANDLE              SockEvent;
@@ -3055,7 +3178,7 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
                            FALSE);
 
     if( !NT_SUCCESS(Status) )
-        return -1;
+        return SOCKET_ERROR;
 
     /* Set Info Class */
     InfoData.InformationClass = AfdInformationClass;
@@ -3080,7 +3203,7 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
         if (CompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
-            APCContext = Overlapped;
+            APCContext = (PAFDAPCCONTEXT)Overlapped;
             APCFunction = NULL;
             Event = Overlapped->hEvent;
         }
@@ -3094,9 +3217,9 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
                 ERR("Not enough memory for APC Context\n");
                 return WSAEFAULT;
             }
-            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = CompletionRoutine;
-            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = Overlapped;
-            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
+            APCContext->lpCompletionRoutine = CompletionRoutine;
+            APCContext->lpOverlapped = Overlapped;
+            APCContext->lpSocket = Socket;
         }
 
         IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
@@ -3132,7 +3255,7 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
     }
 
     if (Status != STATUS_SUCCESS)
-        return -1;
+        return SOCKET_ERROR;
 
     /* Return Information */
     if (Ulong != NULL)
@@ -3150,7 +3273,7 @@ GetSocketInformation(PSOCKET_INFORMATION Socket,
 
     NtClose( SockEvent );
 
-    return 0;
+    return NO_ERROR;
 
 }
 
@@ -3168,7 +3291,7 @@ SetSocketInformation(PSOCKET_INFORMATION Socket,
     IO_STATUS_BLOCK     DummyIOSB;
     AFD_INFO            InfoData;
     NTSTATUS            Status;
-    PVOID               APCContext;
+    PAFDAPCCONTEXT      APCContext;
     PIO_APC_ROUTINE     APCFunction;
     HANDLE              Event = NULL;
     HANDLE              SockEvent;
@@ -3180,7 +3303,7 @@ SetSocketInformation(PSOCKET_INFORMATION Socket,
                            FALSE);
 
     if( !NT_SUCCESS(Status) )
-        return -1;
+        return SOCKET_ERROR;
 
     /* Set Info Class */
     InfoData.InformationClass = AfdInformationClass;
@@ -3219,7 +3342,7 @@ SetSocketInformation(PSOCKET_INFORMATION Socket,
         if (CompletionRoutine == NULL)
         {
             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
-            APCContext = Overlapped;
+            APCContext = (PAFDAPCCONTEXT)Overlapped;
             APCFunction = NULL;
             Event = Overlapped->hEvent;
         }
@@ -3233,9 +3356,9 @@ SetSocketInformation(PSOCKET_INFORMATION Socket,
                 ERR("Not enough memory for APC Context\n");
                 return WSAEFAULT;
             }
-            ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = CompletionRoutine;
-            ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = Overlapped;
-            ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
+            APCContext->lpCompletionRoutine = CompletionRoutine;
+            APCContext->lpOverlapped = Overlapped;
+            APCContext->lpSocket = Socket;
         }
 
         IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
@@ -3272,7 +3395,7 @@ SetSocketInformation(PSOCKET_INFORMATION Socket,
         return WSA_IO_PENDING;
     }
 
-    return Status == STATUS_SUCCESS ? 0 : -1;
+    return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
 
 }
 
@@ -3314,7 +3437,7 @@ int CreateContext(PSOCKET_INFORMATION Socket)
                            FALSE);
 
     if( !NT_SUCCESS(Status) )
-        return -1;
+        return SOCKET_ERROR;
 
     /* Create Context */
     ContextData.SharedData = *Socket->SharedData;
@@ -3338,7 +3461,7 @@ int CreateContext(PSOCKET_INFORMATION Socket)
                                    NULL,
                                    0);
 
-    /* Wait for Completition */
+    /* Wait for Completion */
     if (Status == STATUS_PENDING)
     {
         WaitForSingleObject(SockEvent, INFINITE);
@@ -3347,7 +3470,7 @@ int CreateContext(PSOCKET_INFORMATION Socket)
 
     NtClose( SockEvent );
 
-    return Status == STATUS_SUCCESS ? 0 : -1;
+    return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
 }
 
 BOOLEAN SockCreateOrReferenceAsyncThread(VOID)
@@ -3451,7 +3574,7 @@ BOOLEAN SockGetAsyncSelectHelperAfdHandle(VOID)
     FILE_COMPLETION_INFORMATION CompletionInfo;
     OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
 
-    /* First, make sure we're not already intialized */
+    /* First, make sure we're not already initialized */
     if (SockAsyncHelperAfdHandle)
     {
         return TRUE;
@@ -3536,7 +3659,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
                 if (0 != (Socket->SharedData->AsyncEvents & FD_READ) &&
                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_READ))
                 {
-                    /* Make the Notifcation */
+                    /* Make the Notification */
                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                                                Socket->SharedData->wMsg,
                                                Socket->Handle,
@@ -3550,7 +3673,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
             if (0 != (Socket->SharedData->AsyncEvents & FD_OOB) &&
                 0 == (Socket->SharedData->AsyncDisabledEvents & FD_OOB))
             {
-                /* Make the Notifcation */
+                /* Make the Notification */
                 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                                            Socket->SharedData->wMsg,
                                            Socket->Handle,
@@ -3564,7 +3687,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
                 if (0 != (Socket->SharedData->AsyncEvents & FD_WRITE) &&
                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_WRITE))
                 {
-                    /* Make the Notifcation */
+                    /* Make the Notification */
                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                                                Socket->SharedData->wMsg,
                                                Socket->Handle,
@@ -3580,7 +3703,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
                 if (0 != (Socket->SharedData->AsyncEvents & FD_CONNECT) &&
                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_CONNECT))
                 {
-                    /* Make the Notifcation */
+                    /* Make the Notification */
                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                         Socket->SharedData->wMsg,
                         Socket->Handle,
@@ -3594,7 +3717,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
                 if (0 != (Socket->SharedData->AsyncEvents & FD_ACCEPT) &&
                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_ACCEPT))
                 {
-                    /* Make the Notifcation */
+                    /* Make the Notification */
                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                                                Socket->SharedData->wMsg,
                                                Socket->Handle,
@@ -3610,7 +3733,7 @@ VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBl
                 if (0 != (Socket->SharedData->AsyncEvents & FD_CLOSE) &&
                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_CLOSE))
                 {
-                    /* Make the Notifcation */
+                    /* Make the Notification */
                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
                                                Socket->SharedData->wMsg,
                                                Socket->Handle,
@@ -3732,7 +3855,7 @@ VOID SockProcessQueuedAsyncSelect(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
         /* Check if the Sequence Number changed by now, in which case quit */
         if (AsyncData->SequenceNumber == Socket->SharedData->SequenceNumber)
         {
-            /* Do the actuall select, if needed */
+            /* Do the actual select, if needed */
             if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)))
             {
                 SockProcessAsyncSelect(Socket, AsyncData);
@@ -3846,5 +3969,3 @@ DllMain(HANDLE hInstDll,
 }
 
 /* EOF */
-
-