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