Leaked source code of windows server 2003
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.
 
 
 
 
 
 

802 lines
20 KiB

//////////////////////////////////////////////////////////////////////
// File: NetworkTools.cpp
//
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
//
// Purpose:
// NetworkTools.cpp: Helper functions that send/receive data.
//
// History:
// 02/22/01 DennisCh Created
//
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//
// Includes
//
//////////////////////////////////////////////////////////////////////
//
// Project headers
//
#include "NetworkTools.h"
#include "ServerCommands.h"
//
// Win32 headers
//
//////////////////////////////////////////////////////////////////////
//
// Globals and statics
//
//////////////////////////////////////////////////////////////////////
extern ServerCommands g_objServerCommands; // Declared in WinHttpStressScheduler.cpp
extern HWND g_hWnd; // Declared in WinHttpStressScheduler.cpp
////////////////////////////////////////////////////////////
// Function: NetworkTools__GetFileNameFromURL(LPTSTR)
//
// Purpose:
// Returns the filename requested from an URL without a querystring.
// For example, if szURL="http://dennisch/files/test.exe" we return "test.exe"
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__GetFileNameFromURL(
LPTSTR szURL, // [IN] Full URL containing the file
LPTSTR szBuffer, // [OUT] Buffer to store the filename from the URL
DWORD dwBufferSize // [IN] Size of buffer szFileName
)
{
TCHAR *pLastSlash;
INT iCharToLookFor;
if (0 >= _tcslen(szURL))
return FALSE;
ZeroMemory(szBuffer, dwBufferSize);
pLastSlash = NULL;
iCharToLookFor = _T('/');
// get the last instance of '/'
pLastSlash = _tcsrchr(szURL, iCharToLookFor);
// skip the last '/'
pLastSlash++;
if (!pLastSlash)
return FALSE;
// copy the filename.extension to the buffer
_tcscpy(szBuffer, pLastSlash);
return TRUE;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__SendResponse(LPTSTR, LPTSTR, LPTSTR)
//
// Purpose:
// Sends a message to the Command Server results page
// via header/headervalue and/or POST data.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__POSTResponse(
LPTSTR szURL, // [IN] string containing URL to POST to
LPSTR szPostData, // [IN] string containing POST data to send. can be NULL
LPTSTR szHeader // [IN] string containing header(s) to send. can be NULL
)
{
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(
szURL,
_tcslen(szURL),
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];
_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;
}
// Set result header if not NULL
if (szHeader)
{
if (!WinHttpAddRequestHeaders(
hRequest,
szHeader,
_tcsclen(szHeader),
WINHTTP_ADDREQ_FLAG_ADD))
{
bResult = FALSE;
goto Exit;
}
}
bResult = WinHttpSendRequest(
hRequest,
_T("Content-Type: application/x-www-form-urlencoded"),
-1L,
szPostData,
strlen(szPostData),
strlen(szPostData),
0);
if (!WinHttpReceiveResponse(hRequest, NULL))
{
bResult = FALSE;
goto Exit;
}
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;
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__URLDownloadToFile(LPCTSTR, LPCTSTR, LPCTSTR)
//
// Purpose:
// Downloads a file pointed to by the URL. Returns TRUE if succesfully downloaded.
// FALSE if not. If the file is in use (ERROR_SHARING_VIOLATION) then we'll
// return TRUE because the file is already on the system and is valid.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__URLDownloadToFile(
LPCTSTR szURL, // [IN] Fully qualified URL pointing to the file to download
LPCTSTR szTargetDir, // [IN] A relative path to the directory to put szTargetFile in. If NULL, then it'll be put in the app's current dir.
LPCTSTR szTargetFile // [IN] Name of the file to download to. Can be NULL. File will be placed in szTargetDir. If it already exists, then we'll try to overwrite it.
)
{
HANDLE hFile = NULL;
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(
szURL,
_tcslen(szURL),
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];
_tcsncpy(szFullPath, urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
szFullPath[urlComponents.dwUrlPathLength] = _T('\0');
_tcsncat(szFullPath, urlComponents.lpszExtraInfo, urlComponents.dwExtraInfoLength);
hRequest = WinHttpOpenRequest(
hSession,
_T("GET"),
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;
}
bResult = WinHttpSendRequest(
hRequest,
NULL,
0,
NULL,
0,
0,
0);
if (!WinHttpReceiveResponse(hRequest, NULL))
{
bResult = FALSE;
goto Exit;
}
// **********************************
// **********************************
// ** Get the filename and extenstion
// ** from the URL
// **
TCHAR szFileName[MAX_PATH]; // name of the new file to write to. will be created in szCurrentDir
ZeroMemory(szFileName, sizeof(szFileName));
// check to see if the user provided a filename to write to
if (szTargetFile)
_tcsncpy(szFileName, szTargetFile, MAX_PATH);
else
{
// user did not specify a filename to write to, so we use the original one from the URL
if (!NetworkTools__GetFileNameFromURL(urlComponents.lpszUrlPath, szFileName, sizeof(szFileName)))
{
bResult = FALSE;
goto Exit;
}
}
// **********************************
// **********************************
// ** Create the directory where the file will reside and set it as the current directory
// **
// if user specified NULL, then we put the file in the current dir.
// else we set the current directory as the one specified
if (szTargetDir)
{
// create the dir. don't care if it fails because it already exists...
CreateDirectory(szTargetDir, NULL);
SetCurrentDirectory(szTargetDir);
}
// create the file to download to.
hFile = CreateFile(
// if the user doesn't specify the filename to write to, use the one from the URL
szFileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if ((hFile == INVALID_HANDLE_VALUE) || !hFile)
{
// We won't return FALSE if the file is in use. This means the file is valid.
if (ERROR_SHARING_VIOLATION == GetLastError())
{
// File is in use that means winhttp is ok. we'll stress the old version
bResult = TRUE;
goto Exit;
}
else
{
bResult = FALSE;
goto Exit;
}
}
// **********************************
// **********************************
// ** Read data from net to file.
// **
LPVOID lpBuffer;
DWORD dwBytesToRead, dwBytesRead;
// read 64K chunks at a time
lpBuffer = NULL;
lpBuffer = new LPVOID[65536];
ZeroMemory(lpBuffer, 65536);
dwBytesToRead = 65536;
dwBytesRead = 65536;
while (WinHttpReadData(hRequest, lpBuffer, dwBytesToRead, &dwBytesRead) && (0 != dwBytesRead))
{
WriteFile(hFile, lpBuffer, dwBytesRead, &dwBytesRead, NULL);
dwBytesRead = 0;
ZeroMemory(lpBuffer, sizeof(lpBuffer));
}
delete [] lpBuffer;
Exit:
if (hRequest)
WinHttpCloseHandle(hRequest);
if (hSession)
WinHttpCloseHandle(hSession);
if (hRoot)
WinHttpCloseHandle(hRoot);
if (hFile && (hFile != INVALID_HANDLE_VALUE))
CloseHandle(hFile);
// restore the current directory from the one that we created the new file in.
SetCurrentDirectory(g_objServerCommands.Get_CurrentWorkingDirectory());
delete [] urlComponents.lpszScheme;
delete [] urlComponents.lpszHostName;
delete [] urlComponents.lpszUrlPath;
delete [] urlComponents.lpszExtraInfo;
delete [] urlComponents.lpszPassword;
delete [] urlComponents.lpszUserName;
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__CopyFile(LPCTSTR, LPCTSTR)
//
// Purpose:
// Wrapper for CopyFile. Copies file szSource to szDestination.
// We'll always overwite the file if it already exists.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__CopyFile(
LPCTSTR szSource,
LPCTSTR szDestination
)
{
BOOL bResult = TRUE;
if (!szSource || !szDestination)
{
bResult = FALSE;
goto Exit;
}
bResult = CopyFile(szSource, szDestination, TRUE);
Exit:
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__PageHeap(BOOL, LPCTSTR)
//
// Purpose:
// Enables/Disables pageheap.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__PageHeap(
BOOL bEnable, // [IN] Enables/Disables pageheap.
LPCTSTR szAppName, // [IN] The executable to enable or disable.
LPCTSTR szCommandLine // [IN] Command line for pageheap.
)
{
BOOL bResult = TRUE;
HINSTANCE hExe = NULL;
LPTSTR szPHCommand = new TCHAR[MAX_PATH];
if (bEnable)
{
hExe = ShellExecute(g_hWnd, _T("open"), _T("pageheap.exe"), szCommandLine, NULL, SW_SHOWMINIMIZED);
}
else
{
ZeroMemory(szPHCommand, MAX_PATH);
_tcscpy(szPHCommand, _T("/disable "));
_tcscat(szPHCommand, szAppName);
hExe = ShellExecute(g_hWnd, _T("open"), _T("pageheap.exe"), szPHCommand, NULL, SW_SHOWMINIMIZED);
}
// Error if HINSTANCE <= 32.
if (32 >= (INT) hExe)
bResult = FALSE;
delete [] szPHCommand;
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__UMDH(LPCTSTR, DWORD, LPCTSTR)
//
// Purpose:
// Enables/Disables UMDH.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__UMDH(
BOOL bEnable, // [IN] Enables/Disables UMDH.
LPCTSTR szAppName, // [IN] The executable to dump.
LPCTSTR szCommandLine, // [IN] Command line for UMDH.
LPCTSTR szLogFile, // [IN] Logfile to create
DWORD dwPID // [IN] The PID of the process to dump
)
{
BOOL bResult = TRUE;
HINSTANCE hExe = NULL;
LPTSTR szCommand = new TCHAR[MAX_PATH];
// build command line and run: "GFLAGS -i <stressExe name> +ust"
ZeroMemory(szCommand, MAX_PATH);
_tcscpy(szCommand, _T("-i "));
_tcscat(szCommand, szAppName);
_tcscat(szCommand, _T(" +ust"));
hExe = ShellExecute(g_hWnd, _T("open"), DEBUGGER_TOOLS_PATH _T("gflags.exe"), szCommand, NULL, SW_SHOWMINIMIZED);
// build the UMDH command line
ZeroMemory(szCommand, MAX_PATH);
_tcscpy(szCommand, _T("-f:stuff.log"));
hExe = ShellExecute(g_hWnd, _T("open"), DEBUGGER_TOOLS_PATH _T("umdh.exe"), szCommand, NULL, SW_SHOWMINIMIZED);
// Error if HINSTANCE <= 32.
if (32 >= (INT) hExe)
bResult = FALSE;
delete [] szCommand;
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__SendLog(LPSTR, LPSTR, LPTSTR, DWORD)
//
// Purpose:
// Sends a log to the Command Server. Takes the log type string and log string.
// Sends the stressInstance ID and client machine name as part of the POST request.
// If this is a general message, then the stressInstanceID should be set to zero. Otherwise
// if and ID is supplied, then stressAdmin will log this to the stressInstanceLog table.
// You can also add headers too.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__SendLog(
LPSTR szLogType,
LPSTR szLogText,
LPTSTR szExtraHeaders,
DWORD dwStressInstanceID
)
{
BOOL bResult = TRUE;
LPSTR szPostLogData = NULL;
CHAR szStressInstanceID[10];
LPSTR szDllVersion = new CHAR[MAX_PATH];
LPSTR szNumber = new CHAR[10];
DWORD dwPostLogDataSize = 0;
if (!szLogType || !szLogText || !g_objServerCommands.Get_ClientMachineName())
{
OutputDebugStringA("NetworkTools__SendLog: ERROR: szLogType, szLogText, or g_objServerCommands.Get_ClientMachineName() is NULL.");
bResult = FALSE;
goto Exit;
}
dwPostLogDataSize = sizeof(FIELDNAME__STRESSINSTANCE_ID) + MAX_PATH;
dwPostLogDataSize += sizeof(FIELDNAME__LOG_TEXT) + strlen(szLogText);
dwPostLogDataSize += sizeof(FIELDNAME__USERINFO_MACHINENAME) + strlen(g_objServerCommands.Get_ClientMachineName());
dwPostLogDataSize += strlen(szLogType);
dwPostLogDataSize += sizeof(FIELDNAME__TESTINFO_TEST_DLL_VERSION) + MAX_PATH;
szPostLogData = new CHAR[dwPostLogDataSize];
ZeroMemory(szPostLogData, dwPostLogDataSize);
// ***************************
// ** add the client's machine name
strcpy(szPostLogData, FIELDNAME__USERINFO_MACHINENAME);
strcat(szPostLogData, g_objServerCommands.Get_ClientMachineName());
// ***************************
// ** add the stressInstance ID if valid
if (0 < dwStressInstanceID)
{
strcat(szPostLogData, "&" FIELDNAME__STRESSINSTANCE_ID);
strcat(szPostLogData, _itoa(dwStressInstanceID, szStressInstanceID, 10));
}
// ***************************
// ** add the log type data
strcat(szPostLogData, "&");
strcat(szPostLogData, szLogType);
// ***************************
// ** add the test dll version info
if (
g_objServerCommands.Get_TestDllFileName() &&
NetworkTools__GetDllVersion(g_objServerCommands.Get_TestDllFileName(), szDllVersion, MAX_PATH)
)
{
strcat(szPostLogData, "&" FIELDNAME__TESTINFO_TEST_DLL_VERSION);
strcat(szPostLogData, szDllVersion);
}
// ***************************
// ** add the log text data
strcat(szPostLogData, "&" FIELDNAME__LOG_TEXT);
strcat(szPostLogData, szLogText);
// ***************************
// ** Send the data
bResult = NetworkTools__POSTResponse(STRESS_COMMAND_SERVER_LOGURL, szPostLogData, szExtraHeaders);
//OutputDebugStringA(szPostLogData);
Exit:
if (szPostLogData)
delete [] szPostLogData;
delete [] szDllVersion;
delete [] szNumber;
return bResult;
}
////////////////////////////////////////////////////////////
// Function: NetworkTools__GetDllVersion(LPTSTR, LPSTR, DWORD)
//
// Purpose:
// Takes a DLL name and return the version as an ASCII string.
//
////////////////////////////////////////////////////////////
BOOL
NetworkTools__GetDllVersion(
LPTSTR lpszDllName,
LPSTR szVersionBuffer,
DWORD dwVersionBufferSize
)
{
BOOL bResult = TRUE;
DWORD dwHandle;
DWORD dwVersionSize;
LPSTR szVersionInfo = NULL;
LPSTR szVersionOutput = NULL;
UINT uiLength;
ZeroMemory(szVersionBuffer, dwVersionBufferSize);
dwVersionSize = GetFileVersionInfoSize(lpszDllName, &dwHandle);
if (0 >= dwVersionSize)
{
bResult = FALSE;
goto Exit;
}
// allocate new buffer for the query
szVersionInfo = new CHAR[dwVersionSize];
ZeroMemory(szVersionInfo, dwVersionSize);
if (!GetFileVersionInfo(lpszDllName, NULL, dwVersionSize, szVersionInfo))
{
bResult = FALSE;
goto Exit;
}
// *****************************
// ** build the version info query string
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
CHAR szVersionQuery[200];
ZeroMemory(szVersionQuery, 200);
// Read the list of languages and code pages.
VerQueryValueA(szVersionInfo,
"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&uiLength);
// build the ver info query string that contains the language bits
sprintf(szVersionQuery, "\\StringFileInfo\\%04x%04x\\ProductVersion", lpTranslate->wLanguage, lpTranslate->wCodePage);
// *****************************
// ** Get the version and copy to buffer
uiLength = 0;
if (!VerQueryValueA(szVersionInfo, szVersionQuery, (VOID **) &szVersionOutput, &uiLength))
{
bResult = FALSE;
goto Exit;
}
// copy the version info string to the buffer
strncpy(szVersionBuffer, (LPSTR) szVersionOutput, dwVersionBufferSize-1);
Exit:
if (szVersionInfo)
delete [] szVersionInfo;
return bResult;
}