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