xref: /reactos/dll/win32/msafd/misc/dllmain.c (revision 4a7f3bdb)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS Ancillary Function Driver DLL
4  * FILE:        dll/win32/msafd/misc/dllmain.c
5  * PURPOSE:     DLL entry point
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Alex Ionescu (alex@relsoft.net)
8  * REVISIONS:
9  *              CSH 01/09-2000 Created
10  *              Alex 16/07/2004 - Complete Rewrite
11  */
12 
13 #include <msafd.h>
14 
15 #include <winuser.h>
16 #include <wchar.h>
17 
18 HANDLE GlobalHeap;
19 WSPUPCALLTABLE Upcalls;
20 DWORD CatalogEntryId; /* CatalogEntryId for upcalls */
21 LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
22 PSOCKET_INFORMATION SocketListHead = NULL;
23 CRITICAL_SECTION SocketListLock;
24 LIST_ENTRY SockHelpersListHead = { NULL, NULL };
25 ULONG SockAsyncThreadRefCount;
26 HANDLE SockAsyncHelperAfdHandle;
27 HANDLE SockAsyncCompletionPort = NULL;
28 BOOLEAN SockAsyncSelectCalled;
29 
30 
31 
32 /*
33  * FUNCTION: Creates a new socket
34  * ARGUMENTS:
35  *     af             = Address family
36  *     type           = Socket type
37  *     protocol       = Protocol type
38  *     lpProtocolInfo = Pointer to protocol information
39  *     g              = Reserved
40  *     dwFlags        = Socket flags
41  *     lpErrno        = Address of buffer for error information
42  * RETURNS:
43  *     Created socket, or INVALID_SOCKET if it could not be created
44  */
45 SOCKET
46 WSPAPI
47 WSPSocket(int AddressFamily,
48           int SocketType,
49           int Protocol,
50           LPWSAPROTOCOL_INFOW lpProtocolInfo,
51           GROUP g,
52           DWORD dwFlags,
53           LPINT lpErrno)
54 {
55     OBJECT_ATTRIBUTES           Object;
56     IO_STATUS_BLOCK             IOSB;
57     USHORT                      SizeOfPacket;
58     ULONG                       SizeOfEA;
59     PAFD_CREATE_PACKET          AfdPacket;
60     HANDLE                      Sock;
61     PSOCKET_INFORMATION         Socket = NULL;
62     PFILE_FULL_EA_INFORMATION   EABuffer = NULL;
63     PHELPER_DATA                HelperData;
64     PVOID                       HelperDLLContext;
65     DWORD                       HelperEvents;
66     UNICODE_STRING              TransportName;
67     UNICODE_STRING              DevName;
68     LARGE_INTEGER               GroupData;
69     INT                         Status;
70     PSOCK_SHARED_INFO           SharedData = NULL;
71 
72     TRACE("Creating Socket, getting TDI Name - AddressFamily (%d)  SocketType (%d)  Protocol (%d).\n",
73         AddressFamily, SocketType, Protocol);
74 
75     if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags3 != 0 && lpProtocolInfo->dwServiceFlags4 != 0)
76     {
77         /* Duplpicating socket from different process */
78         if ((HANDLE)lpProtocolInfo->dwServiceFlags3 == INVALID_HANDLE_VALUE)
79         {
80             Status = WSAEINVAL;
81             goto error;
82         }
83         if ((HANDLE)lpProtocolInfo->dwServiceFlags4 == INVALID_HANDLE_VALUE)
84         {
85             Status = WSAEINVAL;
86             goto error;
87         }
88         SharedData = MapViewOfFile((HANDLE)lpProtocolInfo->dwServiceFlags3,
89                                    FILE_MAP_ALL_ACCESS,
90                                    0,
91                                    0,
92                                    sizeof(SOCK_SHARED_INFO));
93         if (!SharedData)
94         {
95             Status = WSAEINVAL;
96             goto error;
97         }
98         InterlockedIncrement(&SharedData->RefCount);
99         AddressFamily = SharedData->AddressFamily;
100         SocketType = SharedData->SocketType;
101         Protocol = SharedData->Protocol;
102     }
103 
104     if (AddressFamily == AF_UNSPEC && SocketType == 0 && Protocol == 0)
105     {
106         Status = WSAEINVAL;
107         goto error;
108     }
109 
110     /* Set the defaults */
111     if (AddressFamily == AF_UNSPEC)
112         AddressFamily = AF_INET;
113 
114     if (SocketType == 0)
115     {
116         switch (Protocol)
117         {
118         case IPPROTO_TCP:
119             SocketType = SOCK_STREAM;
120             break;
121         case IPPROTO_UDP:
122             SocketType = SOCK_DGRAM;
123             break;
124         case IPPROTO_RAW:
125             SocketType = SOCK_RAW;
126             break;
127         default:
128             TRACE("Unknown Protocol (%d). We will try SOCK_STREAM.\n", Protocol);
129             SocketType = SOCK_STREAM;
130             break;
131         }
132     }
133 
134     if (Protocol == 0)
135     {
136         switch (SocketType)
137         {
138         case SOCK_STREAM:
139             Protocol = IPPROTO_TCP;
140             break;
141         case SOCK_DGRAM:
142             Protocol = IPPROTO_UDP;
143             break;
144         case SOCK_RAW:
145             Protocol = IPPROTO_RAW;
146             break;
147         default:
148             TRACE("Unknown SocketType (%d). We will try IPPROTO_TCP.\n", SocketType);
149             Protocol = IPPROTO_TCP;
150             break;
151         }
152     }
153 
154     /* Get Helper Data and Transport */
155     Status = SockGetTdiName (&AddressFamily,
156                              &SocketType,
157                              &Protocol,
158                              g,
159                              dwFlags,
160                              &TransportName,
161                              &HelperDLLContext,
162                              &HelperData,
163                              &HelperEvents);
164 
165     /* Check for error */
166     if (Status != NO_ERROR)
167     {
168         ERR("SockGetTdiName: Status %x\n", Status);
169         goto error;
170     }
171 
172     /* AFD Device Name */
173     RtlInitUnicodeString(&DevName, L"\\Device\\Afd\\Endpoint");
174 
175     /* Set Socket Data */
176     Socket = HeapAlloc(GlobalHeap, 0, sizeof(*Socket));
177     if (!Socket)
178     {
179         Status = WSAENOBUFS;
180         goto error;
181     }
182     RtlZeroMemory(Socket, sizeof(*Socket));
183     if (SharedData)
184     {
185         Socket->SharedData = SharedData;
186         Socket->SharedDataHandle = (HANDLE)lpProtocolInfo->dwServiceFlags3;
187         Sock = (HANDLE)lpProtocolInfo->dwServiceFlags4;
188         Socket->Handle = (SOCKET)lpProtocolInfo->dwServiceFlags4;
189     }
190     else
191     {
192         Socket->SharedDataHandle = INVALID_HANDLE_VALUE;
193         Socket->SharedData = HeapAlloc(GlobalHeap, 0, sizeof(*Socket->SharedData));
194         if (!Socket->SharedData)
195         {
196             Status = WSAENOBUFS;
197             goto error;
198         }
199         RtlZeroMemory(Socket->SharedData, sizeof(*Socket->SharedData));
200         Socket->SharedData->State = SocketOpen;
201         Socket->SharedData->RefCount = 1L;
202         Socket->SharedData->Listening = FALSE;
203         Socket->SharedData->AddressFamily = AddressFamily;
204         Socket->SharedData->SocketType = SocketType;
205         Socket->SharedData->Protocol = Protocol;
206         Socket->SharedData->SizeOfLocalAddress = HelperData->MaxWSAddressLength;
207         Socket->SharedData->SizeOfRemoteAddress = HelperData->MaxWSAddressLength;
208         Socket->SharedData->UseDelayedAcceptance = HelperData->UseDelayedAcceptance;
209         Socket->SharedData->CreateFlags = dwFlags;
210         Socket->SharedData->ServiceFlags1 = lpProtocolInfo->dwServiceFlags1;
211         Socket->SharedData->ProviderFlags = lpProtocolInfo->dwProviderFlags;
212         Socket->SharedData->UseSAN = FALSE;
213         Socket->SharedData->NonBlocking = FALSE; /* Sockets start blocking */
214         Socket->SharedData->RecvTimeout = INFINITE;
215         Socket->SharedData->SendTimeout = INFINITE;
216         Socket->SharedData->OobInline = FALSE;
217 
218         /* Ask alex about this */
219         if( Socket->SharedData->SocketType == SOCK_DGRAM ||
220             Socket->SharedData->SocketType == SOCK_RAW )
221         {
222             TRACE("Connectionless socket\n");
223             Socket->SharedData->ServiceFlags1 |= XP1_CONNECTIONLESS;
224         }
225         Socket->Handle = INVALID_SOCKET;
226     }
227 
228     Socket->HelperContext = HelperDLLContext;
229     Socket->HelperData = HelperData;
230     Socket->HelperEvents = HelperEvents;
231     Socket->LocalAddress = &Socket->SharedData->WSLocalAddress;
232     Socket->RemoteAddress = &Socket->SharedData->WSRemoteAddress;
233     Socket->SanData = NULL;
234     RtlCopyMemory(&Socket->ProtocolInfo, lpProtocolInfo, sizeof(Socket->ProtocolInfo));
235     if (SharedData)
236         goto ok;
237 
238     /* Packet Size */
239     SizeOfPacket = TransportName.Length + sizeof(AFD_CREATE_PACKET) + sizeof(WCHAR);
240 
241     /* EA Size */
242     SizeOfEA = SizeOfPacket + sizeof(FILE_FULL_EA_INFORMATION) + AFD_PACKET_COMMAND_LENGTH;
243 
244     /* Set up EA Buffer */
245     EABuffer = HeapAlloc(GlobalHeap, 0, SizeOfEA);
246     if (!EABuffer)
247     {
248         Status = WSAENOBUFS;
249         goto error;
250     }
251 
252     RtlZeroMemory(EABuffer, SizeOfEA);
253     EABuffer->NextEntryOffset = 0;
254     EABuffer->Flags = 0;
255     EABuffer->EaNameLength = AFD_PACKET_COMMAND_LENGTH;
256     RtlCopyMemory (EABuffer->EaName,
257                    AfdCommand,
258                    AFD_PACKET_COMMAND_LENGTH + 1);
259     EABuffer->EaValueLength = SizeOfPacket;
260 
261     /* Set up AFD Packet */
262     AfdPacket = (PAFD_CREATE_PACKET)(EABuffer->EaName + EABuffer->EaNameLength + 1);
263     AfdPacket->SizeOfTransportName = TransportName.Length;
264     RtlCopyMemory (AfdPacket->TransportName,
265                    TransportName.Buffer,
266                    TransportName.Length + sizeof(WCHAR));
267     AfdPacket->GroupID = g;
268 
269     /* Set up Endpoint Flags */
270     if ((Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS) != 0)
271     {
272         if ((SocketType != SOCK_DGRAM) && (SocketType != SOCK_RAW))
273         {
274             /* Only RAW or UDP can be Connectionless */
275             Status = WSAEINVAL;
276             goto error;
277         }
278         AfdPacket->EndpointFlags |= AFD_ENDPOINT_CONNECTIONLESS;
279     }
280 
281     if ((Socket->SharedData->ServiceFlags1 & XP1_MESSAGE_ORIENTED) != 0)
282     {
283         if (SocketType == SOCK_STREAM)
284         {
285             if ((Socket->SharedData->ServiceFlags1 & XP1_PSEUDO_STREAM) == 0)
286             {
287                 /* The Provider doesn't actually support Message Oriented Streams */
288                 Status = WSAEINVAL;
289                 goto error;
290             }
291         }
292         AfdPacket->EndpointFlags |= AFD_ENDPOINT_MESSAGE_ORIENTED;
293     }
294 
295     if (SocketType == SOCK_RAW) AfdPacket->EndpointFlags |= AFD_ENDPOINT_RAW;
296 
297     if (dwFlags & (WSA_FLAG_MULTIPOINT_C_ROOT |
298                    WSA_FLAG_MULTIPOINT_C_LEAF |
299                    WSA_FLAG_MULTIPOINT_D_ROOT |
300                    WSA_FLAG_MULTIPOINT_D_LEAF))
301     {
302         if ((Socket->SharedData->ServiceFlags1 & XP1_SUPPORT_MULTIPOINT) == 0)
303         {
304             /* The Provider doesn't actually support Multipoint */
305             Status = WSAEINVAL;
306             goto error;
307         }
308         AfdPacket->EndpointFlags |= AFD_ENDPOINT_MULTIPOINT;
309 
310         if (dwFlags & WSA_FLAG_MULTIPOINT_C_ROOT)
311         {
312             if (((Socket->SharedData->ServiceFlags1 & XP1_MULTIPOINT_CONTROL_PLANE) == 0)
313                 || ((dwFlags & WSA_FLAG_MULTIPOINT_C_LEAF) != 0))
314             {
315                 /* The Provider doesn't support Control Planes, or you already gave a leaf */
316                 Status = WSAEINVAL;
317                 goto error;
318             }
319             AfdPacket->EndpointFlags |= AFD_ENDPOINT_C_ROOT;
320         }
321 
322         if (dwFlags & WSA_FLAG_MULTIPOINT_D_ROOT)
323         {
324             if (((Socket->SharedData->ServiceFlags1 & XP1_MULTIPOINT_DATA_PLANE) == 0)
325                 || ((dwFlags & WSA_FLAG_MULTIPOINT_D_LEAF) != 0))
326             {
327                 /* The Provider doesn't support Data Planes, or you already gave a leaf */
328                 Status = WSAEINVAL;
329                 goto error;
330             }
331             AfdPacket->EndpointFlags |= AFD_ENDPOINT_D_ROOT;
332         }
333     }
334 
335     /* Set up Object Attributes */
336     InitializeObjectAttributes (&Object,
337                                 &DevName,
338                                 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
339                                 0,
340                                 0);
341 
342     /* Create the Socket as asynchronous. That means we have to block
343     ourselves after every call to NtDeviceIoControlFile. This is
344     because the kernel doesn't support overlapping synchronous I/O
345     requests (made from multiple threads) at this time (Sep 2005) */
346     Status = NtCreateFile(&Sock,
347                           GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
348                           &Object,
349                           &IOSB,
350                           NULL,
351                           0,
352                           FILE_SHARE_READ | FILE_SHARE_WRITE,
353                           FILE_OPEN_IF,
354                           0,
355                           EABuffer,
356                           SizeOfEA);
357 
358     HeapFree(GlobalHeap, 0, EABuffer);
359 
360     if (!NT_SUCCESS(Status))
361     {
362         ERR("Failed to open socket. Status 0x%08x\n", Status);
363         Status = TranslateNtStatusError(Status);
364         goto error;
365     }
366 
367     /* Save Handle */
368     Socket->Handle = (SOCKET)Sock;
369 
370     /* Save Group Info */
371     if (g != 0)
372     {
373         GetSocketInformation(Socket,
374                              AFD_INFO_GROUP_ID_TYPE,
375                              NULL,
376                              NULL,
377                              &GroupData,
378                              NULL,
379                              NULL);
380         Socket->SharedData->GroupID = GroupData.u.LowPart;
381         Socket->SharedData->GroupType = GroupData.u.HighPart;
382     }
383 
384     /* Get Window Sizes and Save them */
385     GetSocketInformation (Socket,
386                           AFD_INFO_SEND_WINDOW_SIZE,
387                           NULL,
388                           &Socket->SharedData->SizeOfSendBuffer,
389                           NULL,
390                           NULL,
391                           NULL);
392 
393     GetSocketInformation (Socket,
394                           AFD_INFO_RECEIVE_WINDOW_SIZE,
395                           NULL,
396                           &Socket->SharedData->SizeOfRecvBuffer,
397                           NULL,
398                           NULL,
399                           NULL);
400 ok:
401 
402     /* Save in Process Sockets List */
403     EnterCriticalSection(&SocketListLock);
404     Socket->NextSocket = SocketListHead;
405     SocketListHead = Socket;
406     LeaveCriticalSection(&SocketListLock);
407 
408     /* Create the Socket Context */
409     CreateContext(Socket);
410 
411     /* Notify Winsock */
412     Upcalls.lpWPUModifyIFSHandle(Socket->ProtocolInfo.dwCatalogEntryId, (SOCKET)Sock, lpErrno);
413 
414     /* Return Socket Handle */
415     TRACE("Success %x\n", Sock);
416 
417     return (SOCKET)Sock;
418 
419 error:
420     ERR("Ending %x\n", Status);
421 
422     if( SharedData )
423     {
424         UnmapViewOfFile(SharedData);
425         NtClose((HANDLE)lpProtocolInfo->dwServiceFlags3);
426     }
427     else
428     {
429         if( Socket && Socket->SharedData )
430             HeapFree(GlobalHeap, 0, Socket->SharedData);
431     }
432 
433     if( Socket )
434         HeapFree(GlobalHeap, 0, Socket);
435 
436     if( EABuffer )
437         HeapFree(GlobalHeap, 0, EABuffer);
438 
439     if( lpErrno )
440         *lpErrno = Status;
441 
442     return INVALID_SOCKET;
443 }
444 
445 
446 INT
447 WSPAPI
448 WSPDuplicateSocket(
449     IN  SOCKET Handle,
450     IN  DWORD dwProcessId,
451     OUT LPWSAPROTOCOL_INFOW lpProtocolInfo,
452     OUT LPINT lpErrno)
453 {
454     HANDLE hProcess, hDuplicatedSharedData, hDuplicatedHandle;
455     PSOCKET_INFORMATION Socket;
456     PSOCK_SHARED_INFO pSharedData, pOldSharedData;
457     BOOL bDuplicated;
458 
459     if (Handle == INVALID_SOCKET)
460         return MsafdReturnWithErrno(STATUS_INVALID_PARAMETER, lpErrno, 0, NULL);
461     Socket = GetSocketStructure(Handle);
462     if( !Socket )
463     {
464         if( lpErrno )
465             *lpErrno = WSAENOTSOCK;
466         return SOCKET_ERROR;
467     }
468     if ( !(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId)) )
469         return MsafdReturnWithErrno(STATUS_INVALID_PARAMETER, lpErrno, 0, NULL);
470 
471     /* It is a not yet duplicated socket, so map the memory, copy the SharedData and free heap */
472     if( Socket->SharedDataHandle == INVALID_HANDLE_VALUE )
473     {
474         Socket->SharedDataHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
475                                                      NULL,
476                                                      PAGE_READWRITE | SEC_COMMIT,
477                                                      0,
478                                                      (sizeof(SOCK_SHARED_INFO) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1),
479                                                      NULL);
480         if( Socket->SharedDataHandle == INVALID_HANDLE_VALUE )
481             return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
482         pSharedData = MapViewOfFile(Socket->SharedDataHandle,
483                                     FILE_MAP_ALL_ACCESS,
484                                     0,
485                                     0,
486                                     sizeof(SOCK_SHARED_INFO));
487 
488         RtlCopyMemory(pSharedData, Socket->SharedData, sizeof(SOCK_SHARED_INFO));
489         pOldSharedData = Socket->SharedData;
490         Socket->SharedData = pSharedData;
491         HeapFree(GlobalHeap, 0, pOldSharedData);
492     }
493     /* Duplicate the handles for the new process */
494     bDuplicated = DuplicateHandle(GetCurrentProcess(),
495                                   Socket->SharedDataHandle,
496                                   hProcess,
497                                   (LPHANDLE)&hDuplicatedSharedData,
498                                   0,
499                                   FALSE,
500                                   DUPLICATE_SAME_ACCESS);
501     if (!bDuplicated)
502     {
503         NtClose(hProcess);
504         return MsafdReturnWithErrno(STATUS_ACCESS_DENIED, lpErrno, 0, NULL);
505     }
506     bDuplicated = DuplicateHandle(GetCurrentProcess(),
507                                   (HANDLE)Socket->Handle,
508                                   hProcess,
509                                   (LPHANDLE)&hDuplicatedHandle,
510                                   0,
511                                   FALSE,
512                                   DUPLICATE_SAME_ACCESS);
513     NtClose(hProcess);
514     if( !bDuplicated )
515         return MsafdReturnWithErrno(STATUS_ACCESS_DENIED, lpErrno, 0, NULL);
516 
517 
518     if (!lpProtocolInfo)
519         return MsafdReturnWithErrno(STATUS_ACCESS_VIOLATION, lpErrno, 0, NULL);
520 
521     RtlCopyMemory(lpProtocolInfo, &Socket->ProtocolInfo, sizeof(*lpProtocolInfo));
522 
523     lpProtocolInfo->iAddressFamily = Socket->SharedData->AddressFamily;
524     lpProtocolInfo->iProtocol = Socket->SharedData->Protocol;
525     lpProtocolInfo->iSocketType = Socket->SharedData->SocketType;
526     lpProtocolInfo->dwServiceFlags3 = (DWORD)hDuplicatedSharedData;
527     lpProtocolInfo->dwServiceFlags4 = (DWORD)hDuplicatedHandle;
528 
529     if( lpErrno )
530         *lpErrno = NO_ERROR;
531 
532     return NO_ERROR;
533 }
534 
535 INT
536 TranslateNtStatusError(NTSTATUS Status)
537 {
538     switch (Status)
539     {
540        case STATUS_CANT_WAIT:
541           return WSAEWOULDBLOCK;
542 
543        case STATUS_TIMEOUT:
544           return WSAETIMEDOUT;
545 
546        case STATUS_SUCCESS:
547           return NO_ERROR;
548 
549        case STATUS_FILE_CLOSED:
550          return WSAECONNRESET;
551 
552        case STATUS_END_OF_FILE:
553           return WSAESHUTDOWN;
554 
555        case STATUS_PENDING:
556           return WSA_IO_PENDING;
557 
558        case STATUS_BUFFER_TOO_SMALL:
559        case STATUS_BUFFER_OVERFLOW:
560           return WSAEMSGSIZE;
561 
562        case STATUS_NO_MEMORY:
563        case STATUS_INSUFFICIENT_RESOURCES:
564           return WSAENOBUFS;
565 
566        case STATUS_INVALID_CONNECTION:
567           return WSAENOTCONN;
568 
569        case STATUS_PROTOCOL_NOT_SUPPORTED:
570           return WSAEAFNOSUPPORT;
571 
572        case STATUS_INVALID_ADDRESS:
573           return WSAEADDRNOTAVAIL;
574 
575        case STATUS_REMOTE_NOT_LISTENING:
576        case STATUS_REMOTE_DISCONNECT:
577           return WSAECONNREFUSED;
578 
579        case STATUS_NETWORK_UNREACHABLE:
580           return WSAENETUNREACH;
581 
582        case STATUS_INVALID_PARAMETER:
583           return WSAEINVAL;
584 
585        case STATUS_CANCELLED:
586           return WSA_OPERATION_ABORTED;
587 
588        case STATUS_ADDRESS_ALREADY_EXISTS:
589           return WSAEADDRINUSE;
590 
591        case STATUS_LOCAL_DISCONNECT:
592           return WSAECONNABORTED;
593 
594        case STATUS_ACCESS_VIOLATION:
595           return WSAEFAULT;
596 
597        case STATUS_ACCESS_DENIED:
598           return WSAEACCES;
599 
600        case STATUS_NOT_IMPLEMENTED:
601           return WSAEOPNOTSUPP;
602 
603        default:
604           ERR("MSAFD: Unhandled NTSTATUS value: 0x%x\n", Status);
605           return WSAENETDOWN;
606     }
607 }
608 
609 /*
610  * FUNCTION: Closes an open socket
611  * ARGUMENTS:
612  *     s       = Socket descriptor
613  *     lpErrno = Address of buffer for error information
614  * RETURNS:
615  *     NO_ERROR, or SOCKET_ERROR if the socket could not be closed
616  */
617 INT
618 WSPAPI
619 WSPCloseSocket(IN SOCKET Handle,
620                OUT LPINT lpErrno)
621 {
622     IO_STATUS_BLOCK IoStatusBlock;
623     PSOCKET_INFORMATION Socket = NULL, CurrentSocket;
624     NTSTATUS Status;
625     HANDLE SockEvent;
626     AFD_DISCONNECT_INFO DisconnectInfo;
627     SOCKET_STATE OldState;
628     LONG LingerWait = -1;
629     DWORD References;
630 
631     /* Get the Socket Structure associate to this Socket*/
632     Socket = GetSocketStructure(Handle);
633     if (!Socket)
634     {
635        if (lpErrno) *lpErrno = WSAENOTSOCK;
636        return SOCKET_ERROR;
637     }
638 
639     /* Create the Wait Event */
640     Status = NtCreateEvent(&SockEvent,
641                            EVENT_ALL_ACCESS,
642                            NULL,
643                            SynchronizationEvent,
644                            FALSE);
645 
646     if(!NT_SUCCESS(Status))
647     {
648         ERR("NtCreateEvent failed: 0x%08x", Status);
649         return SOCKET_ERROR;
650     }
651 
652     if (Socket->HelperEvents & WSH_NOTIFY_CLOSE)
653     {
654         Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
655                                                Socket->Handle,
656                                                Socket->TdiAddressHandle,
657                                                Socket->TdiConnectionHandle,
658                                                WSH_NOTIFY_CLOSE);
659 
660         if (Status)
661         {
662             if (lpErrno) *lpErrno = Status;
663             ERR("WSHNotify failed. Error 0x%#x", Status);
664             NtClose(SockEvent);
665             return SOCKET_ERROR;
666         }
667     }
668 
669     /* If a Close is already in Process, give up */
670     if (Socket->SharedData->State == SocketClosed)
671     {
672         WARN("Socket is closing.\n");
673         NtClose(SockEvent);
674         if (lpErrno) *lpErrno = WSAENOTSOCK;
675         return SOCKET_ERROR;
676     }
677 
678     /* Decrement reference count on SharedData */
679     References = InterlockedDecrement(&Socket->SharedData->RefCount);
680     if (References)
681         goto ok;
682 
683     /* Set the state to close */
684     OldState = Socket->SharedData->State;
685     Socket->SharedData->State = SocketClosed;
686 
687     /* If SO_LINGER is ON and the Socket is connected, we need to disconnect */
688     /* FIXME: Should we do this on Datagram Sockets too? */
689     if ((OldState == SocketConnected) && (Socket->SharedData->LingerData.l_onoff))
690     {
691         ULONG SendsInProgress;
692         ULONG SleepWait;
693 
694         /* We need to respect the timeout */
695         SleepWait = 100;
696         LingerWait = Socket->SharedData->LingerData.l_linger * 1000;
697 
698         /* Loop until no more sends are pending, within the timeout */
699         while (LingerWait)
700         {
701             /* Find out how many Sends are in Progress */
702             if (GetSocketInformation(Socket,
703                                      AFD_INFO_SENDS_IN_PROGRESS,
704                                      NULL,
705                                      &SendsInProgress,
706                                      NULL,
707                                      NULL,
708                                      NULL))
709             {
710                 /* Bail out if anything but NO_ERROR */
711                 LingerWait = 0;
712                 break;
713             }
714 
715             /* Bail out if no more sends are pending */
716             if (!SendsInProgress)
717             {
718                 LingerWait = -1;
719                 break;
720             }
721 
722             /*
723              * We have to execute a sleep, so it's kind of like
724              * a block. If the socket is Nonblock, we cannot
725              * go on since asynchronous operation is expected
726              * and we cannot offer it
727              */
728             if (Socket->SharedData->NonBlocking)
729             {
730                 WARN("Would block!\n");
731                 NtClose(SockEvent);
732                 Socket->SharedData->State = OldState;
733                 if (lpErrno) *lpErrno = WSAEWOULDBLOCK;
734                 return SOCKET_ERROR;
735             }
736 
737             /* Now we can sleep, and decrement the linger wait */
738             /*
739             * FIXME: It seems Windows does some funky acceleration
740             * since the waiting seems to be longer and longer. I
741             * don't think this improves performance so much, so we
742             * wait a fixed time instead.
743             */
744             Sleep(SleepWait);
745             LingerWait -= SleepWait;
746         }
747     }
748 
749     if (OldState == SocketConnected)
750     {
751         if (LingerWait <= 0)
752         {
753             DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(0);
754             DisconnectInfo.DisconnectType = LingerWait < 0 ? AFD_DISCONNECT_SEND : AFD_DISCONNECT_ABORT;
755 
756             if (((DisconnectInfo.DisconnectType & AFD_DISCONNECT_SEND) && (!Socket->SharedData->SendShutdown)) ||
757                 ((DisconnectInfo.DisconnectType & AFD_DISCONNECT_ABORT) && (!Socket->SharedData->ReceiveShutdown)))
758             {
759                 /* Send IOCTL */
760                 Status = NtDeviceIoControlFile((HANDLE)Handle,
761                                                SockEvent,
762                                                NULL,
763                                                NULL,
764                                                &IoStatusBlock,
765                                                IOCTL_AFD_DISCONNECT,
766                                                &DisconnectInfo,
767                                                sizeof(DisconnectInfo),
768                                                NULL,
769                                                0);
770 
771                 /* Wait for return */
772                 if (Status == STATUS_PENDING)
773                 {
774                     WaitForSingleObject(SockEvent, INFINITE);
775                     Status = IoStatusBlock.Status;
776                 }
777             }
778         }
779     }
780 
781     /* Cleanup Time! */
782     Socket->HelperContext = NULL;
783     Socket->SharedData->AsyncDisabledEvents = -1;
784     NtClose(Socket->TdiAddressHandle);
785     Socket->TdiAddressHandle = NULL;
786     NtClose(Socket->TdiConnectionHandle);
787     Socket->TdiConnectionHandle = NULL;
788 ok:
789     EnterCriticalSection(&SocketListLock);
790     if (SocketListHead == Socket)
791     {
792         SocketListHead = SocketListHead->NextSocket;
793     }
794     else
795     {
796         CurrentSocket = SocketListHead;
797         while (CurrentSocket->NextSocket)
798         {
799             if (CurrentSocket->NextSocket == Socket)
800             {
801                 CurrentSocket->NextSocket = CurrentSocket->NextSocket->NextSocket;
802                 break;
803             }
804 
805             CurrentSocket = CurrentSocket->NextSocket;
806         }
807     }
808     LeaveCriticalSection(&SocketListLock);
809 
810     /* Close the handle */
811     NtClose((HANDLE)Handle);
812     NtClose(SockEvent);
813 
814     if( Socket->SharedDataHandle != INVALID_HANDLE_VALUE )
815     {
816         /* It is a duplicated socket, so unmap the memory */
817         UnmapViewOfFile(Socket->SharedData);
818         NtClose(Socket->SharedDataHandle);
819         Socket->SharedData = NULL;
820     }
821     if( !References && Socket->SharedData )
822     {
823         HeapFree(GlobalHeap, 0, Socket->SharedData);
824     }
825     HeapFree(GlobalHeap, 0, Socket);
826     return MsafdReturnWithErrno(Status, lpErrno, 0, NULL);
827 }
828 
829 
830 /*
831  * FUNCTION: Associates a local address with a socket
832  * ARGUMENTS:
833  *     s       = Socket descriptor
834  *     name    = Pointer to local address
835  *     namelen = Length of name
836  *     lpErrno = Address of buffer for error information
837  * RETURNS:
838  *     0, or SOCKET_ERROR if the socket could not be bound
839  */
840 INT
841 WSPAPI
842 WSPBind(SOCKET Handle,
843         const struct sockaddr *SocketAddress,
844         int SocketAddressLength,
845         LPINT lpErrno)
846 {
847     IO_STATUS_BLOCK         IOSB;
848     PAFD_BIND_DATA          BindData;
849     PSOCKET_INFORMATION     Socket = NULL;
850     NTSTATUS                Status;
851     SOCKADDR_INFO           SocketInfo;
852     HANDLE                  SockEvent;
853 
854     /* Get the Socket Structure associate to this Socket*/
855     Socket = GetSocketStructure(Handle);
856     if (!Socket)
857     {
858        if (lpErrno) *lpErrno = WSAENOTSOCK;
859        return SOCKET_ERROR;
860     }
861     if (Socket->SharedData->State != SocketOpen)
862     {
863        if (lpErrno) *lpErrno = WSAEINVAL;
864        return SOCKET_ERROR;
865     }
866     if (!SocketAddress || SocketAddressLength < Socket->SharedData->SizeOfLocalAddress)
867     {
868         if (lpErrno) *lpErrno = WSAEINVAL;
869         return SOCKET_ERROR;
870     }
871 
872     /* Get Address Information */
873     Socket->HelperData->WSHGetSockaddrType ((PSOCKADDR)SocketAddress,
874                                             SocketAddressLength,
875                                             &SocketInfo);
876 
877     if (SocketInfo.AddressInfo == SockaddrAddressInfoBroadcast && !Socket->SharedData->Broadcast)
878     {
879        if (lpErrno) *lpErrno = WSAEADDRNOTAVAIL;
880        return SOCKET_ERROR;
881     }
882 
883     Status = NtCreateEvent(&SockEvent,
884                            EVENT_ALL_ACCESS,
885                            NULL,
886                            SynchronizationEvent,
887                            FALSE);
888 
889     if (!NT_SUCCESS(Status))
890     {
891         return SOCKET_ERROR;
892     }
893 
894     /* See below */
895     BindData = HeapAlloc(GlobalHeap, 0, 0xA + SocketAddressLength);
896     if (!BindData)
897     {
898         return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
899     }
900 
901     /* Set up Address in TDI Format */
902     BindData->Address.TAAddressCount = 1;
903     BindData->Address.Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
904     BindData->Address.Address[0].AddressType = SocketAddress->sa_family;
905     RtlCopyMemory (BindData->Address.Address[0].Address,
906                    SocketAddress->sa_data,
907                    SocketAddressLength - sizeof(SocketAddress->sa_family));
908 
909     /* Set the Share Type */
910     if (Socket->SharedData->ExclusiveAddressUse)
911     {
912         BindData->ShareType = AFD_SHARE_EXCLUSIVE;
913     }
914     else if (SocketInfo.EndpointInfo == SockaddrEndpointInfoWildcard)
915     {
916         BindData->ShareType = AFD_SHARE_WILDCARD;
917     }
918     else if (Socket->SharedData->ReuseAddresses)
919     {
920         BindData->ShareType = AFD_SHARE_REUSE;
921     }
922     else
923     {
924         BindData->ShareType = AFD_SHARE_UNIQUE;
925     }
926 
927     /* Send IOCTL */
928     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
929                                    SockEvent,
930                                    NULL,
931                                    NULL,
932                                    &IOSB,
933                                    IOCTL_AFD_BIND,
934                                    BindData,
935                                    0xA + Socket->SharedData->SizeOfLocalAddress, /* Can't figure out a way to calculate this in C*/
936                                    BindData,
937                                    0xA + Socket->SharedData->SizeOfLocalAddress); /* Can't figure out a way to calculate this C */
938 
939     /* Wait for return */
940     if (Status == STATUS_PENDING)
941     {
942         WaitForSingleObject(SockEvent, INFINITE);
943         Status = IOSB.Status;
944     }
945 
946     NtClose( SockEvent );
947     HeapFree(GlobalHeap, 0, BindData);
948 
949     Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
950     if (Status != STATUS_SUCCESS)
951         return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
952 
953     /* Set up Socket Data */
954     Socket->SharedData->State = SocketBound;
955     Socket->TdiAddressHandle = (HANDLE)IOSB.Information;
956 
957     if (Socket->HelperEvents & WSH_NOTIFY_BIND)
958     {
959         Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
960                                                Socket->Handle,
961                                                Socket->TdiAddressHandle,
962                                                Socket->TdiConnectionHandle,
963                                                WSH_NOTIFY_BIND);
964 
965         if (Status)
966         {
967             if (lpErrno) *lpErrno = Status;
968             return SOCKET_ERROR;
969         }
970     }
971 
972     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
973 }
974 
975 int
976 WSPAPI
977 WSPListen(SOCKET Handle,
978           int Backlog,
979           LPINT lpErrno)
980 {
981     IO_STATUS_BLOCK         IOSB;
982     AFD_LISTEN_DATA         ListenData;
983     PSOCKET_INFORMATION     Socket = NULL;
984     HANDLE                  SockEvent;
985     NTSTATUS                Status;
986 
987     /* Get the Socket Structure associate to this Socket*/
988     Socket = GetSocketStructure(Handle);
989     if (!Socket)
990     {
991        if (lpErrno) *lpErrno = WSAENOTSOCK;
992        return SOCKET_ERROR;
993     }
994 
995     if (Socket->SharedData->Listening)
996         return NO_ERROR;
997 
998     Status = NtCreateEvent(&SockEvent,
999                            EVENT_ALL_ACCESS,
1000                            NULL,
1001                            SynchronizationEvent,
1002                            FALSE);
1003 
1004     if( !NT_SUCCESS(Status) )
1005         return SOCKET_ERROR;
1006 
1007     /* Set Up Listen Structure */
1008     ListenData.UseSAN = FALSE;
1009     ListenData.UseDelayedAcceptance = Socket->SharedData->UseDelayedAcceptance;
1010     ListenData.Backlog = Backlog;
1011 
1012     /* Send IOCTL */
1013     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1014                                    SockEvent,
1015                                    NULL,
1016                                    NULL,
1017                                    &IOSB,
1018                                    IOCTL_AFD_START_LISTEN,
1019                                    &ListenData,
1020                                    sizeof(ListenData),
1021                                    NULL,
1022                                    0);
1023 
1024     /* Wait for return */
1025     if (Status == STATUS_PENDING)
1026     {
1027         WaitForSingleObject(SockEvent, INFINITE);
1028         Status = IOSB.Status;
1029     }
1030 
1031     NtClose( SockEvent );
1032 
1033     Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
1034     if (Status != STATUS_SUCCESS)
1035        return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
1036 
1037     /* Set to Listening */
1038     Socket->SharedData->Listening = TRUE;
1039 
1040     if (Socket->HelperEvents & WSH_NOTIFY_LISTEN)
1041     {
1042         Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
1043                                                Socket->Handle,
1044                                                Socket->TdiAddressHandle,
1045                                                Socket->TdiConnectionHandle,
1046                                                WSH_NOTIFY_LISTEN);
1047 
1048         if (Status)
1049         {
1050            if (lpErrno) *lpErrno = Status;
1051            return SOCKET_ERROR;
1052         }
1053     }
1054 
1055     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
1056 }
1057 
1058 
1059 int
1060 WSPAPI
1061 WSPSelect(IN int nfds,
1062           IN OUT fd_set *readfds OPTIONAL,
1063           IN OUT fd_set *writefds OPTIONAL,
1064           IN OUT fd_set *exceptfds OPTIONAL,
1065           IN const struct timeval *timeout OPTIONAL,
1066           OUT LPINT lpErrno)
1067 {
1068     IO_STATUS_BLOCK     IOSB;
1069     PAFD_POLL_INFO      PollInfo;
1070     NTSTATUS            Status;
1071     ULONG               HandleCount;
1072     ULONG               PollBufferSize;
1073     PVOID               PollBuffer;
1074     ULONG               i, j = 0, x;
1075     HANDLE              SockEvent;
1076     LARGE_INTEGER       Timeout;
1077     PSOCKET_INFORMATION Socket;
1078     SOCKET              Handle;
1079     ULONG               Events;
1080     fd_set              selectfds;
1081 
1082     /* Find out how many sockets we have, and how large the buffer needs
1083      * to be */
1084     FD_ZERO(&selectfds);
1085     if (readfds != NULL)
1086     {
1087         for (i = 0; i < readfds->fd_count; i++)
1088         {
1089             FD_SET(readfds->fd_array[i], &selectfds);
1090         }
1091     }
1092     if (writefds != NULL)
1093     {
1094         for (i = 0; i < writefds->fd_count; i++)
1095         {
1096             FD_SET(writefds->fd_array[i], &selectfds);
1097         }
1098     }
1099     if (exceptfds != NULL)
1100     {
1101         for (i = 0; i < exceptfds->fd_count; i++)
1102         {
1103             FD_SET(exceptfds->fd_array[i], &selectfds);
1104         }
1105     }
1106 
1107     HandleCount = selectfds.fd_count;
1108 
1109     if ( HandleCount == 0 )
1110     {
1111         WARN("No handles! Returning SOCKET_ERROR\n", HandleCount);
1112         if (lpErrno) *lpErrno = WSAEINVAL;
1113         return SOCKET_ERROR;
1114     }
1115 
1116     PollBufferSize = sizeof(*PollInfo) + ((HandleCount - 1) * sizeof(AFD_HANDLE));
1117 
1118     TRACE("HandleCount: %u BufferSize: %u\n", HandleCount, PollBufferSize);
1119 
1120     /* Convert Timeout to NT Format */
1121     if (timeout == NULL)
1122     {
1123         Timeout.u.LowPart = -1;
1124         Timeout.u.HighPart = 0x7FFFFFFF;
1125         TRACE("Infinite timeout\n");
1126     }
1127     else
1128     {
1129         Timeout = RtlEnlargedIntegerMultiply
1130             ((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000), -10000);
1131         /* Negative timeouts are illegal.  Since the kernel represents an
1132          * incremental timeout as a negative number, we check for a positive
1133          * result.
1134          */
1135         if (Timeout.QuadPart > 0)
1136         {
1137             if (lpErrno) *lpErrno = WSAEINVAL;
1138             return SOCKET_ERROR;
1139         }
1140         TRACE("Timeout: Orig %d.%06d kernel %d\n",
1141                      timeout->tv_sec, timeout->tv_usec,
1142                      Timeout.u.LowPart);
1143     }
1144 
1145     Status = NtCreateEvent(&SockEvent,
1146                            EVENT_ALL_ACCESS,
1147                            NULL,
1148                            SynchronizationEvent,
1149                            FALSE);
1150 
1151     if(!NT_SUCCESS(Status))
1152     {
1153         if (lpErrno)
1154             *lpErrno = WSAEFAULT;
1155 
1156         ERR("NtCreateEvent failed, 0x%08x\n", Status);
1157         return SOCKET_ERROR;
1158     }
1159 
1160     /* Allocate */
1161     PollBuffer = HeapAlloc(GlobalHeap, 0, PollBufferSize);
1162 
1163     if (!PollBuffer)
1164     {
1165         if (lpErrno)
1166             *lpErrno = WSAEFAULT;
1167         NtClose(SockEvent);
1168         return SOCKET_ERROR;
1169     }
1170 
1171     PollInfo = (PAFD_POLL_INFO)PollBuffer;
1172 
1173     RtlZeroMemory( PollInfo, PollBufferSize );
1174 
1175     /* Number of handles for AFD to Check */
1176     PollInfo->Exclusive = FALSE;
1177     PollInfo->Timeout = Timeout;
1178 
1179     for (i = 0; i < selectfds.fd_count; i++)
1180     {
1181         PollInfo->Handles[i].Handle = selectfds.fd_array[i];
1182     }
1183     if (readfds != NULL) {
1184         for (i = 0; i < readfds->fd_count; i++)
1185         {
1186             for (j = 0; j < HandleCount; j++)
1187             {
1188                 if (PollInfo->Handles[j].Handle == readfds->fd_array[i])
1189                     break;
1190             }
1191             if (j >= HandleCount)
1192             {
1193                 ERR("Error while counting readfds %ld > %ld\n", j, HandleCount);
1194                 if (lpErrno) *lpErrno = WSAEFAULT;
1195                 HeapFree(GlobalHeap, 0, PollBuffer);
1196                 NtClose(SockEvent);
1197                 return SOCKET_ERROR;
1198             }
1199             Socket = GetSocketStructure(readfds->fd_array[i]);
1200             if (!Socket)
1201             {
1202                 ERR("Invalid socket handle provided in readfds %d\n", readfds->fd_array[i]);
1203                 if (lpErrno) *lpErrno = WSAENOTSOCK;
1204                 HeapFree(GlobalHeap, 0, PollBuffer);
1205                 NtClose(SockEvent);
1206                 return SOCKET_ERROR;
1207             }
1208             PollInfo->Handles[j].Events |= AFD_EVENT_RECEIVE |
1209                                            AFD_EVENT_DISCONNECT |
1210                                            AFD_EVENT_ABORT |
1211                                            AFD_EVENT_CLOSE |
1212                                            AFD_EVENT_ACCEPT;
1213             //if (Socket->SharedData->OobInline != 0)
1214             //    PollInfo->Handles[j].Events |= AFD_EVENT_OOB_RECEIVE;
1215         }
1216     }
1217     if (writefds != NULL)
1218     {
1219         for (i = 0; i < writefds->fd_count; i++)
1220         {
1221             for (j = 0; j < HandleCount; j++)
1222             {
1223                 if (PollInfo->Handles[j].Handle == writefds->fd_array[i])
1224                     break;
1225             }
1226             if (j >= HandleCount)
1227             {
1228                 ERR("Error while counting writefds %ld > %ld\n", j, HandleCount);
1229                 if (lpErrno) *lpErrno = WSAEFAULT;
1230                 HeapFree(GlobalHeap, 0, PollBuffer);
1231                 NtClose(SockEvent);
1232                 return SOCKET_ERROR;
1233             }
1234             Socket = GetSocketStructure(writefds->fd_array[i]);
1235             if (!Socket)
1236             {
1237                 ERR("Invalid socket handle provided in writefds %d\n", writefds->fd_array[i]);
1238                 if (lpErrno) *lpErrno = WSAENOTSOCK;
1239                 HeapFree(GlobalHeap, 0, PollBuffer);
1240                 NtClose(SockEvent);
1241                 return SOCKET_ERROR;
1242             }
1243             PollInfo->Handles[j].Handle = writefds->fd_array[i];
1244             PollInfo->Handles[j].Events |= AFD_EVENT_SEND;
1245             if (Socket->SharedData->NonBlocking != 0)
1246                 PollInfo->Handles[j].Events |= AFD_EVENT_CONNECT;
1247         }
1248     }
1249     if (exceptfds != NULL)
1250     {
1251         for (i = 0; i < exceptfds->fd_count; i++)
1252         {
1253             for (j = 0; j < HandleCount; j++)
1254             {
1255                 if (PollInfo->Handles[j].Handle == exceptfds->fd_array[i])
1256                     break;
1257             }
1258             if (j > HandleCount)
1259             {
1260                 ERR("Error while counting exceptfds %ld > %ld\n", j, HandleCount);
1261                 if (lpErrno) *lpErrno = WSAEFAULT;
1262                 HeapFree(GlobalHeap, 0, PollBuffer);
1263                 NtClose(SockEvent);
1264                 return SOCKET_ERROR;
1265             }
1266             Socket = GetSocketStructure(exceptfds->fd_array[i]);
1267             if (!Socket)
1268             {
1269                 TRACE("Invalid socket handle provided in exceptfds %d\n", exceptfds->fd_array[i]);
1270                 if (lpErrno) *lpErrno = WSAENOTSOCK;
1271                 HeapFree(GlobalHeap, 0, PollBuffer);
1272                 NtClose(SockEvent);
1273                 return SOCKET_ERROR;
1274             }
1275             PollInfo->Handles[j].Handle = exceptfds->fd_array[i];
1276             if (Socket->SharedData->OobInline == 0)
1277                 PollInfo->Handles[j].Events |= AFD_EVENT_OOB_RECEIVE;
1278             if (Socket->SharedData->NonBlocking != 0)
1279                 PollInfo->Handles[j].Events |= AFD_EVENT_CONNECT_FAIL;
1280         }
1281     }
1282 
1283     PollInfo->HandleCount = HandleCount;
1284     PollBufferSize = FIELD_OFFSET(AFD_POLL_INFO, Handles) + PollInfo->HandleCount * sizeof(AFD_HANDLE);
1285 
1286     /* Send IOCTL */
1287     Status = NtDeviceIoControlFile((HANDLE)PollInfo->Handles[0].Handle,
1288                                    SockEvent,
1289                                    NULL,
1290                                    NULL,
1291                                    &IOSB,
1292                                    IOCTL_AFD_SELECT,
1293                                    PollInfo,
1294                                    PollBufferSize,
1295                                    PollInfo,
1296                                    PollBufferSize);
1297 
1298     TRACE("DeviceIoControlFile => %x\n", Status);
1299 
1300     /* Wait for Completion */
1301     if (Status == STATUS_PENDING)
1302     {
1303         WaitForSingleObject(SockEvent, INFINITE);
1304         Status = IOSB.Status;
1305     }
1306 
1307     /* Clear the Structures */
1308     if( readfds )
1309         FD_ZERO(readfds);
1310     if( writefds )
1311         FD_ZERO(writefds);
1312     if( exceptfds )
1313         FD_ZERO(exceptfds);
1314 
1315     /* Loop through return structure */
1316     HandleCount = PollInfo->HandleCount;
1317 
1318     /* Return in FDSET Format */
1319     for (i = 0; i < HandleCount; i++)
1320     {
1321         Events = PollInfo->Handles[i].Events;
1322         Handle = PollInfo->Handles[i].Handle;
1323         for(x = 1; x; x<<=1)
1324         {
1325             Socket = GetSocketStructure(Handle);
1326             if (!Socket)
1327             {
1328                 TRACE("Invalid socket handle found %d\n", Handle);
1329                 if (lpErrno) *lpErrno = WSAENOTSOCK;
1330                 HeapFree(GlobalHeap, 0, PollBuffer);
1331                 NtClose(SockEvent);
1332                 return SOCKET_ERROR;
1333             }
1334             switch (Events & x)
1335             {
1336                 case AFD_EVENT_RECEIVE:
1337                 case AFD_EVENT_DISCONNECT:
1338                 case AFD_EVENT_ABORT:
1339                 case AFD_EVENT_ACCEPT:
1340                 case AFD_EVENT_CLOSE:
1341                     TRACE("Event %x on handle %x\n",
1342                         Events,
1343                         Handle);
1344                     if ((Events & x) == AFD_EVENT_DISCONNECT || (Events & x) == AFD_EVENT_CLOSE)
1345                         Socket->SharedData->SocketLastError = WSAECONNRESET;
1346                     if ((Events & x) == AFD_EVENT_ABORT)
1347                         Socket->SharedData->SocketLastError = WSAECONNABORTED;
1348                     if( readfds )
1349                         FD_SET(Handle, readfds);
1350                     break;
1351                 case AFD_EVENT_SEND:
1352                     TRACE("Event %x on handle %x\n",
1353                         Events,
1354                         Handle);
1355                     if (writefds)
1356                         FD_SET(Handle, writefds);
1357                     break;
1358                 case AFD_EVENT_CONNECT:
1359                     TRACE("Event %x on handle %x\n",
1360                         Events,
1361                         Handle);
1362                     if( writefds && Socket->SharedData->NonBlocking != 0 )
1363                         FD_SET(Handle, writefds);
1364                     break;
1365                 case AFD_EVENT_OOB_RECEIVE:
1366                     TRACE("Event %x on handle %x\n",
1367                         Events,
1368                         Handle);
1369                     if( readfds && Socket->SharedData->OobInline != 0 )
1370                         FD_SET(Handle, readfds);
1371                     if( exceptfds && Socket->SharedData->OobInline == 0 )
1372                         FD_SET(Handle, exceptfds);
1373                     break;
1374                 case AFD_EVENT_CONNECT_FAIL:
1375                     TRACE("Event %x on handle %x\n",
1376                         Events,
1377                         Handle);
1378                     if( exceptfds && Socket->SharedData->NonBlocking != 0 )
1379                         FD_SET(Handle, exceptfds);
1380                     break;
1381             }
1382         }
1383     }
1384 
1385     HeapFree( GlobalHeap, 0, PollBuffer );
1386     NtClose( SockEvent );
1387 
1388     if( lpErrno )
1389     {
1390         switch( IOSB.Status )
1391         {
1392             case STATUS_SUCCESS:
1393             case STATUS_TIMEOUT:
1394                 *lpErrno = 0;
1395                 break;
1396             default:
1397                 *lpErrno = WSAEINVAL;
1398                 break;
1399         }
1400         TRACE("*lpErrno = %x\n", *lpErrno);
1401     }
1402 
1403     HandleCount = (readfds ? readfds->fd_count : 0) +
1404                   (writefds && writefds != readfds ? writefds->fd_count : 0) +
1405                   (exceptfds && exceptfds != readfds && exceptfds != writefds ? exceptfds->fd_count : 0);
1406 
1407     TRACE("%d events\n", HandleCount);
1408 
1409     return HandleCount;
1410 }
1411 
1412 DWORD
1413 GetCurrentTimeInSeconds(VOID)
1414 {
1415     SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
1416     union
1417     {
1418         FILETIME ft;
1419         ULONGLONG ll;
1420     } u1970, Time;
1421 
1422     GetSystemTimeAsFileTime(&Time.ft);
1423     SystemTimeToFileTime(&st1970, &u1970.ft);
1424     return (DWORD)((Time.ll - u1970.ll) / 10000000ULL);
1425 }
1426 
1427 SOCKET
1428 WSPAPI
1429 WSPAccept(SOCKET Handle,
1430           struct sockaddr *SocketAddress,
1431           int *SocketAddressLength,
1432           LPCONDITIONPROC lpfnCondition,
1433           DWORD dwCallbackData,
1434           LPINT lpErrno)
1435 {
1436     IO_STATUS_BLOCK             IOSB;
1437     PAFD_RECEIVED_ACCEPT_DATA   ListenReceiveData;
1438     AFD_ACCEPT_DATA             AcceptData;
1439     AFD_DEFER_ACCEPT_DATA       DeferData;
1440     AFD_PENDING_ACCEPT_DATA     PendingAcceptData;
1441     PSOCKET_INFORMATION         Socket = NULL;
1442     NTSTATUS                    Status;
1443     struct fd_set               ReadSet;
1444     struct timeval              Timeout;
1445     PVOID                       PendingData = NULL;
1446     ULONG                       PendingDataLength = 0;
1447     PVOID                       CalleeDataBuffer;
1448     WSABUF                      CallerData, CalleeID, CallerID, CalleeData;
1449     PSOCKADDR                   RemoteAddress =  NULL;
1450     GROUP                       GroupID = 0;
1451     ULONG                       CallBack;
1452     SOCKET                      AcceptSocket;
1453     PSOCKET_INFORMATION         AcceptSocketInfo;
1454     UCHAR                       ReceiveBuffer[0x1A];
1455     HANDLE                      SockEvent;
1456 
1457     /* Get the Socket Structure associate to this Socket*/
1458     Socket = GetSocketStructure(Handle);
1459     if (!Socket)
1460     {
1461        if (lpErrno) *lpErrno = WSAENOTSOCK;
1462        return SOCKET_ERROR;
1463     }
1464     if (!Socket->SharedData->Listening)
1465     {
1466        if (lpErrno) *lpErrno = WSAEINVAL;
1467        return SOCKET_ERROR;
1468     }
1469     if ((SocketAddress && !SocketAddressLength) ||
1470         (SocketAddressLength && !SocketAddress) ||
1471         (SocketAddressLength && *SocketAddressLength < sizeof(SOCKADDR)))
1472     {
1473        if (lpErrno) *lpErrno = WSAEFAULT;
1474        return INVALID_SOCKET;
1475     }
1476 
1477     Status = NtCreateEvent(&SockEvent,
1478                            EVENT_ALL_ACCESS,
1479                            NULL,
1480                            SynchronizationEvent,
1481                            FALSE);
1482 
1483     if( !NT_SUCCESS(Status) )
1484     {
1485         return SOCKET_ERROR;
1486     }
1487 
1488     /* Dynamic Structure...ugh */
1489     ListenReceiveData = (PAFD_RECEIVED_ACCEPT_DATA)ReceiveBuffer;
1490 
1491     /* If this is non-blocking, make sure there's something for us to accept */
1492     FD_ZERO(&ReadSet);
1493     FD_SET(Socket->Handle, &ReadSet);
1494     Timeout.tv_sec=0;
1495     Timeout.tv_usec=0;
1496 
1497     if (WSPSelect(0, &ReadSet, NULL, NULL, &Timeout, lpErrno) == SOCKET_ERROR)
1498     {
1499         NtClose(SockEvent);
1500         return SOCKET_ERROR;
1501     }
1502 
1503     if (ReadSet.fd_array[0] != Socket->Handle)
1504     {
1505         NtClose(SockEvent);
1506         if (lpErrno) *lpErrno = WSAEWOULDBLOCK;
1507         return SOCKET_ERROR;
1508     }
1509 
1510     /* Send IOCTL */
1511     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1512                                    SockEvent,
1513                                    NULL,
1514                                    NULL,
1515                                    &IOSB,
1516                                    IOCTL_AFD_WAIT_FOR_LISTEN,
1517                                    NULL,
1518                                    0,
1519                                    ListenReceiveData,
1520                                    0xA + sizeof(*ListenReceiveData));
1521 
1522     /* Wait for return */
1523     if (Status == STATUS_PENDING)
1524     {
1525         WaitForSingleObject(SockEvent, INFINITE);
1526         Status = IOSB.Status;
1527     }
1528 
1529     if (!NT_SUCCESS(Status))
1530     {
1531         NtClose( SockEvent );
1532         return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1533     }
1534 
1535     if (lpfnCondition != NULL)
1536     {
1537         if ((Socket->SharedData->ServiceFlags1 & XP1_CONNECT_DATA) != 0)
1538         {
1539             /* Find out how much data is pending */
1540             PendingAcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
1541             PendingAcceptData.ReturnSize = TRUE;
1542 
1543             /* Send IOCTL */
1544             Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1545                                            SockEvent,
1546                                            NULL,
1547                                            NULL,
1548                                            &IOSB,
1549                                            IOCTL_AFD_GET_PENDING_CONNECT_DATA,
1550                                            &PendingAcceptData,
1551                                            sizeof(PendingAcceptData),
1552                                            &PendingAcceptData,
1553                                            sizeof(PendingAcceptData));
1554 
1555             /* Wait for return */
1556             if (Status == STATUS_PENDING)
1557             {
1558                 WaitForSingleObject(SockEvent, INFINITE);
1559                 Status = IOSB.Status;
1560             }
1561 
1562             if (!NT_SUCCESS(Status))
1563             {
1564                 NtClose( SockEvent );
1565                 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1566             }
1567 
1568             /* How much data to allocate */
1569             PendingDataLength = IOSB.Information;
1570 
1571             if (PendingDataLength)
1572             {
1573                 /* Allocate needed space */
1574                 PendingData = HeapAlloc(GlobalHeap, 0, PendingDataLength);
1575                 if (!PendingData)
1576                 {
1577                     return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
1578                 }
1579 
1580                 /* We want the data now */
1581                 PendingAcceptData.ReturnSize = FALSE;
1582 
1583                 /* Send IOCTL */
1584                 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1585                                                SockEvent,
1586                                                NULL,
1587                                                NULL,
1588                                                &IOSB,
1589                                                IOCTL_AFD_GET_PENDING_CONNECT_DATA,
1590                                                &PendingAcceptData,
1591                                                sizeof(PendingAcceptData),
1592                                                PendingData,
1593                                                PendingDataLength);
1594 
1595                 /* Wait for return */
1596                 if (Status == STATUS_PENDING)
1597                 {
1598                     WaitForSingleObject(SockEvent, INFINITE);
1599                     Status = IOSB.Status;
1600                 }
1601 
1602                 if (!NT_SUCCESS(Status))
1603                 {
1604                     NtClose( SockEvent );
1605                     return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1606                 }
1607             }
1608         }
1609 
1610         if ((Socket->SharedData->ServiceFlags1 & XP1_QOS_SUPPORTED) != 0)
1611         {
1612             /* I don't support this yet */
1613         }
1614 
1615         /* Build Callee ID */
1616         CalleeID.buf = (PVOID)Socket->LocalAddress;
1617         CalleeID.len = Socket->SharedData->SizeOfLocalAddress;
1618 
1619         RemoteAddress = HeapAlloc(GlobalHeap, 0, sizeof(*RemoteAddress));
1620         if (!RemoteAddress)
1621         {
1622             return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
1623         }
1624 
1625         /* Set up Address in SOCKADDR Format */
1626         RtlCopyMemory (RemoteAddress,
1627                        &ListenReceiveData->Address.Address[0].AddressType,
1628                        sizeof(*RemoteAddress));
1629 
1630         /* Build Caller ID */
1631         CallerID.buf = (PVOID)RemoteAddress;
1632         CallerID.len = sizeof(*RemoteAddress);
1633 
1634         /* Build Caller Data */
1635         CallerData.buf = PendingData;
1636         CallerData.len = PendingDataLength;
1637 
1638         /* Check if socket supports Conditional Accept */
1639         if (Socket->SharedData->UseDelayedAcceptance != 0)
1640         {
1641             /* Allocate Buffer for Callee Data */
1642             CalleeDataBuffer = HeapAlloc(GlobalHeap, 0, 4096);
1643             if (!CalleeDataBuffer) {
1644                 return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
1645             }
1646             CalleeData.buf = CalleeDataBuffer;
1647             CalleeData.len = 4096;
1648         }
1649         else
1650         {
1651             /* Nothing */
1652             CalleeData.buf = 0;
1653             CalleeData.len = 0;
1654         }
1655 
1656         /* Call the Condition Function */
1657         CallBack = (lpfnCondition)(&CallerID,
1658                                    CallerData.buf == NULL ? NULL : &CallerData,
1659                                    NULL,
1660                                    NULL,
1661                                    &CalleeID,
1662                                    CalleeData.buf == NULL ? NULL : &CalleeData,
1663                                    &GroupID,
1664                                    dwCallbackData);
1665 
1666         if (((CallBack == CF_ACCEPT) && GroupID) != 0)
1667         {
1668             /* TBD: Check for Validity */
1669         }
1670 
1671         if (CallBack == CF_ACCEPT)
1672         {
1673             if ((Socket->SharedData->ServiceFlags1 & XP1_QOS_SUPPORTED) != 0)
1674             {
1675                 /* I don't support this yet */
1676             }
1677             if (CalleeData.buf)
1678             {
1679                 // SockSetConnectData Sockets(SocketID), IOCTL_AFD_SET_CONNECT_DATA, CalleeData.Buffer, CalleeData.BuffSize, 0
1680             }
1681         }
1682         else
1683         {
1684             /* Callback rejected. Build Defer Structure */
1685             DeferData.SequenceNumber = ListenReceiveData->SequenceNumber;
1686             DeferData.RejectConnection = (CallBack == CF_REJECT);
1687 
1688             /* Send IOCTL */
1689             Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1690                                            SockEvent,
1691                                            NULL,
1692                                            NULL,
1693                                            &IOSB,
1694                                            IOCTL_AFD_DEFER_ACCEPT,
1695                                            &DeferData,
1696                                            sizeof(DeferData),
1697                                            NULL,
1698                                            0);
1699 
1700             /* Wait for return */
1701             if (Status == STATUS_PENDING)
1702             {
1703                 WaitForSingleObject(SockEvent, INFINITE);
1704                 Status = IOSB.Status;
1705             }
1706 
1707             NtClose( SockEvent );
1708 
1709             if (!NT_SUCCESS(Status))
1710             {
1711                 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1712             }
1713 
1714             if (CallBack == CF_REJECT )
1715             {
1716                 if (lpErrno) *lpErrno = WSAECONNREFUSED;
1717                 return SOCKET_ERROR;
1718             }
1719             else
1720             {
1721                 if (lpErrno) *lpErrno = WSAECONNREFUSED;
1722                 return SOCKET_ERROR;
1723             }
1724         }
1725     }
1726 
1727     /* Create a new Socket */
1728     AcceptSocket = WSPSocket (Socket->SharedData->AddressFamily,
1729                               Socket->SharedData->SocketType,
1730                               Socket->SharedData->Protocol,
1731                               &Socket->ProtocolInfo,
1732                               GroupID,
1733                               Socket->SharedData->CreateFlags,
1734                               lpErrno);
1735     if (AcceptSocket == INVALID_SOCKET)
1736         return SOCKET_ERROR;
1737 
1738     /* Set up the Accept Structure */
1739     AcceptData.ListenHandle = (HANDLE)AcceptSocket;
1740     AcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
1741 
1742     /* Send IOCTL to Accept */
1743     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1744                                    SockEvent,
1745                                    NULL,
1746                                    NULL,
1747                                    &IOSB,
1748                                    IOCTL_AFD_ACCEPT,
1749                                    &AcceptData,
1750                                    sizeof(AcceptData),
1751                                    NULL,
1752                                    0);
1753 
1754     /* Wait for return */
1755     if (Status == STATUS_PENDING)
1756     {
1757         WaitForSingleObject(SockEvent, INFINITE);
1758         Status = IOSB.Status;
1759     }
1760 
1761     Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
1762     if (!NT_SUCCESS(Status))
1763     {
1764         NtClose(SockEvent);
1765         WSPCloseSocket( AcceptSocket, lpErrno );
1766         return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1767     }
1768 
1769     AcceptSocketInfo = GetSocketStructure(AcceptSocket);
1770     if (!AcceptSocketInfo)
1771     {
1772         NtClose(SockEvent);
1773         WSPCloseSocket( AcceptSocket, lpErrno );
1774         return MsafdReturnWithErrno( STATUS_PROTOCOL_NOT_SUPPORTED, lpErrno, 0, NULL );
1775     }
1776 
1777     AcceptSocketInfo->SharedData->State = SocketConnected;
1778     AcceptSocketInfo->SharedData->ConnectTime = GetCurrentTimeInSeconds();
1779 
1780     /* Return Address in SOCKADDR FORMAT */
1781     if( SocketAddress )
1782     {
1783         RtlCopyMemory (SocketAddress,
1784                        &ListenReceiveData->Address.Address[0].AddressType,
1785                        sizeof(*RemoteAddress));
1786         if( SocketAddressLength )
1787             *SocketAddressLength = sizeof(*RemoteAddress);
1788     }
1789 
1790     NtClose( SockEvent );
1791 
1792     /* Re-enable Async Event */
1793     SockReenableAsyncSelectEvent(Socket, FD_ACCEPT);
1794 
1795     TRACE("Socket %x\n", AcceptSocket);
1796 
1797     if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_ACCEPT))
1798     {
1799         Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
1800                                                Socket->Handle,
1801                                                Socket->TdiAddressHandle,
1802                                                Socket->TdiConnectionHandle,
1803                                                WSH_NOTIFY_ACCEPT);
1804 
1805         if (Status)
1806         {
1807             if (lpErrno) *lpErrno = Status;
1808             return SOCKET_ERROR;
1809         }
1810     }
1811 
1812     if (lpErrno) *lpErrno = NO_ERROR;
1813 
1814     /* Return Socket */
1815     return AcceptSocket;
1816 }
1817 
1818 int
1819 WSPAPI
1820 WSPConnect(SOCKET Handle,
1821            const struct sockaddr * SocketAddress,
1822            int SocketAddressLength,
1823            LPWSABUF lpCallerData,
1824            LPWSABUF lpCalleeData,
1825            LPQOS lpSQOS,
1826            LPQOS lpGQOS,
1827            LPINT lpErrno)
1828 {
1829     IO_STATUS_BLOCK         IOSB;
1830     PAFD_CONNECT_INFO       ConnectInfo = NULL;
1831     PSOCKET_INFORMATION     Socket;
1832     NTSTATUS                Status;
1833     INT                     Errno;
1834     ULONG                   ConnectDataLength;
1835     ULONG                   InConnectDataLength;
1836     INT                     BindAddressLength;
1837     PSOCKADDR               BindAddress;
1838     HANDLE                  SockEvent;
1839     int                     SocketDataLength;
1840 
1841     TRACE("Called (%lx) %lx:%d\n", Handle, ((const struct sockaddr_in *)SocketAddress)->sin_addr, ((const struct sockaddr_in *)SocketAddress)->sin_port);
1842 
1843     /* Get the Socket Structure associate to this Socket*/
1844     Socket = GetSocketStructure(Handle);
1845     if (!Socket)
1846     {
1847         if (lpErrno) *lpErrno = WSAENOTSOCK;
1848         return SOCKET_ERROR;
1849     }
1850 
1851     Status = NtCreateEvent(&SockEvent,
1852                            EVENT_ALL_ACCESS,
1853                            NULL,
1854                            SynchronizationEvent,
1855                            FALSE);
1856 
1857     if (!NT_SUCCESS(Status))
1858         return SOCKET_ERROR;
1859 
1860     /* Bind us First */
1861     if (Socket->SharedData->State == SocketOpen)
1862     {
1863         /* Get the Wildcard Address */
1864         BindAddressLength = Socket->HelperData->MaxWSAddressLength;
1865         BindAddress = HeapAlloc(GetProcessHeap(), 0, BindAddressLength);
1866         if (!BindAddress)
1867         {
1868             NtClose(SockEvent);
1869             return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
1870         }
1871         Socket->HelperData->WSHGetWildcardSockaddr (Socket->HelperContext,
1872                                                     BindAddress,
1873                                                     &BindAddressLength);
1874         /* Bind it */
1875         if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
1876             return SOCKET_ERROR;
1877     }
1878 
1879     /* Set the Connect Data */
1880     if (lpCallerData != NULL)
1881     {
1882         ConnectDataLength = lpCallerData->len;
1883         Status = NtDeviceIoControlFile((HANDLE)Handle,
1884                                         SockEvent,
1885                                         NULL,
1886                                         NULL,
1887                                         &IOSB,
1888                                         IOCTL_AFD_SET_CONNECT_DATA,
1889                                         lpCallerData->buf,
1890                                         ConnectDataLength,
1891                                         NULL,
1892                                         0);
1893         /* Wait for return */
1894         if (Status == STATUS_PENDING)
1895         {
1896             WaitForSingleObject(SockEvent, INFINITE);
1897             Status = IOSB.Status;
1898         }
1899 
1900         if (Status != STATUS_SUCCESS)
1901             goto notify;
1902     }
1903 
1904     /* Calculate the size of SocketAddress->sa_data */
1905     SocketDataLength = SocketAddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
1906 
1907     /* Allocate a connection info buffer with SocketDataLength bytes of payload */
1908     ConnectInfo = HeapAlloc(GetProcessHeap(), 0,
1909                             FIELD_OFFSET(AFD_CONNECT_INFO,
1910                                          RemoteAddress.Address[0].Address[SocketDataLength]));
1911     if (!ConnectInfo)
1912     {
1913         Status = STATUS_INSUFFICIENT_RESOURCES;
1914         goto notify;
1915     }
1916 
1917     /* Set up Address in TDI Format */
1918     ConnectInfo->RemoteAddress.TAAddressCount = 1;
1919     ConnectInfo->RemoteAddress.Address[0].AddressLength = SocketDataLength;
1920     ConnectInfo->RemoteAddress.Address[0].AddressType = SocketAddress->sa_family;
1921     RtlCopyMemory(ConnectInfo->RemoteAddress.Address[0].Address,
1922                   SocketAddress->sa_data,
1923                   SocketDataLength);
1924 
1925     /*
1926     * Disable FD_WRITE and FD_CONNECT
1927     * The latter fixes a race condition where the FD_CONNECT is re-enabled
1928     * at the end of this function right after the Async Thread disables it.
1929     * This should only happen at the *next* WSPConnect
1930     */
1931     if (Socket->SharedData->AsyncEvents & FD_CONNECT)
1932     {
1933         Socket->SharedData->AsyncDisabledEvents |= FD_CONNECT | FD_WRITE;
1934     }
1935 
1936     /* Tell AFD that we want Connection Data back, have it allocate a buffer */
1937     if (lpCalleeData != NULL)
1938     {
1939         InConnectDataLength = lpCalleeData->len;
1940         Status = NtDeviceIoControlFile((HANDLE)Handle,
1941                                         SockEvent,
1942                                         NULL,
1943                                         NULL,
1944                                         &IOSB,
1945                                         IOCTL_AFD_SET_CONNECT_DATA_SIZE,
1946                                         &InConnectDataLength,
1947                                         sizeof(InConnectDataLength),
1948                                         NULL,
1949                                         0);
1950 
1951         /* Wait for return */
1952         if (Status == STATUS_PENDING)
1953         {
1954             WaitForSingleObject(SockEvent, INFINITE);
1955             Status = IOSB.Status;
1956         }
1957 
1958         if (Status != STATUS_SUCCESS)
1959             goto notify;
1960     }
1961 
1962     /* AFD doesn't seem to care if these are invalid, but let's 0 them anyways */
1963     ConnectInfo->Root = 0;
1964     ConnectInfo->UseSAN = FALSE;
1965     ConnectInfo->Unknown = 0;
1966 
1967     /* FIXME: Handle Async Connect */
1968     if (Socket->SharedData->NonBlocking)
1969     {
1970         ERR("Async Connect UNIMPLEMENTED!\n");
1971     }
1972 
1973     /* Send IOCTL */
1974     Status = NtDeviceIoControlFile((HANDLE)Handle,
1975                                    SockEvent,
1976                                    NULL,
1977                                    NULL,
1978                                    &IOSB,
1979                                    IOCTL_AFD_CONNECT,
1980                                    ConnectInfo,
1981                                    0x22,
1982                                    NULL,
1983                                    0);
1984     /* Wait for return */
1985     if (Status == STATUS_PENDING)
1986     {
1987         WaitForSingleObject(SockEvent, INFINITE);
1988         Status = IOSB.Status;
1989     }
1990 
1991     Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
1992     if (Status != STATUS_SUCCESS)
1993         goto notify;
1994 
1995     Socket->SharedData->State = SocketConnected;
1996     Socket->TdiConnectionHandle = (HANDLE)IOSB.Information;
1997     Socket->SharedData->ConnectTime = GetCurrentTimeInSeconds();
1998 
1999     /* Get any pending connect data */
2000     if (lpCalleeData != NULL)
2001     {
2002         Status = NtDeviceIoControlFile((HANDLE)Handle,
2003                                        SockEvent,
2004                                        NULL,
2005                                        NULL,
2006                                        &IOSB,
2007                                        IOCTL_AFD_GET_CONNECT_DATA,
2008                                        NULL,
2009                                        0,
2010                                        lpCalleeData->buf,
2011                                        lpCalleeData->len);
2012         /* Wait for return */
2013         if (Status == STATUS_PENDING)
2014         {
2015             WaitForSingleObject(SockEvent, INFINITE);
2016             Status = IOSB.Status;
2017         }
2018     }
2019 
2020     TRACE("Ending %lx\n", IOSB.Status);
2021 
2022 notify:
2023     if (ConnectInfo) HeapFree(GetProcessHeap(), 0, ConnectInfo);
2024 
2025     /* Re-enable Async Event */
2026     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
2027 
2028     /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
2029     SockReenableAsyncSelectEvent(Socket, FD_CONNECT);
2030 
2031     NtClose(SockEvent);
2032 
2033     if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT))
2034     {
2035         Errno = Socket->HelperData->WSHNotify(Socket->HelperContext,
2036                                               Socket->Handle,
2037                                               Socket->TdiAddressHandle,
2038                                               Socket->TdiConnectionHandle,
2039                                               WSH_NOTIFY_CONNECT);
2040 
2041         if (Errno)
2042         {
2043             if (lpErrno) *lpErrno = Errno;
2044             return SOCKET_ERROR;
2045         }
2046     }
2047     else if (Status != STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT_ERROR))
2048     {
2049         Errno = Socket->HelperData->WSHNotify(Socket->HelperContext,
2050                                               Socket->Handle,
2051                                               Socket->TdiAddressHandle,
2052                                               Socket->TdiConnectionHandle,
2053                                               WSH_NOTIFY_CONNECT_ERROR);
2054 
2055         if (Errno)
2056         {
2057             if (lpErrno) *lpErrno = Errno;
2058             return SOCKET_ERROR;
2059         }
2060     }
2061 
2062     return MsafdReturnWithErrno(Status, lpErrno, 0, NULL);
2063 }
2064 int
2065 WSPAPI
2066 WSPShutdown(SOCKET Handle,
2067             int HowTo,
2068             LPINT lpErrno)
2069 
2070 {
2071     IO_STATUS_BLOCK         IOSB;
2072     AFD_DISCONNECT_INFO     DisconnectInfo;
2073     PSOCKET_INFORMATION     Socket = NULL;
2074     NTSTATUS                Status;
2075     HANDLE                  SockEvent;
2076 
2077     TRACE("Called\n");
2078 
2079     /* Get the Socket Structure associate to this Socket*/
2080     Socket = GetSocketStructure(Handle);
2081     if (!Socket)
2082     {
2083        if (lpErrno) *lpErrno = WSAENOTSOCK;
2084        return SOCKET_ERROR;
2085     }
2086 
2087     Status = NtCreateEvent(&SockEvent,
2088                            EVENT_ALL_ACCESS,
2089                            NULL,
2090                            SynchronizationEvent,
2091                            FALSE);
2092 
2093     if( !NT_SUCCESS(Status) )
2094         return SOCKET_ERROR;
2095 
2096     /* Set AFD Disconnect Type */
2097     switch (HowTo)
2098     {
2099         case SD_RECEIVE:
2100             DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV;
2101             Socket->SharedData->ReceiveShutdown = TRUE;
2102             break;
2103         case SD_SEND:
2104             DisconnectInfo.DisconnectType= AFD_DISCONNECT_SEND;
2105             Socket->SharedData->SendShutdown = TRUE;
2106             break;
2107         case SD_BOTH:
2108             DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV | AFD_DISCONNECT_SEND;
2109             Socket->SharedData->ReceiveShutdown = TRUE;
2110             Socket->SharedData->SendShutdown = TRUE;
2111             break;
2112     }
2113 
2114     DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1000000);
2115 
2116     /* Send IOCTL */
2117     Status = NtDeviceIoControlFile((HANDLE)Handle,
2118                                    SockEvent,
2119                                    NULL,
2120                                    NULL,
2121                                    &IOSB,
2122                                    IOCTL_AFD_DISCONNECT,
2123                                    &DisconnectInfo,
2124                                    sizeof(DisconnectInfo),
2125                                    NULL,
2126                                    0);
2127 
2128     /* Wait for return */
2129     if (Status == STATUS_PENDING)
2130     {
2131         WaitForSingleObject(SockEvent, INFINITE);
2132         Status = IOSB.Status;
2133     }
2134 
2135     TRACE("Ending\n");
2136 
2137     NtClose( SockEvent );
2138 
2139     Socket->SharedData->SocketLastError = TranslateNtStatusError(Status);
2140     return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
2141 }
2142 
2143 
2144 INT
2145 WSPAPI
2146 WSPGetSockName(IN SOCKET Handle,
2147                OUT LPSOCKADDR Name,
2148                IN OUT LPINT NameLength,
2149                OUT LPINT lpErrno)
2150 {
2151     IO_STATUS_BLOCK         IOSB;
2152     ULONG                   TdiAddressSize;
2153     PTDI_ADDRESS_INFO       TdiAddress;
2154     PTRANSPORT_ADDRESS      SocketAddress;
2155     PSOCKET_INFORMATION     Socket = NULL;
2156     NTSTATUS                Status;
2157     HANDLE                  SockEvent;
2158 
2159     /* Get the Socket Structure associate to this Socket*/
2160     Socket = GetSocketStructure(Handle);
2161     if (!Socket)
2162     {
2163        if (lpErrno) *lpErrno = WSAENOTSOCK;
2164        return SOCKET_ERROR;
2165     }
2166 
2167     if (!Name || !NameLength)
2168     {
2169         if (lpErrno) *lpErrno = WSAEFAULT;
2170         return SOCKET_ERROR;
2171     }
2172 
2173     Status = NtCreateEvent(&SockEvent,
2174                            EVENT_ALL_ACCESS,
2175                            NULL,
2176                            SynchronizationEvent,
2177                            FALSE);
2178 
2179     if( !NT_SUCCESS(Status) )
2180         return SOCKET_ERROR;
2181 
2182     /* Allocate a buffer for the address */
2183     TdiAddressSize =
2184         sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfLocalAddress;
2185     TdiAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
2186 
2187     if ( TdiAddress == NULL )
2188     {
2189         NtClose( SockEvent );
2190         if (lpErrno) *lpErrno = WSAENOBUFS;
2191         return SOCKET_ERROR;
2192     }
2193 
2194     SocketAddress = &TdiAddress->Address;
2195 
2196     /* Send IOCTL */
2197     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
2198                                    SockEvent,
2199                                    NULL,
2200                                    NULL,
2201                                    &IOSB,
2202                                    IOCTL_AFD_GET_SOCK_NAME,
2203                                    NULL,
2204                                    0,
2205                                    TdiAddress,
2206                                    TdiAddressSize);
2207 
2208     /* Wait for return */
2209     if (Status == STATUS_PENDING)
2210     {
2211         WaitForSingleObject(SockEvent, INFINITE);
2212         Status = IOSB.Status;
2213     }
2214 
2215     NtClose( SockEvent );
2216 
2217     if (NT_SUCCESS(Status))
2218     {
2219         if (*NameLength >= Socket->SharedData->SizeOfLocalAddress)
2220         {
2221             Name->sa_family = SocketAddress->Address[0].AddressType;
2222             RtlCopyMemory (Name->sa_data,
2223                            SocketAddress->Address[0].Address,
2224                            SocketAddress->Address[0].AddressLength);
2225             *NameLength = Socket->SharedData->SizeOfLocalAddress;
2226             TRACE("NameLength %d Address: %x Port %x\n",
2227                           *NameLength, ((struct sockaddr_in *)Name)->sin_addr.s_addr,
2228                           ((struct sockaddr_in *)Name)->sin_port);
2229             HeapFree(GlobalHeap, 0, TdiAddress);
2230             return 0;
2231         }
2232         else
2233         {
2234             HeapFree(GlobalHeap, 0, TdiAddress);
2235             if (lpErrno) *lpErrno = WSAEFAULT;
2236             return SOCKET_ERROR;
2237         }
2238     }
2239 
2240     HeapFree(GlobalHeap, 0, TdiAddress);
2241 
2242     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
2243 }
2244 
2245 
2246 INT
2247 WSPAPI
2248 WSPGetPeerName(IN SOCKET s,
2249                OUT LPSOCKADDR Name,
2250                IN OUT LPINT NameLength,
2251                OUT LPINT lpErrno)
2252 {
2253     IO_STATUS_BLOCK         IOSB;
2254     ULONG                   TdiAddressSize;
2255     PTRANSPORT_ADDRESS      SocketAddress;
2256     PSOCKET_INFORMATION     Socket = NULL;
2257     NTSTATUS                Status;
2258     HANDLE                  SockEvent;
2259 
2260     /* Get the Socket Structure associate to this Socket*/
2261     Socket = GetSocketStructure(s);
2262     if (!Socket)
2263     {
2264         if (lpErrno) *lpErrno = WSAENOTSOCK;
2265         return SOCKET_ERROR;
2266     }
2267 
2268     if (Socket->SharedData->State != SocketConnected)
2269     {
2270         if (lpErrno) *lpErrno = WSAENOTCONN;
2271         return SOCKET_ERROR;
2272     }
2273 
2274     if (!Name || !NameLength)
2275     {
2276         if (lpErrno) *lpErrno = WSAEFAULT;
2277         return SOCKET_ERROR;
2278     }
2279 
2280     Status = NtCreateEvent(&SockEvent,
2281                            EVENT_ALL_ACCESS,
2282                            NULL,
2283                            SynchronizationEvent,
2284                            FALSE);
2285 
2286     if( !NT_SUCCESS(Status) )
2287         return SOCKET_ERROR;
2288 
2289     /* Allocate a buffer for the address */
2290     TdiAddressSize = sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfRemoteAddress;
2291     SocketAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
2292 
2293     if ( SocketAddress == NULL )
2294     {
2295         NtClose( SockEvent );
2296         if (lpErrno) *lpErrno = WSAENOBUFS;
2297         return SOCKET_ERROR;
2298     }
2299 
2300     /* Send IOCTL */
2301     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
2302                                    SockEvent,
2303                                    NULL,
2304                                    NULL,
2305                                    &IOSB,
2306                                    IOCTL_AFD_GET_PEER_NAME,
2307                                    NULL,
2308                                    0,
2309                                    SocketAddress,
2310                                    TdiAddressSize);
2311 
2312     /* Wait for return */
2313     if (Status == STATUS_PENDING)
2314     {
2315         WaitForSingleObject(SockEvent, INFINITE);
2316         Status = IOSB.Status;
2317     }
2318 
2319     NtClose( SockEvent );
2320 
2321     if (NT_SUCCESS(Status))
2322     {
2323         if (*NameLength >= Socket->SharedData->SizeOfRemoteAddress)
2324         {
2325             Name->sa_family = SocketAddress->Address[0].AddressType;
2326             RtlCopyMemory (Name->sa_data,
2327                            SocketAddress->Address[0].Address,
2328                            SocketAddress->Address[0].AddressLength);
2329             *NameLength = Socket->SharedData->SizeOfRemoteAddress;
2330             TRACE("NameLength %d Address: %x Port %x\n",
2331                           *NameLength, ((struct sockaddr_in *)Name)->sin_addr.s_addr,
2332                           ((struct sockaddr_in *)Name)->sin_port);
2333             HeapFree(GlobalHeap, 0, SocketAddress);
2334             return 0;
2335         }
2336         else
2337         {
2338             HeapFree(GlobalHeap, 0, SocketAddress);
2339             if (lpErrno) *lpErrno = WSAEFAULT;
2340             return SOCKET_ERROR;
2341         }
2342     }
2343 
2344     HeapFree(GlobalHeap, 0, SocketAddress);
2345 
2346     return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
2347 }
2348 
2349 INT
2350 WSPAPI
2351 WSPIoctl(IN  SOCKET Handle,
2352          IN  DWORD dwIoControlCode,
2353          IN  LPVOID lpvInBuffer,
2354          IN  DWORD cbInBuffer,
2355          OUT LPVOID lpvOutBuffer,
2356          IN  DWORD cbOutBuffer,
2357          OUT LPDWORD lpcbBytesReturned,
2358          IN  LPWSAOVERLAPPED lpOverlapped,
2359          IN  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
2360          IN  LPWSATHREADID lpThreadId,
2361          OUT LPINT lpErrno)
2362 {
2363     PSOCKET_INFORMATION Socket = NULL;
2364     BOOL NeedsCompletion = lpOverlapped != NULL;
2365     BOOLEAN NonBlocking;
2366     INT Errno = NO_ERROR, Ret = SOCKET_ERROR;
2367     DWORD cbRet = 0;
2368 
2369     /* Get the Socket Structure associate to this Socket*/
2370     Socket = GetSocketStructure(Handle);
2371     if (!Socket)
2372     {
2373         if(lpErrno)
2374             *lpErrno = WSAENOTSOCK;
2375         return SOCKET_ERROR;
2376     }
2377 
2378     if (!lpcbBytesReturned && !lpOverlapped)
2379     {
2380         if(lpErrno)
2381             *lpErrno = WSAEFAULT;
2382         return SOCKET_ERROR;
2383     }
2384 
2385     switch( dwIoControlCode )
2386     {
2387         case FIONBIO:
2388             if( cbInBuffer < sizeof(INT) || IS_INTRESOURCE(lpvInBuffer) )
2389             {
2390                 Errno = WSAEFAULT;
2391                 break;
2392             }
2393             NonBlocking = *((PULONG)lpvInBuffer) ? TRUE : FALSE;
2394             /* Don't allow to go in blocking mode if WSPAsyncSelect or WSPEventSelect is pending */
2395             if (!NonBlocking)
2396             {
2397                 /* If there is an WSPAsyncSelect pending, fail with WSAEINVAL */
2398                 if (Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents))
2399                 {
2400                     Errno = WSAEINVAL;
2401                     break;
2402                 }
2403                 /* If there is an WSPEventSelect pending, fail with WSAEINVAL */
2404                 if (Socket->NetworkEvents)
2405                 {
2406                     Errno = WSAEINVAL;
2407                     break;
2408                 }
2409             }
2410             Socket->SharedData->NonBlocking = NonBlocking ? 1 : 0;
2411             NeedsCompletion = FALSE;
2412             Errno = SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &NonBlocking, NULL, NULL, lpOverlapped, lpCompletionRoutine);
2413             if (Errno == NO_ERROR)
2414                 Ret = NO_ERROR;
2415             break;
2416         case FIONREAD:
2417             if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2418             {
2419                 cbRet = sizeof(ULONG);
2420                 Errno = WSAEFAULT;
2421                 break;
2422             }
2423             if (cbOutBuffer < sizeof(ULONG))
2424             {
2425                 Errno = WSAEINVAL;
2426                 break;
2427             }
2428             NeedsCompletion = FALSE;
2429             Errno = GetSocketInformation(Socket, AFD_INFO_RECEIVE_CONTENT_SIZE, NULL, (PULONG)lpvOutBuffer, NULL, lpOverlapped, lpCompletionRoutine);
2430             if (Errno == NO_ERROR)
2431             {
2432                 cbRet = sizeof(ULONG);
2433                 Ret = NO_ERROR;
2434             }
2435             break;
2436         case SIOCATMARK:
2437             if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2438             {
2439                 cbRet = sizeof(BOOL);
2440                 Errno = WSAEFAULT;
2441                 break;
2442             }
2443             if (cbOutBuffer < sizeof(BOOL))
2444             {
2445                 Errno = WSAEINVAL;
2446                 break;
2447             }
2448             if (Socket->SharedData->SocketType != SOCK_STREAM)
2449             {
2450                 Errno = WSAEINVAL;
2451                 break;
2452             }
2453 
2454             /* FIXME: Return false if OOBINLINE is true for now
2455                We should MSG_PEEK|MSG_OOB check with driver
2456             */
2457             *(BOOL*)lpvOutBuffer = !Socket->SharedData->OobInline;
2458 
2459             cbRet = sizeof(BOOL);
2460             Errno = NO_ERROR;
2461             Ret = NO_ERROR;
2462             break;
2463         case SIO_GET_EXTENSION_FUNCTION_POINTER:
2464             Errno = WSAEINVAL;
2465             break;
2466         case SIO_ADDRESS_LIST_QUERY:
2467             if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2468             {
2469                 cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress);
2470                 Errno = WSAEFAULT;
2471                 break;
2472             }
2473             if (cbOutBuffer < sizeof(INT))
2474             {
2475                 Errno = WSAEINVAL;
2476                 break;
2477             }
2478 
2479             cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress);
2480 
2481             ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->iAddressCount = 1;
2482 
2483             if (cbOutBuffer < (sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress)))
2484             {
2485                 Errno = WSAEFAULT;
2486                 break;
2487             }
2488 
2489             ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].iSockaddrLength = sizeof(Socket->SharedData->WSLocalAddress);
2490             ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].lpSockaddr = &Socket->SharedData->WSLocalAddress;
2491 
2492             Errno = NO_ERROR;
2493             Ret = NO_ERROR;
2494             break;
2495         default:
2496             Errno = Socket->HelperData->WSHIoctl(Socket->HelperContext,
2497                                                  Handle,
2498                                                  Socket->TdiAddressHandle,
2499                                                  Socket->TdiConnectionHandle,
2500                                                  dwIoControlCode,
2501                                                  lpvInBuffer,
2502                                                  cbInBuffer,
2503                                                  lpvOutBuffer,
2504                                                  cbOutBuffer,
2505                                                  &cbRet,
2506                                                  lpOverlapped,
2507                                                  lpCompletionRoutine,
2508                                                  &NeedsCompletion);
2509 
2510             if (Errno == NO_ERROR)
2511                 Ret = NO_ERROR;
2512             break;
2513     }
2514     if (lpOverlapped && NeedsCompletion)
2515     {
2516         lpOverlapped->Internal = Errno;
2517         lpOverlapped->InternalHigh = cbRet;
2518         if (lpCompletionRoutine != NULL)
2519         {
2520             lpCompletionRoutine(Errno, cbRet, lpOverlapped, 0);
2521         }
2522         if (lpOverlapped->hEvent)
2523             SetEvent(lpOverlapped->hEvent);
2524         if (!PostQueuedCompletionStatus((HANDLE)Handle, cbRet, 0, lpOverlapped))
2525         {
2526             ERR("PostQueuedCompletionStatus failed %d\n", GetLastError());
2527         }
2528         return NO_ERROR;
2529     }
2530     if (lpErrno)
2531         *lpErrno = Errno;
2532     if (lpcbBytesReturned)
2533         *lpcbBytesReturned = cbRet;
2534     return Ret;
2535 }
2536 
2537 
2538 INT
2539 WSPAPI
2540 WSPGetSockOpt(IN SOCKET Handle,
2541               IN INT Level,
2542               IN INT OptionName,
2543               OUT CHAR FAR* OptionValue,
2544               IN OUT LPINT OptionLength,
2545               OUT LPINT lpErrno)
2546 {
2547     PSOCKET_INFORMATION Socket = NULL;
2548     PVOID Buffer;
2549     INT BufferSize;
2550     BOOL BoolBuffer;
2551     DWORD DwordBuffer;
2552     INT Errno;
2553 
2554     TRACE("Called\n");
2555 
2556     /* Get the Socket Structure associate to this Socket*/
2557     Socket = GetSocketStructure(Handle);
2558     if (Socket == NULL)
2559     {
2560         if (lpErrno) *lpErrno = WSAENOTSOCK;
2561         return SOCKET_ERROR;
2562     }
2563     if (!OptionLength || !OptionValue)
2564     {
2565         if (lpErrno) *lpErrno = WSAEFAULT;
2566         return SOCKET_ERROR;
2567     }
2568 
2569     switch (Level)
2570     {
2571         case SOL_SOCKET:
2572             switch (OptionName)
2573             {
2574                 case SO_TYPE:
2575                     Buffer = &Socket->SharedData->SocketType;
2576                     BufferSize = sizeof(INT);
2577                     break;
2578 
2579                 case SO_RCVBUF:
2580                     Buffer = &Socket->SharedData->SizeOfRecvBuffer;
2581                     BufferSize = sizeof(INT);
2582                     break;
2583 
2584                 case SO_SNDBUF:
2585                     Buffer = &Socket->SharedData->SizeOfSendBuffer;
2586                     BufferSize = sizeof(INT);
2587                     break;
2588 
2589                 case SO_ACCEPTCONN:
2590                     BoolBuffer = Socket->SharedData->Listening;
2591                     Buffer = &BoolBuffer;
2592                     BufferSize = sizeof(BOOL);
2593                     break;
2594 
2595                 case SO_BROADCAST:
2596                     BoolBuffer = Socket->SharedData->Broadcast;
2597                     Buffer = &BoolBuffer;
2598                     BufferSize = sizeof(BOOL);
2599                     break;
2600 
2601                 case SO_DEBUG:
2602                     BoolBuffer = Socket->SharedData->Debug;
2603                     Buffer = &BoolBuffer;
2604                     BufferSize = sizeof(BOOL);
2605                     break;
2606 
2607                 case SO_DONTLINGER:
2608                     BoolBuffer = (Socket->SharedData->LingerData.l_onoff == 0);
2609                     Buffer = &BoolBuffer;
2610                     BufferSize = sizeof(BOOL);
2611                     break;
2612 
2613                 case SO_LINGER:
2614                     if (Socket->SharedData->SocketType == SOCK_DGRAM)
2615                     {
2616                         if (lpErrno) *lpErrno = WSAENOPROTOOPT;
2617                         return SOCKET_ERROR;
2618                     }
2619                     Buffer = &Socket->SharedData->LingerData;
2620                     BufferSize = sizeof(struct linger);
2621                     break;
2622 
2623                 case SO_OOBINLINE:
2624                     BoolBuffer = (Socket->SharedData->OobInline != 0);
2625                     Buffer = &BoolBuffer;
2626                     BufferSize = sizeof(BOOL);
2627                     break;
2628 
2629                 case SO_KEEPALIVE:
2630                 case SO_DONTROUTE:
2631                    /* These guys go directly to the helper */
2632                    goto SendToHelper;
2633 
2634                 case SO_CONDITIONAL_ACCEPT:
2635                     BoolBuffer = (Socket->SharedData->UseDelayedAcceptance != 0);
2636                     Buffer = &BoolBuffer;
2637                     BufferSize = sizeof(BOOL);
2638                     break;
2639 
2640                 case SO_REUSEADDR:
2641                     BoolBuffer = (Socket->SharedData->ReuseAddresses != 0);
2642                     Buffer = &BoolBuffer;
2643                     BufferSize = sizeof(BOOL);
2644                     break;
2645 
2646                 case SO_EXCLUSIVEADDRUSE:
2647                     BoolBuffer = (Socket->SharedData->ExclusiveAddressUse != 0);
2648                     Buffer = &BoolBuffer;
2649                     BufferSize = sizeof(BOOL);
2650                     break;
2651 
2652                 case SO_ERROR:
2653                     Buffer = &Socket->SharedData->SocketLastError;
2654                     BufferSize = sizeof(INT);
2655                     break;
2656 
2657                 case SO_CONNECT_TIME:
2658                     DwordBuffer = GetCurrentTimeInSeconds() - Socket->SharedData->ConnectTime;
2659                     Buffer = &DwordBuffer;
2660                     BufferSize = sizeof(DWORD);
2661                     break;
2662 
2663                 case SO_SNDTIMEO:
2664                     Buffer = &Socket->SharedData->SendTimeout;
2665                     BufferSize = sizeof(DWORD);
2666                     break;
2667                 case SO_RCVTIMEO:
2668                     Buffer = &Socket->SharedData->RecvTimeout;
2669                     BufferSize = sizeof(DWORD);
2670                     break;
2671                 case SO_PROTOCOL_INFOW:
2672                     Buffer = &Socket->ProtocolInfo;
2673                     BufferSize = sizeof(Socket->ProtocolInfo);
2674                     break;
2675 
2676                 case SO_GROUP_ID:
2677                 case SO_GROUP_PRIORITY:
2678                 case SO_MAX_MSG_SIZE:
2679 
2680                 default:
2681                     DbgPrint("MSAFD: Get unknown optname %x\n", OptionName);
2682                     if (lpErrno) *lpErrno = WSAENOPROTOOPT;
2683                     return SOCKET_ERROR;
2684             }
2685 
2686             if (*OptionLength < BufferSize)
2687             {
2688                 if (lpErrno) *lpErrno = WSAEFAULT;
2689                 *OptionLength = BufferSize;
2690                 return SOCKET_ERROR;
2691             }
2692             RtlCopyMemory(OptionValue, Buffer, BufferSize);
2693 
2694             return 0;
2695 
2696         default:
2697             if (lpErrno) *lpErrno = WSAEINVAL;
2698             return SOCKET_ERROR;
2699     }
2700 
2701 SendToHelper:
2702     Errno = Socket->HelperData->WSHGetSocketInformation(Socket->HelperContext,
2703                                                         Handle,
2704                                                         Socket->TdiAddressHandle,
2705                                                         Socket->TdiConnectionHandle,
2706                                                         Level,
2707                                                         OptionName,
2708                                                         OptionValue,
2709                                                         (LPINT)OptionLength);
2710     if (lpErrno) *lpErrno = Errno;
2711     return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
2712 }
2713 
2714 INT
2715 WSPAPI
2716 WSPSetSockOpt(
2717     IN  SOCKET s,
2718     IN  INT level,
2719     IN  INT optname,
2720     IN  CONST CHAR FAR* optval,
2721     IN  INT optlen,
2722     OUT LPINT lpErrno)
2723 {
2724     PSOCKET_INFORMATION Socket;
2725     INT Errno;
2726 
2727     /* Get the Socket Structure associate to this Socket*/
2728     Socket = GetSocketStructure(s);
2729     if (Socket == NULL)
2730     {
2731         if (lpErrno) *lpErrno = WSAENOTSOCK;
2732         return SOCKET_ERROR;
2733     }
2734     if (!optval)
2735     {
2736         if (lpErrno) *lpErrno = WSAEFAULT;
2737         return SOCKET_ERROR;
2738     }
2739 
2740 
2741     /* FIXME: We should handle some more cases here */
2742     if (level == SOL_SOCKET)
2743     {
2744         switch (optname)
2745         {
2746            case SO_BROADCAST:
2747               if (optlen < sizeof(BOOL))
2748               {
2749                   if (lpErrno) *lpErrno = WSAEFAULT;
2750                   return SOCKET_ERROR;
2751               }
2752               Socket->SharedData->Broadcast = (*optval != 0) ? 1 : 0;
2753               return NO_ERROR;
2754 
2755            case SO_OOBINLINE:
2756               if (optlen < sizeof(BOOL))
2757               {
2758                   if (lpErrno) *lpErrno = WSAEFAULT;
2759                   return SOCKET_ERROR;
2760               }
2761               Socket->SharedData->OobInline = (*optval != 0) ? 1 : 0;
2762               return NO_ERROR;
2763 
2764            case SO_DONTLINGER:
2765               if (optlen < sizeof(BOOL))
2766               {
2767                   if (lpErrno) *lpErrno = WSAEFAULT;
2768                   return SOCKET_ERROR;
2769               }
2770               Socket->SharedData->LingerData.l_onoff = (*optval != 0) ? 0 : 1;
2771               return NO_ERROR;
2772 
2773            case SO_REUSEADDR:
2774               if (optlen < sizeof(BOOL))
2775               {
2776                   if (lpErrno) *lpErrno = WSAEFAULT;
2777                   return SOCKET_ERROR;
2778               }
2779               Socket->SharedData->ReuseAddresses = (*optval != 0) ? 1 : 0;
2780               return NO_ERROR;
2781 
2782            case SO_EXCLUSIVEADDRUSE:
2783               if (optlen < sizeof(BOOL))
2784               {
2785                   if (lpErrno) *lpErrno = WSAEFAULT;
2786                   return SOCKET_ERROR;
2787               }
2788               Socket->SharedData->ExclusiveAddressUse = (*optval != 0) ? 1 : 0;
2789               return NO_ERROR;
2790 
2791            case SO_LINGER:
2792               if (optlen < sizeof(struct linger))
2793               {
2794                   if (lpErrno) *lpErrno = WSAEFAULT;
2795                   return SOCKET_ERROR;
2796               }
2797               RtlCopyMemory(&Socket->SharedData->LingerData,
2798                             optval,
2799                             sizeof(struct linger));
2800               return NO_ERROR;
2801 
2802            case SO_SNDBUF:
2803               if (optlen < sizeof(DWORD))
2804               {
2805                   if (lpErrno) *lpErrno = WSAEFAULT;
2806                   return SOCKET_ERROR;
2807               }
2808 
2809               /* TODO: The total per-socket buffer space reserved for sends */
2810               ERR("Setting send buf to %x is not implemented yet\n", optval);
2811               return NO_ERROR;
2812 
2813            case SO_ERROR:
2814               if (optlen < sizeof(INT))
2815               {
2816                   if (lpErrno) *lpErrno = WSAEFAULT;
2817                   return SOCKET_ERROR;
2818               }
2819 
2820               RtlCopyMemory(&Socket->SharedData->SocketLastError,
2821                             optval,
2822                             sizeof(INT));
2823               return NO_ERROR;
2824 
2825            case SO_SNDTIMEO:
2826               if (optlen < sizeof(DWORD))
2827               {
2828                   if (lpErrno) *lpErrno = WSAEFAULT;
2829                   return SOCKET_ERROR;
2830               }
2831 
2832               RtlCopyMemory(&Socket->SharedData->SendTimeout,
2833                             optval,
2834                             sizeof(DWORD));
2835               return NO_ERROR;
2836 
2837            case SO_RCVTIMEO:
2838               if (optlen < sizeof(DWORD))
2839               {
2840                   if (lpErrno) *lpErrno = WSAEFAULT;
2841                   return SOCKET_ERROR;
2842               }
2843 
2844               RtlCopyMemory(&Socket->SharedData->RecvTimeout,
2845                             optval,
2846                             sizeof(DWORD));
2847               return NO_ERROR;
2848 
2849            case SO_KEEPALIVE:
2850            case SO_DONTROUTE:
2851               /* These go directly to the helper dll */
2852               goto SendToHelper;
2853 
2854            default:
2855               /* Obviously this is a hack */
2856               ERR("MSAFD: Set unknown optname %x\n", optname);
2857               return NO_ERROR;
2858         }
2859     }
2860 
2861 SendToHelper:
2862     Errno = Socket->HelperData->WSHSetSocketInformation(Socket->HelperContext,
2863                                                         s,
2864                                                         Socket->TdiAddressHandle,
2865                                                         Socket->TdiConnectionHandle,
2866                                                         level,
2867                                                         optname,
2868                                                         (PCHAR)optval,
2869                                                         optlen);
2870     if (lpErrno) *lpErrno = Errno;
2871     return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
2872 }
2873 
2874 /*
2875  * FUNCTION: Initialize service provider for a client
2876  * ARGUMENTS:
2877  *     wVersionRequested = Highest WinSock SPI version that the caller can use
2878  *     lpWSPData         = Address of WSPDATA structure to initialize
2879  *     lpProtocolInfo    = Pointer to structure that defines the desired protocol
2880  *     UpcallTable       = Pointer to upcall table of the WinSock DLL
2881  *     lpProcTable       = Address of procedure table to initialize
2882  * RETURNS:
2883  *     Status of operation
2884  */
2885 INT
2886 WSPAPI
2887 WSPStartup(IN  WORD wVersionRequested,
2888            OUT LPWSPDATA lpWSPData,
2889            IN  LPWSAPROTOCOL_INFOW lpProtocolInfo,
2890            IN  WSPUPCALLTABLE UpcallTable,
2891            OUT LPWSPPROC_TABLE lpProcTable)
2892 
2893 {
2894     NTSTATUS Status;
2895 
2896     if (((LOBYTE(wVersionRequested) == 2) && (HIBYTE(wVersionRequested) < 2)) ||
2897         (LOBYTE(wVersionRequested) < 2))
2898     {
2899         ERR("WSPStartup NOT SUPPORTED for version 0x%X\n", wVersionRequested);
2900         return WSAVERNOTSUPPORTED;
2901     }
2902     else
2903         Status = NO_ERROR;
2904     /* FIXME: Enable all cases of WSPStartup status */
2905     Upcalls = UpcallTable;
2906 
2907     if (Status == NO_ERROR)
2908     {
2909         lpProcTable->lpWSPAccept = WSPAccept;
2910         lpProcTable->lpWSPAddressToString = WSPAddressToString;
2911         lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
2912         lpProcTable->lpWSPBind = WSPBind;
2913         lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
2914         lpProcTable->lpWSPCleanup = WSPCleanup;
2915         lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
2916         lpProcTable->lpWSPConnect = WSPConnect;
2917         lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
2918         lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
2919         lpProcTable->lpWSPEventSelect = WSPEventSelect;
2920         lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
2921         lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
2922         lpProcTable->lpWSPGetSockName = WSPGetSockName;
2923         lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
2924         lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
2925         lpProcTable->lpWSPIoctl = WSPIoctl;
2926         lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
2927         lpProcTable->lpWSPListen = WSPListen;
2928         lpProcTable->lpWSPRecv = WSPRecv;
2929         lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
2930         lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
2931         lpProcTable->lpWSPSelect = WSPSelect;
2932         lpProcTable->lpWSPSend = WSPSend;
2933         lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
2934         lpProcTable->lpWSPSendTo = WSPSendTo;
2935         lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
2936         lpProcTable->lpWSPShutdown = WSPShutdown;
2937         lpProcTable->lpWSPSocket = WSPSocket;
2938         lpProcTable->lpWSPStringToAddress = WSPStringToAddress;
2939         lpWSPData->wVersion     = MAKEWORD(2, 2);
2940         lpWSPData->wHighVersion = MAKEWORD(2, 2);
2941         /* Save CatalogEntryId for all upcalls */
2942         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
2943     }
2944 
2945     TRACE("Status (%d).\n", Status);
2946     return Status;
2947 }
2948 
2949 
2950 INT
2951 WSPAPI
2952 WSPAddressToString(IN LPSOCKADDR lpsaAddress,
2953                    IN DWORD dwAddressLength,
2954                    IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
2955                    OUT LPWSTR lpszAddressString,
2956                    IN OUT LPDWORD lpdwAddressStringLength,
2957                    OUT LPINT lpErrno)
2958 {
2959     DWORD size;
2960     WCHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
2961     WCHAR *p;
2962 
2963     if (!lpsaAddress || !lpszAddressString || !lpdwAddressStringLength)
2964     {
2965         if (lpErrno) *lpErrno = WSAEFAULT;
2966         return SOCKET_ERROR;
2967     }
2968 
2969     switch (lpsaAddress->sa_family)
2970     {
2971         case AF_INET:
2972             if (dwAddressLength < sizeof(SOCKADDR_IN))
2973             {
2974                 if (lpErrno) *lpErrno = WSAEINVAL;
2975                 return SOCKET_ERROR;
2976             }
2977             swprintf(buffer,
2978                      L"%u.%u.%u.%u:%u",
2979                      (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 24 & 0xff),
2980                      (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 16 & 0xff),
2981                      (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 8 & 0xff),
2982                      (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) & 0xff),
2983                      ntohs(((SOCKADDR_IN *)lpsaAddress)->sin_port));
2984 
2985             p = wcschr(buffer, L':');
2986             if (!((SOCKADDR_IN *)lpsaAddress)->sin_port)
2987             {
2988                 *p = 0;
2989             }
2990             break;
2991         default:
2992             if (lpErrno) *lpErrno = WSAEINVAL;
2993             return SOCKET_ERROR;
2994     }
2995 
2996     size = wcslen(buffer) + 1;
2997 
2998     if (*lpdwAddressStringLength < size)
2999     {
3000         *lpdwAddressStringLength = size;
3001         if (lpErrno) *lpErrno = WSAEFAULT;
3002         return SOCKET_ERROR;
3003     }
3004 
3005     *lpdwAddressStringLength = size;
3006     wcscpy(lpszAddressString, buffer);
3007     return 0;
3008 }
3009 
3010 INT
3011 WSPAPI
3012 WSPStringToAddress(IN LPWSTR AddressString,
3013                    IN INT AddressFamily,
3014                    IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
3015                    OUT LPSOCKADDR lpAddress,
3016                    IN OUT LPINT lpAddressLength,
3017                    OUT LPINT lpErrno)
3018 {
3019     int numdots = 0;
3020     USHORT port;
3021     LONG inetaddr = 0, ip_part;
3022     LPWSTR *bp = NULL;
3023     SOCKADDR_IN *sockaddr;
3024 
3025     if (!lpAddressLength || !lpAddress || !AddressString)
3026     {
3027         if (lpErrno) *lpErrno = WSAEINVAL;
3028         return SOCKET_ERROR;
3029     }
3030 
3031     sockaddr = (SOCKADDR_IN *)lpAddress;
3032 
3033     /* Set right address family */
3034     if (lpProtocolInfo != NULL)
3035     {
3036         sockaddr->sin_family = lpProtocolInfo->iAddressFamily;
3037     }
3038     else
3039     {
3040         sockaddr->sin_family = AddressFamily;
3041     }
3042 
3043     /* Report size */
3044     if (AddressFamily == AF_INET)
3045     {
3046         if (*lpAddressLength < (INT)sizeof(SOCKADDR_IN))
3047         {
3048             if (lpErrno) *lpErrno = WSAEFAULT;
3049         }
3050         else
3051         {
3052             // translate ip string to ip
3053 
3054             /* Get ip number */
3055             bp = &AddressString;
3056             inetaddr = 0;
3057 
3058             while (*bp < &AddressString[wcslen(AddressString)])
3059             {
3060                 ip_part = wcstol(*bp, bp, 10);
3061                 /* ip part number should be in range 0-255 */
3062                 if (ip_part < 0 || ip_part > 255)
3063                 {
3064                     if (lpErrno) *lpErrno = WSAEINVAL;
3065                     return SOCKET_ERROR;
3066                 }
3067                 inetaddr = (inetaddr << 8) + ip_part;
3068                 /* we end on string end or port separator */
3069                 if ((*bp)[0] == 0 || (*bp)[0] == L':')
3070                     break;
3071                 /* ip parts are dot separated. verify it */
3072                 if ((*bp)[0] != L'.')
3073                 {
3074                     if (lpErrno) *lpErrno = WSAEINVAL;
3075                     return SOCKET_ERROR;
3076                 }
3077                 /* count the dots */
3078                 numdots++;
3079                 /* move over the dot to next ip part */
3080                 (*bp)++;
3081             }
3082 
3083             /* check dots count */
3084             if (numdots != 3)
3085             {
3086                 if (lpErrno) *lpErrno = WSAEINVAL;
3087                 return SOCKET_ERROR;
3088             }
3089 
3090             /* Get port number */
3091             if ((*bp)[0] == L':')
3092             {
3093                 /* move over the column to port part */
3094                 (*bp)++;
3095                 /* next char should be numeric */
3096                 if ((*bp)[0] < L'0' || (*bp)[0] > L'9')
3097                 {
3098                     if (lpErrno) *lpErrno = WSAEINVAL;
3099                     return SOCKET_ERROR;
3100                 }
3101                 port = wcstol(*bp, bp, 10);
3102             }
3103             else
3104             {
3105                 port = 0;
3106             }
3107 
3108             if (lpErrno) *lpErrno = NO_ERROR;
3109             /* rest sockaddr.sin_addr.s_addr
3110             for we need to be sure it is zero when we come to while */
3111             *lpAddressLength = sizeof(*sockaddr);
3112             memset(lpAddress, 0, sizeof(*sockaddr));
3113             sockaddr->sin_family = AF_INET;
3114             sockaddr->sin_addr.s_addr = inetaddr;
3115             sockaddr->sin_port = port;
3116         }
3117     }
3118 
3119     if (lpErrno && !*lpErrno)
3120     {
3121         return 0;
3122     }
3123 
3124     return SOCKET_ERROR;
3125 }
3126 
3127 /*
3128  * FUNCTION: Cleans up service provider for a client
3129  * ARGUMENTS:
3130  *     lpErrno = Address of buffer for error information
3131  * RETURNS:
3132  *     0 if successful, or SOCKET_ERROR if not
3133  */
3134 INT
3135 WSPAPI
3136 WSPCleanup(OUT LPINT lpErrno)
3137 
3138 {
3139     TRACE("Leaving.\n");
3140 
3141     if (lpErrno) *lpErrno = NO_ERROR;
3142 
3143     return 0;
3144 }
3145 
3146 VOID
3147 NTAPI
3148 AfdInfoAPC(PVOID ApcContext,
3149     PIO_STATUS_BLOCK IoStatusBlock,
3150     ULONG Reserved)
3151 {
3152     PAFDAPCCONTEXT Context = ApcContext;
3153 
3154     Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0);
3155     HeapFree(GlobalHeap, 0, ApcContext);
3156 }
3157 
3158 int
3159 GetSocketInformation(PSOCKET_INFORMATION Socket,
3160                      ULONG AfdInformationClass,
3161                      PBOOLEAN Boolean OPTIONAL,
3162                      PULONG Ulong OPTIONAL,
3163                      PLARGE_INTEGER LargeInteger OPTIONAL,
3164                      LPWSAOVERLAPPED Overlapped OPTIONAL,
3165                      LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL)
3166 {
3167     PIO_STATUS_BLOCK    IOSB;
3168     IO_STATUS_BLOCK     DummyIOSB;
3169     AFD_INFO            InfoData;
3170     NTSTATUS            Status;
3171     PAFDAPCCONTEXT      APCContext;
3172     PIO_APC_ROUTINE     APCFunction;
3173     HANDLE              Event = NULL;
3174     HANDLE              SockEvent;
3175 
3176     Status = NtCreateEvent(&SockEvent,
3177                            EVENT_ALL_ACCESS,
3178                            NULL,
3179                            SynchronizationEvent,
3180                            FALSE);
3181 
3182     if( !NT_SUCCESS(Status) )
3183         return SOCKET_ERROR;
3184 
3185     /* Set Info Class */
3186     InfoData.InformationClass = AfdInformationClass;
3187 
3188     /* Verify if we should use APC */
3189     if (Overlapped == NULL)
3190     {
3191         /* Not using Overlapped structure, so use normal blocking on event */
3192         APCContext = NULL;
3193         APCFunction = NULL;
3194         Event = SockEvent;
3195         IOSB = &DummyIOSB;
3196     }
3197     else
3198     {
3199         /* Overlapped request for non overlapped opened socket */
3200         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
3201         {
3202             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
3203             return 0;
3204         }
3205         if (CompletionRoutine == NULL)
3206         {
3207             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
3208             APCContext = (PAFDAPCCONTEXT)Overlapped;
3209             APCFunction = NULL;
3210             Event = Overlapped->hEvent;
3211         }
3212         else
3213         {
3214             /* Using Overlapped Structure and a Completition Routine, so use an APC */
3215             APCFunction = &AfdInfoAPC; // should be a private io completition function inside us
3216             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
3217             if (!APCContext)
3218             {
3219                 ERR("Not enough memory for APC Context\n");
3220                 return WSAEFAULT;
3221             }
3222             APCContext->lpCompletionRoutine = CompletionRoutine;
3223             APCContext->lpOverlapped = Overlapped;
3224             APCContext->lpSocket = Socket;
3225         }
3226 
3227         IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
3228     }
3229 
3230     IOSB->Status = STATUS_PENDING;
3231 
3232     /* Send IOCTL */
3233     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3234                                    Event,
3235                                    APCFunction,
3236                                    APCContext,
3237                                    IOSB,
3238                                    IOCTL_AFD_GET_INFO,
3239                                    &InfoData,
3240                                    sizeof(InfoData),
3241                                    &InfoData,
3242                                    sizeof(InfoData));
3243 
3244     /* Wait for return */
3245     if (Status == STATUS_PENDING && Overlapped == NULL)
3246     {
3247         WaitForSingleObject(SockEvent, INFINITE);
3248         Status = IOSB->Status;
3249     }
3250 
3251     TRACE("Status %x Information %d\n", Status, IOSB->Information);
3252 
3253     if (Status == STATUS_PENDING)
3254     {
3255         TRACE("Leaving (Pending)\n");
3256         return WSA_IO_PENDING;
3257     }
3258 
3259     if (Status != STATUS_SUCCESS)
3260         return SOCKET_ERROR;
3261 
3262     /* Return Information */
3263     if (Ulong != NULL)
3264     {
3265         *Ulong = InfoData.Information.Ulong;
3266     }
3267     if (LargeInteger != NULL)
3268     {
3269         *LargeInteger = InfoData.Information.LargeInteger;
3270     }
3271     if (Boolean != NULL)
3272     {
3273         *Boolean = InfoData.Information.Boolean;
3274     }
3275 
3276     NtClose( SockEvent );
3277 
3278     return NO_ERROR;
3279 
3280 }
3281 
3282 
3283 int
3284 SetSocketInformation(PSOCKET_INFORMATION Socket,
3285                      ULONG AfdInformationClass,
3286                      PBOOLEAN Boolean OPTIONAL,
3287                      PULONG Ulong OPTIONAL,
3288                      PLARGE_INTEGER LargeInteger OPTIONAL,
3289                      LPWSAOVERLAPPED Overlapped OPTIONAL,
3290                      LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL)
3291 {
3292     PIO_STATUS_BLOCK    IOSB;
3293     IO_STATUS_BLOCK     DummyIOSB;
3294     AFD_INFO            InfoData;
3295     NTSTATUS            Status;
3296     PAFDAPCCONTEXT      APCContext;
3297     PIO_APC_ROUTINE     APCFunction;
3298     HANDLE              Event = NULL;
3299     HANDLE              SockEvent;
3300 
3301     Status = NtCreateEvent(&SockEvent,
3302                            EVENT_ALL_ACCESS,
3303                            NULL,
3304                            SynchronizationEvent,
3305                            FALSE);
3306 
3307     if( !NT_SUCCESS(Status) )
3308         return SOCKET_ERROR;
3309 
3310     /* Set Info Class */
3311     InfoData.InformationClass = AfdInformationClass;
3312 
3313     /* Set Information */
3314     if (Ulong != NULL)
3315     {
3316         InfoData.Information.Ulong = *Ulong;
3317     }
3318     if (LargeInteger != NULL)
3319     {
3320         InfoData.Information.LargeInteger = *LargeInteger;
3321     }
3322     if (Boolean != NULL)
3323     {
3324         InfoData.Information.Boolean = *Boolean;
3325     }
3326 
3327     /* Verify if we should use APC */
3328     if (Overlapped == NULL)
3329     {
3330         /* Not using Overlapped structure, so use normal blocking on event */
3331         APCContext = NULL;
3332         APCFunction = NULL;
3333         Event = SockEvent;
3334         IOSB = &DummyIOSB;
3335     }
3336     else
3337     {
3338         /* Overlapped request for non overlapped opened socket */
3339         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
3340         {
3341             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
3342             return 0;
3343         }
3344         if (CompletionRoutine == NULL)
3345         {
3346             /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
3347             APCContext = (PAFDAPCCONTEXT)Overlapped;
3348             APCFunction = NULL;
3349             Event = Overlapped->hEvent;
3350         }
3351         else
3352         {
3353             /* Using Overlapped Structure and a Completition Routine, so use an APC */
3354             APCFunction = &AfdInfoAPC; // should be a private io completition function inside us
3355             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
3356             if (!APCContext)
3357             {
3358                 ERR("Not enough memory for APC Context\n");
3359                 return WSAEFAULT;
3360             }
3361             APCContext->lpCompletionRoutine = CompletionRoutine;
3362             APCContext->lpOverlapped = Overlapped;
3363             APCContext->lpSocket = Socket;
3364         }
3365 
3366         IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
3367     }
3368 
3369     IOSB->Status = STATUS_PENDING;
3370 
3371     /* Send IOCTL */
3372     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3373                                    Event,
3374                                    APCFunction,
3375                                    APCContext,
3376                                    IOSB,
3377                                    IOCTL_AFD_SET_INFO,
3378                                    &InfoData,
3379                                    sizeof(InfoData),
3380                                    NULL,
3381                                    0);
3382 
3383     /* Wait for return */
3384     if (Status == STATUS_PENDING && Overlapped == NULL)
3385     {
3386         WaitForSingleObject(SockEvent, INFINITE);
3387         Status = IOSB->Status;
3388     }
3389 
3390     NtClose( SockEvent );
3391 
3392     TRACE("Status %x Information %d\n", Status, IOSB->Information);
3393 
3394     if (Status == STATUS_PENDING)
3395     {
3396         TRACE("Leaving (Pending)\n");
3397         return WSA_IO_PENDING;
3398     }
3399 
3400     return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
3401 
3402 }
3403 
3404 PSOCKET_INFORMATION
3405 GetSocketStructure(SOCKET Handle)
3406 {
3407     PSOCKET_INFORMATION CurrentSocket;
3408 
3409     EnterCriticalSection(&SocketListLock);
3410 
3411     CurrentSocket = SocketListHead;
3412     while (CurrentSocket)
3413     {
3414         if (CurrentSocket->Handle == Handle)
3415         {
3416             LeaveCriticalSection(&SocketListLock);
3417             return CurrentSocket;
3418         }
3419 
3420         CurrentSocket = CurrentSocket->NextSocket;
3421     }
3422 
3423     LeaveCriticalSection(&SocketListLock);
3424 
3425     return NULL;
3426 }
3427 
3428 int CreateContext(PSOCKET_INFORMATION Socket)
3429 {
3430     IO_STATUS_BLOCK     IOSB;
3431     SOCKET_CONTEXT      ContextData;
3432     NTSTATUS            Status;
3433     HANDLE              SockEvent;
3434 
3435     Status = NtCreateEvent(&SockEvent,
3436                            EVENT_ALL_ACCESS,
3437                            NULL,
3438                            SynchronizationEvent,
3439                            FALSE);
3440 
3441     if( !NT_SUCCESS(Status) )
3442         return SOCKET_ERROR;
3443 
3444     /* Create Context */
3445     ContextData.SharedData = *Socket->SharedData;
3446     ContextData.SizeOfHelperData = 0;
3447     RtlCopyMemory (&ContextData.LocalAddress,
3448                    Socket->LocalAddress,
3449                    Socket->SharedData->SizeOfLocalAddress);
3450     RtlCopyMemory (&ContextData.RemoteAddress,
3451                    Socket->RemoteAddress,
3452                    Socket->SharedData->SizeOfRemoteAddress);
3453 
3454     /* Send IOCTL */
3455     Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3456                                    SockEvent,
3457                                    NULL,
3458                                    NULL,
3459                                    &IOSB,
3460                                    IOCTL_AFD_SET_CONTEXT,
3461                                    &ContextData,
3462                                    sizeof(ContextData),
3463                                    NULL,
3464                                    0);
3465 
3466     /* Wait for Completion */
3467     if (Status == STATUS_PENDING)
3468     {
3469         WaitForSingleObject(SockEvent, INFINITE);
3470         Status = IOSB.Status;
3471     }
3472 
3473     NtClose( SockEvent );
3474 
3475     return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
3476 }
3477 
3478 BOOLEAN SockCreateOrReferenceAsyncThread(VOID)
3479 {
3480     HANDLE hAsyncThread;
3481     DWORD AsyncThreadId;
3482     HANDLE AsyncEvent;
3483     OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
3484     NTSTATUS Status;
3485 
3486     /* Check if the Thread Already Exists */
3487     if (SockAsyncThreadRefCount)
3488     {
3489         ASSERT(SockAsyncCompletionPort);
3490         return TRUE;
3491     }
3492 
3493     /* Create the Completion Port */
3494     if (!SockAsyncCompletionPort)
3495     {
3496         Status = NtCreateIoCompletion(&SockAsyncCompletionPort,
3497                                       IO_COMPLETION_ALL_ACCESS,
3498                                       NULL,
3499                                       2); // Allow 2 threads only
3500         if (!NT_SUCCESS(Status))
3501         {
3502              ERR("Failed to create completion port: 0x%08x\n", Status);
3503              return FALSE;
3504         }
3505         /* Protect Handle */
3506         HandleFlags.ProtectFromClose = TRUE;
3507         HandleFlags.Inherit = FALSE;
3508         Status = NtSetInformationObject(SockAsyncCompletionPort,
3509                                         ObjectHandleFlagInformation,
3510                                         &HandleFlags,
3511                                         sizeof(HandleFlags));
3512     }
3513 
3514     /* Create the Async Event */
3515     Status = NtCreateEvent(&AsyncEvent,
3516                            EVENT_ALL_ACCESS,
3517                            NULL,
3518                            NotificationEvent,
3519                            FALSE);
3520 
3521     /* Create the Async Thread */
3522     hAsyncThread = CreateThread(NULL,
3523                                 0,
3524                                 SockAsyncThread,
3525                                 NULL,
3526                                 0,
3527                                 &AsyncThreadId);
3528 
3529     /* Close the Handle */
3530     NtClose(hAsyncThread);
3531 
3532     /* Increase the Reference Count */
3533     SockAsyncThreadRefCount++;
3534     return TRUE;
3535 }
3536 
3537 ULONG
3538 NTAPI
3539 SockAsyncThread(PVOID ThreadParam)
3540 {
3541     PVOID AsyncContext;
3542     PASYNC_COMPLETION_ROUTINE AsyncCompletionRoutine;
3543     IO_STATUS_BLOCK IOSB;
3544     NTSTATUS Status;
3545 
3546     /* Make the Thread Higher Priority */
3547     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
3548 
3549     /* Do a KQUEUE/WorkItem Style Loop, thanks to IoCompletion Ports */
3550     do
3551     {
3552         Status =  NtRemoveIoCompletion (SockAsyncCompletionPort,
3553                                         (PVOID*)&AsyncCompletionRoutine,
3554                                         &AsyncContext,
3555                                         &IOSB,
3556                                         NULL);
3557         /* Call the Async Function */
3558         if (NT_SUCCESS(Status))
3559         {
3560             (*AsyncCompletionRoutine)(AsyncContext, &IOSB);
3561         }
3562         else
3563         {
3564             /* It Failed, sleep for a second */
3565             Sleep(1000);
3566         }
3567     } while ((Status != STATUS_TIMEOUT));
3568 
3569     /* The Thread has Ended */
3570     return 0;
3571 }
3572 
3573 BOOLEAN SockGetAsyncSelectHelperAfdHandle(VOID)
3574 {
3575     UNICODE_STRING AfdHelper;
3576     OBJECT_ATTRIBUTES ObjectAttributes;
3577     IO_STATUS_BLOCK IoSb;
3578     FILE_COMPLETION_INFORMATION CompletionInfo;
3579     OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
3580 
3581     /* First, make sure we're not already initialized */
3582     if (SockAsyncHelperAfdHandle)
3583     {
3584         return TRUE;
3585     }
3586 
3587     /* Set up Handle Name and Object */
3588     RtlInitUnicodeString(&AfdHelper, L"\\Device\\Afd\\AsyncSelectHlp" );
3589                          InitializeObjectAttributes(&ObjectAttributes,
3590                          &AfdHelper,
3591                          OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
3592                          NULL,
3593                          NULL);
3594 
3595     /* Open the Handle to AFD */
3596     NtCreateFile(&SockAsyncHelperAfdHandle,
3597                  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3598                  &ObjectAttributes,
3599                  &IoSb,
3600                  NULL,
3601                  0,
3602                  FILE_SHARE_READ | FILE_SHARE_WRITE,
3603                  FILE_OPEN_IF,
3604                  0,
3605                  NULL,
3606                  0);
3607 
3608     /*
3609      * Now Set up the Completion Port Information
3610      * This means that whenever a Poll is finished, the routine will be executed
3611      */
3612     CompletionInfo.Port = SockAsyncCompletionPort;
3613     CompletionInfo.Key = SockAsyncSelectCompletionRoutine;
3614     NtSetInformationFile(SockAsyncHelperAfdHandle,
3615                          &IoSb,
3616                          &CompletionInfo,
3617                          sizeof(CompletionInfo),
3618                          FileCompletionInformation);
3619 
3620 
3621     /* Protect the Handle */
3622     HandleFlags.ProtectFromClose = TRUE;
3623     HandleFlags.Inherit = FALSE;
3624     NtSetInformationObject(SockAsyncCompletionPort,
3625                            ObjectHandleFlagInformation,
3626                            &HandleFlags,
3627                            sizeof(HandleFlags));
3628 
3629 
3630     /* Set this variable to true so that Send/Recv/Accept will know wether to renable disabled events */
3631     SockAsyncSelectCalled = TRUE;
3632     return TRUE;
3633 }
3634 
3635 VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
3636 {
3637 
3638     PASYNC_DATA AsyncData = Context;
3639     PSOCKET_INFORMATION Socket;
3640     ULONG x;
3641 
3642     /* Get the Socket */
3643     Socket = AsyncData->ParentSocket;
3644 
3645     /* Check if the Sequence  Number Changed behind our back */
3646     if (AsyncData->SequenceNumber != Socket->SharedData->SequenceNumber )
3647     {
3648         return;
3649     }
3650 
3651     /* Check we were manually called b/c of a failure */
3652     if (!NT_SUCCESS(IoStatusBlock->Status))
3653     {
3654         /* FIXME: Perform Upcall */
3655         return;
3656     }
3657 
3658     for (x = 1; x; x<<=1)
3659     {
3660         switch (AsyncData->AsyncSelectInfo.Handles[0].Events & x)
3661         {
3662             case AFD_EVENT_RECEIVE:
3663                 if (0 != (Socket->SharedData->AsyncEvents & FD_READ) &&
3664                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_READ))
3665                 {
3666                     /* Make the Notification */
3667                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3668                                                Socket->SharedData->wMsg,
3669                                                Socket->Handle,
3670                                                WSAMAKESELECTREPLY(FD_READ, 0));
3671                     /* Disable this event until the next read(); */
3672                     Socket->SharedData->AsyncDisabledEvents |= FD_READ;
3673                 }
3674             break;
3675 
3676             case AFD_EVENT_OOB_RECEIVE:
3677             if (0 != (Socket->SharedData->AsyncEvents & FD_OOB) &&
3678                 0 == (Socket->SharedData->AsyncDisabledEvents & FD_OOB))
3679             {
3680                 /* Make the Notification */
3681                 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3682                                            Socket->SharedData->wMsg,
3683                                            Socket->Handle,
3684                                            WSAMAKESELECTREPLY(FD_OOB, 0));
3685                 /* Disable this event until the next read(); */
3686                 Socket->SharedData->AsyncDisabledEvents |= FD_OOB;
3687             }
3688             break;
3689 
3690             case AFD_EVENT_SEND:
3691                 if (0 != (Socket->SharedData->AsyncEvents & FD_WRITE) &&
3692                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_WRITE))
3693                 {
3694                     /* Make the Notification */
3695                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3696                                                Socket->SharedData->wMsg,
3697                                                Socket->Handle,
3698                                                WSAMAKESELECTREPLY(FD_WRITE, 0));
3699                     /* Disable this event until the next write(); */
3700                     Socket->SharedData->AsyncDisabledEvents |= FD_WRITE;
3701                 }
3702                 break;
3703 
3704                 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
3705             case AFD_EVENT_CONNECT:
3706             case AFD_EVENT_CONNECT_FAIL:
3707                 if (0 != (Socket->SharedData->AsyncEvents & FD_CONNECT) &&
3708                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_CONNECT))
3709                 {
3710                     /* Make the Notification */
3711                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3712                         Socket->SharedData->wMsg,
3713                         Socket->Handle,
3714                         WSAMAKESELECTREPLY(FD_CONNECT, 0));
3715                     /* Disable this event forever; */
3716                     Socket->SharedData->AsyncDisabledEvents |= FD_CONNECT;
3717                 }
3718                 break;
3719 
3720             case AFD_EVENT_ACCEPT:
3721                 if (0 != (Socket->SharedData->AsyncEvents & FD_ACCEPT) &&
3722                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_ACCEPT))
3723                 {
3724                     /* Make the Notification */
3725                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3726                                                Socket->SharedData->wMsg,
3727                                                Socket->Handle,
3728                                                WSAMAKESELECTREPLY(FD_ACCEPT, 0));
3729                     /* Disable this event until the next accept(); */
3730                     Socket->SharedData->AsyncDisabledEvents |= FD_ACCEPT;
3731                 }
3732                 break;
3733 
3734             case AFD_EVENT_DISCONNECT:
3735             case AFD_EVENT_ABORT:
3736             case AFD_EVENT_CLOSE:
3737                 if (0 != (Socket->SharedData->AsyncEvents & FD_CLOSE) &&
3738                     0 == (Socket->SharedData->AsyncDisabledEvents & FD_CLOSE))
3739                 {
3740                     /* Make the Notification */
3741                     (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3742                                                Socket->SharedData->wMsg,
3743                                                Socket->Handle,
3744                                                WSAMAKESELECTREPLY(FD_CLOSE, 0));
3745                     /* Disable this event forever; */
3746                     Socket->SharedData->AsyncDisabledEvents |= FD_CLOSE;
3747                 }
3748                  break;
3749             /* FIXME: Support QOS */
3750         }
3751     }
3752 
3753     /* Check if there are any events left for us to check */
3754     if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0 )
3755     {
3756         return;
3757     }
3758 
3759     /* Keep Polling */
3760     SockProcessAsyncSelect(Socket, AsyncData);
3761     return;
3762 }
3763 
3764 VOID SockProcessAsyncSelect(PSOCKET_INFORMATION Socket, PASYNC_DATA AsyncData)
3765 {
3766 
3767     ULONG lNetworkEvents;
3768     NTSTATUS Status;
3769 
3770     /* Set up the Async Data Event Info */
3771     AsyncData->AsyncSelectInfo.Timeout.HighPart = 0x7FFFFFFF;
3772     AsyncData->AsyncSelectInfo.Timeout.LowPart = 0xFFFFFFFF;
3773     AsyncData->AsyncSelectInfo.HandleCount = 1;
3774     AsyncData->AsyncSelectInfo.Exclusive = TRUE;
3775     AsyncData->AsyncSelectInfo.Handles[0].Handle = Socket->Handle;
3776     AsyncData->AsyncSelectInfo.Handles[0].Events = 0;
3777 
3778     /* Remove unwanted events */
3779     lNetworkEvents = Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents);
3780 
3781     /* Set Events to wait for */
3782     if (lNetworkEvents & FD_READ)
3783     {
3784         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_RECEIVE;
3785     }
3786 
3787     if (lNetworkEvents & FD_WRITE)
3788     {
3789         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_SEND;
3790     }
3791 
3792     if (lNetworkEvents & FD_OOB)
3793     {
3794         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_OOB_RECEIVE;
3795     }
3796 
3797     if (lNetworkEvents & FD_ACCEPT)
3798     {
3799         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_ACCEPT;
3800     }
3801 
3802     /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
3803     if (lNetworkEvents & FD_CONNECT)
3804     {
3805         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL;
3806     }
3807 
3808     if (lNetworkEvents & FD_CLOSE)
3809     {
3810         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT | AFD_EVENT_CLOSE;
3811     }
3812 
3813     if (lNetworkEvents & FD_QOS)
3814     {
3815         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_QOS;
3816     }
3817 
3818     if (lNetworkEvents & FD_GROUP_QOS)
3819     {
3820         AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_GROUP_QOS;
3821     }
3822 
3823     /* Send IOCTL */
3824     Status = NtDeviceIoControlFile (SockAsyncHelperAfdHandle,
3825                                     NULL,
3826                                     NULL,
3827                                     AsyncData,
3828                                     &AsyncData->IoStatusBlock,
3829                                     IOCTL_AFD_SELECT,
3830                                     &AsyncData->AsyncSelectInfo,
3831                                     sizeof(AsyncData->AsyncSelectInfo),
3832                                     &AsyncData->AsyncSelectInfo,
3833                                     sizeof(AsyncData->AsyncSelectInfo));
3834 
3835     /* I/O Manager Won't call the completion routine, let's do it manually */
3836     if (NT_SUCCESS(Status))
3837     {
3838         return;
3839     }
3840     else
3841     {
3842         AsyncData->IoStatusBlock.Status = Status;
3843         SockAsyncSelectCompletionRoutine(AsyncData, &AsyncData->IoStatusBlock);
3844     }
3845 }
3846 
3847 VOID SockProcessQueuedAsyncSelect(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
3848 {
3849     PASYNC_DATA AsyncData = Context;
3850     BOOL FreeContext = TRUE;
3851     PSOCKET_INFORMATION Socket;
3852 
3853     /* Get the Socket */
3854     Socket = AsyncData->ParentSocket;
3855 
3856     /* If someone closed it, stop the function */
3857     if (Socket->SharedData->State != SocketClosed)
3858     {
3859         /* Check if the Sequence Number changed by now, in which case quit */
3860         if (AsyncData->SequenceNumber == Socket->SharedData->SequenceNumber)
3861         {
3862             /* Do the actual select, if needed */
3863             if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)))
3864             {
3865                 SockProcessAsyncSelect(Socket, AsyncData);
3866                 FreeContext = FALSE;
3867             }
3868         }
3869     }
3870 
3871     /* Free the Context */
3872     if (FreeContext)
3873     {
3874         HeapFree(GetProcessHeap(), 0, AsyncData);
3875     }
3876 
3877     return;
3878 }
3879 
3880 VOID
3881 SockReenableAsyncSelectEvent (IN PSOCKET_INFORMATION Socket,
3882                               IN ULONG Event)
3883 {
3884     PASYNC_DATA AsyncData;
3885 
3886     /* Make sure the event is actually disabled */
3887     if (!(Socket->SharedData->AsyncDisabledEvents & Event))
3888     {
3889         return;
3890     }
3891 
3892     /* Re-enable it */
3893     Socket->SharedData->AsyncDisabledEvents &= ~Event;
3894 
3895     /* Return if no more events are being polled */
3896     if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0 )
3897     {
3898         return;
3899     }
3900 
3901     /* Wait on new events */
3902     AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(ASYNC_DATA));
3903     if (!AsyncData) return;
3904 
3905     /* Create the Asynch Thread if Needed */
3906     SockCreateOrReferenceAsyncThread();
3907 
3908     /* Increase the sequence number to stop anything else */
3909     Socket->SharedData->SequenceNumber++;
3910 
3911     /* Set up the Async Data */
3912     AsyncData->ParentSocket = Socket;
3913     AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber;
3914 
3915     /* Begin Async Select by using I/O Completion */
3916     NtSetIoCompletion(SockAsyncCompletionPort,
3917                      (PVOID)&SockProcessQueuedAsyncSelect,
3918                      AsyncData,
3919                      0,
3920                      0);
3921 
3922     /* All done */
3923     return;
3924 }
3925 
3926 BOOL
3927 WINAPI
3928 DllMain(HANDLE hInstDll,
3929         ULONG dwReason,
3930         PVOID Reserved)
3931 {
3932 
3933     switch (dwReason)
3934     {
3935     case DLL_PROCESS_ATTACH:
3936 
3937         TRACE("Loading MSAFD.DLL \n");
3938 
3939         /* Don't need thread attach notifications
3940         so disable them to improve performance */
3941         DisableThreadLibraryCalls(hInstDll);
3942 
3943         /* List of DLL Helpers */
3944         InitializeListHead(&SockHelpersListHead);
3945 
3946         /* Heap to use when allocating */
3947         GlobalHeap = GetProcessHeap();
3948 
3949         /* Initialize the lock that protects our socket list */
3950         InitializeCriticalSection(&SocketListLock);
3951 
3952         TRACE("MSAFD.DLL has been loaded\n");
3953 
3954         break;
3955 
3956     case DLL_THREAD_ATTACH:
3957         break;
3958 
3959     case DLL_THREAD_DETACH:
3960         break;
3961 
3962     case DLL_PROCESS_DETACH:
3963 
3964         /* Delete the socket list lock */
3965         DeleteCriticalSection(&SocketListLock);
3966 
3967         break;
3968     }
3969 
3970     TRACE("DllMain of msafd.dll (leaving)\n");
3971 
3972     return TRUE;
3973 }
3974 
3975 /* EOF */
3976