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