d9fbb9070b93b41a4bf6f77782541a7e84137a6d
[reactos.git] / dll / win32 / msafd / misc / dllmain.c
1
2 /*
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Ancillary Function Driver DLL
5 * FILE: misc/dllmain.c
6 * PURPOSE: DLL entry point
7 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * Alex Ionescu (alex@relsoft.net)
9 * REVISIONS:
10 * CSH 01/09-2000 Created
11 * Alex 16/07/2004 - Complete Rewrite
12 */
13 #include <msafd.h>
14
15 #include <debug.h>
16
17 #ifdef DBG
18 //DWORD DebugTraceLevel = DEBUG_ULTRA;
19 DWORD DebugTraceLevel = 0;
20 #endif /* DBG */
21
22 HANDLE GlobalHeap;
23 WSPUPCALLTABLE Upcalls;
24 LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
25 ULONG SocketCount = 0;
26 PSOCKET_INFORMATION *Sockets = NULL;
27 LIST_ENTRY SockHelpersListHead = {NULL};
28 ULONG SockAsyncThreadRefCount;
29 HANDLE SockAsyncHelperAfdHandle;
30 HANDLE SockAsyncCompletionPort;
31 BOOLEAN SockAsyncSelectCalled;
32
33 SOCKET
34 WSPAPI
35 WSPSocket(
36 int AddressFamily,
37 int SocketType,
38 int Protocol,
39 LPWSAPROTOCOL_INFOW lpProtocolInfo,
40 GROUP g,
41 DWORD dwFlags,
42 LPINT lpErrno)
43 /*
44 * FUNCTION: Creates a new socket
45 * ARGUMENTS:
46 * af = Address family
47 * type = Socket type
48 * protocol = Protocol type
49 * lpProtocolInfo = Pointer to protocol information
50 * g = Reserved
51 * dwFlags = Socket flags
52 * lpErrno = Address of buffer for error information
53 * RETURNS:
54 * Created socket, or INVALID_SOCKET if it could not be created
55 */
56 {
57 OBJECT_ATTRIBUTES Object;
58 IO_STATUS_BLOCK IOSB;
59 USHORT SizeOfPacket;
60 ULONG SizeOfEA;
61 PAFD_CREATE_PACKET AfdPacket;
62 HANDLE Sock;
63 PSOCKET_INFORMATION Socket = NULL, PrevSocket = NULL;
64 PFILE_FULL_EA_INFORMATION EABuffer = NULL;
65 PHELPER_DATA HelperData;
66 PVOID HelperDLLContext;
67 DWORD HelperEvents;
68 UNICODE_STRING TransportName;
69 UNICODE_STRING DevName;
70 LARGE_INTEGER GroupData;
71 INT Status;
72
73 AFD_DbgPrint(MAX_TRACE, ("Creating Socket, getting TDI Name\n"));
74 AFD_DbgPrint(MAX_TRACE, ("AddressFamily (%d) SocketType (%d) Protocol (%d).\n",
75 AddressFamily, SocketType, Protocol));
76
77 /* Get Helper Data and Transport */
78 Status = SockGetTdiName (&AddressFamily,
79 &SocketType,
80 &Protocol,
81 g,
82 dwFlags,
83 &TransportName,
84 &HelperDLLContext,
85 &HelperData,
86 &HelperEvents);
87
88 /* Check for error */
89 if (Status != NO_ERROR) {
90 AFD_DbgPrint(MID_TRACE,("SockGetTdiName: Status %x\n", Status));
91 goto error;
92 }
93
94 /* AFD Device Name */
95 RtlInitUnicodeString(&DevName, L"\\Device\\Afd\\Endpoint");
96
97 /* Set Socket Data */
98 Socket = HeapAlloc(GlobalHeap, 0, sizeof(*Socket));
99 RtlZeroMemory(Socket, sizeof(*Socket));
100 Socket->RefCount = 2;
101 Socket->Handle = -1;
102 Socket->SharedData.State = SocketOpen;
103 Socket->SharedData.AddressFamily = AddressFamily;
104 Socket->SharedData.SocketType = SocketType;
105 Socket->SharedData.Protocol = Protocol;
106 Socket->HelperContext = HelperDLLContext;
107 Socket->HelperData = HelperData;
108 Socket->HelperEvents = HelperEvents;
109 Socket->LocalAddress = &Socket->WSLocalAddress;
110 Socket->SharedData.SizeOfLocalAddress = HelperData->MaxWSAddressLength;
111 Socket->RemoteAddress = &Socket->WSRemoteAddress;
112 Socket->SharedData.SizeOfRemoteAddress = HelperData->MaxWSAddressLength;
113 Socket->SharedData.UseDelayedAcceptance = HelperData->UseDelayedAcceptance;
114 Socket->SharedData.CreateFlags = dwFlags;
115 Socket->SharedData.CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
116 Socket->SharedData.ServiceFlags1 = lpProtocolInfo->dwServiceFlags1;
117 Socket->SharedData.ProviderFlags = lpProtocolInfo->dwProviderFlags;
118 Socket->SharedData.GroupID = g;
119 Socket->SharedData.GroupType = 0;
120 Socket->SharedData.UseSAN = FALSE;
121 Socket->SharedData.NonBlocking = FALSE; /* Sockets start blocking */
122 Socket->SanData = NULL;
123
124 /* Ask alex about this */
125 if( Socket->SharedData.SocketType == SOCK_DGRAM ||
126 Socket->SharedData.SocketType == SOCK_RAW ) {
127 AFD_DbgPrint(MID_TRACE,("Connectionless socket\n"));
128 Socket->SharedData.ServiceFlags1 |= XP1_CONNECTIONLESS;
129 }
130
131 /* Packet Size */
132 SizeOfPacket = TransportName.Length + sizeof(AFD_CREATE_PACKET) + sizeof(WCHAR);
133
134 /* EA Size */
135 SizeOfEA = SizeOfPacket + sizeof(FILE_FULL_EA_INFORMATION) + AFD_PACKET_COMMAND_LENGTH;
136
137 /* Set up EA Buffer */
138 EABuffer = HeapAlloc(GlobalHeap, 0, SizeOfEA);
139 RtlZeroMemory(EABuffer, SizeOfEA);
140 EABuffer->NextEntryOffset = 0;
141 EABuffer->Flags = 0;
142 EABuffer->EaNameLength = AFD_PACKET_COMMAND_LENGTH;
143 RtlCopyMemory (EABuffer->EaName,
144 AfdCommand,
145 AFD_PACKET_COMMAND_LENGTH + 1);
146 EABuffer->EaValueLength = SizeOfPacket;
147
148 /* Set up AFD Packet */
149 AfdPacket = (PAFD_CREATE_PACKET)(EABuffer->EaName + EABuffer->EaNameLength + 1);
150 AfdPacket->SizeOfTransportName = TransportName.Length;
151 RtlCopyMemory (AfdPacket->TransportName,
152 TransportName.Buffer,
153 TransportName.Length + sizeof(WCHAR));
154 AfdPacket->GroupID = g;
155
156 /* Set up Endpoint Flags */
157 if ((Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS) != 0) {
158 if ((SocketType != SOCK_DGRAM) && (SocketType != SOCK_RAW)) {
159 goto error; /* Only RAW or UDP can be Connectionless */
160 }
161 AfdPacket->EndpointFlags |= AFD_ENDPOINT_CONNECTIONLESS;
162 }
163
164 if ((Socket->SharedData.ServiceFlags1 & XP1_MESSAGE_ORIENTED) != 0) {
165 if (SocketType == SOCK_STREAM) {
166 if ((Socket->SharedData.ServiceFlags1 & XP1_PSEUDO_STREAM) == 0) {
167 goto error; /* The Provider doesn't actually support Message Oriented Streams */
168 }
169 }
170 AfdPacket->EndpointFlags |= AFD_ENDPOINT_MESSAGE_ORIENTED;
171 }
172
173 if (SocketType == SOCK_RAW) AfdPacket->EndpointFlags |= AFD_ENDPOINT_RAW;
174
175 if (dwFlags & (WSA_FLAG_MULTIPOINT_C_ROOT |
176 WSA_FLAG_MULTIPOINT_C_LEAF |
177 WSA_FLAG_MULTIPOINT_D_ROOT |
178 WSA_FLAG_MULTIPOINT_D_LEAF)) {
179 if ((Socket->SharedData.ServiceFlags1 & XP1_SUPPORT_MULTIPOINT) == 0) {
180 goto error; /* The Provider doesn't actually support Multipoint */
181 }
182 AfdPacket->EndpointFlags |= AFD_ENDPOINT_MULTIPOINT;
183 if (dwFlags & WSA_FLAG_MULTIPOINT_C_ROOT) {
184 if (((Socket->SharedData.ServiceFlags1 & XP1_MULTIPOINT_CONTROL_PLANE) == 0)
185 || ((dwFlags & WSA_FLAG_MULTIPOINT_C_LEAF) != 0)) {
186 goto error; /* The Provider doesn't support Control Planes, or you already gave a leaf */
187 }
188 AfdPacket->EndpointFlags |= AFD_ENDPOINT_C_ROOT;
189 }
190 if (dwFlags & WSA_FLAG_MULTIPOINT_D_ROOT) {
191 if (((Socket->SharedData.ServiceFlags1 & XP1_MULTIPOINT_DATA_PLANE) == 0)
192 || ((dwFlags & WSA_FLAG_MULTIPOINT_D_LEAF) != 0)) {
193 goto error; /* The Provider doesn't support Data Planes, or you already gave a leaf */
194 }
195 AfdPacket->EndpointFlags |= AFD_ENDPOINT_D_ROOT;
196 }
197 }
198
199 /* Set up Object Attributes */
200 InitializeObjectAttributes (&Object,
201 &DevName,
202 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
203 0,
204 0);
205
206 /* Create the Socket as asynchronous. That means we have to block
207 ourselves after every call to NtDeviceIoControlFile. This is
208 because the kernel doesn't support overlapping synchronous I/O
209 requests (made from multiple threads) at this time (Sep 2005) */
210 ZwCreateFile(&Sock,
211 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
212 &Object,
213 &IOSB,
214 NULL,
215 0,
216 FILE_SHARE_READ | FILE_SHARE_WRITE,
217 FILE_OPEN_IF,
218 0,
219 EABuffer,
220 SizeOfEA);
221
222 /* Save Handle */
223 Socket->Handle = (SOCKET)Sock;
224
225 /* XXX See if there's a structure we can reuse -- We need to do this
226 * more properly. */
227 PrevSocket = GetSocketStructure( (SOCKET)Sock );
228
229 if( PrevSocket ) {
230 RtlCopyMemory( PrevSocket, Socket, sizeof(*Socket) );
231 RtlFreeHeap( GlobalHeap, 0, Socket );
232 Socket = PrevSocket;
233 }
234
235 /* Save Group Info */
236 if (g != 0) {
237 GetSocketInformation(Socket, AFD_INFO_GROUP_ID_TYPE, 0, &GroupData);
238
239 Socket->SharedData.GroupID = GroupData.u.LowPart;
240 Socket->SharedData.GroupType = GroupData.u.HighPart;
241 }
242
243 /* Get Window Sizes and Save them */
244 GetSocketInformation (Socket,
245 AFD_INFO_SEND_WINDOW_SIZE,
246 &Socket->SharedData.SizeOfSendBuffer,
247 NULL);
248 GetSocketInformation (Socket,
249 AFD_INFO_RECEIVE_WINDOW_SIZE,
250 &Socket->SharedData.SizeOfRecvBuffer,
251 NULL);
252
253 /* Save in Process Sockets List */
254 Sockets[SocketCount] = Socket;
255 SocketCount ++;
256
257 /* Create the Socket Context */
258 CreateContext(Socket);
259
260 /* Notify Winsock */
261 Upcalls.lpWPUModifyIFSHandle(1, (SOCKET)Sock, lpErrno);
262
263 /* Return Socket Handle */
264 AFD_DbgPrint(MID_TRACE,("Success %x\n", Sock));
265 return (SOCKET)Sock;
266
267 error:
268 AFD_DbgPrint(MID_TRACE,("Ending %x\n", Status));
269
270 if( lpErrno ) *lpErrno = Status;
271
272 return INVALID_SOCKET;
273 }
274
275
276 DWORD MsafdReturnWithErrno( NTSTATUS Status, LPINT Errno, DWORD Received,
277 LPDWORD ReturnedBytes ) {
278 if( ReturnedBytes ) *ReturnedBytes = 0;
279 if( Errno ) {
280 switch (Status) {
281 case STATUS_CANT_WAIT: *Errno = WSAEWOULDBLOCK; break;
282 case STATUS_TIMEOUT: *Errno = WSAETIMEDOUT; break;
283 case STATUS_SUCCESS:
284 /* Return Number of bytes Read */
285 if( ReturnedBytes ) *ReturnedBytes = Received; break;
286 case STATUS_END_OF_FILE: *Errno = WSAESHUTDOWN; break;
287 case STATUS_PENDING: *Errno = WSA_IO_PENDING; break;
288 case STATUS_BUFFER_OVERFLOW: *Errno = WSAEMSGSIZE; break;
289 case STATUS_INSUFFICIENT_RESOURCES: *Errno = WSA_NOT_ENOUGH_MEMORY; break;
290 case STATUS_INVALID_CONNECTION: *Errno = WSAEAFNOSUPPORT; break;
291 default:
292 DbgPrint("MSAFD: Error %x is unknown\n", Status);
293 *Errno = WSAEINVAL; break;
294 }
295 }
296
297 /* Success */
298 return Status == STATUS_SUCCESS ? 0 : SOCKET_ERROR;
299 }
300
301
302 INT
303 WSPAPI
304 WSPCloseSocket(
305 IN SOCKET Handle,
306 OUT LPINT lpErrno)
307 /*
308 * FUNCTION: Closes an open socket
309 * ARGUMENTS:
310 * s = Socket descriptor
311 * lpErrno = Address of buffer for error information
312 * RETURNS:
313 * NO_ERROR, or SOCKET_ERROR if the socket could not be closed
314 */
315 {
316 IO_STATUS_BLOCK IoStatusBlock;
317 PSOCKET_INFORMATION Socket = NULL;
318 NTSTATUS Status;
319 HANDLE SockEvent;
320 AFD_DISCONNECT_INFO DisconnectInfo;
321 SOCKET_STATE OldState;
322
323 /* Create the Wait Event */
324 Status = NtCreateEvent(&SockEvent,
325 GENERIC_READ | GENERIC_WRITE,
326 NULL,
327 1,
328 FALSE);
329
330 if(!NT_SUCCESS(Status)) return SOCKET_ERROR;
331
332 /* Get the Socket Structure associate to this Socket*/
333 Socket = GetSocketStructure(Handle);
334
335 /* If a Close is already in Process, give up */
336 if (Socket->SharedData.State == SocketClosed) {
337 *lpErrno = WSAENOTSOCK;
338 return SOCKET_ERROR;
339 }
340
341 /* Set the state to close */
342 OldState = Socket->SharedData.State;
343 Socket->SharedData.State = SocketClosed;
344
345 /* If SO_LINGER is ON and the Socket is connected, we need to disconnect */
346 /* FIXME: Should we do this on Datagram Sockets too? */
347 if ((OldState == SocketConnected) && (Socket->SharedData.LingerData.l_onoff)) {
348 ULONG LingerWait;
349 ULONG SendsInProgress;
350 ULONG SleepWait;
351
352 /* We need to respect the timeout */
353 SleepWait = 100;
354 LingerWait = Socket->SharedData.LingerData.l_linger * 1000;
355
356 /* Loop until no more sends are pending, within the timeout */
357 while (LingerWait) {
358
359 /* Find out how many Sends are in Progress */
360 if (GetSocketInformation(Socket,
361 AFD_INFO_SENDS_IN_PROGRESS,
362 &SendsInProgress,
363 NULL)) {
364 /* Bail out if anything but NO_ERROR */
365 LingerWait = 0;
366 break;
367 }
368
369 /* Bail out if no more sends are pending */
370 if (!SendsInProgress) break;
371
372 /*
373 * We have to execute a sleep, so it's kind of like
374 * a block. If the socket is Nonblock, we cannot
375 * go on since asyncronous operation is expected
376 * and we cannot offer it
377 */
378 if (Socket->SharedData.NonBlocking) {
379 Socket->SharedData.State = OldState;
380 *lpErrno = WSAEWOULDBLOCK;
381 return SOCKET_ERROR;
382 }
383
384 /* Now we can sleep, and decrement the linger wait */
385 /*
386 * FIXME: It seems Windows does some funky acceleration
387 * since the waiting seems to be longer and longer. I
388 * don't think this improves performance so much, so we
389 * wait a fixed time instead.
390 */
391 Sleep(SleepWait);
392 LingerWait -= SleepWait;
393 }
394
395 /*
396 * We have reached the timeout or sends are over.
397 * Disconnect if the timeout has been reached.
398 */
399 if (LingerWait <= 0) {
400
401 DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(0);
402 DisconnectInfo.DisconnectType = AFD_DISCONNECT_ABORT;
403
404 /* Send IOCTL */
405 Status = NtDeviceIoControlFile((HANDLE)Handle,
406 SockEvent,
407 NULL,
408 NULL,
409 &IoStatusBlock,
410 IOCTL_AFD_DISCONNECT,
411 &DisconnectInfo,
412 sizeof(DisconnectInfo),
413 NULL,
414 0);
415
416 /* Wait for return */
417 if (Status == STATUS_PENDING) {
418 WaitForSingleObject(SockEvent, INFINITE);
419 }
420 }
421 }
422
423 /* FIXME: We should notify the Helper DLL of WSH_NOTIFY_CLOSE */
424
425 /* Cleanup Time! */
426 Socket->HelperContext = NULL;
427 Socket->SharedData.AsyncDisabledEvents = -1;
428 NtClose(Socket->TdiAddressHandle);
429 Socket->TdiAddressHandle = NULL;
430 NtClose(Socket->TdiConnectionHandle);
431 Socket->TdiConnectionHandle = NULL;
432
433 /* Close the handle */
434 NtClose((HANDLE)Handle);
435
436 return NO_ERROR;
437 }
438
439 INT
440 WSPAPI
441 WSPBind(
442 SOCKET Handle,
443 const struct sockaddr *SocketAddress,
444 int SocketAddressLength,
445 LPINT lpErrno)
446 /*
447 * FUNCTION: Associates a local address with a socket
448 * ARGUMENTS:
449 * s = Socket descriptor
450 * name = Pointer to local address
451 * namelen = Length of name
452 * lpErrno = Address of buffer for error information
453 * RETURNS:
454 * 0, or SOCKET_ERROR if the socket could not be bound
455 */
456 {
457 IO_STATUS_BLOCK IOSB;
458 PAFD_BIND_DATA BindData;
459 PSOCKET_INFORMATION Socket = NULL;
460 NTSTATUS Status;
461 UCHAR BindBuffer[0x1A];
462 SOCKADDR_INFO SocketInfo;
463 HANDLE SockEvent;
464
465 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
466 NULL, 1, FALSE );
467
468 if( !NT_SUCCESS(Status) ) return -1;
469
470 /* Get the Socket Structure associate to this Socket*/
471 Socket = GetSocketStructure(Handle);
472
473 /* Dynamic Structure...ugh */
474 BindData = (PAFD_BIND_DATA)BindBuffer;
475
476 /* Set up Address in TDI Format */
477 BindData->Address.TAAddressCount = 1;
478 BindData->Address.Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
479 BindData->Address.Address[0].AddressType = SocketAddress->sa_family;
480 RtlCopyMemory (BindData->Address.Address[0].Address,
481 SocketAddress->sa_data,
482 SocketAddressLength - sizeof(SocketAddress->sa_family));
483
484 /* Get Address Information */
485 Socket->HelperData->WSHGetSockaddrType ((PSOCKADDR)SocketAddress,
486 SocketAddressLength,
487 &SocketInfo);
488
489 /* Set the Share Type */
490 if (Socket->SharedData.ExclusiveAddressUse) {
491 BindData->ShareType = AFD_SHARE_EXCLUSIVE;
492 }
493 else if (SocketInfo.EndpointInfo == SockaddrEndpointInfoWildcard) {
494 BindData->ShareType = AFD_SHARE_WILDCARD;
495 }
496 else if (Socket->SharedData.ReuseAddresses) {
497 BindData->ShareType = AFD_SHARE_REUSE;
498 } else {
499 BindData->ShareType = AFD_SHARE_UNIQUE;
500 }
501
502 /* Send IOCTL */
503 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
504 SockEvent,
505 NULL,
506 NULL,
507 &IOSB,
508 IOCTL_AFD_BIND,
509 BindData,
510 0xA + Socket->SharedData.SizeOfLocalAddress, /* Can't figure out a way to calculate this in C*/
511 BindData,
512 0xA + Socket->SharedData.SizeOfLocalAddress); /* Can't figure out a way to calculate this C */
513
514 /* Wait for return */
515 if (Status == STATUS_PENDING) {
516 WaitForSingleObject(SockEvent, INFINITE);
517 }
518
519 /* Set up Socket Data */
520 Socket->SharedData.State = SocketBound;
521 Socket->TdiAddressHandle = (HANDLE)IOSB.Information;
522
523 NtClose( SockEvent );
524
525 return MsafdReturnWithErrno
526 ( IOSB.Status, lpErrno, IOSB.Information, NULL );
527 }
528
529 int
530 WSPAPI
531 WSPListen(
532 SOCKET Handle,
533 int Backlog,
534 LPINT lpErrno)
535 {
536 IO_STATUS_BLOCK IOSB;
537 AFD_LISTEN_DATA ListenData;
538 PSOCKET_INFORMATION Socket = NULL;
539 HANDLE SockEvent;
540 NTSTATUS Status;
541
542 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
543 NULL, 1, FALSE );
544
545 if( !NT_SUCCESS(Status) ) return -1;
546
547 /* Get the Socket Structure associate to this Socket*/
548 Socket = GetSocketStructure(Handle);
549
550 /* Set Up Listen Structure */
551 ListenData.UseSAN = FALSE;
552 ListenData.UseDelayedAcceptance = Socket->SharedData.UseDelayedAcceptance;
553 ListenData.Backlog = Backlog;
554
555 /* Send IOCTL */
556 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
557 SockEvent,
558 NULL,
559 NULL,
560 &IOSB,
561 IOCTL_AFD_START_LISTEN,
562 &ListenData,
563 sizeof(ListenData),
564 NULL,
565 0);
566
567 /* Wait for return */
568 if (Status == STATUS_PENDING) {
569 WaitForSingleObject(SockEvent, INFINITE);
570 }
571
572 /* Set to Listening */
573 Socket->SharedData.Listening = TRUE;
574
575 NtClose( SockEvent );
576
577 return MsafdReturnWithErrno
578 ( IOSB.Status, lpErrno, IOSB.Information, NULL );
579 }
580
581
582 int
583 WSPAPI
584 WSPSelect(
585 int nfds,
586 fd_set *readfds,
587 fd_set *writefds,
588 fd_set *exceptfds,
589 struct timeval *timeout,
590 LPINT lpErrno)
591 {
592 IO_STATUS_BLOCK IOSB;
593 PAFD_POLL_INFO PollInfo;
594 NTSTATUS Status;
595 ULONG HandleCount, OutCount = 0;
596 ULONG PollBufferSize;
597 PVOID PollBuffer;
598 ULONG i, j = 0, x;
599 HANDLE SockEvent;
600 BOOL HandleCounted;
601 LARGE_INTEGER Timeout;
602
603 /* Find out how many sockets we have, and how large the buffer needs
604 * to be */
605
606 HandleCount =
607 ( readfds ? readfds->fd_count : 0 ) +
608 ( writefds ? writefds->fd_count : 0 ) +
609 ( exceptfds ? exceptfds->fd_count : 0 );
610
611 if( HandleCount < 0 || nfds != 0 ) HandleCount = nfds * 3;
612
613 PollBufferSize = sizeof(*PollInfo) + (HandleCount * sizeof(AFD_HANDLE));
614
615 AFD_DbgPrint(MID_TRACE,("HandleCount: %d BufferSize: %d\n",
616 HandleCount, PollBufferSize));
617
618 /* Convert Timeout to NT Format */
619 if (timeout == NULL) {
620 Timeout.u.LowPart = -1;
621 Timeout.u.HighPart = 0x7FFFFFFF;
622 AFD_DbgPrint(MAX_TRACE,("Infinite timeout\n"));
623 } else {
624 Timeout = RtlEnlargedIntegerMultiply
625 ((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000), -10000);
626 /* Negative timeouts are illegal. Since the kernel represents an
627 * incremental timeout as a negative number, we check for a positive
628 * result.
629 */
630 if (Timeout.QuadPart > 0) {
631 if (lpErrno) *lpErrno = WSAEINVAL;
632 return SOCKET_ERROR;
633 }
634 AFD_DbgPrint(MAX_TRACE,("Timeout: Orig %d.%06d kernel %d\n",
635 timeout->tv_sec, timeout->tv_usec,
636 Timeout.u.LowPart));
637 }
638
639 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
640 NULL, 1, FALSE );
641
642 if( !NT_SUCCESS(Status) ) return SOCKET_ERROR;
643
644 /* Allocate */
645 PollBuffer = HeapAlloc(GlobalHeap, 0, PollBufferSize);
646
647 if (!PollBuffer) {
648 if (lpErrno) *lpErrno = WSAEFAULT;
649 NtClose(SockEvent);
650 return SOCKET_ERROR;
651 }
652
653 PollInfo = (PAFD_POLL_INFO)PollBuffer;
654
655 RtlZeroMemory( PollInfo, PollBufferSize );
656
657 /* Number of handles for AFD to Check */
658 PollInfo->HandleCount = HandleCount;
659 PollInfo->Exclusive = FALSE;
660 PollInfo->Timeout = Timeout;
661
662 if (readfds != NULL) {
663 for (i = 0; i < readfds->fd_count; i++, j++) {
664 PollInfo->Handles[j].Handle = readfds->fd_array[i];
665 PollInfo->Handles[j].Events = AFD_EVENT_RECEIVE |
666 AFD_EVENT_DISCONNECT |
667 AFD_EVENT_ABORT |
668 AFD_EVENT_ACCEPT;
669 }
670 }
671 if (writefds != NULL) {
672 for (i = 0; i < writefds->fd_count; i++, j++) {
673 PollInfo->Handles[j].Handle = writefds->fd_array[i];
674 PollInfo->Handles[j].Events = AFD_EVENT_SEND |
675 AFD_EVENT_CONNECT;
676 }
677 }
678 if (exceptfds != NULL) {
679 for (i = 0; i < exceptfds->fd_count; i++, j++) {
680 PollInfo->Handles[j].Handle = exceptfds->fd_array[i];
681 PollInfo->Handles[j].Events = AFD_EVENT_OOB_RECEIVE |
682 AFD_EVENT_CONNECT_FAIL;
683 }
684 }
685
686 /* Send IOCTL */
687 Status = NtDeviceIoControlFile( (HANDLE)PollInfo->Handles[0].Handle,
688 SockEvent,
689 NULL,
690 NULL,
691 &IOSB,
692 IOCTL_AFD_SELECT,
693 PollInfo,
694 PollBufferSize,
695 PollInfo,
696 PollBufferSize);
697
698 AFD_DbgPrint(MID_TRACE,("DeviceIoControlFile => %x\n", Status));
699
700 /* Wait for Completition */
701 if (Status == STATUS_PENDING) {
702 WaitForSingleObject(SockEvent, INFINITE);
703 }
704
705 /* Clear the Structures */
706 if( readfds ) FD_ZERO(readfds);
707 if( writefds ) FD_ZERO(writefds);
708 if( exceptfds ) FD_ZERO(exceptfds);
709
710 /* Loop through return structure */
711 HandleCount = PollInfo->HandleCount;
712
713 /* Return in FDSET Format */
714 for (i = 0; i < HandleCount; i++) {
715 HandleCounted = FALSE;
716 for(x = 1; x; x<<=1) {
717 switch (PollInfo->Handles[i].Events & x) {
718 case AFD_EVENT_RECEIVE:
719 case AFD_EVENT_DISCONNECT:
720 case AFD_EVENT_ABORT:
721 case AFD_EVENT_ACCEPT:
722 case AFD_EVENT_CLOSE:
723 AFD_DbgPrint(MID_TRACE,("Event %x on handle %x\n",
724 PollInfo->Handles[i].Events,
725 PollInfo->Handles[i].Handle));
726 if (! HandleCounted) {
727 OutCount++;
728 HandleCounted = TRUE;
729 }
730 if( readfds ) FD_SET(PollInfo->Handles[i].Handle, readfds);
731 break;
732
733 case AFD_EVENT_SEND: case AFD_EVENT_CONNECT:
734 AFD_DbgPrint(MID_TRACE,("Event %x on handle %x\n",
735 PollInfo->Handles[i].Events,
736 PollInfo->Handles[i].Handle));
737 if (! HandleCounted) {
738 OutCount++;
739 HandleCounted = TRUE;
740 }
741 if( writefds ) FD_SET(PollInfo->Handles[i].Handle, writefds);
742 break;
743
744 case AFD_EVENT_OOB_RECEIVE: case AFD_EVENT_CONNECT_FAIL:
745 AFD_DbgPrint(MID_TRACE,("Event %x on handle %x\n",
746 PollInfo->Handles[i].Events,
747 PollInfo->Handles[i].Handle));
748 if (! HandleCounted) {
749 OutCount++;
750 HandleCounted = TRUE;
751 }
752 if( exceptfds ) FD_SET(PollInfo->Handles[i].Handle, exceptfds);
753 break;
754 }
755 }
756 }
757
758 HeapFree( GlobalHeap, 0, PollBuffer );
759 NtClose( SockEvent );
760
761
762 if( lpErrno ) {
763 switch( IOSB.Status ) {
764 case STATUS_SUCCESS:
765 case STATUS_TIMEOUT: *lpErrno = 0; break;
766 default: *lpErrno = WSAEINVAL; break;
767 }
768 AFD_DbgPrint(MID_TRACE,("*lpErrno = %x\n", *lpErrno));
769 }
770
771 AFD_DbgPrint(MID_TRACE,("%d events\n", OutCount));
772
773 return OutCount;
774 }
775
776 SOCKET
777 WSPAPI
778 WSPAccept(
779 SOCKET Handle,
780 struct sockaddr *SocketAddress,
781 int *SocketAddressLength,
782 LPCONDITIONPROC lpfnCondition,
783 DWORD_PTR dwCallbackData,
784 LPINT lpErrno)
785 {
786 IO_STATUS_BLOCK IOSB;
787 PAFD_RECEIVED_ACCEPT_DATA ListenReceiveData;
788 AFD_ACCEPT_DATA AcceptData;
789 AFD_DEFER_ACCEPT_DATA DeferData;
790 AFD_PENDING_ACCEPT_DATA PendingAcceptData;
791 PSOCKET_INFORMATION Socket = NULL;
792 NTSTATUS Status;
793 struct fd_set ReadSet;
794 struct timeval Timeout;
795 PVOID PendingData = NULL;
796 ULONG PendingDataLength = 0;
797 PVOID CalleeDataBuffer;
798 WSABUF CallerData, CalleeID, CallerID, CalleeData;
799 PSOCKADDR RemoteAddress = NULL;
800 GROUP GroupID = 0;
801 ULONG CallBack;
802 WSAPROTOCOL_INFOW ProtocolInfo;
803 SOCKET AcceptSocket;
804 UCHAR ReceiveBuffer[0x1A];
805 HANDLE SockEvent;
806
807 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
808 NULL, 1, FALSE );
809
810 if( !NT_SUCCESS(Status) ) {
811 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
812 return INVALID_SOCKET;
813 }
814
815 /* Dynamic Structure...ugh */
816 ListenReceiveData = (PAFD_RECEIVED_ACCEPT_DATA)ReceiveBuffer;
817
818 /* Get the Socket Structure associate to this Socket*/
819 Socket = GetSocketStructure(Handle);
820
821 /* If this is non-blocking, make sure there's something for us to accept */
822 FD_ZERO(&ReadSet);
823 FD_SET(Socket->Handle, &ReadSet);
824 Timeout.tv_sec=0;
825 Timeout.tv_usec=0;
826
827 WSPSelect(0, &ReadSet, NULL, NULL, &Timeout, NULL);
828
829 if (ReadSet.fd_array[0] != Socket->Handle) return 0;
830
831 /* Send IOCTL */
832 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
833 SockEvent,
834 NULL,
835 NULL,
836 &IOSB,
837 IOCTL_AFD_WAIT_FOR_LISTEN,
838 NULL,
839 0,
840 ListenReceiveData,
841 0xA + sizeof(*ListenReceiveData));
842
843 /* Wait for return */
844 if (Status == STATUS_PENDING) {
845 WaitForSingleObject(SockEvent, INFINITE);
846 Status = IOSB.Status;
847 }
848
849 if (!NT_SUCCESS(Status)) {
850 NtClose( SockEvent );
851 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
852 return INVALID_SOCKET;
853 }
854
855 if (lpfnCondition != NULL) {
856 if ((Socket->SharedData.ServiceFlags1 & XP1_CONNECT_DATA) != 0) {
857 /* Find out how much data is pending */
858 PendingAcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
859 PendingAcceptData.ReturnSize = TRUE;
860
861 /* Send IOCTL */
862 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
863 SockEvent,
864 NULL,
865 NULL,
866 &IOSB,
867 IOCTL_AFD_GET_PENDING_CONNECT_DATA,
868 &PendingAcceptData,
869 sizeof(PendingAcceptData),
870 &PendingAcceptData,
871 sizeof(PendingAcceptData));
872
873 /* Wait for return */
874 if (Status == STATUS_PENDING) {
875 WaitForSingleObject(SockEvent, INFINITE);
876 Status = IOSB.Status;
877 }
878
879 if (!NT_SUCCESS(Status)) {
880 NtClose( SockEvent );
881 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
882 return INVALID_SOCKET;
883 }
884
885 /* How much data to allocate */
886 PendingDataLength = IOSB.Information;
887
888 if (PendingDataLength) {
889 /* Allocate needed space */
890 PendingData = HeapAlloc(GlobalHeap, 0, PendingDataLength);
891
892 /* We want the data now */
893 PendingAcceptData.ReturnSize = FALSE;
894
895 /* Send IOCTL */
896 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
897 SockEvent,
898 NULL,
899 NULL,
900 &IOSB,
901 IOCTL_AFD_GET_PENDING_CONNECT_DATA,
902 &PendingAcceptData,
903 sizeof(PendingAcceptData),
904 PendingData,
905 PendingDataLength);
906
907 /* Wait for return */
908 if (Status == STATUS_PENDING) {
909 WaitForSingleObject(SockEvent, INFINITE);
910 Status = IOSB.Status;
911 }
912
913 if (!NT_SUCCESS(Status)) {
914 NtClose( SockEvent );
915 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
916 return INVALID_SOCKET;
917 }
918 }
919 }
920
921 if ((Socket->SharedData.ServiceFlags1 & XP1_QOS_SUPPORTED) != 0) {
922 /* I don't support this yet */
923 }
924
925 /* Build Callee ID */
926 CalleeID.buf = (PVOID)Socket->LocalAddress;
927 CalleeID.len = Socket->SharedData.SizeOfLocalAddress;
928
929 /* Set up Address in SOCKADDR Format */
930 RtlCopyMemory (RemoteAddress,
931 &ListenReceiveData->Address.Address[0].AddressType,
932 sizeof(*RemoteAddress));
933
934 /* Build Caller ID */
935 CallerID.buf = (PVOID)RemoteAddress;
936 CallerID.len = sizeof(*RemoteAddress);
937
938 /* Build Caller Data */
939 CallerData.buf = PendingData;
940 CallerData.len = PendingDataLength;
941
942 /* Check if socket supports Conditional Accept */
943 if (Socket->SharedData.UseDelayedAcceptance != 0) {
944 /* Allocate Buffer for Callee Data */
945 CalleeDataBuffer = HeapAlloc(GlobalHeap, 0, 4096);
946 CalleeData.buf = CalleeDataBuffer;
947 CalleeData.len = 4096;
948 } else {
949 /* Nothing */
950 CalleeData.buf = 0;
951 CalleeData.len = 0;
952 }
953
954 /* Call the Condition Function */
955 CallBack = (lpfnCondition)( &CallerID,
956 CallerData.buf == NULL
957 ? NULL
958 : & CallerData,
959 NULL,
960 NULL,
961 &CalleeID,
962 CalleeData.buf == NULL
963 ? NULL
964 : & CalleeData,
965 &GroupID,
966 dwCallbackData);
967
968 if (((CallBack == CF_ACCEPT) && GroupID) != 0) {
969 /* TBD: Check for Validity */
970 }
971
972 if (CallBack == CF_ACCEPT) {
973
974 if ((Socket->SharedData.ServiceFlags1 & XP1_QOS_SUPPORTED) != 0) {
975 /* I don't support this yet */
976 }
977
978 if (CalleeData.buf) {
979 // SockSetConnectData Sockets(SocketID), IOCTL_AFD_SET_CONNECT_DATA, CalleeData.Buffer, CalleeData.BuffSize, 0
980 }
981
982 } else {
983 /* Callback rejected. Build Defer Structure */
984 DeferData.SequenceNumber = ListenReceiveData->SequenceNumber;
985 DeferData.RejectConnection = (CallBack == CF_REJECT);
986
987 /* Send IOCTL */
988 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
989 SockEvent,
990 NULL,
991 NULL,
992 &IOSB,
993 IOCTL_AFD_DEFER_ACCEPT,
994 &DeferData,
995 sizeof(DeferData),
996 NULL,
997 0);
998
999 /* Wait for return */
1000 if (Status == STATUS_PENDING) {
1001 WaitForSingleObject(SockEvent, INFINITE);
1002 Status = IOSB.Status;
1003 }
1004
1005 NtClose( SockEvent );
1006
1007 if (!NT_SUCCESS(Status)) {
1008 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1009 return INVALID_SOCKET;
1010 }
1011
1012 if (CallBack == CF_REJECT ) {
1013 *lpErrno = WSAECONNREFUSED;
1014 return INVALID_SOCKET;
1015 } else {
1016 *lpErrno = WSAECONNREFUSED;
1017 return INVALID_SOCKET;
1018 }
1019 }
1020 }
1021
1022 /* Create a new Socket */
1023 ProtocolInfo.dwCatalogEntryId = Socket->SharedData.CatalogEntryId;
1024 ProtocolInfo.dwServiceFlags1 = Socket->SharedData.ServiceFlags1;
1025 ProtocolInfo.dwProviderFlags = Socket->SharedData.ProviderFlags;
1026
1027 AcceptSocket = WSPSocket (Socket->SharedData.AddressFamily,
1028 Socket->SharedData.SocketType,
1029 Socket->SharedData.Protocol,
1030 &ProtocolInfo,
1031 GroupID,
1032 Socket->SharedData.CreateFlags,
1033 NULL);
1034
1035 /* Set up the Accept Structure */
1036 AcceptData.ListenHandle = AcceptSocket;
1037 AcceptData.SequenceNumber = ListenReceiveData->SequenceNumber;
1038
1039 /* Send IOCTL to Accept */
1040 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1041 SockEvent,
1042 NULL,
1043 NULL,
1044 &IOSB,
1045 IOCTL_AFD_ACCEPT,
1046 &AcceptData,
1047 sizeof(AcceptData),
1048 NULL,
1049 0);
1050
1051 /* Wait for return */
1052 if (Status == STATUS_PENDING) {
1053 WaitForSingleObject(SockEvent, INFINITE);
1054 Status = IOSB.Status;
1055 }
1056
1057 if (!NT_SUCCESS(Status)) {
1058 WSPCloseSocket( AcceptSocket, lpErrno );
1059 MsafdReturnWithErrno( Status, lpErrno, 0, NULL );
1060 return INVALID_SOCKET;
1061 }
1062
1063 /* Return Address in SOCKADDR FORMAT */
1064 if( SocketAddress ) {
1065 RtlCopyMemory (SocketAddress,
1066 &ListenReceiveData->Address.Address[0].AddressType,
1067 sizeof(*RemoteAddress));
1068 if( SocketAddressLength )
1069 *SocketAddressLength =
1070 ListenReceiveData->Address.Address[0].AddressLength;
1071 }
1072
1073 NtClose( SockEvent );
1074
1075 /* Re-enable Async Event */
1076 SockReenableAsyncSelectEvent(Socket, FD_ACCEPT);
1077
1078 AFD_DbgPrint(MID_TRACE,("Socket %x\n", AcceptSocket));
1079
1080 *lpErrno = 0;
1081
1082 /* Return Socket */
1083 return AcceptSocket;
1084 }
1085
1086 int
1087 WSPAPI
1088 WSPConnect(
1089 SOCKET Handle,
1090 const struct sockaddr * SocketAddress,
1091 int SocketAddressLength,
1092 LPWSABUF lpCallerData,
1093 LPWSABUF lpCalleeData,
1094 LPQOS lpSQOS,
1095 LPQOS lpGQOS,
1096 LPINT lpErrno)
1097 {
1098 IO_STATUS_BLOCK IOSB;
1099 PAFD_CONNECT_INFO ConnectInfo;
1100 PSOCKET_INFORMATION Socket = NULL;
1101 NTSTATUS Status;
1102 UCHAR ConnectBuffer[0x22];
1103 ULONG ConnectDataLength;
1104 ULONG InConnectDataLength;
1105 INT BindAddressLength;
1106 PSOCKADDR BindAddress;
1107 HANDLE SockEvent;
1108
1109 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1110 NULL, 1, FALSE );
1111
1112 if( !NT_SUCCESS(Status) ) return -1;
1113
1114 AFD_DbgPrint(MID_TRACE,("Called\n"));
1115
1116 /* Get the Socket Structure associate to this Socket*/
1117 Socket = GetSocketStructure(Handle);
1118
1119 /* Bind us First */
1120 if (Socket->SharedData.State == SocketOpen) {
1121
1122 /* Get the Wildcard Address */
1123 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
1124 BindAddress = HeapAlloc(GetProcessHeap(), 0, BindAddressLength);
1125 Socket->HelperData->WSHGetWildcardSockaddr (Socket->HelperContext,
1126 BindAddress,
1127 &BindAddressLength);
1128
1129 /* Bind it */
1130 WSPBind(Handle, BindAddress, BindAddressLength, NULL);
1131 }
1132
1133 /* Set the Connect Data */
1134 if (lpCallerData != NULL) {
1135 ConnectDataLength = lpCallerData->len;
1136 Status = NtDeviceIoControlFile((HANDLE)Handle,
1137 SockEvent,
1138 NULL,
1139 NULL,
1140 &IOSB,
1141 IOCTL_AFD_SET_CONNECT_DATA,
1142 lpCallerData->buf,
1143 ConnectDataLength,
1144 NULL,
1145 0);
1146 /* Wait for return */
1147 if (Status == STATUS_PENDING) {
1148 WaitForSingleObject(SockEvent, INFINITE);
1149 Status = IOSB.Status;
1150 }
1151 }
1152
1153 /* Dynamic Structure...ugh */
1154 ConnectInfo = (PAFD_CONNECT_INFO)ConnectBuffer;
1155
1156 /* Set up Address in TDI Format */
1157 ConnectInfo->RemoteAddress.TAAddressCount = 1;
1158 ConnectInfo->RemoteAddress.Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
1159 ConnectInfo->RemoteAddress.Address[0].AddressType = SocketAddress->sa_family;
1160 RtlCopyMemory (ConnectInfo->RemoteAddress.Address[0].Address,
1161 SocketAddress->sa_data,
1162 SocketAddressLength - sizeof(SocketAddress->sa_family));
1163
1164 /*
1165 * Disable FD_WRITE and FD_CONNECT
1166 * The latter fixes a race condition where the FD_CONNECT is re-enabled
1167 * at the end of this function right after the Async Thread disables it.
1168 * This should only happen at the *next* WSPConnect
1169 */
1170 if (Socket->SharedData.AsyncEvents & FD_CONNECT) {
1171 Socket->SharedData.AsyncDisabledEvents |= FD_CONNECT | FD_WRITE;
1172 }
1173
1174 /* Tell AFD that we want Connection Data back, have it allocate a buffer */
1175 if (lpCalleeData != NULL) {
1176 InConnectDataLength = lpCalleeData->len;
1177 Status = NtDeviceIoControlFile((HANDLE)Handle,
1178 SockEvent,
1179 NULL,
1180 NULL,
1181 &IOSB,
1182 IOCTL_AFD_SET_CONNECT_DATA_SIZE,
1183 &InConnectDataLength,
1184 sizeof(InConnectDataLength),
1185 NULL,
1186 0);
1187
1188 /* Wait for return */
1189 if (Status == STATUS_PENDING) {
1190 WaitForSingleObject(SockEvent, INFINITE);
1191 Status = IOSB.Status;
1192 }
1193 }
1194
1195 /* AFD doesn't seem to care if these are invalid, but let's 0 them anyways */
1196 ConnectInfo->Root = 0;
1197 ConnectInfo->UseSAN = FALSE;
1198 ConnectInfo->Unknown = 0;
1199
1200 /* FIXME: Handle Async Connect */
1201 if (Socket->SharedData.NonBlocking) {
1202 AFD_DbgPrint(MIN_TRACE, ("Async Connect UNIMPLEMENTED!\n"));
1203 }
1204
1205 /* Send IOCTL */
1206 Status = NtDeviceIoControlFile((HANDLE)Handle,
1207 SockEvent,
1208 NULL,
1209 NULL,
1210 &IOSB,
1211 IOCTL_AFD_CONNECT,
1212 ConnectInfo,
1213 0x22,
1214 NULL,
1215 0);
1216 /* Wait for return */
1217 if (Status == STATUS_PENDING) {
1218 WaitForSingleObject(SockEvent, INFINITE);
1219 Status = IOSB.Status;
1220 }
1221
1222 /* Get any pending connect data */
1223 if (lpCalleeData != NULL) {
1224 Status = NtDeviceIoControlFile((HANDLE)Handle,
1225 SockEvent,
1226 NULL,
1227 NULL,
1228 &IOSB,
1229 IOCTL_AFD_GET_CONNECT_DATA,
1230 NULL,
1231 0,
1232 lpCalleeData->buf,
1233 lpCalleeData->len);
1234 /* Wait for return */
1235 if (Status == STATUS_PENDING) {
1236 WaitForSingleObject(SockEvent, INFINITE);
1237 Status = IOSB.Status;
1238 }
1239 }
1240
1241 /* Re-enable Async Event */
1242 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
1243
1244 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
1245 SockReenableAsyncSelectEvent(Socket, FD_CONNECT);
1246
1247 AFD_DbgPrint(MID_TRACE,("Ending\n"));
1248
1249 NtClose( SockEvent );
1250
1251 return MsafdReturnWithErrno( IOSB.Status, lpErrno, 0, NULL );
1252 }
1253 int
1254 WSPAPI
1255 WSPShutdown(
1256 SOCKET Handle,
1257 int HowTo,
1258 LPINT lpErrno)
1259
1260 {
1261 IO_STATUS_BLOCK IOSB;
1262 AFD_DISCONNECT_INFO DisconnectInfo;
1263 PSOCKET_INFORMATION Socket = NULL;
1264 NTSTATUS Status;
1265 HANDLE SockEvent;
1266
1267 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1268 NULL, 1, FALSE );
1269
1270 if( !NT_SUCCESS(Status) ) return -1;
1271
1272 AFD_DbgPrint(MID_TRACE,("Called\n"));
1273
1274 /* Get the Socket Structure associate to this Socket*/
1275 Socket = GetSocketStructure(Handle);
1276
1277 /* Set AFD Disconnect Type */
1278 switch (HowTo) {
1279
1280 case SD_RECEIVE:
1281 DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV;
1282 Socket->SharedData.ReceiveShutdown = TRUE;
1283 break;
1284
1285 case SD_SEND:
1286 DisconnectInfo.DisconnectType= AFD_DISCONNECT_SEND;
1287 Socket->SharedData.SendShutdown = TRUE;
1288 break;
1289
1290 case SD_BOTH:
1291 DisconnectInfo.DisconnectType = AFD_DISCONNECT_RECV | AFD_DISCONNECT_SEND;
1292 Socket->SharedData.ReceiveShutdown = TRUE;
1293 Socket->SharedData.SendShutdown = TRUE;
1294 break;
1295 }
1296
1297 DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1);
1298
1299 /* Send IOCTL */
1300 Status = NtDeviceIoControlFile((HANDLE)Handle,
1301 SockEvent,
1302 NULL,
1303 NULL,
1304 &IOSB,
1305 IOCTL_AFD_DISCONNECT,
1306 &DisconnectInfo,
1307 sizeof(DisconnectInfo),
1308 NULL,
1309 0);
1310
1311 /* Wait for return */
1312 if (Status == STATUS_PENDING) {
1313 WaitForSingleObject(SockEvent, INFINITE);
1314 }
1315
1316 AFD_DbgPrint(MID_TRACE,("Ending\n"));
1317
1318 NtClose( SockEvent );
1319
1320 return MsafdReturnWithErrno( IOSB.Status, lpErrno, 0, NULL );
1321 }
1322
1323
1324 INT
1325 WSPAPI
1326 WSPGetSockName(
1327 IN SOCKET Handle,
1328 OUT LPSOCKADDR Name,
1329 IN OUT LPINT NameLength,
1330 OUT LPINT lpErrno)
1331 {
1332 IO_STATUS_BLOCK IOSB;
1333 ULONG TdiAddressSize;
1334 PTDI_ADDRESS_INFO TdiAddress;
1335 PTRANSPORT_ADDRESS SocketAddress;
1336 PSOCKET_INFORMATION Socket = NULL;
1337 NTSTATUS Status;
1338 HANDLE SockEvent;
1339
1340 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1341 NULL, 1, FALSE );
1342
1343 if( !NT_SUCCESS(Status) ) return SOCKET_ERROR;
1344
1345 /* Get the Socket Structure associate to this Socket*/
1346 Socket = GetSocketStructure(Handle);
1347
1348 /* Allocate a buffer for the address */
1349 TdiAddressSize = FIELD_OFFSET(TDI_ADDRESS_INFO,
1350 Address.Address[0].Address) +
1351 Socket->SharedData.SizeOfLocalAddress;
1352 TdiAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
1353
1354 if ( TdiAddress == NULL ) {
1355 NtClose( SockEvent );
1356 *lpErrno = WSAENOBUFS;
1357 return SOCKET_ERROR;
1358 }
1359
1360 SocketAddress = &TdiAddress->Address;
1361
1362 /* Send IOCTL */
1363 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1364 SockEvent,
1365 NULL,
1366 NULL,
1367 &IOSB,
1368 IOCTL_AFD_GET_SOCK_NAME,
1369 NULL,
1370 0,
1371 TdiAddress,
1372 TdiAddressSize);
1373
1374 /* Wait for return */
1375 if (Status == STATUS_PENDING) {
1376 WaitForSingleObject(SockEvent, INFINITE);
1377 Status = IOSB.Status;
1378 }
1379
1380 NtClose( SockEvent );
1381
1382 if (NT_SUCCESS(Status)) {
1383 if (*NameLength >= SocketAddress->Address[0].AddressLength) {
1384 Name->sa_family = SocketAddress->Address[0].AddressType;
1385 RtlCopyMemory (Name->sa_data,
1386 SocketAddress->Address[0].Address,
1387 SocketAddress->Address[0].AddressLength);
1388 *NameLength = 2 + SocketAddress->Address[0].AddressLength;
1389 AFD_DbgPrint
1390 (MID_TRACE,
1391 ("NameLength %d Address: %x Port %x\n",
1392 *NameLength,
1393 ((struct sockaddr_in *)Name)->sin_addr.s_addr,
1394 ((struct sockaddr_in *)Name)->sin_port));
1395 HeapFree(GlobalHeap, 0, TdiAddress);
1396 return 0;
1397 } else {
1398 HeapFree(GlobalHeap, 0, TdiAddress);
1399 *lpErrno = WSAEFAULT;
1400 return SOCKET_ERROR;
1401 }
1402 }
1403
1404 return MsafdReturnWithErrno
1405 ( IOSB.Status, lpErrno, 0, NULL );
1406 }
1407
1408
1409 INT
1410 WSPAPI
1411 WSPGetPeerName(
1412 IN SOCKET s,
1413 OUT LPSOCKADDR Name,
1414 IN OUT LPINT NameLength,
1415 OUT LPINT lpErrno)
1416 {
1417 IO_STATUS_BLOCK IOSB;
1418 ULONG TdiAddressSize;
1419 PTDI_ADDRESS_INFO TdiAddress;
1420 PTRANSPORT_ADDRESS SocketAddress;
1421 PSOCKET_INFORMATION Socket = NULL;
1422 NTSTATUS Status;
1423 HANDLE SockEvent;
1424
1425 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1426 NULL, 1, FALSE );
1427
1428 if( !NT_SUCCESS(Status) ) return SOCKET_ERROR;
1429
1430 /* Get the Socket Structure associate to this Socket*/
1431 Socket = GetSocketStructure(s);
1432
1433 /* Allocate a buffer for the address */
1434 TdiAddressSize = FIELD_OFFSET(TDI_ADDRESS_INFO,
1435 Address.Address[0].Address) +
1436 Socket->SharedData.SizeOfLocalAddress;
1437 TdiAddress = HeapAlloc(GlobalHeap, 0, TdiAddressSize);
1438
1439 if ( TdiAddress == NULL ) {
1440 NtClose( SockEvent );
1441 *lpErrno = WSAENOBUFS;
1442 return SOCKET_ERROR;
1443 }
1444
1445 SocketAddress = &TdiAddress->Address;
1446
1447 /* Send IOCTL */
1448 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1449 SockEvent,
1450 NULL,
1451 NULL,
1452 &IOSB,
1453 IOCTL_AFD_GET_PEER_NAME,
1454 NULL,
1455 0,
1456 TdiAddress,
1457 TdiAddressSize);
1458
1459 /* Wait for return */
1460 if (Status == STATUS_PENDING) {
1461 WaitForSingleObject(SockEvent, INFINITE);
1462 Status = IOSB.Status;
1463 }
1464
1465 NtClose( SockEvent );
1466
1467 if (NT_SUCCESS(Status)) {
1468 if (*NameLength >= SocketAddress->Address[0].AddressLength) {
1469 Name->sa_family = SocketAddress->Address[0].AddressType;
1470 RtlCopyMemory (Name->sa_data,
1471 SocketAddress->Address[0].Address,
1472 SocketAddress->Address[0].AddressLength);
1473 *NameLength = 2 + SocketAddress->Address[0].AddressLength;
1474 AFD_DbgPrint
1475 (MID_TRACE,
1476 ("NameLength %d Address: %s Port %x\n",
1477 *NameLength,
1478 ((struct sockaddr_in *)Name)->sin_addr.s_addr,
1479 ((struct sockaddr_in *)Name)->sin_port));
1480 HeapFree(GlobalHeap, 0, TdiAddress);
1481 return 0;
1482 } else {
1483 HeapFree(GlobalHeap, 0, TdiAddress);
1484 *lpErrno = WSAEFAULT;
1485 return SOCKET_ERROR;
1486 }
1487 }
1488
1489 return MsafdReturnWithErrno
1490 ( IOSB.Status, lpErrno, 0, NULL );
1491 }
1492
1493 INT
1494 WSPAPI
1495 WSPIoctl(
1496 IN SOCKET Handle,
1497 IN DWORD dwIoControlCode,
1498 IN LPVOID lpvInBuffer,
1499 IN DWORD cbInBuffer,
1500 OUT LPVOID lpvOutBuffer,
1501 IN DWORD cbOutBuffer,
1502 OUT LPDWORD lpcbBytesReturned,
1503 IN LPWSAOVERLAPPED lpOverlapped,
1504 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1505 IN LPWSATHREADID lpThreadId,
1506 OUT LPINT lpErrno)
1507 {
1508 PSOCKET_INFORMATION Socket = NULL;
1509
1510 /* Get the Socket Structure associate to this Socket*/
1511 Socket = GetSocketStructure(Handle);
1512
1513 switch( dwIoControlCode ) {
1514 case FIONBIO:
1515 if( cbInBuffer < sizeof(INT) ) return SOCKET_ERROR;
1516 Socket->SharedData.NonBlocking = *((PINT)lpvInBuffer) ? 1 : 0;
1517 AFD_DbgPrint(MID_TRACE,("[%x] Set nonblocking %d\n",
1518 Handle, Socket->SharedData.NonBlocking));
1519 return 0;
1520
1521 case FIONREAD:
1522 return GetSocketInformation(Socket, AFD_INFO_RECEIVE_CONTENT_SIZE, (PULONG)lpvOutBuffer, NULL);
1523
1524 default:
1525 *lpErrno = WSAEINVAL;
1526 return SOCKET_ERROR;
1527 }
1528 }
1529
1530
1531 INT
1532 WSPAPI
1533 WSPGetSockOpt(
1534 IN SOCKET Handle,
1535 IN INT Level,
1536 IN INT OptionName,
1537 OUT CHAR FAR* OptionValue,
1538 IN OUT LPINT OptionLength,
1539 OUT LPINT lpErrno)
1540 {
1541 PSOCKET_INFORMATION Socket = NULL;
1542 PVOID Buffer;
1543 INT BufferSize;
1544 BOOLEAN BoolBuffer;
1545
1546 /* Get the Socket Structure associate to this Socket*/
1547 Socket = GetSocketStructure(Handle);
1548 if (Socket == NULL)
1549 {
1550 *lpErrno = WSAENOTSOCK;
1551 return SOCKET_ERROR;
1552 }
1553
1554 AFD_DbgPrint(MID_TRACE, ("Called\n"));
1555
1556 switch (Level)
1557 {
1558 case SOL_SOCKET:
1559 switch (OptionName)
1560 {
1561 case SO_TYPE:
1562 Buffer = &Socket->SharedData.SocketType;
1563 BufferSize = sizeof(INT);
1564 break;
1565
1566 case SO_RCVBUF:
1567 Buffer = &Socket->SharedData.SizeOfRecvBuffer;
1568 BufferSize = sizeof(INT);
1569 break;
1570
1571 case SO_SNDBUF:
1572 Buffer = &Socket->SharedData.SizeOfSendBuffer;
1573 BufferSize = sizeof(INT);
1574 break;
1575
1576 case SO_ACCEPTCONN:
1577 BoolBuffer = Socket->SharedData.Listening;
1578 Buffer = &BoolBuffer;
1579 BufferSize = sizeof(BOOLEAN);
1580 break;
1581
1582 case SO_BROADCAST:
1583 BoolBuffer = Socket->SharedData.Broadcast;
1584 Buffer = &BoolBuffer;
1585 BufferSize = sizeof(BOOLEAN);
1586 break;
1587
1588 case SO_DEBUG:
1589 BoolBuffer = Socket->SharedData.Debug;
1590 Buffer = &BoolBuffer;
1591 BufferSize = sizeof(BOOLEAN);
1592 break;
1593
1594 /* case SO_CONDITIONAL_ACCEPT: */
1595 case SO_DONTLINGER:
1596 case SO_DONTROUTE:
1597 case SO_ERROR:
1598 case SO_GROUP_ID:
1599 case SO_GROUP_PRIORITY:
1600 case SO_KEEPALIVE:
1601 case SO_LINGER:
1602 case SO_MAX_MSG_SIZE:
1603 case SO_OOBINLINE:
1604 case SO_PROTOCOL_INFO:
1605 case SO_REUSEADDR:
1606 AFD_DbgPrint(MID_TRACE, ("Unimplemented option (%x)\n",
1607 OptionName));
1608
1609 default:
1610 *lpErrno = WSAEINVAL;
1611 return SOCKET_ERROR;
1612 }
1613
1614 if (*OptionLength < BufferSize)
1615 {
1616 *lpErrno = WSAEFAULT;
1617 *OptionLength = BufferSize;
1618 return SOCKET_ERROR;
1619 }
1620 RtlCopyMemory(OptionValue, Buffer, BufferSize);
1621
1622 return 0;
1623
1624 case IPPROTO_TCP: /* FIXME */
1625 default:
1626 *lpErrno = WSAEINVAL;
1627 return SOCKET_ERROR;
1628 }
1629 }
1630
1631
1632 INT
1633 WSPAPI
1634 WSPStartup(
1635 IN WORD wVersionRequested,
1636 OUT LPWSPDATA lpWSPData,
1637 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
1638 IN WSPUPCALLTABLE UpcallTable,
1639 OUT LPWSPPROC_TABLE lpProcTable)
1640 /*
1641 * FUNCTION: Initialize service provider for a client
1642 * ARGUMENTS:
1643 * wVersionRequested = Highest WinSock SPI version that the caller can use
1644 * lpWSPData = Address of WSPDATA structure to initialize
1645 * lpProtocolInfo = Pointer to structure that defines the desired protocol
1646 * UpcallTable = Pointer to upcall table of the WinSock DLL
1647 * lpProcTable = Address of procedure table to initialize
1648 * RETURNS:
1649 * Status of operation
1650 */
1651 {
1652 NTSTATUS Status;
1653
1654 AFD_DbgPrint(MAX_TRACE, ("wVersionRequested (0x%X) \n", wVersionRequested));
1655
1656 Status = NO_ERROR;
1657
1658 Upcalls = UpcallTable;
1659
1660 if (Status == NO_ERROR) {
1661 lpProcTable->lpWSPAccept = WSPAccept;
1662 lpProcTable->lpWSPAddressToString = WSPAddressToString;
1663 lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
1664 lpProcTable->lpWSPBind = WSPBind;
1665 lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
1666 lpProcTable->lpWSPCleanup = WSPCleanup;
1667 lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
1668 lpProcTable->lpWSPConnect = WSPConnect;
1669 lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
1670 lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
1671 lpProcTable->lpWSPEventSelect = WSPEventSelect;
1672 lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
1673 lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
1674 lpProcTable->lpWSPGetSockName = WSPGetSockName;
1675 lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
1676 lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
1677 lpProcTable->lpWSPIoctl = WSPIoctl;
1678 lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
1679 lpProcTable->lpWSPListen = WSPListen;
1680 lpProcTable->lpWSPRecv = WSPRecv;
1681 lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
1682 lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
1683 lpProcTable->lpWSPSelect = WSPSelect;
1684 lpProcTable->lpWSPSend = WSPSend;
1685 lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
1686 lpProcTable->lpWSPSendTo = WSPSendTo;
1687 lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
1688 lpProcTable->lpWSPShutdown = WSPShutdown;
1689 lpProcTable->lpWSPSocket = WSPSocket;
1690 lpProcTable->lpWSPStringToAddress = WSPStringToAddress;
1691
1692 lpWSPData->wVersion = MAKEWORD(2, 2);
1693 lpWSPData->wHighVersion = MAKEWORD(2, 2);
1694 }
1695
1696 AFD_DbgPrint(MAX_TRACE, ("Status (%d).\n", Status));
1697
1698 return Status;
1699 }
1700
1701
1702 INT
1703 WSPAPI
1704 WSPCleanup(
1705 OUT LPINT lpErrno)
1706 /*
1707 * FUNCTION: Cleans up service provider for a client
1708 * ARGUMENTS:
1709 * lpErrno = Address of buffer for error information
1710 * RETURNS:
1711 * 0 if successful, or SOCKET_ERROR if not
1712 */
1713 {
1714 AFD_DbgPrint(MAX_TRACE, ("\n"));
1715
1716
1717 AFD_DbgPrint(MAX_TRACE, ("Leaving.\n"));
1718
1719 *lpErrno = NO_ERROR;
1720
1721 return 0;
1722 }
1723
1724
1725
1726 int
1727 GetSocketInformation(
1728 PSOCKET_INFORMATION Socket,
1729 ULONG AfdInformationClass,
1730 PULONG Ulong OPTIONAL,
1731 PLARGE_INTEGER LargeInteger OPTIONAL)
1732 {
1733 IO_STATUS_BLOCK IOSB;
1734 AFD_INFO InfoData;
1735 NTSTATUS Status;
1736 HANDLE SockEvent;
1737
1738 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1739 NULL, 1, FALSE );
1740
1741 if( !NT_SUCCESS(Status) ) return -1;
1742
1743 /* Set Info Class */
1744 InfoData.InformationClass = AfdInformationClass;
1745
1746 /* Send IOCTL */
1747 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1748 SockEvent,
1749 NULL,
1750 NULL,
1751 &IOSB,
1752 IOCTL_AFD_GET_INFO,
1753 &InfoData,
1754 sizeof(InfoData),
1755 &InfoData,
1756 sizeof(InfoData));
1757
1758 /* Wait for return */
1759 if (Status == STATUS_PENDING) {
1760 WaitForSingleObject(SockEvent, INFINITE);
1761 }
1762
1763 /* Return Information */
1764 *Ulong = InfoData.Information.Ulong;
1765 if (LargeInteger != NULL) {
1766 *LargeInteger = InfoData.Information.LargeInteger;
1767 }
1768
1769 NtClose( SockEvent );
1770
1771 return 0;
1772
1773 }
1774
1775
1776 int
1777 SetSocketInformation(
1778 PSOCKET_INFORMATION Socket,
1779 ULONG AfdInformationClass,
1780 PULONG Ulong OPTIONAL,
1781 PLARGE_INTEGER LargeInteger OPTIONAL)
1782 {
1783 IO_STATUS_BLOCK IOSB;
1784 AFD_INFO InfoData;
1785 NTSTATUS Status;
1786 HANDLE SockEvent;
1787
1788 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1789 NULL, 1, FALSE );
1790
1791 if( !NT_SUCCESS(Status) ) return -1;
1792
1793 /* Set Info Class */
1794 InfoData.InformationClass = AfdInformationClass;
1795
1796 /* Set Information */
1797 InfoData.Information.Ulong = *Ulong;
1798 if (LargeInteger != NULL) {
1799 InfoData.Information.LargeInteger = *LargeInteger;
1800 }
1801
1802 AFD_DbgPrint(MID_TRACE,("XXX Info %x (Data %x)\n",
1803 AfdInformationClass, *Ulong));
1804
1805 /* Send IOCTL */
1806 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1807 SockEvent,
1808 NULL,
1809 NULL,
1810 &IOSB,
1811 IOCTL_AFD_GET_INFO,
1812 &InfoData,
1813 sizeof(InfoData),
1814 NULL,
1815 0);
1816
1817 /* Wait for return */
1818 if (Status == STATUS_PENDING) {
1819 WaitForSingleObject(SockEvent, INFINITE);
1820 }
1821
1822 NtClose( SockEvent );
1823
1824 return 0;
1825
1826 }
1827
1828 PSOCKET_INFORMATION
1829 GetSocketStructure(
1830 SOCKET Handle)
1831 {
1832 ULONG i;
1833
1834 for (i=0; i<SocketCount; i++) {
1835 if (Sockets[i]->Handle == Handle) {
1836 return Sockets[i];
1837 }
1838 }
1839 return 0;
1840 }
1841
1842 int CreateContext(PSOCKET_INFORMATION Socket)
1843 {
1844 IO_STATUS_BLOCK IOSB;
1845 SOCKET_CONTEXT ContextData;
1846 NTSTATUS Status;
1847 HANDLE SockEvent;
1848
1849 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
1850 NULL, 1, FALSE );
1851
1852 if( !NT_SUCCESS(Status) ) return -1;
1853
1854 /* Create Context */
1855 ContextData.SharedData = Socket->SharedData;
1856 ContextData.SizeOfHelperData = 0;
1857 RtlCopyMemory (&ContextData.LocalAddress,
1858 Socket->LocalAddress,
1859 Socket->SharedData.SizeOfLocalAddress);
1860 RtlCopyMemory (&ContextData.RemoteAddress,
1861 Socket->RemoteAddress,
1862 Socket->SharedData.SizeOfRemoteAddress);
1863
1864 /* Send IOCTL */
1865 Status = NtDeviceIoControlFile( (HANDLE)Socket->Handle,
1866 SockEvent,
1867 NULL,
1868 NULL,
1869 &IOSB,
1870 IOCTL_AFD_SET_CONTEXT,
1871 &ContextData,
1872 sizeof(ContextData),
1873 NULL,
1874 0);
1875
1876 /* Wait for Completition */
1877 if (Status == STATUS_PENDING) {
1878 WaitForSingleObject(SockEvent, INFINITE);
1879 }
1880
1881 NtClose( SockEvent );
1882
1883 return 0;
1884 }
1885
1886 BOOLEAN SockCreateOrReferenceAsyncThread(VOID)
1887 {
1888 HANDLE hAsyncThread;
1889 DWORD AsyncThreadId;
1890 HANDLE AsyncEvent;
1891 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1892 NTSTATUS Status;
1893
1894 /* Check if the Thread Already Exists */
1895 if (SockAsyncThreadRefCount) {
1896 return TRUE;
1897 }
1898
1899 /* Create the Completion Port */
1900 if (!SockAsyncCompletionPort) {
1901 Status = NtCreateIoCompletion(&SockAsyncCompletionPort,
1902 IO_COMPLETION_ALL_ACCESS,
1903 NULL,
1904 2); // Allow 2 threads only
1905
1906 /* Protect Handle */
1907 HandleFlags.ProtectFromClose = TRUE;
1908 HandleFlags.Inherit = FALSE;
1909 Status = NtSetInformationObject(SockAsyncCompletionPort,
1910 ObjectHandleFlagInformation,
1911 &HandleFlags,
1912 sizeof(HandleFlags));
1913 }
1914
1915 /* Create the Async Event */
1916 Status = NtCreateEvent(&AsyncEvent,
1917 EVENT_ALL_ACCESS,
1918 NULL,
1919 NotificationEvent,
1920 FALSE);
1921
1922 /* Create the Async Thread */
1923 hAsyncThread = CreateThread(NULL,
1924 0,
1925 (LPTHREAD_START_ROUTINE)SockAsyncThread,
1926 NULL,
1927 0,
1928 &AsyncThreadId);
1929
1930 /* Close the Handle */
1931 NtClose(hAsyncThread);
1932
1933 /* Increase the Reference Count */
1934 SockAsyncThreadRefCount++;
1935 return TRUE;
1936 }
1937
1938 int SockAsyncThread(PVOID ThreadParam)
1939 {
1940 PVOID AsyncContext;
1941 PASYNC_COMPLETION_ROUTINE AsyncCompletionRoutine;
1942 IO_STATUS_BLOCK IOSB;
1943 NTSTATUS Status;
1944
1945 /* Make the Thread Higher Priority */
1946 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
1947
1948 /* Do a KQUEUE/WorkItem Style Loop, thanks to IoCompletion Ports */
1949 do {
1950 Status = NtRemoveIoCompletion (SockAsyncCompletionPort,
1951 (PVOID*)&AsyncCompletionRoutine,
1952 &AsyncContext,
1953 &IOSB,
1954 NULL);
1955
1956 /* Call the Async Function */
1957 if (NT_SUCCESS(Status)) {
1958 (*AsyncCompletionRoutine)(AsyncContext, &IOSB);
1959 } else {
1960 /* It Failed, sleep for a second */
1961 Sleep(1000);
1962 }
1963 } while ((Status != STATUS_TIMEOUT));
1964
1965 /* The Thread has Ended */
1966 return 0;
1967 }
1968
1969 BOOLEAN SockGetAsyncSelectHelperAfdHandle(VOID)
1970 {
1971 UNICODE_STRING AfdHelper;
1972 OBJECT_ATTRIBUTES ObjectAttributes;
1973 IO_STATUS_BLOCK IoSb;
1974 NTSTATUS Status;
1975 FILE_COMPLETION_INFORMATION CompletionInfo;
1976 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
1977
1978 /* First, make sure we're not already intialized */
1979 if (SockAsyncHelperAfdHandle) {
1980 return TRUE;
1981 }
1982
1983 /* Set up Handle Name and Object */
1984 RtlInitUnicodeString(&AfdHelper, L"\\Device\\Afd\\AsyncSelectHlp" );
1985 InitializeObjectAttributes(&ObjectAttributes,
1986 &AfdHelper,
1987 OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
1988 NULL,
1989 NULL);
1990
1991 /* Open the Handle to AFD */
1992 Status = NtCreateFile(&SockAsyncHelperAfdHandle,
1993 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1994 &ObjectAttributes,
1995 &IoSb,
1996 NULL,
1997 0,
1998 FILE_SHARE_READ | FILE_SHARE_WRITE,
1999 FILE_OPEN_IF,
2000 0,
2001 NULL,
2002 0);
2003
2004 /*
2005 * Now Set up the Completion Port Information
2006 * This means that whenever a Poll is finished, the routine will be executed
2007 */
2008 CompletionInfo.Port = SockAsyncCompletionPort;
2009 CompletionInfo.Key = SockAsyncSelectCompletionRoutine;
2010 Status = NtSetInformationFile(SockAsyncHelperAfdHandle,
2011 &IoSb,
2012 &CompletionInfo,
2013 sizeof(CompletionInfo),
2014 FileCompletionInformation);
2015
2016
2017 /* Protect the Handle */
2018 HandleFlags.ProtectFromClose = TRUE;
2019 HandleFlags.Inherit = FALSE;
2020 Status = NtSetInformationObject(SockAsyncCompletionPort,
2021 ObjectHandleFlagInformation,
2022 &HandleFlags,
2023 sizeof(HandleFlags));
2024
2025
2026 /* Set this variable to true so that Send/Recv/Accept will know wether to renable disabled events */
2027 SockAsyncSelectCalled = TRUE;
2028 return TRUE;
2029 }
2030
2031 VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
2032 {
2033
2034 PASYNC_DATA AsyncData = Context;
2035 PSOCKET_INFORMATION Socket;
2036 ULONG x;
2037
2038 /* Get the Socket */
2039 Socket = AsyncData->ParentSocket;
2040
2041 /* Check if the Sequence Number Changed behind our back */
2042 if (AsyncData->SequenceNumber != Socket->SharedData.SequenceNumber ){
2043 return;
2044 }
2045
2046 /* Check we were manually called b/c of a failure */
2047 if (!NT_SUCCESS(IoStatusBlock->Status)) {
2048 /* FIXME: Perform Upcall */
2049 return;
2050 }
2051
2052 for (x = 1; x; x<<=1) {
2053 switch (AsyncData->AsyncSelectInfo.Handles[0].Events & x) {
2054 case AFD_EVENT_RECEIVE:
2055 if (0 != (Socket->SharedData.AsyncEvents & FD_READ) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_READ)) {
2056 /* Make the Notifcation */
2057 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2058 Socket->SharedData.wMsg,
2059 Socket->Handle,
2060 WSAMAKESELECTREPLY(FD_READ, 0));
2061 /* Disable this event until the next read(); */
2062 Socket->SharedData.AsyncDisabledEvents |= FD_READ;
2063 }
2064 break;
2065
2066 case AFD_EVENT_OOB_RECEIVE:
2067 if (0 != (Socket->SharedData.AsyncEvents & FD_OOB) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_OOB)) {
2068 /* Make the Notifcation */
2069 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2070 Socket->SharedData.wMsg,
2071 Socket->Handle,
2072 WSAMAKESELECTREPLY(FD_OOB, 0));
2073 /* Disable this event until the next read(); */
2074 Socket->SharedData.AsyncDisabledEvents |= FD_OOB;
2075 }
2076 break;
2077
2078 case AFD_EVENT_SEND:
2079 if (0 != (Socket->SharedData.AsyncEvents & FD_WRITE) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_WRITE)) {
2080 /* Make the Notifcation */
2081 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2082 Socket->SharedData.wMsg,
2083 Socket->Handle,
2084 WSAMAKESELECTREPLY(FD_WRITE, 0));
2085 /* Disable this event until the next write(); */
2086 Socket->SharedData.AsyncDisabledEvents |= FD_WRITE;
2087 }
2088 break;
2089
2090 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
2091 case AFD_EVENT_CONNECT:
2092 if (0 != (Socket->SharedData.AsyncEvents & FD_CONNECT) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_CONNECT)) {
2093 /* Make the Notifcation */
2094 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2095 Socket->SharedData.wMsg,
2096 Socket->Handle,
2097 WSAMAKESELECTREPLY(FD_CONNECT, 0));
2098 /* Disable this event forever; */
2099 Socket->SharedData.AsyncDisabledEvents |= FD_CONNECT;
2100 }
2101 break;
2102
2103 case AFD_EVENT_ACCEPT:
2104 if (0 != (Socket->SharedData.AsyncEvents & FD_ACCEPT) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_ACCEPT)) {
2105 /* Make the Notifcation */
2106 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2107 Socket->SharedData.wMsg,
2108 Socket->Handle,
2109 WSAMAKESELECTREPLY(FD_ACCEPT, 0));
2110 /* Disable this event until the next accept(); */
2111 Socket->SharedData.AsyncDisabledEvents |= FD_ACCEPT;
2112 }
2113 break;
2114
2115 case AFD_EVENT_DISCONNECT:
2116 case AFD_EVENT_ABORT:
2117 case AFD_EVENT_CLOSE:
2118 if (0 != (Socket->SharedData.AsyncEvents & FD_CLOSE) && 0 == (Socket->SharedData.AsyncDisabledEvents & FD_CLOSE)) {
2119 /* Make the Notifcation */
2120 (Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
2121 Socket->SharedData.wMsg,
2122 Socket->Handle,
2123 WSAMAKESELECTREPLY(FD_CLOSE, 0));
2124 /* Disable this event forever; */
2125 Socket->SharedData.AsyncDisabledEvents |= FD_CLOSE;
2126 }
2127 break;
2128
2129 /* FIXME: Support QOS */
2130 }
2131 }
2132
2133 /* Check if there are any events left for us to check */
2134 if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0 ) {
2135 return;
2136 }
2137
2138 /* Keep Polling */
2139 SockProcessAsyncSelect(Socket, AsyncData);
2140 return;
2141 }
2142
2143 VOID SockProcessAsyncSelect(PSOCKET_INFORMATION Socket, PASYNC_DATA AsyncData)
2144 {
2145
2146 ULONG lNetworkEvents;
2147 NTSTATUS Status;
2148
2149 /* Set up the Async Data Event Info */
2150 AsyncData->AsyncSelectInfo.Timeout.HighPart = 0x7FFFFFFF;
2151 AsyncData->AsyncSelectInfo.Timeout.LowPart = 0xFFFFFFFF;
2152 AsyncData->AsyncSelectInfo.HandleCount = 1;
2153 AsyncData->AsyncSelectInfo.Exclusive = TRUE;
2154 AsyncData->AsyncSelectInfo.Handles[0].Handle = Socket->Handle;
2155 AsyncData->AsyncSelectInfo.Handles[0].Events = 0;
2156
2157 /* Remove unwanted events */
2158 lNetworkEvents = Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents);
2159
2160 /* Set Events to wait for */
2161 if (lNetworkEvents & FD_READ) {
2162 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_RECEIVE;
2163 }
2164
2165 if (lNetworkEvents & FD_WRITE) {
2166 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_SEND;
2167 }
2168
2169 if (lNetworkEvents & FD_OOB) {
2170 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_OOB_RECEIVE;
2171 }
2172
2173 if (lNetworkEvents & FD_ACCEPT) {
2174 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_ACCEPT;
2175 }
2176
2177 /* FIXME: THIS IS NOT RIGHT!!! HACK HACK HACK! */
2178 if (lNetworkEvents & FD_CONNECT) {
2179 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL;
2180 }
2181
2182 if (lNetworkEvents & FD_CLOSE) {
2183 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT;
2184 }
2185
2186 if (lNetworkEvents & FD_QOS) {
2187 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_QOS;
2188 }
2189
2190 if (lNetworkEvents & FD_GROUP_QOS) {
2191 AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_GROUP_QOS;
2192 }
2193
2194 /* Send IOCTL */
2195 Status = NtDeviceIoControlFile (SockAsyncHelperAfdHandle,
2196 NULL,
2197 NULL,
2198 AsyncData,
2199 &AsyncData->IoStatusBlock,
2200 IOCTL_AFD_SELECT,
2201 &AsyncData->AsyncSelectInfo,
2202 sizeof(AsyncData->AsyncSelectInfo),
2203 &AsyncData->AsyncSelectInfo,
2204 sizeof(AsyncData->AsyncSelectInfo));
2205
2206 /* I/O Manager Won't call the completion routine, let's do it manually */
2207 if (NT_SUCCESS(Status)) {
2208 return;
2209 } else {
2210 AsyncData->IoStatusBlock.Status = Status;
2211 SockAsyncSelectCompletionRoutine(AsyncData, &AsyncData->IoStatusBlock);
2212 }
2213 }
2214
2215 VOID SockProcessQueuedAsyncSelect(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
2216 {
2217 PASYNC_DATA AsyncData = Context;
2218 BOOL FreeContext = TRUE;
2219 PSOCKET_INFORMATION Socket;
2220
2221 /* Get the Socket */
2222 Socket = AsyncData->ParentSocket;
2223
2224 /* If someone closed it, stop the function */
2225 if (Socket->SharedData.State != SocketClosed) {
2226 /* Check if the Sequence Number changed by now, in which case quit */
2227 if (AsyncData->SequenceNumber == Socket->SharedData.SequenceNumber) {
2228 /* Do the actuall select, if needed */
2229 if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents))) {
2230 SockProcessAsyncSelect(Socket, AsyncData);
2231 FreeContext = FALSE;
2232 }
2233 }
2234 }
2235
2236 /* Free the Context */
2237 if (FreeContext) {
2238 HeapFree(GetProcessHeap(), 0, AsyncData);
2239 }
2240
2241 return;
2242 }
2243
2244 VOID
2245 SockReenableAsyncSelectEvent (
2246 IN PSOCKET_INFORMATION Socket,
2247 IN ULONG Event
2248 )
2249 {
2250 PASYNC_DATA AsyncData;
2251
2252 /* Make sure the event is actually disabled */
2253 if (!(Socket->SharedData.AsyncDisabledEvents & Event)) {
2254 return;
2255 }
2256
2257 /* Re-enable it */
2258 Socket->SharedData.AsyncDisabledEvents &= ~Event;
2259
2260 /* Return if no more events are being polled */
2261 if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0 ) {
2262 return;
2263 }
2264
2265 /* Wait on new events */
2266 AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(ASYNC_DATA));
2267
2268 /* Create the Asynch Thread if Needed */
2269 SockCreateOrReferenceAsyncThread();
2270
2271 /* Increase the sequence number to stop anything else */
2272 Socket->SharedData.SequenceNumber++;
2273
2274 /* Set up the Async Data */
2275 AsyncData->ParentSocket = Socket;
2276 AsyncData->SequenceNumber = Socket->SharedData.SequenceNumber;
2277
2278 /* Begin Async Select by using I/O Completion */
2279 NtSetIoCompletion(SockAsyncCompletionPort,
2280 (PVOID)&SockProcessQueuedAsyncSelect,
2281 AsyncData,
2282 0,
2283 0);
2284
2285 /* All done */
2286 return;
2287 }
2288
2289 BOOL
2290 STDCALL
2291 DllMain(HANDLE hInstDll,
2292 ULONG dwReason,
2293 PVOID Reserved)
2294 {
2295
2296 switch (dwReason) {
2297 case DLL_PROCESS_ATTACH:
2298
2299 AFD_DbgPrint(MAX_TRACE, ("Loading MSAFD.DLL \n"));
2300
2301 /* Don't need thread attach notifications
2302 so disable them to improve performance */
2303 DisableThreadLibraryCalls(hInstDll);
2304
2305 /* List of DLL Helpers */
2306 InitializeListHead(&SockHelpersListHead);
2307
2308 /* Heap to use when allocating */
2309 GlobalHeap = GetProcessHeap();
2310
2311 /* Allocate Heap for 1024 Sockets, can be expanded later */
2312 Sockets = HeapAlloc(GetProcessHeap(), 0, sizeof(PSOCKET_INFORMATION) * 1024);
2313
2314 AFD_DbgPrint(MAX_TRACE, ("MSAFD.DLL has been loaded\n"));
2315
2316 break;
2317
2318 case DLL_THREAD_ATTACH:
2319 break;
2320
2321 case DLL_THREAD_DETACH:
2322 break;
2323
2324 case DLL_PROCESS_DETACH:
2325 break;
2326 }
2327
2328 AFD_DbgPrint(MAX_TRACE, ("DllMain of msafd.dll (leaving)\n"));
2329
2330 return TRUE;
2331 }
2332
2333 /* EOF */
2334
2335