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