[MSAFD] Disable setting blocking mode if there are WSPAsyncSelect or WSPEventSelect...
[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
1355 Status = NtCreateEvent(&SockEvent,
1356 EVENT_ALL_ACCESS,
1357 NULL,
1358 1,
1359 FALSE);
1360
1361 if( !NT_SUCCESS(Status) )
1362 {
1363 return SOCKET_ERROR;
1364 }
1365
1366 /* Dynamic Structure...ugh */
1367 ListenReceiveData = (PAFD_RECEIVED_ACCEPT_DATA)ReceiveBuffer;
1368
1369 /* If this is non-blocking, make sure there's something for us to accept */
1370 FD_ZERO(&ReadSet);
1371 FD_SET(Socket->Handle, &ReadSet);
1372 Timeout.tv_sec=0;
1373 Timeout.tv_usec=0;
1374
1375 if (WSPSelect(0, &ReadSet, NULL, NULL, &Timeout, lpErrno) == SOCKET_ERROR)
1376 {
1377 NtClose(SockEvent);
1378 return SOCKET_ERROR;
1379 }
1380
1381 if (ReadSet.fd_array[0] != Socket->Handle)
1382 {
1383 NtClose(SockEvent);
1384 if (lpErrno) *lpErrno = WSAEWOULDBLOCK;
1385 return SOCKET_ERROR;
1386 }
1387
1388 /* Send IOCTL */
1389 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1390 SockEvent,
1391 NULL,
1392 NULL,
1393 &IOSB,
1394 IOCTL_AFD_WAIT_FOR_LISTEN,
1395 NULL,
1396 0,
1397 ListenReceiveData,
1398 0xA + sizeof(*ListenReceiveData));
1399
1400 /* Wait for return */
1401 if (Status == STATUS_PENDING)
1402 {
1403 WaitForSingleObject(SockEvent, INFINITE);
1404 Status = IOSB.Status;
1405 }
1406
1407 if (!NT_SUCCESS(Status))
1408 {
1409 NtClose( SockEvent );
1410 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1411 }
1412
1413 if (lpfnCondition != NULL)
1414 {
1415 if ((Socket->SharedData->ServiceFlags1 & XP1_CONNECT_DATA) != 0)
1416 {
1417 /* Find out how much data is pending */
1418 PendingAcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
1419 PendingAcceptData.ReturnSize = TRUE;
1420
1421 /* Send IOCTL */
1422 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1423 SockEvent,
1424 NULL,
1425 NULL,
1426 &IOSB,
1427 IOCTL_AFD_GET_PENDING_CONNECT_DATA,
1428 &PendingAcceptData,
1429 sizeof(PendingAcceptData),
1430 &PendingAcceptData,
1431 sizeof(PendingAcceptData));
1432
1433 /* Wait for return */
1434 if (Status == STATUS_PENDING)
1435 {
1436 WaitForSingleObject(SockEvent, INFINITE);
1437 Status = IOSB.Status;
1438 }
1439
1440 if (!NT_SUCCESS(Status))
1441 {
1442 NtClose( SockEvent );
1443 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1444 }
1445
1446 /* How much data to allocate */
1447 PendingDataLength = IOSB.Information;
1448
1449 if (PendingDataLength)
1450 {
1451 /* Allocate needed space */
1452 PendingData = HeapAlloc(GlobalHeap, 0, PendingDataLength);
1453 if (!PendingData)
1454 {
1455 return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
1456 }
1457
1458 /* We want the data now */
1459 PendingAcceptData.ReturnSize = FALSE;
1460
1461 /* Send IOCTL */
1462 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1463 SockEvent,
1464 NULL,
1465 NULL,
1466 &IOSB,
1467 IOCTL_AFD_GET_PENDING_CONNECT_DATA,
1468 &PendingAcceptData,
1469 sizeof(PendingAcceptData),
1470 PendingData,
1471 PendingDataLength);
1472
1473 /* Wait for return */
1474 if (Status == STATUS_PENDING)
1475 {
1476 WaitForSingleObject(SockEvent, INFINITE);
1477 Status = IOSB.Status;
1478 }
1479
1480 if (!NT_SUCCESS(Status))
1481 {
1482 NtClose( SockEvent );
1483 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1484 }
1485 }
1486 }
1487
1488 if ((Socket->SharedData->ServiceFlags1 & XP1_QOS_SUPPORTED) != 0)
1489 {
1490 /* I don't support this yet */
1491 }
1492
1493 /* Build Callee ID */
1494 CalleeID.buf = (PVOID)Socket->LocalAddress;
1495 CalleeID.len = Socket->SharedData->SizeOfLocalAddress;
1496
1497 RemoteAddress = HeapAlloc(GlobalHeap, 0, sizeof(*RemoteAddress));
1498 if (!RemoteAddress)
1499 {
1500 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
1501 }
1502
1503 /* Set up Address in SOCKADDR Format */
1504 RtlCopyMemory (RemoteAddress,
1505 &ListenReceiveData->Address.Address[0].AddressType,
1506 sizeof(*RemoteAddress));
1507
1508 /* Build Caller ID */
1509 CallerID.buf = (PVOID)RemoteAddress;
1510 CallerID.len = sizeof(*RemoteAddress);
1511
1512 /* Build Caller Data */
1513 CallerData.buf = PendingData;
1514 CallerData.len = PendingDataLength;
1515
1516 /* Check if socket supports Conditional Accept */
1517 if (Socket->SharedData->UseDelayedAcceptance != 0)
1518 {
1519 /* Allocate Buffer for Callee Data */
1520 CalleeDataBuffer = HeapAlloc(GlobalHeap, 0, 4096);
1521 if (!CalleeDataBuffer) {
1522 return MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
1523 }
1524 CalleeData.buf = CalleeDataBuffer;
1525 CalleeData.len = 4096;
1526 }
1527 else
1528 {
1529 /* Nothing */
1530 CalleeData.buf = 0;
1531 CalleeData.len = 0;
1532 }
1533
1534 /* Call the Condition Function */
1535 CallBack = (lpfnCondition)(&CallerID,
1536 CallerData.buf == NULL ? NULL : &CallerData,
1537 NULL,
1538 NULL,
1539 &CalleeID,
1540 CalleeData.buf == NULL ? NULL : &CalleeData,
1541 &GroupID,
1542 dwCallbackData);
1543
1544 if (((CallBack == CF_ACCEPT) && GroupID) != 0)
1545 {
1546 /* TBD: Check for Validity */
1547 }
1548
1549 if (CallBack == CF_ACCEPT)
1550 {
1551 if ((Socket->SharedData->ServiceFlags1 & XP1_QOS_SUPPORTED) != 0)
1552 {
1553 /* I don't support this yet */
1554 }
1555 if (CalleeData.buf)
1556 {
1557 // SockSetConnectData Sockets(SocketID), IOCTL_AFD_SET_CONNECT_DATA, CalleeData.Buffer, CalleeData.BuffSize, 0
1558 }
1559 }
1560 else
1561 {
1562 /* Callback rejected. Build Defer Structure */
1563 DeferData.SequenceNumber = ListenReceiveData->SequenceNumber;
1564 DeferData.RejectConnection = (CallBack == CF_REJECT);
1565
1566 /* Send IOCTL */
1567 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1568 SockEvent,
1569 NULL,
1570 NULL,
1571 &IOSB,
1572 IOCTL_AFD_DEFER_ACCEPT,
1573 &DeferData,
1574 sizeof(DeferData),
1575 NULL,
1576 0);
1577
1578 /* Wait for return */
1579 if (Status == STATUS_PENDING)
1580 {
1581 WaitForSingleObject(SockEvent, INFINITE);
1582 Status = IOSB.Status;
1583 }
1584
1585 NtClose( SockEvent );
1586
1587 if (!NT_SUCCESS(Status))
1588 {
1589 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1590 }
1591
1592 if (CallBack == CF_REJECT )
1593 {
1594 if (lpErrno) *lpErrno = WSAECONNREFUSED;
1595 return SOCKET_ERROR;
1596 }
1597 else
1598 {
1599 if (lpErrno) *lpErrno = WSAECONNREFUSED;
1600 return SOCKET_ERROR;
1601 }
1602 }
1603 }
1604
1605 /* Create a new Socket */
1606 AcceptSocket = WSPSocket (Socket->SharedData->AddressFamily,
1607 Socket->SharedData->SocketType,
1608 Socket->SharedData->Protocol,
1609 &Socket->ProtocolInfo,
1610 GroupID,
1611 Socket->SharedData->CreateFlags,
1612 lpErrno);
1613 if (AcceptSocket == INVALID_SOCKET)
1614 return SOCKET_ERROR;
1615
1616 /* Set up the Accept Structure */
1617 AcceptData.ListenHandle = (HANDLE)AcceptSocket;
1618 AcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
1619
1620 /* Send IOCTL to Accept */
1621 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
1622 SockEvent,
1623 NULL,
1624 NULL,
1625 &IOSB,
1626 IOCTL_AFD_ACCEPT,
1627 &AcceptData,
1628 sizeof(AcceptData),
1629 NULL,
1630 0);
1631
1632 /* Wait for return */
1633 if (Status == STATUS_PENDING)
1634 {
1635 WaitForSingleObject(SockEvent, INFINITE);
1636 Status = IOSB.Status;
1637 }
1638
1639 if (!NT_SUCCESS(Status))
1640 {
1641 NtClose(SockEvent);
1642 WSPCloseSocket( AcceptSocket, lpErrno );
1643 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1644 }
1645
1646 AcceptSocketInfo = GetSocketStructure(AcceptSocket);
1647 if (!AcceptSocketInfo)
1648 {
1649 NtClose(SockEvent);
1650 WSPCloseSocket( AcceptSocket, lpErrno );
1651 return MsafdReturnWithErrno( STATUS_PROTOCOL_NOT_SUPPORTED, lpErrno, 0, NULL );
1652 }
1653
1654 AcceptSocketInfo->SharedData->State = SocketConnected;
1655
1656 /* Return Address in SOCKADDR FORMAT */
1657 if( SocketAddress )
1658 {
1659 RtlCopyMemory (SocketAddress,
1660 &ListenReceiveData->Address.Address[0].AddressType,
1661 sizeof(*RemoteAddress));
1662 if( SocketAddressLength )
1663 *SocketAddressLength = sizeof(*RemoteAddress);
1664 }
1665
1666 NtClose( SockEvent );
1667
1668 /* Re-enable Async Event */
1669 SockReenableAsyncSelectEvent(Socket, FD_ACCEPT);
1670
1671 TRACE("Socket %x\n", AcceptSocket);
1672
1673 if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_ACCEPT))
1674 {
1675 Status = Socket->HelperData->WSHNotify(Socket->HelperContext,
1676 Socket->Handle,
1677 Socket->TdiAddressHandle,
1678 Socket->TdiConnectionHandle,
1679 WSH_NOTIFY_ACCEPT);
1680
1681 if (Status)
1682 {
1683 if (lpErrno) *lpErrno = Status;
1684 return SOCKET_ERROR;
1685 }
1686 }
1687
1688 if (lpErrno) *lpErrno = NO_ERROR;
1689
1690 /* Return Socket */
1691 return AcceptSocket;
1692 }
1693
1694 int
1695 WSPAPI
1696 WSPConnect(SOCKET Handle,
1697 const struct sockaddr * SocketAddress,
1698 int SocketAddressLength,
1699 LPWSABUF lpCallerData,
1700 LPWSABUF lpCalleeData,
1701 LPQOS lpSQOS,
1702 LPQOS lpGQOS,
1703 LPINT lpErrno)
1704 {
1705 IO_STATUS_BLOCK IOSB;
1706 PAFD_CONNECT_INFO ConnectInfo = NULL;
1707 PSOCKET_INFORMATION Socket;
1708 NTSTATUS Status;
1709 INT Errno;
1710 ULONG ConnectDataLength;
1711 ULONG InConnectDataLength;
1712 INT BindAddressLength;
1713 PSOCKADDR BindAddress;
1714 HANDLE SockEvent;
1715 int SocketDataLength;
1716
1717 TRACE("Called (%lx) %lx:%d\n", Handle, ((const struct sockaddr_in *)SocketAddress)->sin_addr, ((const struct sockaddr_in *)SocketAddress)->sin_port);
1718
1719 /* Get the Socket Structure associate to this Socket*/
1720 Socket = GetSocketStructure(Handle);
1721 if (!Socket)
1722 {
1723 if (lpErrno) *lpErrno = WSAENOTSOCK;
1724 return SOCKET_ERROR;
1725 }
1726
1727 Status = NtCreateEvent(&SockEvent,
1728 EVENT_ALL_ACCESS,
1729 NULL,
1730 1,
1731 FALSE);
1732
1733 if (!NT_SUCCESS(Status))
1734 return SOCKET_ERROR;
1735
1736 /* Bind us First */
1737 if (Socket->SharedData->State == SocketOpen)
1738 {
1739 /* Get the Wildcard Address */
1740 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
1741 BindAddress = HeapAlloc(GetProcessHeap(), 0, BindAddressLength);
1742 if (!BindAddress)
1743 {
1744 NtClose(SockEvent);
1745 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
1746 }
1747 Socket->HelperData->WSHGetWildcardSockaddr (Socket->HelperContext,
1748 BindAddress,
1749 &BindAddressLength);
1750 /* Bind it */
1751 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
1752 return SOCKET_ERROR;
1753 }
1754
1755 /* Set the Connect Data */
1756 if (lpCallerData != NULL)
1757 {
1758 ConnectDataLength = lpCallerData->len;
1759 Status = NtDeviceIoControlFile((HANDLE)Handle,
1760 SockEvent,
1761 NULL,
1762 NULL,
1763 &IOSB,
1764 IOCTL_AFD_SET_CONNECT_DATA,
1765 lpCallerData->buf,
1766 ConnectDataLength,
1767 NULL,
1768 0);
1769 /* Wait for return */
1770 if (Status == STATUS_PENDING)
1771 {
1772 WaitForSingleObject(SockEvent, INFINITE);
1773 Status = IOSB.Status;
1774 }
1775
1776 if (Status != STATUS_SUCCESS)
1777 goto notify;
1778 }
1779
1780 /* Calculate the size of SocketAddress->sa_data */
1781 SocketDataLength = SocketAddressLength - FIELD_OFFSET(struct sockaddr, sa_data);
1782
1783 /* Allocate a connection info buffer with SocketDataLength bytes of payload */
1784 ConnectInfo = HeapAlloc(GetProcessHeap(), 0,
1785 FIELD_OFFSET(AFD_CONNECT_INFO,
1786 RemoteAddress.Address[0].Address[SocketDataLength]));
1787 if (!ConnectInfo)
1788 {
1789 Status = STATUS_INSUFFICIENT_RESOURCES;
1790 goto notify;
1791 }
1792
1793 /* Set up Address in TDI Format */
1794 ConnectInfo->RemoteAddress.TAAddressCount = 1;
1795 ConnectInfo->RemoteAddress.Address[0].AddressLength = SocketDataLength;
1796 ConnectInfo->RemoteAddress.Address[0].AddressType = SocketAddress->sa_family;
1797 RtlCopyMemory(ConnectInfo->RemoteAddress.Address[0].Address,
1798 SocketAddress->sa_data,
1799 SocketDataLength);
1800
1801 /*
1802 * Disable FD_WRITE and FD_CONNECT
1803 * The latter fixes a race condition where the FD_CONNECT is re-enabled
1804 * at the end of this function right after the Async Thread disables it.
1805 * This should only happen at the *next* WSPConnect
1806 */
1807 if (Socket->SharedData->AsyncEvents & FD_CONNECT)
1808 {
1809 Socket->SharedData->AsyncDisabledEvents |= FD_CONNECT | FD_WRITE;
1810 }
1811
1812 /* Tell AFD that we want Connection Data back, have it allocate a buffer */
1813 if (lpCalleeData != NULL)
1814 {
1815 InConnectDataLength = lpCalleeData->len;
1816 Status = NtDeviceIoControlFile((HANDLE)Handle,
1817 SockEvent,
1818 NULL,
1819 NULL,
1820 &IOSB,
1821 IOCTL_AFD_SET_CONNECT_DATA_SIZE,
1822 &InConnectDataLength,
1823 sizeof(InConnectDataLength),
1824 NULL,
1825 0);
1826
1827 /* Wait for return */
1828 if (Status == STATUS_PENDING)
1829 {
1830 WaitForSingleObject(SockEvent, INFINITE);
1831 Status = IOSB.Status;
1832 }
1833
1834 if (Status != STATUS_SUCCESS)
1835 goto notify;
1836 }
1837
1838 /* AFD doesn't seem to care if these are invalid, but let's 0 them anyways */
1839 ConnectInfo->Root = 0;
1840 ConnectInfo->UseSAN = FALSE;
1841 ConnectInfo->Unknown = 0;
1842
1843 /* FIXME: Handle Async Connect */
1844 if (Socket->SharedData->NonBlocking)
1845 {
1846 ERR("Async Connect UNIMPLEMENTED!\n");
1847 }
1848
1849 /* Send IOCTL */
1850 Status = NtDeviceIoControlFile((HANDLE)Handle,
1851 SockEvent,
1852 NULL,
1853 NULL,
1854 &IOSB,
1855 IOCTL_AFD_CONNECT,
1856 ConnectInfo,
1857 0x22,
1858 NULL,
1859 0);
1860 /* Wait for return */
1861 if (Status == STATUS_PENDING)
1862 {
1863 WaitForSingleObject(SockEvent, INFINITE);
1864 Status = IOSB.Status;
1865 }
1866
1867 if (Status != STATUS_SUCCESS)
1868 goto notify;
1869
1870 Socket->SharedData->State = SocketConnected;
1871 Socket->TdiConnectionHandle = (HANDLE)IOSB.Information;
1872
1873 /* Get any pending connect data */
1874 if (lpCalleeData != NULL)
1875 {
1876 Status = NtDeviceIoControlFile((HANDLE)Handle,
1877 SockEvent,
1878 NULL,
1879 NULL,
1880 &IOSB,
1881 IOCTL_AFD_GET_CONNECT_DATA,
1882 NULL,
1883 0,
1884 lpCalleeData->buf,
1885 lpCalleeData->len);
1886 /* Wait for return */
1887 if (Status == STATUS_PENDING)
1888 {
1889 WaitForSingleObject(SockEvent, INFINITE);
1890 Status = IOSB.Status;
1891 }
1892 }
1893
1894 TRACE("Ending %lx\n", IOSB.Status);
1895
1896 notify:
1897 if (ConnectInfo) HeapFree(GetProcessHeap(), 0, ConnectInfo);
1898
1899 /* Re-enable Async Event */
1900 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
1901
1902 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
1903 SockReenableAsyncSelectEvent(Socket, FD_CONNECT);
1904
1905 NtClose(SockEvent);
1906
1907 if (Status == STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT))
1908 {
1909 Errno = Socket->HelperData->WSHNotify(Socket->HelperContext,
1910 Socket->Handle,
1911 Socket->TdiAddressHandle,
1912 Socket->TdiConnectionHandle,
1913 WSH_NOTIFY_CONNECT);
1914
1915 if (Errno)
1916 {
1917 if (lpErrno) *lpErrno = Errno;
1918 return SOCKET_ERROR;
1919 }
1920 }
1921 else if (Status != STATUS_SUCCESS && (Socket->HelperEvents & WSH_NOTIFY_CONNECT_ERROR))
1922 {
1923 Errno = Socket->HelperData->WSHNotify(Socket->HelperContext,
1924 Socket->Handle,
1925 Socket->TdiAddressHandle,
1926 Socket->TdiConnectionHandle,
1927 WSH_NOTIFY_CONNECT_ERROR);
1928
1929 if (Errno)
1930 {
1931 if (lpErrno) *lpErrno = Errno;
1932 return SOCKET_ERROR;
1933 }
1934 }
1935
1936 return MsafdReturnWithErrno(Status, lpErrno, 0, NULL);
1937 }
1938 int
1939 WSPAPI
1940 WSPShutdown(SOCKET Handle,
1941 int HowTo,
1942 LPINT lpErrno)
1943
1944 {
1945 IO_STATUS_BLOCK IOSB;
1946 AFD_DISCONNECT_INFO DisconnectInfo;
1947 PSOCKET_INFORMATION Socket = NULL;
1948 NTSTATUS Status;
1949 HANDLE SockEvent;
1950
1951 TRACE("Called\n");
1952
1953 /* Get the Socket Structure associate to this Socket*/
1954 Socket = GetSocketStructure(Handle);
1955 if (!Socket)
1956 {
1957 if (lpErrno) *lpErrno = WSAENOTSOCK;
1958 return SOCKET_ERROR;
1959 }
1960
1961 Status = NtCreateEvent(&SockEvent,
1962 EVENT_ALL_ACCESS,
1963 NULL,
1964 1,
1965 FALSE);
1966
1967 if( !NT_SUCCESS(Status) )
1968 return SOCKET_ERROR;
1969
1970 /* Set AFD Disconnect Type */
1971 switch (HowTo)
1972 {
1973 case SD_RECEIVE:
1974 DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV;
1975 Socket->SharedData->ReceiveShutdown = TRUE;
1976 break;
1977 case SD_SEND:
1978 DisconnectInfo.DisconnectType= AFD_DISCONNECT_SEND;
1979 Socket->SharedData->SendShutdown = TRUE;
1980 break;
1981 case SD_BOTH:
1982 DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV | AFD_DISCONNECT_SEND;
1983 Socket->SharedData->ReceiveShutdown = TRUE;
1984 Socket->SharedData->SendShutdown = TRUE;
1985 break;
1986 }
1987
1988 DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1000000);
1989
1990 /* Send IOCTL */
1991 Status = NtDeviceIoControlFile((HANDLE)Handle,
1992 SockEvent,
1993 NULL,
1994 NULL,
1995 &IOSB,
1996 IOCTL_AFD_DISCONNECT,
1997 &DisconnectInfo,
1998 sizeof(DisconnectInfo),
1999 NULL,
2000 0);
2001
2002 /* Wait for return */
2003 if (Status == STATUS_PENDING)
2004 {
2005 WaitForSingleObject(SockEvent, INFINITE);
2006 Status = IOSB.Status;
2007 }
2008
2009 TRACE("Ending\n");
2010
2011 NtClose( SockEvent );
2012
2013 return MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
2014 }
2015
2016
2017 INT
2018 WSPAPI
2019 WSPGetSockName(IN SOCKET Handle,
2020 OUT LPSOCKADDR Name,
2021 IN OUT LPINT NameLength,
2022 OUT LPINT lpErrno)
2023 {
2024 IO_STATUS_BLOCK IOSB;
2025 ULONG TdiAddressSize;
2026 PTDI_ADDRESS_INFO TdiAddress;
2027 PTRANSPORT_ADDRESS SocketAddress;
2028 PSOCKET_INFORMATION Socket = NULL;
2029 NTSTATUS Status;
2030 HANDLE SockEvent;
2031
2032 /* Get the Socket Structure associate to this Socket*/
2033 Socket = GetSocketStructure(Handle);
2034 if (!Socket)
2035 {
2036 if (lpErrno) *lpErrno = WSAENOTSOCK;
2037 return SOCKET_ERROR;
2038 }
2039
2040 if (!Name || !NameLength)
2041 {
2042 if (lpErrno) *lpErrno = WSAEFAULT;
2043 return SOCKET_ERROR;
2044 }
2045
2046 Status = NtCreateEvent(&SockEvent,
2047 EVENT_ALL_ACCESS,
2048 NULL,
2049 1,
2050 FALSE);
2051
2052 if( !NT_SUCCESS(Status) )
2053 return SOCKET_ERROR;
2054
2055 /* Allocate a buffer for the address */
2056 TdiAddressSize =
2057 sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfLocalAddress;
2058 TdiAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
2059
2060 if ( TdiAddress == NULL )
2061 {
2062 NtClose( SockEvent );
2063 if (lpErrno) *lpErrno = WSAENOBUFS;
2064 return SOCKET_ERROR;
2065 }
2066
2067 SocketAddress = &TdiAddress->Address;
2068
2069 /* Send IOCTL */
2070 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
2071 SockEvent,
2072 NULL,
2073 NULL,
2074 &IOSB,
2075 IOCTL_AFD_GET_SOCK_NAME,
2076 NULL,
2077 0,
2078 TdiAddress,
2079 TdiAddressSize);
2080
2081 /* Wait for return */
2082 if (Status == STATUS_PENDING)
2083 {
2084 WaitForSingleObject(SockEvent, INFINITE);
2085 Status = IOSB.Status;
2086 }
2087
2088 NtClose( SockEvent );
2089
2090 if (NT_SUCCESS(Status))
2091 {
2092 if (*NameLength >= Socket->SharedData->SizeOfLocalAddress)
2093 {
2094 Name->sa_family = SocketAddress->Address[0].AddressType;
2095 RtlCopyMemory (Name->sa_data,
2096 SocketAddress->Address[0].Address,
2097 SocketAddress->Address[0].AddressLength);
2098 *NameLength = Socket->SharedData->SizeOfLocalAddress;
2099 TRACE("NameLength %d Address: %x Port %x\n",
2100 *NameLength, ((struct sockaddr_in *)Name)->sin_addr.s_addr,
2101 ((struct sockaddr_in *)Name)->sin_port);
2102 HeapFree(GlobalHeap, 0, TdiAddress);
2103 return 0;
2104 }
2105 else
2106 {
2107 HeapFree(GlobalHeap, 0, TdiAddress);
2108 if (lpErrno) *lpErrno = WSAEFAULT;
2109 return SOCKET_ERROR;
2110 }
2111 }
2112
2113 HeapFree(GlobalHeap, 0, TdiAddress);
2114
2115 return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
2116 }
2117
2118
2119 INT
2120 WSPAPI
2121 WSPGetPeerName(IN SOCKET s,
2122 OUT LPSOCKADDR Name,
2123 IN OUT LPINT NameLength,
2124 OUT LPINT lpErrno)
2125 {
2126 IO_STATUS_BLOCK IOSB;
2127 ULONG TdiAddressSize;
2128 PTRANSPORT_ADDRESS SocketAddress;
2129 PSOCKET_INFORMATION Socket = NULL;
2130 NTSTATUS Status;
2131 HANDLE SockEvent;
2132
2133 /* Get the Socket Structure associate to this Socket*/
2134 Socket = GetSocketStructure(s);
2135 if (!Socket)
2136 {
2137 if (lpErrno) *lpErrno = WSAENOTSOCK;
2138 return SOCKET_ERROR;
2139 }
2140
2141 if (Socket->SharedData->State != SocketConnected)
2142 {
2143 if (lpErrno) *lpErrno = WSAENOTCONN;
2144 return SOCKET_ERROR;
2145 }
2146
2147 if (!Name || !NameLength)
2148 {
2149 if (lpErrno) *lpErrno = WSAEFAULT;
2150 return SOCKET_ERROR;
2151 }
2152
2153 Status = NtCreateEvent(&SockEvent,
2154 EVENT_ALL_ACCESS,
2155 NULL,
2156 1,
2157 FALSE);
2158
2159 if( !NT_SUCCESS(Status) )
2160 return SOCKET_ERROR;
2161
2162 /* Allocate a buffer for the address */
2163 TdiAddressSize = sizeof(TRANSPORT_ADDRESS) + Socket->SharedData->SizeOfRemoteAddress;
2164 SocketAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
2165
2166 if ( SocketAddress == NULL )
2167 {
2168 NtClose( SockEvent );
2169 if (lpErrno) *lpErrno = WSAENOBUFS;
2170 return SOCKET_ERROR;
2171 }
2172
2173 /* Send IOCTL */
2174 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
2175 SockEvent,
2176 NULL,
2177 NULL,
2178 &IOSB,
2179 IOCTL_AFD_GET_PEER_NAME,
2180 NULL,
2181 0,
2182 SocketAddress,
2183 TdiAddressSize);
2184
2185 /* Wait for return */
2186 if (Status == STATUS_PENDING)
2187 {
2188 WaitForSingleObject(SockEvent, INFINITE);
2189 Status = IOSB.Status;
2190 }
2191
2192 NtClose( SockEvent );
2193
2194 if (NT_SUCCESS(Status))
2195 {
2196 if (*NameLength >= Socket->SharedData->SizeOfRemoteAddress)
2197 {
2198 Name->sa_family = SocketAddress->Address[0].AddressType;
2199 RtlCopyMemory (Name->sa_data,
2200 SocketAddress->Address[0].Address,
2201 SocketAddress->Address[0].AddressLength);
2202 *NameLength = Socket->SharedData->SizeOfRemoteAddress;
2203 TRACE("NameLength %d Address: %x Port %x\n",
2204 *NameLength, ((struct sockaddr_in *)Name)->sin_addr.s_addr,
2205 ((struct sockaddr_in *)Name)->sin_port);
2206 HeapFree(GlobalHeap, 0, SocketAddress);
2207 return 0;
2208 }
2209 else
2210 {
2211 HeapFree(GlobalHeap, 0, SocketAddress);
2212 if (lpErrno) *lpErrno = WSAEFAULT;
2213 return SOCKET_ERROR;
2214 }
2215 }
2216
2217 HeapFree(GlobalHeap, 0, SocketAddress);
2218
2219 return MsafdReturnWithErrno ( Status, lpErrno, 0, NULL );
2220 }
2221
2222 INT
2223 WSPAPI
2224 WSPIoctl(IN SOCKET Handle,
2225 IN DWORD dwIoControlCode,
2226 IN LPVOID lpvInBuffer,
2227 IN DWORD cbInBuffer,
2228 OUT LPVOID lpvOutBuffer,
2229 IN DWORD cbOutBuffer,
2230 OUT LPDWORD lpcbBytesReturned,
2231 IN LPWSAOVERLAPPED lpOverlapped,
2232 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
2233 IN LPWSATHREADID lpThreadId,
2234 OUT LPINT lpErrno)
2235 {
2236 PSOCKET_INFORMATION Socket = NULL;
2237 BOOLEAN NeedsCompletion = lpOverlapped != NULL;
2238 BOOLEAN NonBlocking;
2239 INT Errno = NO_ERROR, Ret = SOCKET_ERROR;
2240 DWORD cbRet = 0;
2241
2242 /* Get the Socket Structure associate to this Socket*/
2243 Socket = GetSocketStructure(Handle);
2244 if (!Socket)
2245 {
2246 if(lpErrno)
2247 *lpErrno = WSAENOTSOCK;
2248 return SOCKET_ERROR;
2249 }
2250
2251 if (!lpcbBytesReturned && !lpOverlapped)
2252 {
2253 if(lpErrno)
2254 *lpErrno = WSAEFAULT;
2255 return SOCKET_ERROR;
2256 }
2257
2258 switch( dwIoControlCode )
2259 {
2260 case FIONBIO:
2261 if( cbInBuffer < sizeof(INT) || IS_INTRESOURCE(lpvInBuffer) )
2262 {
2263 Errno = WSAEFAULT;
2264 break;
2265 }
2266 NonBlocking = *((PULONG)lpvInBuffer) ? TRUE : FALSE;
2267 /* Don't allow to go in blocking mode if WSPAsyncSelect or WSPEventSelect is pending */
2268 if (!NonBlocking)
2269 {
2270 /* If there is an WSPAsyncSelect pending, fail with WSAEINVAL */
2271 if (Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents))
2272 {
2273 Errno = WSAEINVAL;
2274 break;
2275 }
2276 /* If there is an WSPEventSelect pending, fail with WSAEINVAL */
2277 if (Socket->NetworkEvents)
2278 {
2279 Errno = WSAEINVAL;
2280 break;
2281 }
2282 }
2283 Socket->SharedData->NonBlocking = NonBlocking ? 1 : 0;
2284 NeedsCompletion = FALSE;
2285 Errno = SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &NonBlocking, NULL, NULL, lpOverlapped, lpCompletionRoutine);
2286 if (Errno == NO_ERROR)
2287 Ret = NO_ERROR;
2288 break;
2289 case FIONREAD:
2290 if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2291 {
2292 cbRet = sizeof(ULONG);
2293 Errno = WSAEFAULT;
2294 break;
2295 }
2296 if (cbOutBuffer < sizeof(ULONG))
2297 {
2298 Errno = WSAEINVAL;
2299 break;
2300 }
2301 NeedsCompletion = FALSE;
2302 Errno = GetSocketInformation(Socket, AFD_INFO_RECEIVE_CONTENT_SIZE, NULL, (PULONG)lpvOutBuffer, NULL, lpOverlapped, lpCompletionRoutine);
2303 if (Errno == NO_ERROR)
2304 {
2305 cbRet = sizeof(ULONG);
2306 Ret = NO_ERROR;
2307 }
2308 break;
2309 case SIOCATMARK:
2310 if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2311 {
2312 cbRet = sizeof(BOOL);
2313 Errno = WSAEFAULT;
2314 break;
2315 }
2316 if (cbOutBuffer < sizeof(BOOL))
2317 {
2318 Errno = WSAEINVAL;
2319 break;
2320 }
2321 if (Socket->SharedData->SocketType != SOCK_STREAM)
2322 {
2323 Errno = WSAEINVAL;
2324 break;
2325 }
2326
2327 /* FIXME: Return false if OOBINLINE is true for now
2328 We should MSG_PEEK|MSG_OOB check with driver
2329 */
2330 *(BOOL*)lpvOutBuffer = !Socket->SharedData->OobInline;
2331
2332 cbRet = sizeof(BOOL);
2333 Errno = NO_ERROR;
2334 Ret = NO_ERROR;
2335 break;
2336 case SIO_GET_EXTENSION_FUNCTION_POINTER:
2337 Errno = WSAEINVAL;
2338 break;
2339 case SIO_ADDRESS_LIST_QUERY:
2340 if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0)
2341 {
2342 cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress);
2343 Errno = WSAEFAULT;
2344 break;
2345 }
2346 if (cbOutBuffer < sizeof(INT))
2347 {
2348 Errno = WSAEINVAL;
2349 break;
2350 }
2351
2352 cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress);
2353
2354 ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->iAddressCount = 1;
2355
2356 if (cbOutBuffer < (sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress)))
2357 {
2358 Errno = WSAEFAULT;
2359 break;
2360 }
2361
2362 ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].iSockaddrLength = sizeof(Socket->SharedData->WSLocalAddress);
2363 ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].lpSockaddr = &Socket->SharedData->WSLocalAddress;
2364
2365 Errno = NO_ERROR;
2366 Ret = NO_ERROR;
2367 break;
2368 default:
2369 Errno = Socket->HelperData->WSHIoctl(Socket->HelperContext,
2370 Handle,
2371 Socket->TdiAddressHandle,
2372 Socket->TdiConnectionHandle,
2373 dwIoControlCode,
2374 lpvInBuffer,
2375 cbInBuffer,
2376 lpvOutBuffer,
2377 cbOutBuffer,
2378 &cbRet,
2379 lpOverlapped,
2380 lpCompletionRoutine,
2381 (LPBOOL)&NeedsCompletion);
2382
2383 if (Errno == NO_ERROR)
2384 Ret = NO_ERROR;
2385 break;
2386 }
2387 if (lpOverlapped && NeedsCompletion)
2388 {
2389 lpOverlapped->Internal = Errno;
2390 lpOverlapped->InternalHigh = cbRet;
2391 if (lpCompletionRoutine != NULL)
2392 {
2393 lpCompletionRoutine(Errno, cbRet, lpOverlapped, 0);
2394 }
2395 if (lpOverlapped->hEvent)
2396 SetEvent(lpOverlapped->hEvent);
2397 if (!PostQueuedCompletionStatus((HANDLE)Handle, cbRet, 0, lpOverlapped))
2398 {
2399 ERR("PostQueuedCompletionStatus failed %d\n", GetLastError());
2400 }
2401 return NO_ERROR;
2402 }
2403 if (lpErrno)
2404 *lpErrno = Errno;
2405 if (lpcbBytesReturned)
2406 *lpcbBytesReturned = cbRet;
2407 return Ret;
2408 }
2409
2410
2411 INT
2412 WSPAPI
2413 WSPGetSockOpt(IN SOCKET Handle,
2414 IN INT Level,
2415 IN INT OptionName,
2416 OUT CHAR FAR* OptionValue,
2417 IN OUT LPINT OptionLength,
2418 OUT LPINT lpErrno)
2419 {
2420 PSOCKET_INFORMATION Socket = NULL;
2421 PVOID Buffer;
2422 INT BufferSize;
2423 BOOL BoolBuffer;
2424 INT IntBuffer;
2425 INT Errno;
2426
2427 /* Get the Socket Structure associate to this Socket*/
2428 Socket = GetSocketStructure(Handle);
2429 if (Socket == NULL)
2430 {
2431 if (lpErrno) *lpErrno = WSAENOTSOCK;
2432 return SOCKET_ERROR;
2433 }
2434
2435 TRACE("Called\n");
2436
2437 switch (Level)
2438 {
2439 case SOL_SOCKET:
2440 switch (OptionName)
2441 {
2442 case SO_TYPE:
2443 Buffer = &Socket->SharedData->SocketType;
2444 BufferSize = sizeof(INT);
2445 break;
2446
2447 case SO_RCVBUF:
2448 Buffer = &Socket->SharedData->SizeOfRecvBuffer;
2449 BufferSize = sizeof(INT);
2450 break;
2451
2452 case SO_SNDBUF:
2453 Buffer = &Socket->SharedData->SizeOfSendBuffer;
2454 BufferSize = sizeof(INT);
2455 break;
2456
2457 case SO_ACCEPTCONN:
2458 BoolBuffer = Socket->SharedData->Listening;
2459 Buffer = &BoolBuffer;
2460 BufferSize = sizeof(BOOL);
2461 break;
2462
2463 case SO_BROADCAST:
2464 BoolBuffer = Socket->SharedData->Broadcast;
2465 Buffer = &BoolBuffer;
2466 BufferSize = sizeof(BOOL);
2467 break;
2468
2469 case SO_DEBUG:
2470 BoolBuffer = Socket->SharedData->Debug;
2471 Buffer = &BoolBuffer;
2472 BufferSize = sizeof(BOOL);
2473 break;
2474
2475 case SO_DONTLINGER:
2476 BoolBuffer = (Socket->SharedData->LingerData.l_onoff == 0);
2477 Buffer = &BoolBuffer;
2478 BufferSize = sizeof(BOOL);
2479 break;
2480
2481 case SO_LINGER:
2482 if (Socket->SharedData->SocketType == SOCK_DGRAM)
2483 {
2484 if (lpErrno) *lpErrno = WSAENOPROTOOPT;
2485 return SOCKET_ERROR;
2486 }
2487 Buffer = &Socket->SharedData->LingerData;
2488 BufferSize = sizeof(struct linger);
2489 break;
2490
2491 case SO_OOBINLINE:
2492 BoolBuffer = (Socket->SharedData->OobInline != 0);
2493 Buffer = &BoolBuffer;
2494 BufferSize = sizeof(BOOL);
2495 break;
2496
2497 case SO_KEEPALIVE:
2498 case SO_DONTROUTE:
2499 /* These guys go directly to the helper */
2500 goto SendToHelper;
2501
2502 case SO_CONDITIONAL_ACCEPT:
2503 BoolBuffer = (Socket->SharedData->UseDelayedAcceptance != 0);
2504 Buffer = &BoolBuffer;
2505 BufferSize = sizeof(BOOL);
2506 break;
2507
2508 case SO_REUSEADDR:
2509 BoolBuffer = (Socket->SharedData->ReuseAddresses != 0);
2510 Buffer = &BoolBuffer;
2511 BufferSize = sizeof(BOOL);
2512 break;
2513
2514 case SO_EXCLUSIVEADDRUSE:
2515 BoolBuffer = (Socket->SharedData->ExclusiveAddressUse != 0);
2516 Buffer = &BoolBuffer;
2517 BufferSize = sizeof(BOOL);
2518 break;
2519
2520 case SO_ERROR:
2521 /* HACK: This needs to be properly tracked */
2522 IntBuffer = 0;
2523 DbgPrint("MSAFD: Hacked SO_ERROR returning error %d\n", IntBuffer);
2524
2525 Buffer = &IntBuffer;
2526 BufferSize = sizeof(INT);
2527 break;
2528 case SO_SNDTIMEO:
2529 Buffer = &Socket->SharedData->SendTimeout;
2530 BufferSize = sizeof(DWORD);
2531 break;
2532 case SO_RCVTIMEO:
2533 Buffer = &Socket->SharedData->RecvTimeout;
2534 BufferSize = sizeof(DWORD);
2535 break;
2536 case SO_PROTOCOL_INFOW:
2537 Buffer = &Socket->ProtocolInfo;
2538 BufferSize = sizeof(Socket->ProtocolInfo);
2539 break;
2540
2541 case SO_GROUP_ID:
2542 case SO_GROUP_PRIORITY:
2543 case SO_MAX_MSG_SIZE:
2544
2545 default:
2546 DbgPrint("MSAFD: Get unknown optname %x\n", OptionName);
2547 if (lpErrno) *lpErrno = WSAENOPROTOOPT;
2548 return SOCKET_ERROR;
2549 }
2550
2551 if (*OptionLength < BufferSize)
2552 {
2553 if (lpErrno) *lpErrno = WSAEFAULT;
2554 *OptionLength = BufferSize;
2555 return SOCKET_ERROR;
2556 }
2557 RtlCopyMemory(OptionValue, Buffer, BufferSize);
2558
2559 return 0;
2560
2561 default:
2562 if (lpErrno) *lpErrno = WSAEINVAL;
2563 return SOCKET_ERROR;
2564 }
2565
2566 SendToHelper:
2567 Errno = Socket->HelperData->WSHGetSocketInformation(Socket->HelperContext,
2568 Handle,
2569 Socket->TdiAddressHandle,
2570 Socket->TdiConnectionHandle,
2571 Level,
2572 OptionName,
2573 OptionValue,
2574 (LPINT)OptionLength);
2575 if (lpErrno) *lpErrno = Errno;
2576 return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
2577 }
2578
2579 INT
2580 WSPAPI
2581 WSPSetSockOpt(
2582 IN SOCKET s,
2583 IN INT level,
2584 IN INT optname,
2585 IN CONST CHAR FAR* optval,
2586 IN INT optlen,
2587 OUT LPINT lpErrno)
2588 {
2589 PSOCKET_INFORMATION Socket;
2590 INT Errno;
2591
2592 /* Get the Socket Structure associate to this Socket*/
2593 Socket = GetSocketStructure(s);
2594 if (Socket == NULL)
2595 {
2596 if (lpErrno) *lpErrno = WSAENOTSOCK;
2597 return SOCKET_ERROR;
2598 }
2599
2600
2601 /* FIXME: We should handle some more cases here */
2602 if (level == SOL_SOCKET)
2603 {
2604 switch (optname)
2605 {
2606 case SO_BROADCAST:
2607 if (optlen < sizeof(BOOL))
2608 {
2609 if (lpErrno) *lpErrno = WSAEFAULT;
2610 return SOCKET_ERROR;
2611 }
2612 Socket->SharedData->Broadcast = (*optval != 0) ? 1 : 0;
2613 return NO_ERROR;
2614
2615 case SO_OOBINLINE:
2616 if (optlen < sizeof(BOOL))
2617 {
2618 if (lpErrno) *lpErrno = WSAEFAULT;
2619 return SOCKET_ERROR;
2620 }
2621 Socket->SharedData->OobInline = (*optval != 0) ? 1 : 0;
2622 return NO_ERROR;
2623
2624 case SO_DONTLINGER:
2625 if (optlen < sizeof(BOOL))
2626 {
2627 if (lpErrno) *lpErrno = WSAEFAULT;
2628 return SOCKET_ERROR;
2629 }
2630 Socket->SharedData->LingerData.l_onoff = (*optval != 0) ? 0 : 1;
2631 return NO_ERROR;
2632
2633 case SO_REUSEADDR:
2634 if (optlen < sizeof(BOOL))
2635 {
2636 if (lpErrno) *lpErrno = WSAEFAULT;
2637 return SOCKET_ERROR;
2638 }
2639 Socket->SharedData->ReuseAddresses = (*optval != 0) ? 1 : 0;
2640 return NO_ERROR;
2641
2642 case SO_EXCLUSIVEADDRUSE:
2643 if (optlen < sizeof(BOOL))
2644 {
2645 if (lpErrno) *lpErrno = WSAEFAULT;
2646 return SOCKET_ERROR;
2647 }
2648 Socket->SharedData->ExclusiveAddressUse = (*optval != 0) ? 1 : 0;
2649 return NO_ERROR;
2650
2651 case SO_LINGER:
2652 if (optlen < sizeof(struct linger))
2653 {
2654 if (lpErrno) *lpErrno = WSAEFAULT;
2655 return SOCKET_ERROR;
2656 }
2657 RtlCopyMemory(&Socket->SharedData->LingerData,
2658 optval,
2659 sizeof(struct linger));
2660 return NO_ERROR;
2661
2662 case SO_SNDBUF:
2663 if (optlen < sizeof(DWORD))
2664 {
2665 if (lpErrno) *lpErrno = WSAEFAULT;
2666 return SOCKET_ERROR;
2667 }
2668
2669 /* TODO: The total per-socket buffer space reserved for sends */
2670 ERR("Setting send buf to %x is not implemented yet\n", optval);
2671 return NO_ERROR;
2672
2673 case SO_SNDTIMEO:
2674 if (optlen < sizeof(DWORD))
2675 {
2676 if (lpErrno) *lpErrno = WSAEFAULT;
2677 return SOCKET_ERROR;
2678 }
2679
2680 RtlCopyMemory(&Socket->SharedData->SendTimeout,
2681 optval,
2682 sizeof(DWORD));
2683 return NO_ERROR;
2684
2685 case SO_RCVTIMEO:
2686 if (optlen < sizeof(DWORD))
2687 {
2688 if (lpErrno) *lpErrno = WSAEFAULT;
2689 return SOCKET_ERROR;
2690 }
2691
2692 RtlCopyMemory(&Socket->SharedData->RecvTimeout,
2693 optval,
2694 sizeof(DWORD));
2695 return NO_ERROR;
2696
2697 case SO_KEEPALIVE:
2698 case SO_DONTROUTE:
2699 /* These go directly to the helper dll */
2700 goto SendToHelper;
2701
2702 default:
2703 /* Obviously this is a hack */
2704 ERR("MSAFD: Set unknown optname %x\n", optname);
2705 return NO_ERROR;
2706 }
2707 }
2708
2709 SendToHelper:
2710 Errno = Socket->HelperData->WSHSetSocketInformation(Socket->HelperContext,
2711 s,
2712 Socket->TdiAddressHandle,
2713 Socket->TdiConnectionHandle,
2714 level,
2715 optname,
2716 (PCHAR)optval,
2717 optlen);
2718 if (lpErrno) *lpErrno = Errno;
2719 return (Errno == NO_ERROR) ? NO_ERROR : SOCKET_ERROR;
2720 }
2721
2722 /*
2723 * FUNCTION: Initialize service provider for a client
2724 * ARGUMENTS:
2725 * wVersionRequested = Highest WinSock SPI version that the caller can use
2726 * lpWSPData = Address of WSPDATA structure to initialize
2727 * lpProtocolInfo = Pointer to structure that defines the desired protocol
2728 * UpcallTable = Pointer to upcall table of the WinSock DLL
2729 * lpProcTable = Address of procedure table to initialize
2730 * RETURNS:
2731 * Status of operation
2732 */
2733 INT
2734 WSPAPI
2735 WSPStartup(IN WORD wVersionRequested,
2736 OUT LPWSPDATA lpWSPData,
2737 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
2738 IN WSPUPCALLTABLE UpcallTable,
2739 OUT LPWSPPROC_TABLE lpProcTable)
2740
2741 {
2742 NTSTATUS Status;
2743
2744 if (((LOBYTE(wVersionRequested) == 2) && (HIBYTE(wVersionRequested) < 2)) ||
2745 (LOBYTE(wVersionRequested) < 2))
2746 {
2747 ERR("WSPStartup NOT SUPPORTED for version 0x%X\n", wVersionRequested);
2748 return WSAVERNOTSUPPORTED;
2749 }
2750 else
2751 Status = NO_ERROR;
2752 /* FIXME: Enable all cases of WSPStartup status */
2753 Upcalls = UpcallTable;
2754
2755 if (Status == NO_ERROR)
2756 {
2757 lpProcTable->lpWSPAccept = WSPAccept;
2758 lpProcTable->lpWSPAddressToString = WSPAddressToString;
2759 lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
2760 lpProcTable->lpWSPBind = WSPBind;
2761 lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
2762 lpProcTable->lpWSPCleanup = WSPCleanup;
2763 lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
2764 lpProcTable->lpWSPConnect = WSPConnect;
2765 lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
2766 lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
2767 lpProcTable->lpWSPEventSelect = WSPEventSelect;
2768 lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
2769 lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
2770 lpProcTable->lpWSPGetSockName = WSPGetSockName;
2771 lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
2772 lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
2773 lpProcTable->lpWSPIoctl = WSPIoctl;
2774 lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
2775 lpProcTable->lpWSPListen = WSPListen;
2776 lpProcTable->lpWSPRecv = WSPRecv;
2777 lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
2778 lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
2779 lpProcTable->lpWSPSelect = WSPSelect;
2780 lpProcTable->lpWSPSend = WSPSend;
2781 lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
2782 lpProcTable->lpWSPSendTo = WSPSendTo;
2783 lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
2784 lpProcTable->lpWSPShutdown = WSPShutdown;
2785 lpProcTable->lpWSPSocket = WSPSocket;
2786 lpProcTable->lpWSPStringToAddress = WSPStringToAddress;
2787 lpWSPData->wVersion = MAKEWORD(2, 2);
2788 lpWSPData->wHighVersion = MAKEWORD(2, 2);
2789 /* Save CatalogEntryId for all upcalls */
2790 CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
2791 }
2792
2793 TRACE("Status (%d).\n", Status);
2794 return Status;
2795 }
2796
2797
2798 INT
2799 WSPAPI
2800 WSPAddressToString(IN LPSOCKADDR lpsaAddress,
2801 IN DWORD dwAddressLength,
2802 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
2803 OUT LPWSTR lpszAddressString,
2804 IN OUT LPDWORD lpdwAddressStringLength,
2805 OUT LPINT lpErrno)
2806 {
2807 DWORD size;
2808 WCHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
2809 WCHAR *p;
2810
2811 if (!lpsaAddress || !lpszAddressString || !lpdwAddressStringLength)
2812 {
2813 if (lpErrno) *lpErrno = WSAEFAULT;
2814 return SOCKET_ERROR;
2815 }
2816
2817 switch (lpsaAddress->sa_family)
2818 {
2819 case AF_INET:
2820 if (dwAddressLength < sizeof(SOCKADDR_IN))
2821 {
2822 if (lpErrno) *lpErrno = WSAEINVAL;
2823 return SOCKET_ERROR;
2824 }
2825 swprintf(buffer,
2826 L"%u.%u.%u.%u:%u",
2827 (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 24 & 0xff),
2828 (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 16 & 0xff),
2829 (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) >> 8 & 0xff),
2830 (unsigned int)(ntohl(((SOCKADDR_IN *)lpsaAddress)->sin_addr.s_addr) & 0xff),
2831 ntohs(((SOCKADDR_IN *)lpsaAddress)->sin_port));
2832
2833 p = wcschr(buffer, L':');
2834 if (!((SOCKADDR_IN *)lpsaAddress)->sin_port)
2835 {
2836 *p = 0;
2837 }
2838 break;
2839 default:
2840 if (lpErrno) *lpErrno = WSAEINVAL;
2841 return SOCKET_ERROR;
2842 }
2843
2844 size = wcslen(buffer) + 1;
2845
2846 if (*lpdwAddressStringLength < size)
2847 {
2848 *lpdwAddressStringLength = size;
2849 if (lpErrno) *lpErrno = WSAEFAULT;
2850 return SOCKET_ERROR;
2851 }
2852
2853 *lpdwAddressStringLength = size;
2854 wcscpy(lpszAddressString, buffer);
2855 return 0;
2856 }
2857
2858 INT
2859 WSPAPI
2860 WSPStringToAddress(IN LPWSTR AddressString,
2861 IN INT AddressFamily,
2862 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
2863 OUT LPSOCKADDR lpAddress,
2864 IN OUT LPINT lpAddressLength,
2865 OUT LPINT lpErrno)
2866 {
2867 int pos = 0;
2868 LONG inetaddr = 0;
2869 LPWSTR *bp = NULL;
2870 SOCKADDR_IN *sockaddr;
2871
2872 if (!lpAddressLength || !lpAddress || !AddressString)
2873 {
2874 if (lpErrno) *lpErrno = WSAEINVAL;
2875 return SOCKET_ERROR;
2876 }
2877
2878 sockaddr = (SOCKADDR_IN *)lpAddress;
2879
2880 /* Set right address family */
2881 if (lpProtocolInfo != NULL)
2882 {
2883 sockaddr->sin_family = lpProtocolInfo->iAddressFamily;
2884 }
2885 else
2886 {
2887 sockaddr->sin_family = AddressFamily;
2888 }
2889
2890 /* Report size */
2891 if (AddressFamily == AF_INET)
2892 {
2893 if (*lpAddressLength < (INT)sizeof(SOCKADDR_IN))
2894 {
2895 *lpAddressLength = sizeof(SOCKADDR_IN);
2896 if (lpErrno) *lpErrno = WSAEFAULT;
2897 }
2898 else
2899 {
2900 // translate ip string to ip
2901
2902 /* rest sockaddr.sin_addr.s_addr
2903 for we need to be sure it is zero when we come to while */
2904 memset(lpAddress, 0, sizeof(SOCKADDR_IN));
2905
2906 /* Set right adress family */
2907 sockaddr->sin_family = AF_INET;
2908
2909 /* Get port number */
2910 pos = wcscspn(AddressString, L":") + 1;
2911
2912 if (pos < (int)wcslen(AddressString))
2913 {
2914 sockaddr->sin_port = wcstol(&AddressString[pos], bp, 10);
2915 }
2916 else
2917 {
2918 sockaddr->sin_port = 0;
2919 }
2920
2921 /* Get ip number */
2922 pos = 0;
2923 inetaddr = 0;
2924
2925 while (pos < (int)wcslen(AddressString))
2926 {
2927 inetaddr = (inetaddr << 8) +
2928 ((UCHAR)wcstol(&AddressString[pos], bp, 10));
2929
2930 pos += wcscspn(&AddressString[pos], L".") + 1;
2931 }
2932
2933 if (lpErrno) *lpErrno = NO_ERROR;
2934 sockaddr->sin_addr.s_addr = inetaddr;
2935
2936 }
2937 }
2938
2939 if (lpErrno && !*lpErrno)
2940 {
2941 return 0;
2942 }
2943
2944 return SOCKET_ERROR;
2945 }
2946
2947 /*
2948 * FUNCTION: Cleans up service provider for a client
2949 * ARGUMENTS:
2950 * lpErrno = Address of buffer for error information
2951 * RETURNS:
2952 * 0 if successful, or SOCKET_ERROR if not
2953 */
2954 INT
2955 WSPAPI
2956 WSPCleanup(OUT LPINT lpErrno)
2957
2958 {
2959 TRACE("Leaving.\n");
2960
2961 if (lpErrno) *lpErrno = NO_ERROR;
2962
2963 return 0;
2964 }
2965
2966 VOID
2967 NTAPI
2968 AfdInfoAPC(PVOID ApcContext,
2969 PIO_STATUS_BLOCK IoStatusBlock,
2970 ULONG Reserved)
2971 {
2972 PAFDAPCCONTEXT Context = ApcContext;
2973
2974 Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0);
2975 HeapFree(GlobalHeap, 0, ApcContext);
2976 }
2977
2978 int
2979 GetSocketInformation(PSOCKET_INFORMATION Socket,
2980 ULONG AfdInformationClass,
2981 PBOOLEAN Boolean OPTIONAL,
2982 PULONG Ulong OPTIONAL,
2983 PLARGE_INTEGER LargeInteger OPTIONAL,
2984 LPWSAOVERLAPPED Overlapped OPTIONAL,
2985 LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL)
2986 {
2987 PIO_STATUS_BLOCK IOSB;
2988 IO_STATUS_BLOCK DummyIOSB;
2989 AFD_INFO InfoData;
2990 NTSTATUS Status;
2991 PAFDAPCCONTEXT APCContext;
2992 PIO_APC_ROUTINE APCFunction;
2993 HANDLE Event = NULL;
2994 HANDLE SockEvent;
2995
2996 Status = NtCreateEvent(&SockEvent,
2997 EVENT_ALL_ACCESS,
2998 NULL,
2999 1,
3000 FALSE);
3001
3002 if( !NT_SUCCESS(Status) )
3003 return SOCKET_ERROR;
3004
3005 /* Set Info Class */
3006 InfoData.InformationClass = AfdInformationClass;
3007
3008 /* Verify if we should use APC */
3009 if (Overlapped == NULL)
3010 {
3011 /* Not using Overlapped structure, so use normal blocking on event */
3012 APCContext = NULL;
3013 APCFunction = NULL;
3014 Event = SockEvent;
3015 IOSB = &DummyIOSB;
3016 }
3017 else
3018 {
3019 /* Overlapped request for non overlapped opened socket */
3020 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
3021 {
3022 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
3023 return 0;
3024 }
3025 if (CompletionRoutine == NULL)
3026 {
3027 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
3028 APCContext = (PAFDAPCCONTEXT)Overlapped;
3029 APCFunction = NULL;
3030 Event = Overlapped->hEvent;
3031 }
3032 else
3033 {
3034 /* Using Overlapped Structure and a Completition Routine, so use an APC */
3035 APCFunction = &AfdInfoAPC; // should be a private io completition function inside us
3036 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
3037 if (!APCContext)
3038 {
3039 ERR("Not enough memory for APC Context\n");
3040 return WSAEFAULT;
3041 }
3042 APCContext->lpCompletionRoutine = CompletionRoutine;
3043 APCContext->lpOverlapped = Overlapped;
3044 APCContext->lpSocket = Socket;
3045 }
3046
3047 IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
3048 }
3049
3050 IOSB->Status = STATUS_PENDING;
3051
3052 /* Send IOCTL */
3053 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3054 Event,
3055 APCFunction,
3056 APCContext,
3057 IOSB,
3058 IOCTL_AFD_GET_INFO,
3059 &InfoData,
3060 sizeof(InfoData),
3061 &InfoData,
3062 sizeof(InfoData));
3063
3064 /* Wait for return */
3065 if (Status == STATUS_PENDING && Overlapped == NULL)
3066 {
3067 WaitForSingleObject(SockEvent, INFINITE);
3068 Status = IOSB->Status;
3069 }
3070
3071 TRACE("Status %x Information %d\n", Status, IOSB->Information);
3072
3073 if (Status == STATUS_PENDING)
3074 {
3075 TRACE("Leaving (Pending)\n");
3076 return WSA_IO_PENDING;
3077 }
3078
3079 if (Status != STATUS_SUCCESS)
3080 return SOCKET_ERROR;
3081
3082 /* Return Information */
3083 if (Ulong != NULL)
3084 {
3085 *Ulong = InfoData.Information.Ulong;
3086 }
3087 if (LargeInteger != NULL)
3088 {
3089 *LargeInteger = InfoData.Information.LargeInteger;
3090 }
3091 if (Boolean != NULL)
3092 {
3093 *Boolean = InfoData.Information.Boolean;
3094 }
3095
3096 NtClose( SockEvent );
3097
3098 return NO_ERROR;
3099
3100 }
3101
3102
3103 int
3104 SetSocketInformation(PSOCKET_INFORMATION Socket,
3105 ULONG AfdInformationClass,
3106 PBOOLEAN Boolean OPTIONAL,
3107 PULONG Ulong OPTIONAL,
3108 PLARGE_INTEGER LargeInteger OPTIONAL,
3109 LPWSAOVERLAPPED Overlapped OPTIONAL,
3110 LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL)
3111 {
3112 PIO_STATUS_BLOCK IOSB;
3113 IO_STATUS_BLOCK DummyIOSB;
3114 AFD_INFO InfoData;
3115 NTSTATUS Status;
3116 PAFDAPCCONTEXT APCContext;
3117 PIO_APC_ROUTINE APCFunction;
3118 HANDLE Event = NULL;
3119 HANDLE SockEvent;
3120
3121 Status = NtCreateEvent(&SockEvent,
3122 EVENT_ALL_ACCESS,
3123 NULL,
3124 1,
3125 FALSE);
3126
3127 if( !NT_SUCCESS(Status) )
3128 return SOCKET_ERROR;
3129
3130 /* Set Info Class */
3131 InfoData.InformationClass = AfdInformationClass;
3132
3133 /* Set Information */
3134 if (Ulong != NULL)
3135 {
3136 InfoData.Information.Ulong = *Ulong;
3137 }
3138 if (LargeInteger != NULL)
3139 {
3140 InfoData.Information.LargeInteger = *LargeInteger;
3141 }
3142 if (Boolean != NULL)
3143 {
3144 InfoData.Information.Boolean = *Boolean;
3145 }
3146
3147 /* Verify if we should use APC */
3148 if (Overlapped == NULL)
3149 {
3150 /* Not using Overlapped structure, so use normal blocking on event */
3151 APCContext = NULL;
3152 APCFunction = NULL;
3153 Event = SockEvent;
3154 IOSB = &DummyIOSB;
3155 }
3156 else
3157 {
3158 /* Overlapped request for non overlapped opened socket */
3159 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
3160 {
3161 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
3162 return 0;
3163 }
3164 if (CompletionRoutine == NULL)
3165 {
3166 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
3167 APCContext = (PAFDAPCCONTEXT)Overlapped;
3168 APCFunction = NULL;
3169 Event = Overlapped->hEvent;
3170 }
3171 else
3172 {
3173 /* Using Overlapped Structure and a Completition Routine, so use an APC */
3174 APCFunction = &AfdInfoAPC; // should be a private io completition function inside us
3175 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
3176 if (!APCContext)
3177 {
3178 ERR("Not enough memory for APC Context\n");
3179 return WSAEFAULT;
3180 }
3181 APCContext->lpCompletionRoutine = CompletionRoutine;
3182 APCContext->lpOverlapped = Overlapped;
3183 APCContext->lpSocket = Socket;
3184 }
3185
3186 IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal;
3187 }
3188
3189 IOSB->Status = STATUS_PENDING;
3190
3191 /* Send IOCTL */
3192 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3193 Event,
3194 APCFunction,
3195 APCContext,
3196 IOSB,
3197 IOCTL_AFD_SET_INFO,
3198 &InfoData,
3199 sizeof(InfoData),
3200 NULL,
3201 0);
3202
3203 /* Wait for return */
3204 if (Status == STATUS_PENDING && Overlapped == NULL)
3205 {
3206 WaitForSingleObject(SockEvent, INFINITE);
3207 Status = IOSB->Status;
3208 }
3209
3210 NtClose( SockEvent );
3211
3212 TRACE("Status %x Information %d\n", Status, IOSB->Information);
3213
3214 if (Status == STATUS_PENDING)
3215 {
3216 TRACE("Leaving (Pending)\n");
3217 return WSA_IO_PENDING;
3218 }
3219
3220 return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
3221
3222 }
3223
3224 PSOCKET_INFORMATION
3225 GetSocketStructure(SOCKET Handle)
3226 {
3227 PSOCKET_INFORMATION CurrentSocket;
3228
3229 EnterCriticalSection(&SocketListLock);
3230
3231 CurrentSocket = SocketListHead;
3232 while (CurrentSocket)
3233 {
3234 if (CurrentSocket->Handle == Handle)
3235 {
3236 LeaveCriticalSection(&SocketListLock);
3237 return CurrentSocket;
3238 }
3239
3240 CurrentSocket = CurrentSocket->NextSocket;
3241 }
3242
3243 LeaveCriticalSection(&SocketListLock);
3244
3245 return NULL;
3246 }
3247
3248 int CreateContext(PSOCKET_INFORMATION Socket)
3249 {
3250 IO_STATUS_BLOCK IOSB;
3251 SOCKET_CONTEXT ContextData;
3252 NTSTATUS Status;
3253 HANDLE SockEvent;
3254
3255 Status = NtCreateEvent(&SockEvent,
3256 EVENT_ALL_ACCESS,
3257 NULL,
3258 1,
3259 FALSE);
3260
3261 if( !NT_SUCCESS(Status) )
3262 return SOCKET_ERROR;
3263
3264 /* Create Context */
3265 ContextData.SharedData = *Socket->SharedData;
3266 ContextData.SizeOfHelperData = 0;
3267 RtlCopyMemory (&ContextData.LocalAddress,
3268 Socket->LocalAddress,
3269 Socket->SharedData->SizeOfLocalAddress);
3270 RtlCopyMemory (&ContextData.RemoteAddress,
3271 Socket->RemoteAddress,
3272 Socket->SharedData->SizeOfRemoteAddress);
3273
3274 /* Send IOCTL */
3275 Status = NtDeviceIoControlFile((HANDLE)Socket->Handle,
3276 SockEvent,
3277 NULL,
3278 NULL,
3279 &IOSB,
3280 IOCTL_AFD_SET_CONTEXT,
3281 &ContextData,
3282 sizeof(ContextData),
3283 NULL,
3284 0);
3285
3286 /* Wait for Completition */
3287 if (Status == STATUS_PENDING)
3288 {
3289 WaitForSingleObject(SockEvent, INFINITE);
3290 Status = IOSB.Status;
3291 }
3292
3293 NtClose( SockEvent );
3294
3295 return Status == STATUS_SUCCESS ? NO_ERROR : SOCKET_ERROR;
3296 }
3297
3298 BOOLEAN SockCreateOrReferenceAsyncThread(VOID)
3299 {
3300 HANDLE hAsyncThread;
3301 DWORD AsyncThreadId;
3302 HANDLE AsyncEvent;
3303 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
3304 NTSTATUS Status;
3305
3306 /* Check if the Thread Already Exists */
3307 if (SockAsyncThreadRefCount)
3308 {
3309 ASSERT(SockAsyncCompletionPort);
3310 return TRUE;
3311 }
3312
3313 /* Create the Completion Port */
3314 if (!SockAsyncCompletionPort)
3315 {
3316 Status = NtCreateIoCompletion(&SockAsyncCompletionPort,
3317 IO_COMPLETION_ALL_ACCESS,
3318 NULL,
3319 2); // Allow 2 threads only
3320 if (!NT_SUCCESS(Status))
3321 {
3322 ERR("Failed to create completion port: 0x%08x\n", Status);
3323 return FALSE;
3324 }
3325 /* Protect Handle */
3326 HandleFlags.ProtectFromClose = TRUE;
3327 HandleFlags.Inherit = FALSE;
3328 Status = NtSetInformationObject(SockAsyncCompletionPort,
3329 ObjectHandleFlagInformation,
3330 &HandleFlags,
3331 sizeof(HandleFlags));
3332 }
3333
3334 /* Create the Async Event */
3335 Status = NtCreateEvent(&AsyncEvent,
3336 EVENT_ALL_ACCESS,
3337 NULL,
3338 NotificationEvent,
3339 FALSE);
3340
3341 /* Create the Async Thread */
3342 hAsyncThread = CreateThread(NULL,
3343 0,
3344 (LPTHREAD_START_ROUTINE)SockAsyncThread,
3345 NULL,
3346 0,
3347 &AsyncThreadId);
3348
3349 /* Close the Handle */
3350 NtClose(hAsyncThread);
3351
3352 /* Increase the Reference Count */
3353 SockAsyncThreadRefCount++;
3354 return TRUE;
3355 }
3356
3357 int SockAsyncThread(PVOID ThreadParam)
3358 {
3359 PVOID AsyncContext;
3360 PASYNC_COMPLETION_ROUTINE AsyncCompletionRoutine;
3361 IO_STATUS_BLOCK IOSB;
3362 NTSTATUS Status;
3363
3364 /* Make the Thread Higher Priority */
3365 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
3366
3367 /* Do a KQUEUE/WorkItem Style Loop, thanks to IoCompletion Ports */
3368 do
3369 {
3370 Status = NtRemoveIoCompletion (SockAsyncCompletionPort,
3371 (PVOID*)&AsyncCompletionRoutine,
3372 &AsyncContext,
3373 &IOSB,
3374 NULL);
3375 /* Call the Async Function */
3376 if (NT_SUCCESS(Status))
3377 {
3378 (*AsyncCompletionRoutine)(AsyncContext, &IOSB);
3379 }
3380 else
3381 {
3382 /* It Failed, sleep for a second */
3383 Sleep(1000);
3384 }
3385 } while ((Status != STATUS_TIMEOUT));
3386
3387 /* The Thread has Ended */
3388 return 0;
3389 }
3390
3391 BOOLEAN SockGetAsyncSelectHelperAfdHandle(VOID)
3392 {
3393 UNICODE_STRING AfdHelper;
3394 OBJECT_ATTRIBUTES ObjectAttributes;
3395 IO_STATUS_BLOCK IoSb;
3396 FILE_COMPLETION_INFORMATION CompletionInfo;
3397 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
3398
3399 /* First, make sure we're not already intialized */
3400 if (SockAsyncHelperAfdHandle)
3401 {
3402 return TRUE;
3403 }
3404
3405 /* Set up Handle Name and Object */
3406 RtlInitUnicodeString(&AfdHelper, L"\\Device\\Afd\\AsyncSelectHlp" );
3407 InitializeObjectAttributes(&ObjectAttributes,
3408 &AfdHelper,
3409 OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
3410 NULL,
3411 NULL);
3412
3413 /* Open the Handle to AFD */
3414 NtCreateFile(&SockAsyncHelperAfdHandle,
3415 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3416 &ObjectAttributes,
3417 &IoSb,
3418 NULL,
3419 0,
3420 FILE_SHARE_READ | FILE_SHARE_WRITE,
3421 FILE_OPEN_IF,
3422 0,
3423 NULL,
3424 0);
3425
3426 /*
3427 * Now Set up the Completion Port Information
3428 * This means that whenever a Poll is finished, the routine will be executed
3429 */
3430 CompletionInfo.Port = SockAsyncCompletionPort;
3431 CompletionInfo.Key = SockAsyncSelectCompletionRoutine;
3432 NtSetInformationFile(SockAsyncHelperAfdHandle,
3433 &IoSb,
3434 &CompletionInfo,
3435 sizeof(CompletionInfo),
3436 FileCompletionInformation);
3437
3438
3439 /* Protect the Handle */
3440 HandleFlags.ProtectFromClose = TRUE;
3441 HandleFlags.Inherit = FALSE;
3442 NtSetInformationObject(SockAsyncCompletionPort,
3443 ObjectHandleFlagInformation,
3444 &HandleFlags,
3445 sizeof(HandleFlags));
3446
3447
3448 /* Set this variable to true so that Send/Recv/Accept will know wether to renable disabled events */
3449 SockAsyncSelectCalled = TRUE;
3450 return TRUE;
3451 }
3452
3453 VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
3454 {
3455
3456 PASYNC_DATA AsyncData = Context;
3457 PSOCKET_INFORMATION Socket;
3458 ULONG x;
3459
3460 /* Get the Socket */
3461 Socket = AsyncData->ParentSocket;
3462
3463 /* Check if the Sequence Number Changed behind our back */
3464 if (AsyncData->SequenceNumber != Socket->SharedData->SequenceNumber )
3465 {
3466 return;
3467 }
3468
3469 /* Check we were manually called b/c of a failure */
3470 if (!NT_SUCCESS(IoStatusBlock->Status))
3471 {
3472 /* FIXME: Perform Upcall */
3473 return;
3474 }
3475
3476 for (x = 1; x; x<<=1)
3477 {
3478 switch (AsyncData->AsyncSelectInfo.Handles[0].Events & x)
3479 {
3480 case AFD_EVENT_RECEIVE:
3481 if (0 != (Socket->SharedData->AsyncEvents & FD_READ) &&
3482 0 == (Socket->SharedData->AsyncDisabledEvents & FD_READ))
3483 {
3484 /* Make the Notifcation */
3485 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3486 Socket->SharedData->wMsg,
3487 Socket->Handle,
3488 WSAMAKESELECTREPLY(FD_READ, 0));
3489 /* Disable this event until the next read(); */
3490 Socket->SharedData->AsyncDisabledEvents |= FD_READ;
3491 }
3492 break;
3493
3494 case AFD_EVENT_OOB_RECEIVE:
3495 if (0 != (Socket->SharedData->AsyncEvents & FD_OOB) &&
3496 0 == (Socket->SharedData->AsyncDisabledEvents & FD_OOB))
3497 {
3498 /* Make the Notifcation */
3499 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3500 Socket->SharedData->wMsg,
3501 Socket->Handle,
3502 WSAMAKESELECTREPLY(FD_OOB, 0));
3503 /* Disable this event until the next read(); */
3504 Socket->SharedData->AsyncDisabledEvents |= FD_OOB;
3505 }
3506 break;
3507
3508 case AFD_EVENT_SEND:
3509 if (0 != (Socket->SharedData->AsyncEvents & FD_WRITE) &&
3510 0 == (Socket->SharedData->AsyncDisabledEvents & FD_WRITE))
3511 {
3512 /* Make the Notifcation */
3513 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3514 Socket->SharedData->wMsg,
3515 Socket->Handle,
3516 WSAMAKESELECTREPLY(FD_WRITE, 0));
3517 /* Disable this event until the next write(); */
3518 Socket->SharedData->AsyncDisabledEvents |= FD_WRITE;
3519 }
3520 break;
3521
3522 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
3523 case AFD_EVENT_CONNECT:
3524 case AFD_EVENT_CONNECT_FAIL:
3525 if (0 != (Socket->SharedData->AsyncEvents & FD_CONNECT) &&
3526 0 == (Socket->SharedData->AsyncDisabledEvents & FD_CONNECT))
3527 {
3528 /* Make the Notifcation */
3529 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3530 Socket->SharedData->wMsg,
3531 Socket->Handle,
3532 WSAMAKESELECTREPLY(FD_CONNECT, 0));
3533 /* Disable this event forever; */
3534 Socket->SharedData->AsyncDisabledEvents |= FD_CONNECT;
3535 }
3536 break;
3537
3538 case AFD_EVENT_ACCEPT:
3539 if (0 != (Socket->SharedData->AsyncEvents & FD_ACCEPT) &&
3540 0 == (Socket->SharedData->AsyncDisabledEvents & FD_ACCEPT))
3541 {
3542 /* Make the Notifcation */
3543 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3544 Socket->SharedData->wMsg,
3545 Socket->Handle,
3546 WSAMAKESELECTREPLY(FD_ACCEPT, 0));
3547 /* Disable this event until the next accept(); */
3548 Socket->SharedData->AsyncDisabledEvents |= FD_ACCEPT;
3549 }
3550 break;
3551
3552 case AFD_EVENT_DISCONNECT:
3553 case AFD_EVENT_ABORT:
3554 case AFD_EVENT_CLOSE:
3555 if (0 != (Socket->SharedData->AsyncEvents & FD_CLOSE) &&
3556 0 == (Socket->SharedData->AsyncDisabledEvents & FD_CLOSE))
3557 {
3558 /* Make the Notifcation */
3559 (Upcalls.lpWPUPostMessage)(Socket->SharedData->hWnd,
3560 Socket->SharedData->wMsg,
3561 Socket->Handle,
3562 WSAMAKESELECTREPLY(FD_CLOSE, 0));
3563 /* Disable this event forever; */
3564 Socket->SharedData->AsyncDisabledEvents |= FD_CLOSE;
3565 }
3566 break;
3567 /* FIXME: Support QOS */
3568 }
3569 }
3570
3571 /* Check if there are any events left for us to check */
3572 if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0 )
3573 {
3574 return;
3575 }
3576
3577 /* Keep Polling */
3578 SockProcessAsyncSelect(Socket, AsyncData);
3579 return;
3580 }
3581
3582 VOID SockProcessAsyncSelect(PSOCKET_INFORMATION Socket, PASYNC_DATA AsyncData)
3583 {
3584
3585 ULONG lNetworkEvents;
3586 NTSTATUS Status;
3587
3588 /* Set up the Async Data Event Info */
3589 AsyncData->AsyncSelectInfo.Timeout.HighPart = 0x7FFFFFFF;
3590 AsyncData->AsyncSelectInfo.Timeout.LowPart = 0xFFFFFFFF;
3591 AsyncData->AsyncSelectInfo.HandleCount = 1;
3592 AsyncData->AsyncSelectInfo.Exclusive = TRUE;
3593 AsyncData->AsyncSelectInfo.Handles[0].Handle = Socket->Handle;
3594 AsyncData->AsyncSelectInfo.Handles[0].Events = 0;
3595
3596 /* Remove unwanted events */
3597 lNetworkEvents = Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents);
3598
3599 /* Set Events to wait for */
3600 if (lNetworkEvents & FD_READ)
3601 {
3602 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_RECEIVE;
3603 }
3604
3605 if (lNetworkEvents & FD_WRITE)
3606 {
3607 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_SEND;
3608 }
3609
3610 if (lNetworkEvents & FD_OOB)
3611 {
3612 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_OOB_RECEIVE;
3613 }
3614
3615 if (lNetworkEvents & FD_ACCEPT)
3616 {
3617 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_ACCEPT;
3618 }
3619
3620 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
3621 if (lNetworkEvents & FD_CONNECT)
3622 {
3623 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL;
3624 }
3625
3626 if (lNetworkEvents & FD_CLOSE)
3627 {
3628 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT | AFD_EVENT_CLOSE;
3629 }
3630
3631 if (lNetworkEvents & FD_QOS)
3632 {
3633 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_QOS;
3634 }
3635
3636 if (lNetworkEvents & FD_GROUP_QOS)
3637 {
3638 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_GROUP_QOS;
3639 }
3640
3641 /* Send IOCTL */
3642 Status = NtDeviceIoControlFile (SockAsyncHelperAfdHandle,
3643 NULL,
3644 NULL,
3645 AsyncData,
3646 &AsyncData->IoStatusBlock,
3647 IOCTL_AFD_SELECT,
3648 &AsyncData->AsyncSelectInfo,
3649 sizeof(AsyncData->AsyncSelectInfo),
3650 &AsyncData->AsyncSelectInfo,
3651 sizeof(AsyncData->AsyncSelectInfo));
3652
3653 /* I/O Manager Won't call the completion routine, let's do it manually */
3654 if (NT_SUCCESS(Status))
3655 {
3656 return;
3657 }
3658 else
3659 {
3660 AsyncData->IoStatusBlock.Status = Status;
3661 SockAsyncSelectCompletionRoutine(AsyncData, &AsyncData->IoStatusBlock);
3662 }
3663 }
3664
3665 VOID SockProcessQueuedAsyncSelect(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
3666 {
3667 PASYNC_DATA AsyncData = Context;
3668 BOOL FreeContext = TRUE;
3669 PSOCKET_INFORMATION Socket;
3670
3671 /* Get the Socket */
3672 Socket = AsyncData->ParentSocket;
3673
3674 /* If someone closed it, stop the function */
3675 if (Socket->SharedData->State != SocketClosed)
3676 {
3677 /* Check if the Sequence Number changed by now, in which case quit */
3678 if (AsyncData->SequenceNumber == Socket->SharedData->SequenceNumber)
3679 {
3680 /* Do the actuall select, if needed */
3681 if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)))
3682 {
3683 SockProcessAsyncSelect(Socket, AsyncData);
3684 FreeContext = FALSE;
3685 }
3686 }
3687 }
3688
3689 /* Free the Context */
3690 if (FreeContext)
3691 {
3692 HeapFree(GetProcessHeap(), 0, AsyncData);
3693 }
3694
3695 return;
3696 }
3697
3698 VOID
3699 SockReenableAsyncSelectEvent (IN PSOCKET_INFORMATION Socket,
3700 IN ULONG Event)
3701 {
3702 PASYNC_DATA AsyncData;
3703
3704 /* Make sure the event is actually disabled */
3705 if (!(Socket->SharedData->AsyncDisabledEvents & Event))
3706 {
3707 return;
3708 }
3709
3710 /* Re-enable it */
3711 Socket->SharedData->AsyncDisabledEvents &= ~Event;
3712
3713 /* Return if no more events are being polled */
3714 if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0 )
3715 {
3716 return;
3717 }
3718
3719 /* Wait on new events */
3720 AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(ASYNC_DATA));
3721 if (!AsyncData) return;
3722
3723 /* Create the Asynch Thread if Needed */
3724 SockCreateOrReferenceAsyncThread();
3725
3726 /* Increase the sequence number to stop anything else */
3727 Socket->SharedData->SequenceNumber++;
3728
3729 /* Set up the Async Data */
3730 AsyncData->ParentSocket = Socket;
3731 AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber;
3732
3733 /* Begin Async Select by using I/O Completion */
3734 NtSetIoCompletion(SockAsyncCompletionPort,
3735 (PVOID)&SockProcessQueuedAsyncSelect,
3736 AsyncData,
3737 0,
3738 0);
3739
3740 /* All done */
3741 return;
3742 }
3743
3744 BOOL
3745 WINAPI
3746 DllMain(HANDLE hInstDll,
3747 ULONG dwReason,
3748 PVOID Reserved)
3749 {
3750
3751 switch (dwReason)
3752 {
3753 case DLL_PROCESS_ATTACH:
3754
3755 TRACE("Loading MSAFD.DLL \n");
3756
3757 /* Don't need thread attach notifications
3758 so disable them to improve performance */
3759 DisableThreadLibraryCalls(hInstDll);
3760
3761 /* List of DLL Helpers */
3762 InitializeListHead(&SockHelpersListHead);
3763
3764 /* Heap to use when allocating */
3765 GlobalHeap = GetProcessHeap();
3766
3767 /* Initialize the lock that protects our socket list */
3768 InitializeCriticalSection(&SocketListLock);
3769
3770 TRACE("MSAFD.DLL has been loaded\n");
3771
3772 break;
3773
3774 case DLL_THREAD_ATTACH:
3775 break;
3776
3777 case DLL_THREAD_DETACH:
3778 break;
3779
3780 case DLL_PROCESS_DETACH:
3781
3782 /* Delete the socket list lock */
3783 DeleteCriticalSection(&SocketListLock);
3784
3785 break;
3786 }
3787
3788 TRACE("DllMain of msafd.dll (leaving)\n");
3789
3790 return TRUE;
3791 }
3792
3793 /* EOF */
3794
3795