/*++ Copyright (C) Microsoft Corporation, 1991 - 1999 Module Name: initnt.cxx Abstract: This module contains the code used to initialize the RPC runtime. One routine gets called when a process attaches to the dll. Another routine gets called the first time an RPC API is called. Author: Michael Montague (mikemon) 03-May-1991 Revision History: Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff --*/ #include #include #include #include #include #include #include #include #include int RpcHasBeenInitialized = 0; RTL_CRITICAL_SECTION GlobalMutex; RPC_SERVER * GlobalRpcServer; BOOL g_fClientSideDebugInfoEnabled = FALSE; BOOL g_fServerSideDebugInfoEnabled = FALSE; BOOL g_fSendEEInfo = FALSE; LRPC_SERVER *GlobalLrpcServer = NULL; HINSTANCE hInstanceDLL ; EXTERN_C HINSTANCE g_hRpcrt4; DWORD gPageSize; DWORD gThreadTimeout; UINT gNumberOfProcessors; DWORD gAllocationGranularity; BOOL gfServerPlatform; ULONGLONG gPhysicalMemorySize; // in megabytes // // By default the non pipe arguments cannot be more than 4 Megs // DWORD gMaxRpcSize = 0x400000; DWORD gProrateStart = 0; DWORD gProrateMax = 0; DWORD gProrateFactor = 0; void *g_rc4SafeCtx = 0; extern "C" { BOOLEAN InitializeDLL ( IN HINSTANCE DllHandle, IN ULONG Reason, IN PCONTEXT Context OPTIONAL ) /*++ Routine Description: This routine will get called: when a process attaches to this dll, and when a process detaches from this dll. Return Value: TRUE - Initialization successfully occurred. FALSE - Insufficient memory is available for the process to attach to this dll. --*/ { NTSTATUS NtStatus; UNUSED(Context); switch (Reason) { case DLL_PROCESS_ATTACH: hInstanceDLL = DllHandle ; g_hRpcrt4 = DllHandle; GlobalMutex.DebugInfo = NULL; NtStatus = RtlInitializeCriticalSectionAndSpinCount(&GlobalMutex, PREALLOCATE_EVENT_MASK); if (NT_SUCCESS(NtStatus) == 0) { return(FALSE); } // initialize safe rc4 operations. if(!rc4_safe_startup( &g_rc4SafeCtx )) { (void) RtlDeleteCriticalSection(&GlobalMutex); return FALSE; } break; case DLL_PROCESS_DETACH: // // If shutting down because of a FreeLibrary call, cleanup // if (Context == NULL) { ShutdownLrpcClient(); } if (GlobalMutex.DebugInfo != NULL) { NtStatus = RtlDeleteCriticalSection(&GlobalMutex); ASSERT(NT_SUCCESS(NtStatus)); } if (g_rc4SafeCtx) rc4_safe_shutdown( g_rc4SafeCtx ); // free safe rc4 resources. break; case DLL_THREAD_DETACH: THREAD * Thread = RpcpGetThreadPointer(); #ifdef RPC_OLD_IO_PROTECTION if (Thread) { Thread->UnprotectThread(); } #else delete Thread; #endif break; } return(TRUE); } } //extern "C" end #ifdef NO_RECURSIVE_MUTEXES unsigned int RecursionCount = 0; #endif // NO_RECURSIVE_MUTEXES extern int InitializeRpcAllocator(void); extern RPC_STATUS ReadPolicySettings(void); const ULONG MEGABYTE = 0x100000; typedef struct tagBasicSystemInfo { DWORD m_dwPageSize; ULONGLONG m_dwPhysicalMemorySize; DWORD m_dwNumberOfProcessors; ULONG AllocationGranularity; BOOL m_fServerPlatform; } BasicSystemInfo; BOOL GetBasicSystemInfo ( IN OUT BasicSystemInfo *basicSystemInfo ) /*++ Routine Description: Gets basic system information. We don't use the Win32 GetSystemInfo, because under NT it accesses the image header, which may not be available if the image was loaded from the network, and the network failed. Therefore, we need a function that accesses just what we need, and nothing else. Arguments: The basic system info structure. Return Value: 0 - failure non-0 - success. --*/ { // // Query system info (for # of processors) and product type // SYSTEM_BASIC_INFORMATION BasicInfo; NTSTATUS Status; BOOL b; Status = NtQuerySystemInformation( SystemBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL ); if ( !NT_SUCCESS(Status) ) { DbgPrintEx(DPFLTR_RPCPROXY_ID, DPFLTR_ERROR_LEVEL, "RPCTRANS: NtQuerySystemInformation failed: %x\n", Status); return 0; } basicSystemInfo->m_dwPageSize = BasicInfo.PageSize; basicSystemInfo->m_dwNumberOfProcessors = BasicInfo.NumberOfProcessors; basicSystemInfo->m_dwPhysicalMemorySize = ((BasicInfo.NumberOfPhysicalPages * (ULONGLONG) basicSystemInfo->m_dwPageSize) / MEGABYTE); basicSystemInfo->AllocationGranularity = BasicInfo.AllocationGranularity; NT_PRODUCT_TYPE type; b = RtlGetNtProductType(&type); if (b) { basicSystemInfo->m_fServerPlatform = (type != NtProductWinNt); return 1; } else { DbgPrintEx(DPFLTR_RPCPROXY_ID, DPFLTR_ERROR_LEVEL, "RpcGetNtProductType failed, usign default\n"); return 0; } } RPC_STATUS PerformRpcInitialization ( void ) /*++ Routine Description: This routine will get called the first time that an RPC runtime API is called. There is actually a race condition, which we prevent by grabbing a mutex and then performing the initialization. We only want to initialize once. Return Value: RPC_S_OK - This status code indicates that the runtime has been correctly initialized and is ready to go. RPC_S_OUT_OF_MEMORY - If initialization failed, it is most likely due to insufficient memory being available. --*/ { if ( RpcHasBeenInitialized == 0 ) { RequestGlobalMutex(); if ( RpcHasBeenInitialized == 0 ) { RPC_STATUS Status; BasicSystemInfo SystemInfo; BOOL b; b = GetBasicSystemInfo(&SystemInfo); if (!b) { ClearGlobalMutex(); return RPC_S_OUT_OF_MEMORY; } gNumberOfProcessors = SystemInfo.m_dwNumberOfProcessors; gPageSize = SystemInfo.m_dwPageSize; gAllocationGranularity = SystemInfo.AllocationGranularity; gfServerPlatform = SystemInfo.m_fServerPlatform; gPhysicalMemorySize = SystemInfo.m_dwPhysicalMemorySize; // Should be something like 64kb / 4kb. ASSERT(gAllocationGranularity % gPageSize == 0); if (( InitializeRpcAllocator() != 0) || ( InitializeServerDLL() != 0 )) { ClearGlobalMutex(); return(RPC_S_OUT_OF_MEMORY); } Status = InitializeEPMapperClient(); if (Status != RPC_S_OK) { ClearGlobalMutex(); return Status; } Status = ReadPolicySettings(); if (Status != RPC_S_OK) { ClearGlobalMutex(); return Status; } if (gfServerPlatform) { gThreadTimeout = 90*1000; } else { gThreadTimeout = 30*1000; } Status = InitializeCellHeap(); if (Status != RPC_S_OK) { ClearGlobalMutex(); return Status; } RpcHasBeenInitialized = 1; ClearGlobalMutex(); if (LoadLibrary(RPC_CONST_SSTRING("rpcrt4.dll")) == 0) { return RPC_S_OUT_OF_MEMORY; } } else { ClearGlobalMutex(); } } return(RPC_S_OK); } #ifdef DBG long lGlobalMutexCount = 0; #endif void GlobalMutexRequestExternal ( void ) /*++ Routine Description: Request the global mutex. --*/ { GlobalMutexRequest(); } void GlobalMutexClearExternal ( void ) /*++ Routine Description: Clear the global mutex. --*/ { GlobalMutexClear(); }