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