/*++ Copyright (c) 1995 Microsoft Corporation Module Name: apc.c Abstract: This module implements the APC helper functions for the WinSock 2.0 helper library. This particular implementation is specific to NT 3.51. Author: Keith Moore (keithmo) 20-Jun-1995 Revision History: --*/ #include "precomp.h" VOID WINAPI WahpIntermediateApc( LPVOID Context, LPVOID SystemArgument1, LPVOID SystemArgument2 ); // // Public functions. // DWORD WINAPI WahOpenApcHelper( OUT LPHANDLE HelperHandle ) /*++ Routine Description: This routine opens the WinSock 2.0 APC helper device. Arguments: HelperHandle - Points to a HANDLE that will receive an open handle to the APC helper device. Return Value: DWORD - NO_ERROR if successful, a Win32 error code if not. --*/ { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING helperName; IO_STATUS_BLOCK ioStatusBlock; // // Validate parameters. // if( HelperHandle == NULL ) { return ERROR_INVALID_PARAMETER; } // // Open the helper device. // RtlInitUnicodeString( &helperName, L"\\Device\\Afd\\Helper" ); InitializeObjectAttributes( &objectAttributes, // ObjectAttributes &helperName, // ObjectName OBJ_CASE_INSENSITIVE, // Attributes NULL, // RootDirectory NULL // SecurityDescriptor ); status = NtCreateFile( HelperHandle, // FileHandle GENERIC_READ | // DesiredAccess GENERIC_WRITE | SYNCHRONIZE, &objectAttributes, // ObjectAttributes &ioStatusBlock, // IoStatusBlock NULL, // AllocationSize 0, // FileAttributes FILE_SHARE_READ | // ShareAccess FILE_SHARE_WRITE, FILE_OPEN_IF, // CreateDisposition FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions NULL, // EaBuffer 0 // EaLength ); if( NT_SUCCESS(status) ) { return NO_ERROR; } return RtlNtStatusToDosError( status ); } // WahOpenApcHelper DWORD WINAPI WahCloseApcHelper( IN HANDLE HelperHandle ) /*++ Routine Description: This function closes the WinSock 2.0 APC helper device. Arguments: HelperHandle - The handle to close. Return Value: DWORD - NO_ERROR if successful, a Win32 error code if not. --*/ { NTSTATUS status; // // Validate parameters. // if( HelperHandle == NULL ) { return ERROR_INVALID_PARAMETER; } // // Close the handle. // status = NtClose( HelperHandle ); if( NT_SUCCESS(status) ) { return NO_ERROR; } return RtlNtStatusToDosError( status ); } // WahCloseApcHelper DWORD WINAPI WahOpenCurrentThread( IN HANDLE HelperHandle, OUT LPWSATHREADID ThreadId ) /*++ Routine Description: This function opens a handle to the current thread. Arguments: HelperHandle - An open handle to the APC helper device. ThreadId - Points to a WSATHREADID structure that will receive an open handle to the current thread and an (optional) OS- dependent thread identifier. Return Value: DWORD - NO_ERROR if successful, a Win32 error code if not. --*/ { NTSTATUS status; // // Validate parameters. // if( ( HelperHandle == NULL ) || ( ThreadId == NULL ) ) { return ERROR_INVALID_PARAMETER; } // // Duplicate the current thread pseudo handle. // status = NtDuplicateObject( NtCurrentProcess(), // SourceProcessHandle NtCurrentThread(), // SourceHandle NtCurrentProcess(), // TargetProcessHandle &ThreadId->ThreadHandle, // TargetHandle 0, // DesiredAccess 0, // HandleAttributes DUPLICATE_SAME_ACCESS // Options ); if( NT_SUCCESS(status) ) { // // The NT implementation of the APC helper does not really // need the OS-dependent thread identifier, but we'll store // the current thread ID in the structure just for completeness. // ThreadId->Reserved = (DWORD)NtCurrentTeb()->ClientId.UniqueThread; return NO_ERROR; } return RtlNtStatusToDosError( status ); } // WahOpenCurrentThread DWORD WINAPI WahCloseThread( IN HANDLE HelperHandle, IN LPWSATHREADID ThreadId ) /*++ Routine Description: This routine closes an open thread handle. Arguments: HelperHandle - An open handle to the APC helper device. ThreadId - Points to a WSATHREADID structure initialized by a previous call to WahOpenCurrentThread(). Return Value: DWORD - NO_ERROR if successful, a Win32 error code if not. --*/ { NTSTATUS status; UNREFERENCED_PARAMETER( HelperHandle ); // // Validate parameters. // if( ( ThreadId == NULL ) || ( ThreadId->ThreadHandle == NULL ) ) { return ERROR_INVALID_PARAMETER; } // // Close the handle. // status = NtClose( ThreadId->ThreadHandle ); if( NT_SUCCESS(status) ) { // // Clear the fields in case the client tries something stupid. // ThreadId->ThreadHandle = NULL; ThreadId->Reserved = 0; return NO_ERROR; } return RtlNtStatusToDosError( status ); } // WahCloseThread DWORD WINAPI WahQueueUserApc( IN HANDLE HelperHandle, IN LPWSATHREADID ThreadId, IN LPWSAUSERAPC ApcRoutine, IN DWORD ApcContext OPTIONAL ) /*++ Routine Description: This routine queues a user-mode APC for the specified thread. Arguments: HelperHandle - An open handle to the APC helper device. ThreadId - Points to a WSATHREADID structure initialized by a previous call to WahOpenCurrentThread(). ApcRoutine - Points to the APC code to execute when the specified thread enters an alertable wait. ApcContext - An uninterpreted context value to pass to the APC routine. Return Value: DWORD - NO_ERROR if successful, a Win32 error code if not. --*/ { NTSTATUS status; AFD_QUEUE_APC_INFO apcInfo; IO_STATUS_BLOCK ioStatusBlock; // // Validate parameters. // if( ( HelperHandle == NULL ) || ( ThreadId == NULL ) || ( ThreadId->ThreadHandle == NULL ) || ( ApcRoutine == NULL ) ) { return ERROR_INVALID_PARAMETER; } // // Ask the helper to queue the APC. We'll actually schedule // WahpIntermediateApc as the "real" APC, which will unpack // the parameters and call the routine specified by ApcRoutine. // apcInfo.Thread = ThreadId->ThreadHandle; apcInfo.ApcRoutine = WahpIntermediateApc; apcInfo.ApcContext = (PVOID)ApcContext; apcInfo.SystemArgument1 = ApcRoutine; apcInfo.SystemArgument2 = NULL; status = NtDeviceIoControlFile( HelperHandle, // FileHandle NULL, // Event NULL, // ApcRoutine NULL, // ApcContext &ioStatusBlock, // IoStatusBlock IOCTL_AFD_QUEUE_APC, // IoControlCode &apcInfo, // InputBuffer sizeof(apcInfo), // InputBufferLength NULL, // OutputBuffer 0 // OutputBufferLength ); if( NT_SUCCESS(status) ) { return NO_ERROR; } return RtlNtStatusToDosError( status ); } // WahQueueUserApc // // Private functions. // VOID WINAPI WahpIntermediateApc( LPVOID Context, LPVOID SystemArgument1, LPVOID SystemArgument2 ) /*++ Routine Description: This is the "real" APC as scheduled by the NT kernel. It packages the parameters into the "portable" (with Win95) form, then calls the user-specified APC function. Arguments: Context - The APC context. This is just the ApcContext as passed into WahQueueUserApc. SystemArgument1 - This points to the "portable" APC function (this is the ApcRoutine as passed into WahQueueUserApc). SystemArgument2 - Unused. Return Value: None. --*/ { UNREFERENCED_PARAMETER( SystemArgument2 ); // // Just call through to the user's APC function. // ((LPWSAUSERAPC)SystemArgument1)( (DWORD)Context ); } // WahpIntermediateApc