📄 locplugin.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
// Abstract: Implements routines required to process plugin DLLs
#include <locCore.hpp>
//
// Callbacks that plugins call
//
// Process NewProviderReport callback
static DWORD NewProviderReportInd(HANDLE provContext, LOCATION_REPORT *pNewReport) {
return g_pPluginMgr->NewProviderReportInd(provContext,pNewReport);
}
// Process ProviderUnavailable callback
static DWORD ProviderUnavailableInd(HANDLE provContext) {
return g_pPluginMgr->ProviderUnavailableInd(provContext);
}
// Process NewResolverReport callback
static DWORD NewResolverReportInd(HANDLE resContext, LOCATION_REPORT *pNewReport) {
return g_pPluginMgr->NewResolverReportInd(resContext, pNewReport);
}
//
// Helper functions
//
// Helper that reads a REG_MULTI_SZ of GUIDs, parses, and stores in pReportTypes.
static BOOL ReadGuidsFromReg(CReg *pRegPlugin, const WCHAR *pPluginName, const WCHAR *pRegValueName,
GUID *pGuids, DWORD *pNumGuids, DWORD maxToRead)
{
const WCHAR *pRegString = pRegPlugin->ValueSZ(pRegValueName);
DEBUGCHK(*pNumGuids == 0);
if (NULL == pRegString) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have value <%s> set\r\n",pPluginName,pRegValueName));
return FALSE;
}
const WCHAR *pTrav = pRegString;
while (*pTrav) {
if (*pNumGuids >= maxToRead) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has > <%d> guids for <%s>\r\n",pPluginName,maxToRead,pRegValueName));
return FALSE;
}
if (! svsutil_ReadGuidW(pTrav,&pGuids[*pNumGuids],TRUE)) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has misformatted GUID report type number: <%d>\r\n",pPluginName,*pNumGuids));
return FALSE;
}
*pNumGuids = (*pNumGuids) + 1;
// For REG_SZ case, we're done after reading our first GUID
if (maxToRead == 1)
return TRUE;
// REG_MULTI_SZ case, move on to next string.
pTrav += wcslen(pTrav) + 1;
}
return ((*pNumGuids) > 0);
}
//
// Threads spun up to process GetLocation & Stop calls into the plugins.
//
// Thread spun when a provider is requested to generate reports
static DWORD GetProviderLocationThread(LPVOID lpv) {
provider_t *pProv = (provider_t*)lpv;
pProv->GetProviderLocation();
return 0;
}
// Thread spun when a resolver is requested to resolve reports
static DWORD GetResolverLocationThread(LPVOID lpv) {
resolver_t *pRes = (resolver_t*)((plugin_t*)lpv);
pRes->GetResolverLocation();
return 0;
}
//
// plugin_t implementation - basic plugin object. The provider
// and resolver inherit from this implementation
//
// Create base plugin, reading as much as possible.
plugin_t::plugin_t(CReg *pRegPlugin, const WCHAR *keyName) {
DEBUGCHK(pRegPlugin->IsOK());
DWORD regValueType;
DWORD regValueLen;
m_numActiveIoctlCallers = 0;
m_workerThrdCookie = 0;
m_loadSuccess = FALSE;
m_pluginState = PLUGIN_STATE_ERROR;
m_immediateRestart = FALSE;
memset(m_receivedReport,0,sizeof(m_receivedReport));
m_dllName = pRegPlugin->ValueSZ(g_rvDll);
if (m_dllName.empty()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have DLL set\r\n",keyName));
return;
}
DWORD numGuids = 0; // dummy variable...
if (! ReadGuidsFromReg(pRegPlugin,keyName,g_rvGuid,&m_guid,&numGuids,1))
return;
if (! pRegPlugin->GetLengthAndType(g_rvPreference,®ValueLen,®ValueType)) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have Preference set\r\n",keyName));
return;
}
m_preference = pRegPlugin->ValueDW(g_rvPreference);
m_pluginFlags = pRegPlugin->ValueDW(g_rvPluginFlags);
if (PLUGIN_FLAGS_DISABLED & m_pluginFlags) {
DEBUGMSG(ZONE_PLUGIN,(L"LOC: ERROR: Plugin <%s> has been disabled via PLUGIN_FLAGS_DISABLED setting\r\n",keyName));
return;
}
if (! pRegPlugin->GetLengthAndType(g_rvRetryOnFailure,®ValueLen,®ValueType)) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have RetryOnFailure set.\r\n",keyName));
return;
}
m_retryOnFailure = pRegPlugin->ValueDW(g_rvRetryOnFailure);
if (! pRegPlugin->GetLengthAndType(g_rvMaximumInitialWait,®ValueLen,®ValueType)) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have MaximumInitialWait set.\r\n",keyName));
return;
}
m_initialWaitTime = pRegPlugin->ValueDW(g_rvMaximumInitialWait);
m_numGeneratedReportTypes = 0;
if (! ReadGuidsFromReg(pRegPlugin,keyName,g_rvGeneratedReports,m_generatedReportTypes,
&m_numGeneratedReportTypes,MAX_PLUGIN_REPORT_TYPES)) {
return;
}
m_friendlyName = pRegPlugin->ValueSZ(g_rvFriendlyName);
if (m_friendlyName.size() >= MAX_PLUGIN_FRIENDLY_NAME) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has friendly name > <%d> characters\r\n",keyName,MAX_PLUGIN_FRIENDLY_NAME));
// This is not a fatal error. However we do need to clear this, since
// later we assume the length is < MAX_PLUGIN_FRIENDLY_NAME chars.
m_friendlyName = NULL;
}
m_version = pRegPlugin->ValueDW(g_rvVersion,1);
m_pluginState = PLUGIN_STATE_OFF; // Indicate no errors so far.
memset(&m_lastUpdate,0,sizeof(m_lastUpdate));
}
// Helper to load the plugin DLL itself
BOOL plugin_t::LoadPlugin(void) {
DEBUGMSG(ZONE_PLUGIN,(L"LOC: Loading plugin for DLL <%s>\r\n",GetName()));
m_dllHInstance = LoadLibrary(m_dllName);
if (!m_dllHInstance.valid()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: LoadLibrary on plugin DLL <%s> failed. GLE=0x%08x\r\n",GetName(),GetLastError()));
return FALSE;
}
return TRUE;
}
// Returns index int m_generatedReportTypes of given report, -1 if not supported
DWORD plugin_t::FindGeneratedReportIndex(const GUID *pReportType) {
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
if (0 == memcmp(&m_generatedReportTypes[i],pReportType,sizeof(GUID)))
return i;
}
return (DWORD)-1;
}
// Returns TRUE if the plugin can generate (in theory, even if it plugin
// is not available at the moment) a report.
BOOL plugin_t::CanGenerateReportType(const GUID *pReportType) {
return (FindGeneratedReportIndex(pReportType) != (DWORD)-1);
}
// When a plugin has a new report arrived, mark its type as such as such.
void plugin_t::IndicateReceivedReport(const GUID *pReportType) {
DWORD index = FindGeneratedReportIndex(pReportType);
DEBUGCHK(index < MAX_PLUGIN_REPORT_TYPES);
m_receivedReport[index] = TRUE;
GetCurrentFT(&m_lastUpdate);
}
// Determines whether a plugin has received a callback indicating
// report of this type.
BOOL plugin_t::HasReceivedReport(const GUID *pReportType) {
DWORD index = FindGeneratedReportIndex(pReportType);
DEBUGCHK(index < MAX_PLUGIN_REPORT_TYPES);
return m_receivedReport[index];
}
// Fills out PLUGIN_INFORMATION structure for this plugin
void plugin_t::GetPluginInfo(PLUGIN_INFORMATION *pPluginInfo) {
pPluginInfo->version = m_version;
memcpy(&pPluginInfo->guid,&m_guid,sizeof(m_guid));
wcscpy(pPluginInfo->friendlyName,m_friendlyName);
pPluginInfo->pluginState = m_pluginState;
pPluginInfo->retryInterval = m_retryOnFailure;
pPluginInfo->maximumInitialWait = m_initialWaitTime;
memcpy(&pPluginInfo->lastUpdate,&m_lastUpdate,sizeof(FILETIME));
pPluginInfo->numReportsGenerated = m_numGeneratedReportTypes;
memcpy(&pPluginInfo->reportsGenerated,m_generatedReportTypes,
sizeof(GUID)*m_numGeneratedReportTypes);
pPluginInfo->pluginFlags = m_pluginFlags;
}
// Returns which reportTypes the plugin can possibly generate
void plugin_t::GetGeneratedReportInfo(GUID *pReportTypes, DWORD *numReportTypes) {
if ((m_numGeneratedReportTypes == 0) || (m_numGeneratedReportTypes > MAX_PLUGIN_REPORT_TYPES)) {
// pReportTypes is guaranteed to be MAX_PLUGIN_REPORT_TYPES*sizeof(GUID)
// We do run-time check, rather only having DEBUGCHK, to satisfy prefix.
DEBUGCHK(0);
*numReportTypes = 0;
return;
}
*numReportTypes = m_numGeneratedReportTypes;
memcpy(pReportTypes,m_generatedReportTypes,m_numGeneratedReportTypes*sizeof(GUID));
}
// Alerts the plugin manager that a fatal error has occured during
// a callback. The plugin manager processes this and in turn calls
// SetFatalError back on the callback
void plugin_t::ReportFatalError() {
// For locking, most of the time this function is called in the exception
// handler for one of the callbacks where lock will not be held. There
// are some cases where g_pLocLock already is held by caller, but extra
// lock is OK because FatalPluginError never releases the lock.
g_pLocLock->Lock();
g_pPluginMgr->FatalPluginError(this);
g_pLocLock->Unlock();
}
// Called when a plugin is in the process of shutting down when a new
// application has registered for it and hence it needs to restart right away.
void plugin_t::SetImmediateRestart(void) {
m_immediateRestart = TRUE;
}
// Blocks until any PSL calls into the plugin IOCTL processor have returned.
void plugin_t::WaitOnOpenIoctlCalls(void) {
DEBUGCHK(g_pLocLock->IsLocked());
#ifdef DEBUG
// Number of times we've polled while waiting to shutdown.
DWORD numRetries = 0;
#endif
while (m_numActiveIoctlCallers) {
#ifdef DEBUG
numRetries++;
// Taking this many retries indicates plugin IOCTL worker(s) blocked too long.
// This is not fatal but merits investigation.
DEBUGCHK(g_pollRetriesWarnOnUnload != numRetries);
#endif
DEBUGMSG(ZONE_PLUGIN | ZONE_THREAD,(L"LOC: Waiting <%d> ms for plugin <%s> IOCTL calls to complete\r\n",
g_pollOnUnload,GetName()));
g_pLocLock->Unlock();
Sleep(g_pollOnUnload);
g_pLocLock->Lock();
}
}
// Block until the plugin's ProviderGetLocation/ResolverGetLocation
// thread comes to a halt
void plugin_t::WaitOnRunningGetLocThread(void) {
DEBUGCHK(g_pLocLock->IsLocked());
#ifdef DEBUG
// Number of times we've polled while waiting to shutdown.
DWORD numRetries = 0;
#endif
while (m_workerThrdCookie) {
#ifdef DEBUG
numRetries++;
// Taking this many retries indicate plugin stop thread is blocked for too long.
// This is not fatal but merits investigation.
DEBUGCHK(g_pollRetriesWarnOnUnload != numRetries);
#endif
DEBUGMSG(ZONE_PLUGIN | ZONE_THREAD,(L"LOC: Waiting <%d> ms for plugin <%s> GetLocationReport thread to complete\r\n",
g_pollOnUnload,GetName()));
g_pLocLock->Unlock();
Sleep(g_pollOnUnload);
g_pLocLock->Lock();
}
}
#ifdef DEBUG
// Print GUIDs in a list to DEBUGOUT
void DbgPrintGuids(const GUID *pGuids, DWORD numGuids) {
for (DWORD i = 0; i < numGuids; i++) {
DEBUGMSG(1,(L"LOC: GUID = <" SVSUTIL_GUID_FORMAT_W L">\r\n",
SVSUTIL_RGUID_ELEMENTS(pGuids[i])));
}
}
// Prints PLUGIN_INFORMATION to DEBUGOUT
void plugin_t::DbgPrintSettings(void) {
DEBUGMSG(1,(L"LOC: DllName = <%s>, GUID=<" SVSUTIL_GUID_FORMAT_W L">\r\n",
GetName(), SVSUTIL_RGUID_ELEMENTS(m_guid)));
DEBUGMSG(1,(L"LOC: Preference = <%d>, PluginFlags = <0x%08x>, Retry On Failure = <%d>\r\n",
m_preference,m_pluginFlags,m_retryOnFailure));
DEBUGMSG(1,(L"LOC: Generated GUIDs: \r\n"));
DbgPrintGuids(m_generatedReportTypes,m_numGeneratedReportTypes);
}
#endif
// Delete resources associated with plugin. If plugin is on,
// then take care of alerting it to the new state.
// This BLOCKS until the plugin is ready to be unloaded - i.e. all
// open threads are finished running.
provider_t::~provider_t() {
if (! m_loadSuccess) {
DEBUGCHK(g_serviceState == SERVICE_STATE_STARTING_UP);
// If loading the plugin failed, then we shouldn't call into
// Stop/Uninitialize at all.
return;
}
DEBUGMSG(ZONE_INIT | ZONE_PROVIDER,(L"LOC: Beginning to uninit Provider DLL <%s>\r\n",GetName()));
if (m_pluginState >= PLUGIN_STATE_UNAVAILABLE) {
// The plugin's stop still needs to be called. Do here, rather
// than spawning up a thread.
SetState(PLUGIN_STATE_SHUTTING_DOWN);
CallProvStop();
}
// Wait until any outstanding references to the provider have stopped
WaitOnOpenIoctlCalls();
WaitOnRunningGetLocThread();
// Finally, call the uninit.
CallProvUnInit();
DEBUGMSG(ZONE_INIT | ZONE_PROVIDER,(L"LOC: Completed uninit Provider DLL <%s>\r\n",GetName()));
}
//
// provider_t implements provider wrapper
//
// Reads provider registry settings, loads DLLs, and call ProviderInitialize
void provider_t::InitProvider(CReg *pRegPlugin, const WCHAR *keyName) {
DEBUGMSG(ZONE_PROVIDER,(L"LOC: Initializing provider <%s>\r\n",keyName));
DEBUGCHK(m_pluginState == PLUGIN_STATE_ERROR); // Should've been reset before calling here
DWORD regValueType;
DWORD regValueLen;
// Read registry settings
if (! pRegPlugin->GetLengthAndType(g_rvPollInterval, ®ValueLen, ®ValueType)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -