2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Ancillary Function Driver DLL
5 * PURPOSE: DLL entry point
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/09-2000 Created
15 /* See debug.h for debug/trace constants */
16 DWORD DebugTraceLevel
= MIN_TRACE
;
17 //DWORD DebugTraceLevel = DEBUG_ULTRA;
21 /* To make the linker happy */
22 VOID STDCALL
KeBugCheck (ULONG BugCheckCode
) {}
26 WSPUPCALLTABLE Upcalls
;
27 LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest
;
28 CRITICAL_SECTION InitCriticalSection
;
29 DWORD StartupCount
= 0;
30 HANDLE CommandChannel
;
39 DWORD NotificationEvents
,
40 PUNICODE_STRING TdiDeviceName
)
42 * FUNCTION: Opens a socket
44 * Socket = Address of buffer to place socket descriptor
45 * AddressFamily = Address family
46 * SocketType = Type of socket
47 * Protocol = Protocol type
48 * HelperContext = Pointer to context information for helper DLL
49 * NotificationEvents = Events for which helper DLL is to be notified
50 * TdiDeviceName = Pointer to name of TDI device to use
55 OBJECT_ATTRIBUTES ObjectAttributes
;
56 PAFD_SOCKET_INFORMATION SocketInfo
;
57 PFILE_FULL_EA_INFORMATION EaInfo
;
58 UNICODE_STRING DeviceName
;
65 AFD_DbgPrint(MAX_TRACE
, ("Socket (0x%X) TdiDeviceName (%wZ)\n",
66 Socket
, TdiDeviceName
));
68 AFD_DbgPrint(MAX_TRACE
, ("Socket2 (0x%X) TdiDeviceName (%S)\n",
69 Socket
, TdiDeviceName
->Buffer
));
71 EaShort
= sizeof(FILE_FULL_EA_INFORMATION
) +
73 sizeof(AFD_SOCKET_INFORMATION
);
75 EaLength
= EaShort
+ TdiDeviceName
->Length
+ sizeof(WCHAR
);
77 EaInfo
= (PFILE_FULL_EA_INFORMATION
)HeapAlloc(GlobalHeap
, 0, EaLength
);
79 return STATUS_INSUFFICIENT_RESOURCES
;
82 RtlZeroMemory(EaInfo
, EaLength
);
83 EaInfo
->EaNameLength
= AFD_SOCKET_LENGTH
;
84 RtlCopyMemory(EaInfo
->EaName
,
87 EaInfo
->EaValueLength
= sizeof(AFD_SOCKET_INFORMATION
);
89 SocketInfo
= (PAFD_SOCKET_INFORMATION
)(EaInfo
->EaName
+ AFD_SOCKET_LENGTH
);
90 SocketInfo
->CommandChannel
= FALSE
;
91 SocketInfo
->AddressFamily
= AddressFamily
;
92 SocketInfo
->SocketType
= SocketType
;
93 SocketInfo
->Protocol
= Protocol
;
94 SocketInfo
->HelperContext
= HelperContext
;
95 SocketInfo
->NotificationEvents
= NotificationEvents
;
96 /* Zeroed above so initialized to a wildcard address if a raw socket */
97 SocketInfo
->Name
.sa_family
= AddressFamily
;
99 /* Store TDI device name last in buffer */
100 SocketInfo
->TdiDeviceName
.Buffer
= (PWCHAR
)(EaInfo
+ EaShort
);
101 SocketInfo
->TdiDeviceName
.MaximumLength
= TdiDeviceName
->Length
+ sizeof(WCHAR
);
102 RtlCopyUnicodeString(&SocketInfo
->TdiDeviceName
, TdiDeviceName
);
104 AFD_DbgPrint(MAX_TRACE
, ("EaInfo at (0x%X) EaLength is (%d).\n", (UINT
)EaInfo
, (INT
)EaLength
));
106 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\Afd");
107 InitializeObjectAttributes(
114 Status
= NtCreateFile(
116 FILE_GENERIC_READ
| FILE_GENERIC_WRITE
,
123 FILE_SYNCHRONOUS_IO_ALERT
,
127 HeapFree(GlobalHeap
, 0, EaInfo
);
129 if (!NT_SUCCESS(Status
)) {
130 AFD_DbgPrint(MIN_TRACE
, ("Error opening device (Status 0x%X).\n",
132 return STATUS_INSUFFICIENT_RESOURCES
;
135 *Socket
= (SOCKET
)FileHandle
;
137 return STATUS_SUCCESS
;
147 IN LPWSAPROTOCOL_INFOW lpProtocolInfo
,
152 * FUNCTION: Creates a new socket
154 * af = Address family
156 * protocol = Protocol type
157 * lpProtocolInfo = Pointer to protocol information
159 * dwFlags = Socket flags
160 * lpErrno = Address of buffer for error information
162 * Created socket, or INVALID_SOCKET if it could not be created
165 WSAPROTOCOL_INFOW ProtocolInfo
;
166 UNICODE_STRING TdiDeviceName
;
167 DWORD NotificationEvents
;
168 PWSHELPER_DLL HelperDLL
;
178 AFD_DbgPrint(MAX_TRACE
, ("af (%d) type (%d) protocol (%d).\n",
179 af
, type
, protocol
));
181 if (!lpProtocolInfo
) {
182 lpProtocolInfo
= &ProtocolInfo
;
183 ZeroMemory(&ProtocolInfo
, sizeof(WSAPROTOCOL_INFOW
));
185 ProtocolInfo
.iAddressFamily
= af
;
186 ProtocolInfo
.iSocketType
= type
;
187 ProtocolInfo
.iProtocol
= protocol
;
190 HelperDLL
= LocateHelperDLL(lpProtocolInfo
);
192 *lpErrno
= WSAEAFNOSUPPORT
;
193 return INVALID_SOCKET
;
196 AddressFamily
= lpProtocolInfo
->iAddressFamily
;
197 SocketType
= lpProtocolInfo
->iSocketType
;
198 Protocol
= lpProtocolInfo
->iProtocol
;
200 Status
= HelperDLL
->EntryTable
.lpWSHOpenSocket2(
208 &NotificationEvents
);
209 if (Status
!= NO_ERROR
) {
211 return INVALID_SOCKET
;
214 NtStatus
= OpenSocket(&Socket
,
222 RtlFreeUnicodeString(&TdiDeviceName
);
223 if (!NT_SUCCESS(NtStatus
)) {
224 *lpErrno
= RtlNtStatusToDosError(Status
);
225 return INVALID_SOCKET
;
228 /* FIXME: Assumes catalog entry id to be 1 */
229 Socket2
= Upcalls
.lpWPUModifyIFSHandle(1, Socket
, lpErrno
);
231 if (Socket2
== INVALID_SOCKET
) {
233 AFD_DbgPrint(MIN_TRACE
, ("FIXME: Cleanup.\n"));
234 return INVALID_SOCKET
;
239 AFD_DbgPrint(MID_TRACE
, ("Returning socket descriptor (0x%X).\n", Socket2
));
251 * FUNCTION: Closes an open socket
253 * s = Socket descriptor
254 * lpErrno = Address of buffer for error information
256 * NO_ERROR, or SOCKET_ERROR if the socket could not be closed
261 AFD_DbgPrint(MAX_TRACE
, ("s (0x%X).\n", s
));
263 Status
= NtClose((HANDLE
)s
);
265 if (NT_SUCCESS(Status
)) {
270 *lpErrno
= WSAENOTSOCK
;
279 IN CONST LPSOCKADDR name
,
283 * FUNCTION: Associates a local address with a socket
285 * s = Socket descriptor
286 * name = Pointer to local address
287 * namelen = Length of name
288 * lpErrno = Address of buffer for error information
290 * 0, or SOCKET_ERROR if the socket could not be bound
293 AFD_DbgPrint(MAX_TRACE
, ("s (0x%X) name (0x%X) namelen (%d).\n", s
, name
, namelen
));
296 FILE_REQUEST_BIND Request
;
297 FILE_REPLY_BIND Reply
;
298 IO_STATUS_BLOCK Iosb
;
301 RtlCopyMemory(&Request
.Name
, name
, sizeof(SOCKADDR
));
303 Status
= NtDeviceIoControlFile(
311 sizeof(FILE_REQUEST_BIND
),
313 sizeof(FILE_REPLY_BIND
));
315 if (Status
== STATUS_PENDING
) {
316 if (!NT_SUCCESS(NtWaitForSingleObject((HANDLE
)s
, FALSE
, NULL
))) {
317 /* FIXME: What error code should be returned? */
318 *lpErrno
= WSAENOBUFS
;
323 if (!NT_SUCCESS(Status
)) {
324 *lpErrno
= WSAENOBUFS
;
336 IN OUT LPFD_SET readfds
,
337 IN OUT LPFD_SET writefds
,
338 IN OUT LPFD_SET exceptfds
,
339 IN CONST LPTIMEVAL timeout
,
342 * FUNCTION: Returns status of one or more sockets
344 * nfds = Always ignored
345 * readfds = Pointer to socket set to be checked for readability (optional)
346 * writefds = Pointer to socket set to be checked for writability (optional)
347 * exceptfds = Pointer to socket set to be checked for errors (optional)
348 * timeout = Pointer to a TIMEVAL structure indicating maximum wait time
349 * (NULL means wait forever)
350 * lpErrno = Address of buffer for error information
352 * Number of ready socket descriptors, or SOCKET_ERROR if an error ocurred
355 PFILE_REQUEST_SELECT Request
;
356 FILE_REPLY_SELECT Reply
;
357 IO_STATUS_BLOCK Iosb
;
365 AFD_DbgPrint(MAX_TRACE
, ("readfds (0x%X) writefds (0x%X) exceptfds (0x%X).\n",
366 readfds
, writefds
, exceptfds
));
368 /* FIXME: For now, all reads are timed out immediately */
369 if (readfds
!= NULL
) {
370 AFD_DbgPrint(MID_TRACE
, ("Timing out read query.\n"));
371 *lpErrno
= WSAETIMEDOUT
;
375 /* FIXME: For now, always allow write */
376 if (writefds
!= NULL
) {
377 AFD_DbgPrint(MID_TRACE
, ("Setting one socket writeable.\n"));
384 if ((readfds
!= NULL
) && (readfds
->fd_count
> 0)) {
385 ReadSize
= (readfds
->fd_count
* sizeof(SOCKET
)) + sizeof(UINT
);
389 if ((writefds
!= NULL
) && (writefds
->fd_count
> 0)) {
390 WriteSize
= (writefds
->fd_count
* sizeof(SOCKET
)) + sizeof(UINT
);
394 if ((exceptfds
!= NULL
) && (exceptfds
->fd_count
> 0)) {
395 ExceptSize
= (exceptfds
->fd_count
* sizeof(SOCKET
)) + sizeof(UINT
);
398 Size
= ReadSize
+ WriteSize
+ ExceptSize
;
400 Request
= (PFILE_REQUEST_SELECT
)HeapAlloc(
401 GlobalHeap
, 0, sizeof(FILE_REQUEST_SELECT
) + Size
);
403 *lpErrno
= WSAENOBUFS
;
407 /* Put FD SETs after request structure */
408 Current
= (Request
+ 1);
411 Request
->ReadFDSet
= (LPFD_SET
)Current
;
413 RtlCopyMemory(Request
->ReadFDSet
, readfds
, ReadSize
);
415 Request
->ReadFDSet
= NULL
;
419 Request
->WriteFDSet
= (LPFD_SET
)Current
;
420 Current
+= WriteSize
;
421 RtlCopyMemory(Request
->WriteFDSet
, writefds
, WriteSize
);
423 Request
->WriteFDSet
= NULL
;
426 if (ExceptSize
> 0) {
427 Request
->ExceptFDSet
= (LPFD_SET
)Current
;
428 RtlCopyMemory(Request
->ExceptFDSet
, exceptfds
, ExceptSize
);
430 Request
->ExceptFDSet
= NULL
;
433 AFD_DbgPrint(MAX_TRACE
, ("R1 (0x%X) W1 (0x%X).\n", Request
->ReadFDSet
, Request
->WriteFDSet
));
435 Status
= NtDeviceIoControlFile(
443 sizeof(FILE_REQUEST_SELECT
) + Size
,
445 sizeof(FILE_REPLY_SELECT
));
447 HeapFree(GlobalHeap
, 0, Request
);
449 if (Status
== STATUS_PENDING
) {
450 AFD_DbgPrint(MAX_TRACE
, ("Waiting on transport.\n"));
451 /* FIXME: Wait only for blocking sockets */
452 Status
= NtWaitForSingleObject(CommandChannel
, FALSE
, NULL
);
455 if (!NT_SUCCESS(Status
)) {
456 AFD_DbgPrint(MAX_TRACE
, ("Status (0x%X).\n", Status
));
457 *lpErrno
= WSAENOBUFS
;
461 AFD_DbgPrint(MAX_TRACE
, ("Select successful. Status (0x%X) Count (0x%X).\n",
462 Reply
.Status
, Reply
.SocketCount
));
464 *lpErrno
= Reply
.Status
;
466 return Reply
.SocketCount
;
470 NTSTATUS
OpenCommandChannel(
473 * FUNCTION: Opens a command channel to afd.sys
477 * Status of operation
480 OBJECT_ATTRIBUTES ObjectAttributes
;
481 PAFD_SOCKET_INFORMATION SocketInfo
;
482 PFILE_FULL_EA_INFORMATION EaInfo
;
483 UNICODE_STRING DeviceName
;
484 IO_STATUS_BLOCK Iosb
;
490 AFD_DbgPrint(MAX_TRACE
, ("Called\n"));
492 EaShort
= sizeof(FILE_FULL_EA_INFORMATION
) +
494 sizeof(AFD_SOCKET_INFORMATION
);
498 EaInfo
= (PFILE_FULL_EA_INFORMATION
)HeapAlloc(GlobalHeap
, 0, EaLength
);
500 return STATUS_INSUFFICIENT_RESOURCES
;
503 RtlZeroMemory(EaInfo
, EaLength
);
504 EaInfo
->EaNameLength
= AFD_SOCKET_LENGTH
;
505 RtlCopyMemory(EaInfo
->EaName
,
508 EaInfo
->EaValueLength
= sizeof(AFD_SOCKET_INFORMATION
);
510 SocketInfo
= (PAFD_SOCKET_INFORMATION
)(EaInfo
->EaName
+ AFD_SOCKET_LENGTH
);
511 SocketInfo
->CommandChannel
= TRUE
;
513 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\Afd");
514 InitializeObjectAttributes(
521 Status
= NtCreateFile(
523 FILE_GENERIC_READ
| FILE_GENERIC_WRITE
,
530 FILE_SYNCHRONOUS_IO_ALERT
,
534 if (!NT_SUCCESS(Status
)) {
535 AFD_DbgPrint(MIN_TRACE
, ("Error opening device (Status 0x%X).\n",
540 CommandChannel
= FileHandle
;
542 return STATUS_SUCCESS
;
546 NTSTATUS
CloseCommandChannel(
549 * FUNCTION: Closes command channel to afd.sys
553 * Status of operation
556 AFD_DbgPrint(MAX_TRACE
, ("Called.\n"));
558 return NtClose(CommandChannel
);
565 IN WORD wVersionRequested
,
566 OUT LPWSPDATA lpWSPData
,
567 IN LPWSAPROTOCOL_INFOW lpProtocolInfo
,
568 IN WSPUPCALLTABLE UpcallTable
,
569 OUT LPWSPPROC_TABLE lpProcTable
)
571 * FUNCTION: Initialize service provider for a client
573 * wVersionRequested = Highest WinSock SPI version that the caller can use
574 * lpWSPData = Address of WSPDATA structure to initialize
575 * lpProtocolInfo = Pointer to structure that defines the desired protocol
576 * UpcallTable = Pointer to upcall table of the WinSock DLL
577 * lpProcTable = Address of procedure table to initialize
579 * Status of operation
585 AFD_DbgPrint(MAX_TRACE
, ("wVersionRequested (0x%X) \n", wVersionRequested
));
587 EnterCriticalSection(&InitCriticalSection
);
589 Upcalls
= UpcallTable
;
591 if (StartupCount
== 0) {
592 /* First time called */
594 Status
= WSAVERNOTSUPPORTED
;
596 Status
= OpenCommandChannel();
597 if (NT_SUCCESS(Status
)) {
598 hWS2_32
= GetModuleHandle(L
"ws2_32.dll");
599 if (hWS2_32
!= NULL
) {
600 lpWPUCompleteOverlappedRequest
= (LPWPUCOMPLETEOVERLAPPEDREQUEST
)
601 GetProcAddress(hWS2_32
, "WPUCompleteOverlappedRequest");
602 if (lpWPUCompleteOverlappedRequest
!= NULL
) {
607 AFD_DbgPrint(MIN_TRACE
, ("GetModuleHandle() failed for ws2_32.dll\n"));
610 AFD_DbgPrint(MIN_TRACE
, ("Cannot open afd.sys\n"));
617 LeaveCriticalSection(&InitCriticalSection
);
619 if (Status
== NO_ERROR
) {
620 lpProcTable
->lpWSPAccept
= WSPAccept
;
621 lpProcTable
->lpWSPAddressToString
= WSPAddressToString
;
622 lpProcTable
->lpWSPAsyncSelect
= WSPAsyncSelect
;
623 lpProcTable
->lpWSPBind
= WSPBind
;
624 lpProcTable
->lpWSPCancelBlockingCall
= WSPCancelBlockingCall
;
625 lpProcTable
->lpWSPCleanup
= WSPCleanup
;
626 lpProcTable
->lpWSPCloseSocket
= WSPCloseSocket
;
627 lpProcTable
->lpWSPConnect
= WSPConnect
;
628 lpProcTable
->lpWSPDuplicateSocket
= WSPDuplicateSocket
;
629 lpProcTable
->lpWSPEnumNetworkEvents
= WSPEnumNetworkEvents
;
630 lpProcTable
->lpWSPEventSelect
= WSPEventSelect
;
631 lpProcTable
->lpWSPGetOverlappedResult
= WSPGetOverlappedResult
;
632 lpProcTable
->lpWSPGetPeerName
= WSPGetPeerName
;
633 lpProcTable
->lpWSPGetSockName
= WSPGetSockName
;
634 lpProcTable
->lpWSPGetSockOpt
= WSPGetSockOpt
;
635 lpProcTable
->lpWSPGetQOSByName
= WSPGetQOSByName
;
636 lpProcTable
->lpWSPIoctl
= WSPIoctl
;
637 lpProcTable
->lpWSPJoinLeaf
= WSPJoinLeaf
;
638 lpProcTable
->lpWSPListen
= WSPListen
;
639 lpProcTable
->lpWSPRecv
= WSPRecv
;
640 lpProcTable
->lpWSPRecvDisconnect
= WSPRecvDisconnect
;
641 lpProcTable
->lpWSPRecvFrom
= WSPRecvFrom
;
642 lpProcTable
->lpWSPSelect
= WSPSelect
;
643 lpProcTable
->lpWSPSend
= WSPSend
;
644 lpProcTable
->lpWSPSendDisconnect
= WSPSendDisconnect
;
645 lpProcTable
->lpWSPSendTo
= WSPSendTo
;
646 lpProcTable
->lpWSPSetSockOpt
= WSPSetSockOpt
;
647 lpProcTable
->lpWSPShutdown
= WSPShutdown
;
648 lpProcTable
->lpWSPSocket
= WSPSocket
;
649 lpProcTable
->lpWSPStringToAddress
= WSPStringToAddress
;
651 lpWSPData
->wVersion
= MAKEWORD(2, 2);
652 lpWSPData
->wHighVersion
= MAKEWORD(2, 2);
655 AFD_DbgPrint(MAX_TRACE
, ("Status (%d).\n", Status
));
666 * FUNCTION: Cleans up service provider for a client
668 * lpErrno = Address of buffer for error information
670 * 0 if successful, or SOCKET_ERROR if not
673 AFD_DbgPrint(MAX_TRACE
, ("\n"));
675 EnterCriticalSection(&InitCriticalSection
);
677 if (StartupCount
> 0) {
680 if (StartupCount
== 0) {
681 AFD_DbgPrint(MAX_TRACE
, ("Cleaning up msafd.dll.\n"));
683 CloseCommandChannel();
687 LeaveCriticalSection(&InitCriticalSection
);
697 DllMain(HANDLE hInstDll
,
701 AFD_DbgPrint(MAX_TRACE
, ("DllMain of msafd.dll\n"));
704 case DLL_PROCESS_ATTACH
:
705 /* Don't need thread attach notifications
706 so disable them to improve performance */
707 DisableThreadLibraryCalls(hInstDll
);
709 InitializeCriticalSection(&InitCriticalSection
);
711 GlobalHeap
= GetProcessHeap();
713 CreateHelperDLLDatabase();
716 case DLL_THREAD_ATTACH
:
719 case DLL_THREAD_DETACH
:
722 case DLL_PROCESS_DETACH
:
723 DestroyHelperDLLDatabase();
725 DeleteCriticalSection(&InitCriticalSection
);
729 AFD_DbgPrint(MAX_TRACE
, ("DllMain of msafd.dll (leaving)\n"));