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