You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1459 lines
44 KiB
1459 lines
44 KiB
///////////////////////////////////////////////////////////////////////////
|
|
// File: WinHttpStressScheduler.cpp
|
|
//
|
|
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Purpose:
|
|
// ServerCommands.cpp: implementation of the ServerCommands class.
|
|
// This class is used to retrieve and act on command from the server.
|
|
//
|
|
// History:
|
|
// 02/08/01 DennisCh Created
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// WIN32 headers
|
|
//
|
|
|
|
//
|
|
// Project headers
|
|
//
|
|
#include "ServerCommands.h"
|
|
#include "NetworkTools.h"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Globals and statics
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
HANDLE g_hQueryServerForCommands; // Handle for the thread that queries the server for commands
|
|
CRITICAL_SECTION g_csServerCommandsVars; // For protecting CommandServer private member vars. Used in the QueryServerForCommands_ThreadProc.
|
|
|
|
extern ServerCommands g_objServerCommands; // Declared in WinHttpStressScheduler.cpp
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: QueryServerForCommands_ThreadProc(LPVOID)
|
|
//
|
|
// Purpose:
|
|
// This method sends a request to the command server for instructions
|
|
// and saves them in the public vars of ServerCommands.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
DWORD
|
|
WINAPI
|
|
QueryServerForCommands_ThreadProc(
|
|
LPVOID lpParam // [IN] thread proc param
|
|
)
|
|
{
|
|
BOOL bResult = TRUE;
|
|
HINTERNET hRoot = NULL;
|
|
HINTERNET hSession = NULL;
|
|
HINTERNET hRequest = NULL;
|
|
URL_COMPONENTSW urlComponents;
|
|
|
|
// Allocate space for URL components
|
|
ZeroMemory(&urlComponents, sizeof(urlComponents));
|
|
|
|
urlComponents.dwSchemeLength = MAX_PATH;
|
|
urlComponents.lpszScheme = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.dwHostNameLength = MAX_PATH;
|
|
urlComponents.lpszHostName = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.dwUrlPathLength = MAX_PATH;
|
|
urlComponents.lpszUrlPath = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.dwExtraInfoLength = MAX_PATH;
|
|
urlComponents.lpszExtraInfo = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.dwUserNameLength = MAX_PATH;
|
|
urlComponents.lpszUserName = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.dwPasswordLength = MAX_PATH;
|
|
urlComponents.lpszPassword = new TCHAR[MAX_PATH];
|
|
|
|
urlComponents.nPort = 0;
|
|
|
|
urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
|
|
|
|
|
|
// crack the Command Server URL to be used later
|
|
if (!WinHttpCrackUrl(
|
|
g_objServerCommands.Get_CommandServerURL(),
|
|
_tcslen(g_objServerCommands.Get_CommandServerURL()),
|
|
ICU_ESCAPE,
|
|
&urlComponents)
|
|
)
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
hRoot = WinHttpOpen(
|
|
STRESS_SCHEDULER_USER_AGENT,
|
|
WINHTTP_ACCESS_TYPE_NO_PROXY,
|
|
NULL,
|
|
NULL,
|
|
0);
|
|
|
|
if (!hRoot)
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
hSession = WinHttpConnect(
|
|
hRoot,
|
|
urlComponents.lpszHostName,
|
|
// If the URL in urlComponents uses standard HTTP or HTTPS ports then use INTERNET_DEFAULT_PORT. Otherwise use the non-standard port gleaned from the URL.
|
|
((urlComponents.nPort == 80) || (urlComponents.nPort == 443)) ? INTERNET_DEFAULT_PORT : urlComponents.nPort,
|
|
0);
|
|
|
|
if (!hSession)
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// Build a full URL with path and querystring
|
|
TCHAR szFullPath[MAX_PATH*2];
|
|
|
|
ZeroMemory(szFullPath, sizeof(szFullPath));
|
|
_tcsncpy(szFullPath, urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
|
|
//szFullPath[urlComponents.dwUrlPathLength] = _T('\0');
|
|
_tcsncat(szFullPath, urlComponents.lpszExtraInfo, urlComponents.dwExtraInfoLength);
|
|
|
|
hRequest = WinHttpOpenRequest(
|
|
hSession,
|
|
_T("POST"),
|
|
szFullPath,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
// if the URL in urlComponents uses HTTPS then pass in WINHTTP_FLAG_SECURE to this param. Otherwise, 0.
|
|
(0 == _tcsnicmp(urlComponents.lpszScheme, _T("https"), 5)) ? WINHTTP_FLAG_SECURE : 0);
|
|
|
|
if (!hRequest)
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// Set reasonable timeouts just in case
|
|
if (!WinHttpSetTimeouts(hRequest, 5000, 5000, 5000, 5000))
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the computer name and send it in a POST request
|
|
LPSTR szPost, szMachineName;
|
|
|
|
szPost = new CHAR[MAX_PATH];
|
|
szMachineName = new CHAR[MAX_PATH];
|
|
|
|
|
|
GetEnvironmentVariableA("COMPUTERNAME", szMachineName, MAX_PATH);
|
|
strcpy(szPost, FIELDNAME__USERINFO_MACHINENAME);
|
|
strcat(szPost, szMachineName);
|
|
|
|
bResult = WinHttpSendRequest(
|
|
hRequest,
|
|
_T("Content-Type: application/x-www-form-urlencoded"),
|
|
-1L,
|
|
szPost,
|
|
strlen(szPost),
|
|
strlen(szPost),
|
|
0);
|
|
|
|
|
|
delete [] szPost;
|
|
delete [] szMachineName;
|
|
szPost = NULL;
|
|
szMachineName = NULL;
|
|
|
|
if (!WinHttpReceiveResponse(hRequest, NULL))
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
|
|
TCHAR szBuffer[MAX_URL];
|
|
DWORD dwBufferSize, dwIndex;
|
|
|
|
|
|
// get all command headers that we're interested in.
|
|
// make sure there are no pending operations on member vars (pServerCommands->Set_* functions)
|
|
EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__EXIT: Exit if header is present, else continue.
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__EXIT, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_ExitStress(TRUE);
|
|
else
|
|
g_objServerCommands.Set_ExitStress(FALSE);
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__WINHTTP_DLL_URL: valid values: Valid URL
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__WINHTTP_DLL_URL, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_WinHttpDllURL(szBuffer, dwBufferSize);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__WINHTTP_PDB_URL: valid values: Valid URL
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__WINHTTP_PDB_URL, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_WinHttpPDBURL(szBuffer, dwBufferSize);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__WINHTTP_SYM_URL: valid values: Valid URL
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__WINHTTP_SYM_URL, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_WinHttpSYMURL(szBuffer, dwBufferSize);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__COMMANDSERVER_URL: valid values: Valid URL
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__COMMANDSERVER_URL, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_CommandServerURL(szBuffer, dwBufferSize);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__BEGIN_TIME_HOUR: valid values: Valid string from 0-23
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__BEGIN_TIME_HOUR, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_TimeStressBegins(szBuffer, NULL);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__BEGIN_TIME_MINUTE: valid values: Valid string from 0-59
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__BEGIN_TIME_MINUTE, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_TimeStressBegins(NULL, szBuffer);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__END_TIME_HOUR: valid values: Valid string from 0-23
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__END_TIME_HOUR, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_TimeStressEnds(szBuffer, NULL);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__END_TIME_MINUTE: valid values: Valid string from 0-59
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__END_TIME_MINUTE, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_TimeStressEnds(NULL, szBuffer);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__RUN_FOREVER: valid values: doesn't matter. As long as header is present it gets sent
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__RUN_FOREVER, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_RunForever(TRUE);
|
|
else
|
|
g_objServerCommands.Set_RunForever(FALSE);
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__UPDATE_INTERVAL: valid values: Valid string in INTERNET_RFC1123 format
|
|
DWORD dwTimeOut;
|
|
dwTimeOut = 0;
|
|
dwIndex = 0;
|
|
dwBufferSize = sizeof(DWORD);
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER, COMMANDHEADER__UPDATE_INTERVAL, &dwTimeOut, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.Set_CommandServerUpdateInterval(dwTimeOut);
|
|
else
|
|
bResult = FALSE;
|
|
|
|
|
|
|
|
// *********************************
|
|
// *********************************
|
|
// **** Query commands for building stress Instance objects
|
|
// ****
|
|
// **** COMMANDHEADER__STRESS_EXE_URL: valid values: Valid URL
|
|
DWORD dwStressExeID;
|
|
DWORD dwPageHeapCommandIndex,
|
|
dwUMDHCommandIndex,
|
|
dwStressPDBIndex,
|
|
dwStressSYMIndex,
|
|
dwStressMemDmpPathIndex,
|
|
dwStressExeIDIndex;
|
|
LPTSTR szPageheapCommand,
|
|
szUMDHCommand,
|
|
szStressPDB_URL,
|
|
szStressSYM_URL,
|
|
szStressMemDmpPath,
|
|
szStressExeID;
|
|
|
|
szPageheapCommand = new TCHAR[MAX_PATH];
|
|
szUMDHCommand = new TCHAR[MAX_PATH];
|
|
szStressPDB_URL = new TCHAR[MAX_STRESS_URL];
|
|
szStressSYM_URL = new TCHAR[MAX_STRESS_URL];
|
|
szStressMemDmpPath = new TCHAR[MAX_PATH];
|
|
szStressExeID = new TCHAR[MAX_PATH];
|
|
|
|
if (!g_objServerCommands.IsStressRunning())
|
|
{
|
|
// free all old StressExeURLs first - we're replacing it with new URLs anyway
|
|
g_objServerCommands.Clear_StressExeURLs();
|
|
|
|
dwIndex = 0;
|
|
dwStressExeIDIndex = 0;
|
|
dwPageHeapCommandIndex = 0;
|
|
dwUMDHCommandIndex = 0;
|
|
dwStressPDBIndex = 0;
|
|
dwStressSYMIndex = 0;
|
|
dwStressMemDmpPathIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
|
|
while (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_EXE_URL, szBuffer, &dwBufferSize, &dwIndex))
|
|
{
|
|
// *************************************
|
|
// *************************************
|
|
// ** COMMANDHEADER__MEMORY_DUMP_PATH: A valid path
|
|
ZeroMemory(szStressMemDmpPath, MAX_PATH);
|
|
dwBufferSize = MAX_PATH;
|
|
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__MEMORY_DUMP_PATH, szStressMemDmpPath, &dwBufferSize, &dwStressMemDmpPathIndex);
|
|
|
|
|
|
// *************************************
|
|
// *************************************
|
|
// ** Get COMMANDHEADER__STRESS_PDB_URL if there is one
|
|
// **
|
|
ZeroMemory(szStressPDB_URL, MAX_STRESS_URL);
|
|
dwBufferSize = MAX_STRESS_URL;
|
|
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_PDB_URL, szStressPDB_URL, &dwBufferSize, &dwStressPDBIndex);
|
|
|
|
|
|
// *************************************
|
|
// *************************************
|
|
// ** Get COMMANDHEADER__STRESS_SYM_URL if there is one
|
|
// **
|
|
ZeroMemory(szStressSYM_URL, MAX_STRESS_URL);
|
|
dwBufferSize = MAX_STRESS_URL;
|
|
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_SYM_URL, szStressSYM_URL, &dwBufferSize, &dwStressSYMIndex);
|
|
|
|
|
|
// *************************************
|
|
// *************************************
|
|
// ** Get COMMANDHEADER__STRESS_EXE_PAGEHEAP if there is one
|
|
// **
|
|
ZeroMemory(szPageheapCommand, MAX_PATH);
|
|
dwBufferSize = MAX_PATH;
|
|
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_EXE_PAGEHEAP, szPageheapCommand, &dwBufferSize, &dwPageHeapCommandIndex);
|
|
|
|
// *************************************
|
|
// *************************************
|
|
// ** Get COMMANDHEADER__STRESS_EXE_UMDH if there is one
|
|
// **
|
|
ZeroMemory(szUMDHCommand, MAX_PATH);
|
|
dwBufferSize = MAX_PATH;
|
|
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_EXE_UMDH, szUMDHCommand, &dwBufferSize, &dwUMDHCommandIndex);
|
|
|
|
|
|
// *************************************
|
|
// *************************************
|
|
// ** Get COMMANDHEADER__STRESS_EXE_INSTANCEID
|
|
// For each COMMANDHEADER__STRESS_EXE_URL, there must be an index for the stress instance from the StressADMIN DB table.
|
|
// This identifies the stressinstance run. The test case (stressinstance) WILL NOT be added and run without an ID number.
|
|
ZeroMemory(szStressExeID, MAX_PATH);
|
|
dwBufferSize = MAX_PATH;
|
|
|
|
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__STRESS_EXE_INSTANCEID, szStressExeID, &dwBufferSize, &dwStressExeIDIndex))
|
|
{
|
|
// convert header ID string to a DWORD
|
|
dwStressExeID = _ttol(szStressExeID);
|
|
|
|
// only add valid stressInstances with valid ID's
|
|
if (0 < dwStressExeID)
|
|
{
|
|
g_objServerCommands.Create_StressInstance(
|
|
dwStressExeID,
|
|
szPageheapCommand,
|
|
szUMDHCommand,
|
|
szStressPDB_URL,
|
|
szStressSYM_URL,
|
|
szStressMemDmpPath,
|
|
szBuffer);
|
|
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, MAX_URL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete [] szPageheapCommand;
|
|
delete [] szUMDHCommand;
|
|
delete [] szStressMemDmpPath;
|
|
delete [] szStressPDB_URL;
|
|
delete [] szStressSYM_URL;
|
|
delete [] szStressExeID;
|
|
|
|
|
|
// *********************************
|
|
// **** COMMANDHEADER__ABORT: Abort the stress instance running specified by this header.
|
|
dwIndex = 0;
|
|
dwBufferSize = MAX_URL;
|
|
ZeroMemory(szBuffer, sizeof(szBuffer));
|
|
while (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, COMMANDHEADER__ABORT, szBuffer, &dwBufferSize, &dwIndex))
|
|
g_objServerCommands.AbortStressInstance(_ttol(szBuffer));
|
|
|
|
|
|
LeaveCriticalSection(&g_csServerCommandsVars);
|
|
|
|
|
|
Exit:
|
|
if (hRequest)
|
|
WinHttpCloseHandle(hRequest);
|
|
|
|
if (hSession)
|
|
WinHttpCloseHandle(hSession);
|
|
|
|
if (hRoot)
|
|
WinHttpCloseHandle(hRoot);
|
|
|
|
delete [] urlComponents.lpszScheme;
|
|
delete [] urlComponents.lpszHostName;
|
|
delete [] urlComponents.lpszUrlPath;
|
|
delete [] urlComponents.lpszExtraInfo;
|
|
delete [] urlComponents.lpszPassword;
|
|
delete [] urlComponents.lpszUserName;
|
|
|
|
ExitThread(bResult);
|
|
}
|
|
|
|
|
|
|
|
|
|
// *******************************************************************
|
|
// *******************************************************************
|
|
// ****
|
|
// **** ServerCommands class member functions
|
|
// ****
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ServerCommands::ServerCommands()
|
|
{
|
|
m_dwCommandServerUpdateInternval = STRESS_COMMAND_SERVER_UPDATE_INTERVAL;
|
|
m_bExit = FALSE;
|
|
m_dwStressInstanceIterator = NULL;
|
|
g_hQueryServerForCommands = NULL;
|
|
|
|
m_szCommandServerURL = new TCHAR[MAX_STRESS_URL];
|
|
m_szCommandServerResultsURL = new TCHAR[MAX_STRESS_URL];
|
|
m_szWinHttpDLL_DownloadURL = new TCHAR[MAX_STRESS_URL];
|
|
m_szWinHttpPDB_DownloadURL = new TCHAR[MAX_STRESS_URL];
|
|
m_szWinHttpSYM_DownloadURL = new TCHAR[MAX_STRESS_URL];
|
|
m_szWinHttpDLL_FileName = new TCHAR[MAX_PATH];
|
|
m_szStressSchedulerCurrentDirectory = new TCHAR[MAX_PATH];
|
|
m_szClientMachineName = new CHAR[MAX_PATH];
|
|
|
|
ZeroMemory(m_szCommandServerURL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szCommandServerResultsURL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szWinHttpDLL_DownloadURL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szWinHttpPDB_DownloadURL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szWinHttpSYM_DownloadURL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szWinHttpDLL_FileName, MAX_PATH);
|
|
ZeroMemory(m_szStressSchedulerCurrentDirectory, MAX_PATH);
|
|
ZeroMemory(m_szClientMachineName, MAX_PATH);
|
|
|
|
// initilize start/end times to -1 so we know that
|
|
// there are not valid time and we'll skip the Begin/End stress time check
|
|
// until we get real values from the command server
|
|
m_iTimeStressBeginsHour = -1;
|
|
m_iTimeStressBeginsMinute = -1;
|
|
m_iTimeStressEndsHour = -1;
|
|
m_iTimeStressEndsMinute = -1;
|
|
m_bRunForever = 0;
|
|
|
|
// Set default URLs
|
|
wcsncpy(m_szCommandServerURL, STRESS_COMMAND_SERVER_URL, sizeof(STRESS_COMMAND_SERVER_URL));
|
|
wcsncpy(m_szCommandServerResultsURL, STRESS_COMMAND_SERVER_RESULTS_URL, sizeof(STRESS_COMMAND_SERVER_RESULTS_URL));
|
|
|
|
// Get the current working directory
|
|
GetCurrentDirectory(MAX_PATH, m_szStressSchedulerCurrentDirectory);
|
|
|
|
// Get the client's machine name
|
|
GetEnvironmentVariableA("COMPUTERNAME", m_szClientMachineName, MAX_PATH);
|
|
|
|
InitializeCriticalSection(&g_csServerCommandsVars);
|
|
|
|
// Tell the client that we are alive and also send system info
|
|
RegisterClient();
|
|
|
|
}
|
|
|
|
|
|
ServerCommands::~ServerCommands()
|
|
{
|
|
DWORD dwThreadExitCode = 0;
|
|
|
|
// LOGLOG: stressScheduler has exited
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_EXIT, "WinHttpStressScheduler has exited.", NULL, NULL);
|
|
|
|
// Shut down QueryServer thread
|
|
GetExitCodeThread(g_hQueryServerForCommands, &dwThreadExitCode);
|
|
|
|
if (STILL_ACTIVE == dwThreadExitCode)
|
|
WaitForSingleObject(g_hQueryServerForCommands, INFINITE);
|
|
|
|
// free allocated memory for URLs
|
|
Clear_StressExeURLs();
|
|
|
|
// Free our handles
|
|
CloseHandle(g_hQueryServerForCommands);
|
|
DeleteCriticalSection(&g_csServerCommandsVars);
|
|
|
|
delete [] m_szCommandServerURL;
|
|
delete [] m_szCommandServerResultsURL;
|
|
delete [] m_szWinHttpDLL_DownloadURL;
|
|
delete [] m_szWinHttpPDB_DownloadURL;
|
|
delete [] m_szWinHttpSYM_DownloadURL;
|
|
delete [] m_szWinHttpDLL_FileName;
|
|
delete [] m_szStressSchedulerCurrentDirectory;
|
|
delete [] m_szClientMachineName;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::GetCurrentWorkingDirectory()
|
|
//
|
|
// Purpose:
|
|
// Returns string containing the current working directory for
|
|
// this application.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
ServerCommands::Get_CurrentWorkingDirectory()
|
|
{
|
|
return m_szStressSchedulerCurrentDirectory;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_ClientMachineName()
|
|
//
|
|
// Purpose:
|
|
// Returns string containing the machine's NETBIOS name
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPSTR
|
|
ServerCommands::Get_ClientMachineName()
|
|
{
|
|
return m_szClientMachineName;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::QueryServerForCommands()
|
|
//
|
|
// Purpose:
|
|
// This method sends a request to the command server for instructions
|
|
// and saves them in our private vars.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
ServerCommands::QueryServerForCommands()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
DWORD dwThreadID = 0;
|
|
DWORD dwTimeOut = 0;
|
|
DWORD dwThreadExitCode = 0;
|
|
|
|
// See if thread is still active before spinning off a new one
|
|
GetExitCodeThread(g_hQueryServerForCommands, &dwThreadExitCode);
|
|
|
|
if (STILL_ACTIVE == dwThreadExitCode)
|
|
{
|
|
// wait for existing thread to finish
|
|
dwTimeOut = 0;
|
|
dwTimeOut = WaitForSingleObject(g_hQueryServerForCommands, 500);
|
|
|
|
if (WAIT_TIMEOUT == dwTimeOut)
|
|
bResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// free handle for previous thread
|
|
CloseHandle(g_hQueryServerForCommands);
|
|
|
|
// spin off thread to query server
|
|
g_hQueryServerForCommands = NULL;
|
|
g_hQueryServerForCommands = CreateThread(NULL, 0, QueryServerForCommands_ThreadProc, (LPVOID) this, 0, &dwThreadID);
|
|
|
|
if (!g_hQueryServerForCommands)
|
|
bResult = FALSE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Download_WinHttpDLL()
|
|
//
|
|
// Purpose:
|
|
// Downloads the test DLL and symbols.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL ServerCommands::Download_WinHttpDLL()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
LPTSTR szSymbolFileName = new TCHAR[MAX_PATH];
|
|
LPTSTR szBuffer = new TCHAR[MAX_PATH];
|
|
|
|
|
|
// ************************
|
|
// ************************
|
|
// ** download the file to the system32 directory
|
|
// **
|
|
if (!GetSystemDirectory(szBuffer, MAX_PATH))
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// download DLL if needed
|
|
if (_tcsclen(m_szWinHttpDLL_DownloadURL) > 0)
|
|
bResult =
|
|
NetworkTools__URLDownloadToFile(
|
|
m_szWinHttpDLL_DownloadURL,
|
|
szBuffer,
|
|
m_szWinHttpDLL_FileName);
|
|
|
|
if (bResult)
|
|
{
|
|
// download PDB file if needed
|
|
if (_tcsclen(m_szWinHttpPDB_DownloadURL) > 0)
|
|
{
|
|
NetworkTools__GetFileNameFromURL(m_szWinHttpPDB_DownloadURL, szSymbolFileName, MAX_PATH);
|
|
|
|
if (NetworkTools__URLDownloadToFile(m_szWinHttpPDB_DownloadURL, szBuffer, szSymbolFileName))
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "PDB symbol file downloaded successfully.", NULL, 0);
|
|
else
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "PDB symbol file failed to downloaded.", NULL, 0);
|
|
}
|
|
|
|
|
|
// download sym file if needed
|
|
if (_tcsclen(m_szWinHttpSYM_DownloadURL) > 0)
|
|
{
|
|
NetworkTools__GetFileNameFromURL(m_szWinHttpSYM_DownloadURL, szSymbolFileName, MAX_PATH);
|
|
|
|
if (NetworkTools__URLDownloadToFile(m_szWinHttpSYM_DownloadURL, szBuffer, szSymbolFileName))
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "SYM symbol file downloaded successfully.", NULL, 0);
|
|
else
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "SYM symbol file failed to downloaded.", NULL, 0);
|
|
}
|
|
}
|
|
|
|
// if failed to download DLL, it's probably in use. We'll try to regsvr32 it anyways if it's there.
|
|
|
|
// ************************
|
|
// ************************
|
|
// ** regsvr32'ed the dll just downloaded
|
|
// **
|
|
HINSTANCE hLib;
|
|
|
|
hLib = LoadLibrary(m_szWinHttpDLL_FileName);
|
|
|
|
if (hLib < (HINSTANCE)HINSTANCE_ERROR)
|
|
{
|
|
// unable to load the DLL;
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// **********************
|
|
// **********************
|
|
// ** Register the DLL
|
|
typedef VOID (CALLBACK* LPFNDLLFUNC1)();
|
|
LPFNDLLFUNC1 lpDllEntryPoint;
|
|
|
|
// Find the entry point.
|
|
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib, "DllRegisterServer");
|
|
|
|
if (lpDllEntryPoint != NULL)
|
|
(*lpDllEntryPoint)();
|
|
else
|
|
{
|
|
//unable to locate entry point - regsvr failed
|
|
bResult = FALSE;
|
|
}
|
|
|
|
|
|
Exit:
|
|
if (bResult)
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_INFORMATION, "winhttp5.dll downloaded and registered successfully.", NULL, 0);
|
|
|
|
delete [] szSymbolFileName;
|
|
delete [] szBuffer;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_RunForever(BOOL)
|
|
//
|
|
// Purpose:
|
|
// Pass in TRUE to run forever ignoring begin/end time, FALSE not to.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_RunForever(
|
|
BOOL bRunForever // [IN] TRUE to run forever ignoring begin/end time, FALSE not to.
|
|
)
|
|
{
|
|
m_bRunForever = bRunForever;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_ExitStress(BOOL)
|
|
//
|
|
// Purpose:
|
|
// Pass in TRUE to exit stress as soon as possible and FALSE
|
|
// not to.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_ExitStress(
|
|
BOOL bExitStress // [IN] TRUE to exit stress, FALSE not to.
|
|
)
|
|
{
|
|
m_bExit = bExitStress;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_WinHttpDllURL(LPTSTR, DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in an URL and its size and to get the WinHttp DLL from.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_WinHttpDllURL(
|
|
LPTSTR szBuffer, // [IN] string buffer containing URL to the WINHTTP DLL
|
|
DWORD dwBufferSize // [IN] size of the szBuffer in TCHARs
|
|
)
|
|
{
|
|
_tcscpy(m_szWinHttpDLL_DownloadURL, szBuffer);
|
|
|
|
// Get the full DLL filename from the URL
|
|
NetworkTools__GetFileNameFromURL(m_szWinHttpDLL_DownloadURL, m_szWinHttpDLL_FileName, MAX_PATH);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_WinHttpPDBURL(LPTSTR, DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in an URL and its size and to get the WinHttp PDB file from.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_WinHttpPDBURL(
|
|
LPTSTR szBuffer, // [IN] string buffer containing URL to the WINHTTP DLL
|
|
DWORD dwBufferSize // [IN] size of the szBuffer in TCHARs
|
|
)
|
|
{
|
|
_tcscpy(m_szWinHttpPDB_DownloadURL, szBuffer);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_WinHttpSYMURL(LPTSTR, DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in an URL and its size and to get the WinHttp SYM file from.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_WinHttpSYMURL(
|
|
LPTSTR szBuffer, // [IN] string buffer containing URL to the WINHTTP DLL
|
|
DWORD dwBufferSize // [IN] size of the szBuffer in TCHARs
|
|
)
|
|
{
|
|
_tcscpy(m_szWinHttpSYM_DownloadURL, szBuffer);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_CommandServerURL(LPTSTR)
|
|
//
|
|
// Purpose:
|
|
// Pass in a timeout value in milliseconds to query the
|
|
// Command Server for commands.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_CommandServerURL(
|
|
LPTSTR szBuffer, // [IN] string buffer containing URL to the WINHTTP DLL
|
|
DWORD dwBufferSize // [IN] size of the szBuffer in TCHARs
|
|
)
|
|
{
|
|
_tcscpy(m_szCommandServerURL, szBuffer);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_CommandServerUpdateInterval(DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in a timeout value in milliseconds to query the
|
|
// Command Server for commands.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_CommandServerUpdateInterval(
|
|
DWORD dwUpdateInterval // [IN] time to wait before pinging the Command Server in milliseconds
|
|
)
|
|
{
|
|
// server update interval must be at least greater than the minimum timeout
|
|
if (STRESS_COMMAND_SERVER_MINIMUM_UPDATE_INTERVAL < dwUpdateInterval &&
|
|
STRESS_COMMAND_SERVER_MAXIMUM_UPDATE_INTERVAL > dwUpdateInterval)
|
|
m_dwCommandServerUpdateInternval = dwUpdateInterval;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_TimeStressBegins(DWORD, DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in a time string to begin stress in 24 hour time.
|
|
// Takes two parameters to set the hour and minute. A parameter
|
|
// will be ignored if NULL.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_TimeStressBegins(
|
|
LPTSTR szHour, // [IN] 0-23 parameter ignored if < 0
|
|
LPTSTR szMinute // [IN] 0-59 parameter ignored if < 0
|
|
)
|
|
{
|
|
if (szHour)
|
|
m_iTimeStressBeginsHour = _ttoi(szHour);
|
|
|
|
if (szMinute)
|
|
m_iTimeStressBeginsMinute = _ttoi(szMinute);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Set_TimeStressEnds(DWORD, DWORD)
|
|
//
|
|
// Purpose:
|
|
// Pass in a time string to end stress in 24 hour time.
|
|
// Takes two parameters to set the hour and minute. A parameter
|
|
// will be ignored if NULL.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Set_TimeStressEnds(
|
|
LPTSTR szHour, // [IN] 0-23 parameter ignored if < 0
|
|
LPTSTR szMinute // [IN] 0-59 parameter ignored if < 0
|
|
)
|
|
{
|
|
if (szHour)
|
|
m_iTimeStressEndsHour = _ttoi(szHour);
|
|
|
|
if (szMinute)
|
|
m_iTimeStressEndsMinute = _ttoi(szMinute);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Create_StressInstance(LPTSTR)
|
|
//
|
|
// Purpose:
|
|
// Pass in an URL and its size and it will be added to the
|
|
// m_arStressInstanceList list. There is no limit on the number of
|
|
// URLs that can be added.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Create_StressInstance(
|
|
DWORD dwStressInstanceID, // [IN] ID from the stressAdmin DB identifying this stressInstance
|
|
LPTSTR szPageHeapCommand, // [IN] string buffer containing the pageheap command line
|
|
LPTSTR szUMDHCommand, // [IN] string buffer containing the UMDH command line
|
|
LPTSTR szPDB_URL, // [IN] string buffer containing URL to the stress EXE's PDB file
|
|
LPTSTR szSYM_URL, // [IN] string buffer containing URL to the stress EXE's SYM file
|
|
LPTSTR szMemDumpPath, // [IN] string buffer containing path to create memory dump files
|
|
LPTSTR szEXE_URL // [IN] string buffer containing URL to the stress EXE
|
|
)
|
|
{
|
|
PSTRESSINSTANCE pStressInstance = NULL;
|
|
|
|
// verify params just in case
|
|
if (!szEXE_URL)
|
|
return;
|
|
|
|
// allocate memory for the object and put it in the list
|
|
pStressInstance = new StressInstance;
|
|
|
|
pStressInstance->Set_UMDHCommands(szUMDHCommand);
|
|
pStressInstance->Set_PageHeapCommands(szPageHeapCommand);
|
|
pStressInstance->Set_StressExeID(dwStressInstanceID);
|
|
pStressInstance->Set_StressExeURL(szEXE_URL);
|
|
pStressInstance->Set_StressExeMemoryDumpPath(szMemDumpPath);
|
|
pStressInstance->Set_StressExePdbURL(szPDB_URL);
|
|
pStressInstance->Set_StressExeSymURL(szSYM_URL);
|
|
|
|
m_arStressInstanceList.push_back(pStressInstance);
|
|
m_dwStressInstanceIterator = m_arStressInstanceList.begin();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Clear_StressExeURLs()
|
|
//
|
|
// Purpose:
|
|
// Frees memory from the m_arStressExeList vector.
|
|
//
|
|
// Called by: QueryServerForCommands_ThreadProc and ~ServerCommands
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::Clear_StressExeURLs()
|
|
{
|
|
// don't want to delete StressInstances if it's still running
|
|
if (IsStressRunning())
|
|
return;
|
|
|
|
/*
|
|
// walk the list and delete from the front to back
|
|
while (!m_arStressInstanceList.empty())
|
|
m_arStressInstanceList.erase(m_arStressInstanceList.begin());
|
|
*/
|
|
|
|
StressInstance *pStressInstance = NULL;
|
|
|
|
for (int iIndex=0; iIndex < m_arStressInstanceList.size(); iIndex++)
|
|
{
|
|
pStressInstance = m_arStressInstanceList[iIndex];
|
|
m_arStressInstanceList.erase(&m_arStressInstanceList[iIndex]);
|
|
delete [] pStressInstance;
|
|
}
|
|
|
|
m_dwStressInstanceIterator = NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_CommandServerUpdateInterval()
|
|
//
|
|
// Purpose:
|
|
// Returns the current setting for the Command Server Update
|
|
// interval.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
DWORD
|
|
ServerCommands::Get_CommandServerUpdateInterval()
|
|
{
|
|
if (STRESS_COMMAND_SERVER_MINIMUM_UPDATE_INTERVAL < m_dwCommandServerUpdateInternval &&
|
|
STRESS_COMMAND_SERVER_MAXIMUM_UPDATE_INTERVAL > m_dwCommandServerUpdateInternval)
|
|
return m_dwCommandServerUpdateInternval;
|
|
else
|
|
return STRESS_COMMAND_SERVER_UPDATE_INTERVAL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::BeginStress()
|
|
//
|
|
// Purpose:
|
|
// Queries for commands then starts the StressInstance objects.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
void
|
|
ServerCommands::BeginStress()
|
|
{
|
|
EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
if (!m_arStressInstanceList.empty() && !IsStressRunning())
|
|
{
|
|
// LOGLOG: Stress is beginning
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_BEGIN_STRESS, "Stress is beginning.", NULL, NULL);
|
|
|
|
// first download and regsvr32 the winhttp dll and symbols
|
|
Download_WinHttpDLL();
|
|
|
|
for(int iIndex = 0; iIndex < m_arStressInstanceList.size(); iIndex++)
|
|
m_arStressInstanceList[iIndex]->Begin();
|
|
}
|
|
else
|
|
{
|
|
// ping Command Server for list of stress EXE URLs.
|
|
QueryServerForCommands();
|
|
}
|
|
|
|
LeaveCriticalSection(&g_csServerCommandsVars);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::EndStress()
|
|
//
|
|
// Purpose:
|
|
// Ends stress and posts the results to the Command Server.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
void
|
|
ServerCommands::EndStress()
|
|
{
|
|
EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
if (!m_arStressInstanceList.empty())
|
|
{
|
|
if (IsStressRunning())
|
|
{
|
|
// LOGLOG: Stress is ending
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_END_STRESS, "Stress is ending.", NULL, NULL);
|
|
}
|
|
|
|
for (int iIndex = 0; iIndex < m_arStressInstanceList.size(); iIndex++)
|
|
m_arStressInstanceList[iIndex]->End();
|
|
}
|
|
|
|
// Remove the stress objects that already finished
|
|
Clear_StressExeURLs();
|
|
|
|
LeaveCriticalSection(&g_csServerCommandsVars);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::AbortStressInstance(DWORD)
|
|
//
|
|
// Purpose:
|
|
// Aborts a all stress instances that recieved a server abort message.
|
|
//
|
|
// Called in:
|
|
// QueryServerForCommands_ThreadProc
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
ServerCommands::AbortStressInstance(DWORD dwAbortID)
|
|
{
|
|
// EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
if (!m_arStressInstanceList.empty())
|
|
{
|
|
for (int iIndex = 0; iIndex < m_arStressInstanceList.size(); iIndex++)
|
|
{
|
|
if (m_arStressInstanceList[iIndex]->Get_ID() == dwAbortID)
|
|
m_arStressInstanceList[iIndex]->End();
|
|
}
|
|
}
|
|
|
|
//LeaveCriticalSection(&g_csServerCommandsVars);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::IsStressRunning()
|
|
//
|
|
// Purpose:
|
|
// Returns TRUE if any of the stressinstances is running. FALSE if not.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
ServerCommands::IsStressRunning()
|
|
{
|
|
BOOL bIsRunning = FALSE;
|
|
|
|
EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
if (!m_arStressInstanceList.empty())
|
|
{
|
|
for (int iIndex = 0; iIndex < m_arStressInstanceList.size(); iIndex++)
|
|
{
|
|
if (m_arStressInstanceList[iIndex]->IsRunning(STRESSINSTANCE_STRESS_EXE_CLOSE_TIMEOUT))
|
|
bIsRunning = TRUE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_csServerCommandsVars);
|
|
|
|
return bIsRunning;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::IsTimeToBeginStress()
|
|
//
|
|
// Purpose:
|
|
// TRUE if it's time to begin stress based on the time returned
|
|
// from the Command Server. Will return TRUE if m_sysTimeStressBegins
|
|
// is current or in the future. FALSE if not.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
ServerCommands::IsTimeToBeginStress()
|
|
{
|
|
SYSTEMTIME stCurrent, stBeginStress, stEndStress;
|
|
FILETIME ftCurrent, ftBeginStress, ftEndStress;
|
|
BOOL bResult = FALSE;
|
|
|
|
EnterCriticalSection(&g_csServerCommandsVars);
|
|
|
|
// always run stress now if server tells us to
|
|
if (m_bRunForever)
|
|
{
|
|
bResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// check to see if valid time values have been received. If not, then we always fail.
|
|
if (
|
|
m_iTimeStressBeginsHour < 0 || m_iTimeStressBeginsMinute < 0 ||
|
|
m_iTimeStressEndsHour < 0 || m_iTimeStressEndsMinute < 0
|
|
)
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
GetLocalTime(&stCurrent);
|
|
GetLocalTime(&stBeginStress);
|
|
GetLocalTime(&stEndStress);
|
|
|
|
// use the hour and minute time that we got from the command server
|
|
stBeginStress.wHour = m_iTimeStressBeginsHour;
|
|
stBeginStress.wMinute = m_iTimeStressBeginsMinute;
|
|
|
|
stEndStress.wHour = m_iTimeStressEndsHour;
|
|
stEndStress.wMinute = m_iTimeStressEndsMinute;
|
|
|
|
// convert to file time so we can compare
|
|
SystemTimeToFileTime(&stCurrent, &ftCurrent);
|
|
SystemTimeToFileTime(&stBeginStress, &ftBeginStress);
|
|
SystemTimeToFileTime(&stEndStress, &ftEndStress);
|
|
|
|
|
|
// If EndTime < BeginTime, then it means stress is running for
|
|
// over a day so we have to add 24 hours to the end time.
|
|
ULARGE_INTEGER ulEndStress;
|
|
ULONGLONG ullNanoSecondsInAFreakingDay;
|
|
|
|
ulEndStress.LowPart = ftEndStress.dwLowDateTime;
|
|
ulEndStress.HighPart = ftEndStress.dwHighDateTime;
|
|
|
|
// stress runs across two days so we wrap around one day
|
|
ullNanoSecondsInAFreakingDay = 24 * 60; // minutes in a day
|
|
ullNanoSecondsInAFreakingDay *= 60; // seconds in a day
|
|
ullNanoSecondsInAFreakingDay *= 1000000000; // number of nanoseconds in a day. 10^9 NS in a second
|
|
ullNanoSecondsInAFreakingDay /= 100; // The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601.
|
|
|
|
if (m_iTimeStressEndsHour < m_iTimeStressBeginsHour)
|
|
{
|
|
// ********************
|
|
// ********************
|
|
// ** increase by 24 hours
|
|
// **
|
|
|
|
ulEndStress.QuadPart += ullNanoSecondsInAFreakingDay;
|
|
|
|
// copy back to the original EndStress Date/Time
|
|
ftEndStress.dwHighDateTime = ulEndStress.HighPart;
|
|
ftEndStress.dwLowDateTime = ulEndStress.LowPart;
|
|
|
|
FileTimeToSystemTime(&ftEndStress, &stEndStress);
|
|
}
|
|
else
|
|
{
|
|
// stress runs in the same day
|
|
if ((m_iTimeStressEndsHour == m_iTimeStressBeginsHour) &&
|
|
(m_iTimeStressEndsMinute <= m_iTimeStressBeginsMinute))
|
|
{
|
|
// if 7:30 to 7:20 - we wrap around one day.
|
|
ulEndStress.QuadPart += ullNanoSecondsInAFreakingDay;
|
|
|
|
// copy back to the original EndStress Date/Time
|
|
ftEndStress.dwHighDateTime = ulEndStress.HighPart;
|
|
ftEndStress.dwLowDateTime = ulEndStress.LowPart;
|
|
|
|
FileTimeToSystemTime(&ftEndStress, &stEndStress);
|
|
}
|
|
}
|
|
|
|
|
|
// Begin stress if:
|
|
// (BeginTime <= CurrentTime <= EndTime)
|
|
if ((0 <= CompareFileTime(&ftCurrent, &ftBeginStress)) && (0 <= CompareFileTime(&ftEndStress, &ftCurrent)))
|
|
bResult = TRUE;
|
|
else
|
|
bResult = FALSE;
|
|
|
|
Exit:
|
|
LeaveCriticalSection(&g_csServerCommandsVars);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::IsTimeToExitStress()
|
|
//
|
|
// Purpose:
|
|
// TRUE if it's time to end stress based on the COMMANDHEADER__EXIT headers
|
|
// from the Command Server exists. FALSE if not.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
ServerCommands::IsTimeToExitStress()
|
|
{
|
|
return m_bExit;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_CommandServerURL()
|
|
//
|
|
// Purpose:
|
|
// Returns the Command Server URL.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
ServerCommands::Get_CommandServerURL()
|
|
{
|
|
return m_szCommandServerURL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_CommandServerResultsURL()
|
|
//
|
|
// Purpose:
|
|
// Returns the Command Server Results URL.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
ServerCommands::Get_CommandServerResultsURL()
|
|
{
|
|
return m_szCommandServerResultsURL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_NumberOfStressInstances()
|
|
//
|
|
// Purpose:
|
|
// Returns the number of stressInstances running or pending.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
DWORD
|
|
ServerCommands::Get_NumberOfStressInstances()
|
|
{
|
|
return m_arStressInstanceList.size();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::Get_TestDllFileName()
|
|
//
|
|
// Purpose:
|
|
// Returns the name of the test DLL. ex. "winhttp5.dll"
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
ServerCommands::Get_TestDllFileName()
|
|
{
|
|
// m_szWinHttpDLL_FileName can be NULL in the case that a test DLL is not downloaded
|
|
|
|
if (0 < _tcslen(m_szWinHttpDLL_FileName))
|
|
return m_szWinHttpDLL_FileName;
|
|
else
|
|
return _T("winhttp5.dll");
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: ServerCommands::RegisterClient()
|
|
//
|
|
// Purpose:
|
|
// Sends the command server the system info on this client.
|
|
// This lets the command server know that this client is alive.
|
|
//
|
|
// NOTE: This only works in NT because we query
|
|
// environment vars not present in Win9x
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
ServerCommands::RegisterClient()
|
|
{
|
|
OSVERSIONINFOA osInfo;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwPostSize = 5000;
|
|
DWORD dwTempSize = MAX_PATH;
|
|
DWORD dwSizeSoFar = 0; // size of string written to szTemp so far.
|
|
LPSTR szPost = new CHAR[dwPostSize];
|
|
LPSTR szTemp = new CHAR[dwTempSize];
|
|
|
|
|
|
ZeroMemory(szTemp, dwTempSize);
|
|
ZeroMemory(szPost, dwPostSize);
|
|
|
|
// *********************
|
|
// *********************
|
|
// ** Get windows version info
|
|
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
|
if (!GetVersionExA(&osInfo))
|
|
goto Exit;
|
|
|
|
dwSizeSoFar += GetEnvironmentVariableA("OS", szTemp, dwTempSize);
|
|
dwSizeSoFar += sizeof(FIELDNAME__OS_PLATFORM);
|
|
strcat(szPost, FIELDNAME__OS_PLATFORM);
|
|
strcat(szPost, szTemp);
|
|
|
|
strcat(szPost, "&" FIELDNAME__OS_BUILD);
|
|
strcat(szPost, _itoa(osInfo.dwBuildNumber, szTemp, 10));
|
|
|
|
strcat(szPost, "&" FIELDNAME__OS_MAJORVERSION);
|
|
strcat(szPost, _itoa(osInfo.dwMajorVersion, szTemp, 10));
|
|
|
|
strcat(szPost, "&" FIELDNAME__OS_MINORVERSION);
|
|
strcat(szPost, _itoa(osInfo.dwMinorVersion, szTemp, 10));
|
|
|
|
strcat(szPost, "&" FIELDNAME__OS_EXTRAINFO);
|
|
strcat(szPost, osInfo.szCSDVersion);
|
|
|
|
|
|
// *********************
|
|
// *********************
|
|
// ** Get processor info
|
|
GetEnvironmentVariableA("PROCESSOR_ARCHITECTURE", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__SYSTEMINFO_PROCSSSOR_ARCHITECTURE);
|
|
strcat(szPost, szTemp);
|
|
|
|
GetEnvironmentVariableA("PROCESSOR_IDENTIFIER", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__SYSTEMINFO_PROCSSSOR_ID);
|
|
strcat(szPost, szTemp);
|
|
|
|
GetEnvironmentVariableA("PROCESSOR_LEVEL", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__SYSTEMINFO_PROCSSSOR_LEVEL);
|
|
strcat(szPost, szTemp);
|
|
|
|
GetEnvironmentVariableA("PROCESSOR_REVISION", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__SYSTEMINFO_PROCSSSOR_REVISION);
|
|
strcat(szPost, szTemp);
|
|
|
|
GetEnvironmentVariableA("NUMBER_OF_PROCESSORS", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__SYSTEMINFO_PROCSSSOR_NUMBER_OF);
|
|
strcat(szPost, szTemp);
|
|
|
|
|
|
// *********************
|
|
// *********************
|
|
// ** Get user info
|
|
GetEnvironmentVariableA("USERNAME", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__USERINFO_USERALIAS);
|
|
strcat(szPost, szTemp);
|
|
|
|
GetEnvironmentVariableA("USERDOMAIN", szTemp, dwTempSize);
|
|
strcat(szPost, "&" FIELDNAME__USERINFO_USERDOMAIN);
|
|
strcat(szPost, szTemp);
|
|
|
|
// BUGBUG: someone needs to resolve the user alias to the real full name of the user
|
|
// FIELDNAME__USERINFO_FULLNAME
|
|
|
|
|
|
// get the client's machine name
|
|
strcat(szPost, "&" FIELDNAME__USERINFO_MACHINENAME);
|
|
strcat(szPost, m_szClientMachineName);
|
|
|
|
|
|
// Let the Command Server know that this client is alive
|
|
bResult = NetworkTools__POSTResponse(STRESS_COMMAND_SERVER_REGISTERCLIENT_URL, szPost, NULL);
|
|
|
|
// LOGLOG: stressScheduler has started
|
|
bResult = NetworkTools__SendLog(FIELDNAME__LOGTYPE_START_UP, "WinHttpStressScheduler has started.", NULL, NULL);
|
|
|
|
Exit:
|
|
delete [] szPost;
|
|
delete [] szTemp;
|
|
|
|
return bResult;
|
|
}
|