// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. #include "applicationmanager.h" #include "proxymodule.h" #include "resources.h" #include "SRWExclusiveLock.h" #include "exceptions.h" #include "EventLog.h" extern BOOL g_fInShutdown; // The application manager is a singleton across ANCM. APPLICATION_MANAGER* APPLICATION_MANAGER::sm_pApplicationManager = NULL; // // Retrieves the application info from the application manager // Will create the application info if it isn't initalized // HRESULT APPLICATION_MANAGER::GetOrCreateApplicationInfo( _In_ IHttpContext& pHttpContext, _Out_ std::shared_ptr& ppApplicationInfo ) { auto &pApplication = *pHttpContext.GetApplication(); // The configuration path is unique for each application and is used for the // key in the applicationInfoHash. std::wstring pszApplicationId = pApplication.GetApplicationId(); { // When accessing the m_pApplicationInfoHash, we need to acquire the application manager // lock to avoid races on setting state. SRWSharedLock readLock(m_srwLock); if (g_fInShutdown) { return HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS); } const auto pair = m_pApplicationInfoHash.find(pszApplicationId); if (pair != m_pApplicationInfoHash.end()) { ppApplicationInfo = pair->second; return S_OK; } // It's important to release read lock here so exclusive lock // can be reacquired later as SRW lock doesn't allow upgrades } // Take exclusive lock before creating the application SRWExclusiveLock writeLock(m_srwLock); if (!m_fDebugInitialize) { DebugInitializeFromConfig(m_pHttpServer, pApplication); m_fDebugInitialize = TRUE; } // Check if other thread created the application const auto pair = m_pApplicationInfoHash.find(pszApplicationId); if (pair != m_pApplicationInfoHash.end()) { ppApplicationInfo = pair->second; return S_OK; } ppApplicationInfo = std::make_shared(m_pHttpServer, pApplication, m_handlerResolver); m_pApplicationInfoHash.emplace(pszApplicationId, ppApplicationInfo); return S_OK; } // // Finds any applications affected by a configuration change and calls Recycle on them // InProcess: Triggers g_httpServer->RecycleProcess() and keep the application inside of the manager. // This will cause a shutdown event to occur through the global stop listening event. // OutOfProcess: Removes all applications in the application manager and calls Recycle, which will call Shutdown, // on each application. // HRESULT APPLICATION_MANAGER::RecycleApplicationFromManager( _In_ LPCWSTR pszApplicationId ) { try { std::vector> applicationsToRecycle; if (g_fInShutdown) { // We are already shutting down, ignore this event as a global configuration change event // can occur after global stop listening for some reason. return S_OK; } { SRWExclusiveLock lock(m_srwLock); if (g_fInShutdown) { return S_OK; } const std::wstring configurationPath = pszApplicationId; auto itr = m_pApplicationInfoHash.begin(); while (itr != m_pApplicationInfoHash.end()) { if (itr->second->ConfigurationPathApplies(configurationPath)) { applicationsToRecycle.emplace_back(itr->second); itr = m_pApplicationInfoHash.erase(itr); } else { ++itr; } } // All applications were unloaded reset handler resolver validation logic if (m_pApplicationInfoHash.empty()) { m_handlerResolver.ResetHostingModel(); } } // If we receive a request at this point. // OutOfProcess: we will create a new application with new configuration // InProcess: the request would have to be rejected, as we are about to call g_HttpServer->RecycleProcess // on the worker proocess if (!applicationsToRecycle.empty()) { for (auto& application : applicationsToRecycle) { try { application->ShutDownApplication(/* fServerInitiated */ false); } catch (...) { LOG_ERRORF("Failed to stop application %S", application->QueryApplicationInfoKey().c_str()); OBSERVE_CAUGHT_EXCEPTION(); // Failed to recycle an application. Log an event EventLog::Error( ASPNETCORE_EVENT_RECYCLE_APP_FAILURE, ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG, pszApplicationId); // Need to recycle the process as we cannot recycle the application if (!g_fRecycleProcessCalled) { g_fRecycleProcessCalled = TRUE; m_pHttpServer.RecycleProcess(L"AspNetCore Recycle Process on Demand Due Application Recycle Error"); } } } } } CATCH_RETURN(); return S_OK; } // // Shutsdown all applications in the application hashtable // Only called by OnGlobalStopListening. // VOID APPLICATION_MANAGER::ShutDown() { // We are guaranteed to only have one outstanding OnGlobalStopListening event at a time // However, it is possible to receive multiple OnGlobalStopListening events // Protect against this by checking if we already shut down. g_fInShutdown = TRUE; // During shutdown we lock until we delete the application SRWExclusiveLock lock(m_srwLock); for (auto &pair : m_pApplicationInfoHash) { pair.second->ShutDownApplication(/* fServerInitiated */ true); pair.second = nullptr; } }