windows-nt/Source/XPSP1/NT/enduser/troubleshoot/launcher/server/stateinfo.cpp

579 lines
15 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//
// MODULE: StateInfo.cpp
//
// PURPOSE: Contains sniffing, network and node information. Also is used
// by the Launch module to start the container application.
//
// Basically, this is how the Launch Server packages up info for the
// Local TShoot OCX, launches either IE or HTML Help System to a page
// containing the Local TShoot OCX, and handshakes with the Local TShoot OCX
// to pass that information
//
// Note that CSMStateInfo::GetShooterStates() is called by the
// Local TShoot OCX to pick up the CItem object which contains
// the packaged-up info.
//
// PROJECT: Local Troubleshooter Launcher for the Device Manager
//
// COMPANY: Saltmine Creative, Inc. (206)-633-4743 support@saltmine.com
//
// AUTHOR: Richard Meadows
// COMMENTS BY: Joe Mabel
//
// ORIGINAL DATE: 2-26-98
//
//
// Version Date By Comments
//--------------------------------------------------------------------
// V0.1 - RM Original
///////////////////////
#include "stdafx.h"
#include "atlbase.h"
#include "StateInfo.h"
#include "TSLError.h"
#include "ComGlobals.h"
#include "Registry.h"
#include <stdio.h>
#include <string.h>
#include <memory.h>
//#include <fstream.h>
#include <strstrea.h>
////////////////////////////////////////////////////////
// CItem :
// Data structure for pseudo HTTP "get" in launching Local Troubleshooters
//
CItem::CItem()
{
// initializing this is exactly the same as reinitializing.
ReInit();
}
void CItem::ReInit()
{
memset(m_aszCmds, NULL, SYM_LEN * NODE_COUNT);
memset(m_aszVals, NULL, SYM_LEN * NODE_COUNT);
m_cNodesSet = 0;
_tcscpy(m_szProblemDef, _T("TShootProblem"));
_tcscpy(m_szTypeDef, _T("type"));
m_szPNPDeviceID[0] = NULL;
m_szGuidClass[0] = NULL;
m_szContainerPathName[0] = NULL;
m_szWebPage[0] = NULL;
m_szSniffScriptFile[0] = NULL;
m_eLaunchRegime = launchIndefinite;
m_szMachineID[0] = NULL;
m_szDeviceInstanceID[0] = NULL;
#ifdef _DEBUG
// There are some other things you need to comment out in GetShooterStates
// to allow debugging this service from a tshoot.ocx debug sesstion.
/*
_tcscpy(m_aszCmds[0], m_szTypeDef);
_tcscpy(m_aszVals[0], _T("ras"));
_tcscpy(m_aszCmds[1], m_szProblemDef);
_tcscpy(m_aszVals[1], _T("CnntCnnctAftrDlngWthRS"));
_tcscpy(m_aszCmds[2], _T("SoftwareCompression"));
_tcscpy(m_aszVals[2], _T("0"));
m_cNodesSet = 1;
*/
#endif
return;
}
void CItem::Clear()
{
memset(m_aszCmds, NULL, SYM_LEN * NODE_COUNT);
memset(m_aszVals, NULL, SYM_LEN * NODE_COUNT);
m_cNodesSet = 0;
_tcscpy(m_szProblemDef, _T("TShootProblem"));
_tcscpy(m_szTypeDef, _T("type"));
m_szPNPDeviceID[0] = NULL;
m_szGuidClass[0] = NULL;
m_szContainerPathName[0] = NULL;
m_szWebPage[0] = NULL;
m_szSniffScriptFile[0] = NULL;
m_eLaunchRegime = launchIndefinite;
return;
}
// ----------- Routines to build command/value pairs ------------------
// see documentation of m_aszCmds, m_aszVals for further explanation
void CItem::SetNetwork(LPCTSTR szNetwork)
{
if (NULL != szNetwork && NULL != szNetwork[0])
{
_tcscpy(m_aszCmds[0], m_szTypeDef);
_tcsncpy(m_aszVals[0], szNetwork, SYM_LEN);
}
else
{
m_aszCmds[0][0] = NULL;
m_aszVals[0][0] = NULL;
}
return;
}
void CItem::SetProblem(LPCTSTR szProblem)
{
if (NULL != szProblem && NULL != szProblem[0])
{
_tcscpy(m_aszCmds[1], m_szProblemDef);
_tcsncpy(m_aszVals[1], szProblem, SYM_LEN);
}
else
{
m_aszCmds[1][0] = NULL;
m_aszVals[1][0] = NULL;
}
return;
}
void CItem::SetNode(LPCTSTR szNode, LPCTSTR szState)
{
if (NULL != szNode && NULL != szNode[0]
&& NULL != szState && NULL != szState[0])
{
_tcsncpy(m_aszCmds[m_cNodesSet + 2], szNode, SYM_LEN);
_tcsncpy(m_aszVals[m_cNodesSet + 2], szState, SYM_LEN);
m_cNodesSet++;
}
return;
}
// ----------- Routines to query command/value pairs ------------------
// See documentation of m_aszCmds, m_aszVals for further explanation
// returns true if network has been set
// On success, OUTPUT *pszCmd is "type", *pszVal is network name
bool CItem::GetNetwork(LPTSTR *pszCmd, LPTSTR *pszVal)
{
*pszCmd = m_szTypeDef;
*pszVal = m_aszVals[0];
return *m_aszVals[0] != NULL;
}
// returns true if problem node has been set
// On success, OUTPUT *pszCmd is "TShootProblem", *pszVal is problem node's symbolic name
bool CItem::GetProblem(LPTSTR *pszCmd, LPTSTR *pszVal)
{
*pszCmd = m_szProblemDef;
*pszVal = m_aszVals[1];
return *m_aszVals[1] != NULL;;
}
// output the iNodeC-th non-problem node for which a state has been set.
// On success, OUTPUT *pszCmd is symbolic node name, *pszVal is state
// returns true if at least iNodeC non-problem nodes have been set
bool CItem::GetNodeState(int iNodeC, LPTSTR *pszCmd, LPTSTR *pszVal)
{
if (iNodeC >= m_cNodesSet)
return false;
*pszCmd = m_aszCmds[iNodeC + 2];
*pszVal = m_aszVals[iNodeC + 2];
return true;
}
// ----------- Routines to query whether we know a network ------------
// ----------- & problem node to launch to ----------------------------
// See documentation of m_aszCmds, m_aszVals for further explanation
// NetworkSet returns true if we know which troubleshooter to launch.
bool CItem::NetworkSet()
{
return NULL != m_aszVals[0][0];
}
// ProblemSet returns true if we know which problem to choose.
bool CItem::ProblemSet()
{
return NULL != m_aszVals[1][0];
}
// --------- Interface to other member variables recponsible for launching -----------
void CItem::SetLaunchRegime(ELaunchRegime eLaunchRegime)
{
m_eLaunchRegime = eLaunchRegime;
}
void CItem::SetContainerPathName(TCHAR szContainerPathName[MAX_PATH])
{
if (NULL != szContainerPathName && NULL != szContainerPathName[0])
_tcscpy(m_szContainerPathName, szContainerPathName);
else
m_szContainerPathName[0] = NULL;
return;
}
void CItem::SetWebPage(TCHAR szWebPage[MAX_PATH])
{
if (NULL != szWebPage && NULL != szWebPage[0])
_tcscpy(m_szWebPage, szWebPage);
else
m_szWebPage[0] = NULL;
return;
}
void CItem::SetSniffScriptFile(TCHAR szSniffScriptFile[MAX_PATH])
{
if (NULL != szSniffScriptFile && NULL != szSniffScriptFile[0])
_tcscpy(m_szSniffScriptFile, szSniffScriptFile);
else
m_szSniffScriptFile[0] = NULL;
return;
}
void CItem::SetSniffStandardFile(TCHAR szSniffStandardFile[MAX_PATH])
{
if (NULL != szSniffStandardFile && NULL != szSniffStandardFile[0])
_tcscpy(m_szSniffStandardFile, szSniffStandardFile);
else
m_szSniffStandardFile[0] = NULL;
return;
}
ELaunchRegime CItem::GetLaunchRegime()
{
return m_eLaunchRegime;
}
inline TCHAR* CItem::GetContainerPathName()
{
return m_szContainerPathName;
}
inline TCHAR* CItem::GetWebPage()
{
return m_szWebPage;
}
inline TCHAR* CItem::GetSniffScriptFile()
{
return m_szSniffScriptFile;
}
inline TCHAR* CItem::GetSniffStandardFile()
{
return m_szSniffStandardFile;
}
////////////////////////////////////////////////////////
// CSMStateInfo :
// State information on MSBN Troubleshooters
//
CSMStateInfo::CSMStateInfo()
{
m_csGlobalMemory.Init();
m_csSingleLaunch.Init();
return;
}
CSMStateInfo::~CSMStateInfo()
{
m_csGlobalMemory.Term();
m_csSingleLaunch.Term();
return;
}
// TestPut: Simply copies item to m_Item.
void CSMStateInfo::TestPut(CItem &item)
{
m_csGlobalMemory.Lock();
m_Item = item;
m_csGlobalMemory.Unlock();
return;
}
// TestGet: Simply copies m_Item to item.
void CSMStateInfo::TestGet(CItem &item)
{
m_csGlobalMemory.Lock();
item = m_Item;
m_csGlobalMemory.Unlock();
return;
}
// Copy the item to the global memory and launch a process based on the command.
// Copying the item to global memory is here because the item is what tells the
// launched local troubleshooter what belief network etc. it is being launched to.
// Once we unlock global memory, the Local Troubleshooter OCX can read that item
// and act on it.
BOOL CSMStateInfo::CreateContainer(CItem &item, LPTSTR szCommand)
{
BOOL bOk = TRUE;
HRESULT hRes = S_OK;
STARTUPINFO startup;
PROCESS_INFORMATION process;
memset(&startup, NULL, sizeof(STARTUPINFO));
startup.cb = sizeof(STARTUPINFO);
startup.wShowWindow = SW_SHOWNORMAL;
m_csGlobalMemory.Lock();
m_Item = item;
bOk = CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, NULL, NULL,
&startup, &process);
CloseHandle(process.hThread);
CloseHandle(process.hProcess);
m_csGlobalMemory.Unlock();
return bOk;
}
//
// Copy network_sniff.htm to tssniffAsk.htm if the former exists
// Create (modify) tssniffAsk.htm to be a sniffing stub otherwise
//
BOOL CSMStateInfo::CopySniffScriptFile(CItem &item)
{
TCHAR* szSniffScriptFile = item.GetSniffScriptFile();
TCHAR* szSniffStandardFile = item.GetSniffStandardFile();
if (!*szSniffScriptFile) // no network specific sniff file
{
// szSniffScriptFile contains tssniffAsk.htm
// it means that we have to form this file as an empty stub
ostrstream fileSniffScript;
HANDLE hFile = ::CreateFile(szSniffStandardFile,
GENERIC_WRITE,
0,
NULL, // no security attributes
CREATE_ALWAYS,
FILE_FLAG_RANDOM_ACCESS,
NULL // handle to template file
);
if (hFile != INVALID_HANDLE_VALUE)
{
// form html file - part preceding script
fileSniffScript << "<HTML>" << endl;
fileSniffScript << "<HEAD>" << endl;
fileSniffScript << "<TITLE>GTS LOCAL</TITLE>" << endl;
fileSniffScript << "</HEAD>" << endl;
fileSniffScript << "<SCRIPT LANGUAGE=\"VBSCRIPT\">" << endl;
fileSniffScript << "<!--" << endl;
// form global function
fileSniffScript << "function PerformSniffing()" << endl;
fileSniffScript << "end function" << endl;
// form html file - part after script
fileSniffScript << "-->" << endl;
fileSniffScript << "</SCRIPT>" << endl;
fileSniffScript << "<BODY BGCOLOR=\"#FFFFFF\">" << endl;
fileSniffScript << "</BODY>" << endl;
fileSniffScript << "</HTML>" << endl;
fileSniffScript << ends;
char* str = fileSniffScript.str();
DWORD read;
if (!::WriteFile(hFile, str, strlen(str), &read, NULL))
{
::CloseHandle(hFile);
fileSniffScript.rdbuf()->freeze(0);
return false;
}
::CloseHandle(hFile);
fileSniffScript.rdbuf()->freeze(0);
return true;
}
else
{
return false;
}
}
else
{
return ::CopyFile(szSniffScriptFile, szSniffStandardFile, false);
}
}
// Find the container (HTML Help System or IE) and starting web page, launch, wait to
// see if launch succeeded
bool CSMStateInfo::GoGo(DWORD dwTimeOut, CItem &item, DWORD *pdwResult)
{
bool bResult = true;
HANDLE hLaunchedEvent = NULL;
TCHAR szProcess[MAX_PATH];
TCHAR szWebPage[MAX_PATH];
LPTSTR pszCommand = NULL;
int CommandLen;
DWORD dwError;
int Count = 34;
if (item.GetLaunchRegime() == launchIndefinite ||
!item.GetContainerPathName()[0] ||
!item.GetWebPage()[0]
)
{
*pdwResult = TSL_ERROR_ASSERTION;
return false;
}
do
{
_stprintf(item.m_szEventName, _T("TSL_SHOOTER_Event_%ld"), Count);
if (NULL == (hLaunchedEvent = CreateEvent (NULL, FALSE, FALSE, item.m_szEventName)))
{
dwError = GetLastError();
if (ERROR_ALREADY_EXISTS != dwError)
{
*pdwResult = dwError;
return false;
}
}
} while (NULL == hLaunchedEvent);
// Get the path to internet explorer (or HTML Help System).
_tcscpy(szProcess, item.GetContainerPathName());
// Need to know the location and name of the
// page that asks the service for the CItem
// information.
_tcscpy(szWebPage, item.GetWebPage());
CommandLen = _tcslen(szProcess) + 1 + _tcslen(szWebPage) + 2;
pszCommand = new TCHAR[CommandLen];
if (NULL == pszCommand)
{
*pdwResult = TSL_ERROR_OUT_OF_MEMORY;
return false;
}
_tcscpy(pszCommand, szProcess);
_tcscat(pszCommand, _T(" "));
_tcscat(pszCommand, szWebPage);
m_csSingleLaunch.Lock();
// copy to or create tssniffAsk.htm
if (!CopySniffScriptFile(item))
{
*pdwResult = TSL_E_COPY_SNIFF_SCRIPT;
return false;
}
// CreateContainer copies the item to the global memory and
// launches the command.
if (!CreateContainer(item, pszCommand))
{
*pdwResult = TSL_E_CREATE_PROC;
bResult = false;
}
else
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hLaunchedEvent, dwTimeOut))
{ // The container has the information.
*pdwResult = TSL_OK;
}
else
{ // Wait timed out. Don't know if the operation will work or not work.
*pdwResult = TSL_W_CONTAINER_WAIT_TIMED_OUT;
}
}
m_csSingleLaunch.Unlock();
delete [] pszCommand;
CloseHandle(hLaunchedEvent);
return bResult;
}
// Find the container (HTML Help System or IE) and start it up to a URL which is _not_
// expected to contain Local Troubleshooter, just an arbitrary web page. This should
// only be used when the launch as such can't work, and we are just trying to give them
// somewhere to start troubleshooting, typically the home page which lists all
// trobleshooting belief networks.
bool CSMStateInfo::GoURL(CItem &item, DWORD *pdwResult)
{
bool bResult = true;
TCHAR szProcess[MAX_PATH];
TCHAR szWebPage[MAX_PATH];
LPTSTR pszCommand = NULL;
int CommandLen;
if (item.GetLaunchRegime() != launchDefaultWebPage ||
!item.GetContainerPathName()[0] ||
!item.GetWebPage()[0]
)
{
*pdwResult = TSL_ERROR_ASSERTION;
return false;
}
// Get the path to internet explorer (or HTML Help System).
_tcscpy(szProcess, item.GetContainerPathName());
// Need to know the location and name of the
// page that asks the service for the CItem
// information.
_tcscpy(szWebPage, item.GetWebPage());
CommandLen = _tcslen(szProcess) + 1 + _tcslen(szWebPage) + 2;
pszCommand = new TCHAR[CommandLen];
if (NULL == pszCommand)
{
*pdwResult = TSL_ERROR_OUT_OF_MEMORY;
return false;
}
_tcscpy(pszCommand, szProcess);
_tcscat(pszCommand, _T(" "));
_tcscat(pszCommand, szWebPage);
// CreateContainer is overkill here, but perfectly OK.
if (!CreateContainer(item, pszCommand))
{
*pdwResult = TSL_E_CREATE_PROC;
bResult = false;
}
delete [] pszCommand;
return bResult;
}
// This function is used by the Local Troubleshooter OCX, not by the Launcher.
// This is how the Local Troubleshooter knows what troubleshooting network to launch
// to, as well as any nodes whose states are set.
// GetShooterStates returns the commands and the number of commands for
// the Tshoot.ocx.
// refLaunchState is a member of this instance of the LaunchTS interface.
//
HRESULT CSMStateInfo::GetShooterStates(CItem &refLaunchState, DWORD *pdwResult)
{
HANDLE hHaveItemEvent;
// Get a copy of the launch info state stored in this instance.
// Synchronize with the process that launched the service.
m_csGlobalMemory.Lock();
if (NULL == (hHaveItemEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, m_Item.m_szEventName)))
{
*pdwResult = GetLastError();
m_csGlobalMemory.Unlock();
return TSL_E_FAIL;
}
// Get a copy of the state before unlocking the global memory.
refLaunchState = m_Item;
// Let the other process continue running.
SetEvent(hHaveItemEvent);
m_csGlobalMemory.Unlock();
CloseHandle(hHaveItemEvent);
*pdwResult = 0;
return S_OK;
}