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