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