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