|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name :
ftps.cxx
Abstract:
This file defines the ftp server stress client
Author:
Murali R. Krishnan ( MuraliK ) 25-July-1995
Environment:
Win32 - uses Wininet extensions
Project:
FTP Server DLL
Functions Exported:
Revision History: MuraliK 05-Nov-1995 Added support for GetFile tests
--*/
/************************************************************
* Include Headers ************************************************************/ # include <windows.h>
# include <wininet.h>
# include <stdio.h>
# include <stdlib.h>
# include <iostream.h>
# include <winsock2.h>
#define DEFAULT_TRACE_FLAGS (DEBUG_ITERATION)
# include <dbgutil.h>
# define DEFAULT_NUMBER_OF_THREADS (10)
# define DEFAULT_NUMBER_OF_ITERATIONS (100)
# define MAX_BUFFER_SIZE 64000 // 64K approx
#ifndef _NO_TRACING_
#include <initguid.h>
DEFINE_GUID(IisFtptestGuid, 0x784d8914, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e); #else
DECLARE_DEBUG_VARIABLE(); #endif
DECLARE_DEBUG_PRINTS_OBJECT();
static const char PSZ_APPLICATION_NAME[] = "murali's stresser"; static char * g_lpszServerAddress;
BOOL GenUsageMessage( int argc, char * argv[]);
// Tests the raw connectivity to server.
BOOL TestConnections( int argc, char * argv[]);
// Tests the raw get file from server.
BOOL TestGetFile( int argc, char * argv[]);
//
// The following DefineAllCommands() defines a template for all commands.
// Format: CmdCodeName CommandName Function Pointer Comments
//
// To add addditional test commands, add just another line to the list
// Dont touch any macros below, they are all automatically generated.
// Always the first entry should be usage function.
//
#define DefineAllCommands() \
Cmd( CmdUsage, "usage", GenUsageMessage, \ " Commands Available" ) \ Cmd( CmdConnections, "conn", TestConnections, \ " Raw Connections to server" ) \ Cmd( CmdGetFile, "get", TestGetFile, \ " Simple Get File (/readme.txt) from server" ) \
// Define command codes
# define Cmd( CmdCode, CmdName, CmdFunc, CmdComments) CmdCode,
typedef enum _CmdCodes { DefineAllCommands() maxCmdCode } CmdCodes;
#undef Cmd
// Define the functions and array of mappings
// General command function type
typedef BOOL ( * CMDFUNC)( int argc, char * argv[]);
typedef struct _CmdStruct { CmdCodes cmdCode; char * pszCmdName; CMDFUNC cmdFunc; char * pszCmdComments; } CmdStruct;
// Define Prototypes of command functions
# define Cmd( CmdCode, CmdName, CmdFunc, CmdComments) \
BOOL CmdFunc(int argc, char * argv[]);
// Cause an expansion to generate prototypes
// DefineAllCommands()
// Automatic generation causes a problem when we have NULL in Function ptrs :(
// Let the user explicitly define the prototypes
#undef Cmd
//
// Define the global array of commands
//
# define Cmd( CmdCode, CmdName, CmdFunc, CmdComments) \
{ CmdCode, CmdName, CmdFunc, CmdComments},
static CmdStruct g_cmds[] = {
DefineAllCommands() { maxCmdCode, NULL, NULL} // sentinel command
};
#undef Cmd
/************************************************************
* Functions ************************************************************/
BOOL GenUsageMessage( int argc, char * argv[]) { CmdStruct * pCmd;
printf( " Usage:\n %s <server-name/address> <cmd name> <cmd arguments>\n", argv[0]); for( pCmd = g_cmds; pCmd != NULL && pCmd->cmdCode != maxCmdCode; pCmd++) { printf( "\t%s\t%s\n", pCmd->pszCmdName, pCmd->pszCmdComments); }
return ( TRUE); } // GenUsageMessage()
static CmdStruct * DecodeCommand( char * pszCmd) { CmdStruct * pCmd; if ( pszCmd != NULL) {
for( pCmd = g_cmds; pCmd != NULL && pCmd->cmdCode != maxCmdCode; pCmd++) {
if ( _stricmp( pszCmd, pCmd->pszCmdName) == 0) { return ( pCmd); } } // for
}
return ( &g_cmds[0]); // No match found, return usage message
} // DecodeCommand()
/************************************************************
* Functions ************************************************************/
inline VOID GenUserName( OUT LPSTR pszBuffer, IN LPCSTR pszPrefix, IN DWORD iteration) { // assume sufficient buffer space
// Format of response: [email protected]
sprintf( pszBuffer, "%s@p%d.t%d.%d", pszPrefix, GetCurrentProcessId(), GetCurrentThreadId(), iteration);
return;
} // GenUserName()
DWORD TestConnectionsInOneThread( IN CHAR * pszServer, IN DWORD nIterations) { HINTERNET hinet; HINTERNET hFtp; DWORD NumSuccess = 0; CHAR rgchBuffer[300]; CHAR rgchUserName[100]; DWORD cbBuffer; DWORD dwError; DWORD iter; BOOL fReturn2;
hinet = InternetOpen( PSZ_APPLICATION_NAME, 0, NULL, 0, 0);
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, "InternetOpen()==> %08x\n", hinet)); }
if ( hinet == NULL) {
return (0); }
for( iter = 0 ; iter < nIterations; iter++) {
IF_DEBUG( ITERATION) {
DBGPRINTF(( DBG_CONTEXT, "Iteration = %u\n", iter)); }
GenUserName( rgchUserName, "conn", iter);
hFtp = InternetConnect( hinet, pszServer, 0, "anonymous", rgchUserName, INTERNET_SERVICE_FTP, 0, NULL); IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetConnect()==> %08x\n", hFtp)); }
if ( hFtp == NULL) {
continue; }
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetGetLastResponse()\n")); } cbBuffer = sizeof(rgchBuffer) - 1; if ( InternetGetLastResponseInfo( &dwError, rgchBuffer, &cbBuffer)) {
IF_DEBUG( RESPONSE) {
rgchBuffer[cbBuffer] = '\0'; cout << " ErrorCode = " << dwError << "\tResponse = " << rgchBuffer; } }
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetCloseHandle(%08x)\n", hFtp)); }
if ( InternetCloseHandle(hFtp)) { NumSuccess++; } } // for()
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, "InternetCloseHandle(%08x)\n", hinet)); }
fReturn2 = InternetCloseHandle(hinet);
return ( NumSuccess);
} // TestConnectionsInOneThread()
BOOL TestConnections( int argc, char * argv[]) /*++
This function routinely establishes and throws away connections. It does not do any other work. This is used for testing logon and quit sequences of FTP server.
Arguments: argc count of arguments argv arguments argv[0] = "conn" -- name of this test function argv[1] = # of thread to use for execution argv[2] = # of iterations for each thread.
--*/ { DWORD NumThreads = DEFAULT_NUMBER_OF_THREADS; DWORD NumIterations = DEFAULT_NUMBER_OF_ITERATIONS; DWORD NumSuccesses;
if (argc >= 2 && argv[1] != NULL) {
NumThreads = atoi(argv[1]); }
if (argc >= 3 && argv[2] != NULL) {
NumIterations = atoi(argv[2]); }
// We will implement multithreading later on.
// for now just one thread is used. ( current thread)
NumSuccesses = TestConnectionsInOneThread(g_lpszServerAddress, NumIterations);
cout << " Tested for Iterations : " << NumIterations; cout << " Successes = " << NumSuccesses; cout << " Failures = " << (NumIterations - NumSuccesses) << endl;
return ( NumSuccesses == NumIterations);
} // TestConnections()
DWORD ReadFtpFile( IN HINTERNET hFtp, IN LPCSTR pszFileName, IN DWORD sTimeout) { HINTERNET hFtpFile; CHAR chBuffer[MAX_BUFFER_SIZE]; DWORD dwBytesRead = 0; DWORD dwError = NO_ERROR; BOOL fRead;
if ( hFtp == NULL) {
return ( ERROR_INVALID_PARAMETER); }
hFtpFile = FtpOpenFile( hFtp, pszFileName, GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, "\t\tFtpOpenFile(%s) ==> %08x\n", pszFileName, hFtpFile)); }
if ( hFtpFile == NULL) {
return ( GetLastError()); }
//===================================
//
// Start copying the file from the
// server to the client
//
//====================================
if ( sTimeout != 0) {
//
// sleep causes data time out to occur.
// If there is a non-zero timeout then we will have
// problems with data sockets timing out on server.
//
cout << " Requested " << pszFileName << " Sleeping for " << sTimeout << " seconds" << endl; Sleep( sTimeout * 1000); }
do {
dwError = NO_ERROR;
// read and discard the data.
fRead = InternetReadFile( hFtpFile, (LPVOID) chBuffer, (DWORD) MAX_BUFFER_SIZE, (LPDWORD) &dwBytesRead);
if ( !fRead) {
dwError = GetLastError(); DBGPRINTF(( DBG_CONTEXT, " InternetReadFile(%s) failed." " Error=%d\n", pszFileName, dwError)); }
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetReadFile(%08x, %s) ==> %d" " (Err=%d)\n", hFtpFile, pszFileName, fRead, dwError)); }
} while (fRead && dwBytesRead > 0);
//
// Close the handle for read file
//
if (!InternetCloseHandle(hFtpFile)) {
if ( dwError != NO_ERROR) {
DBGERROR(( DBG_CONTEXT, " Double Errors are occuring Old=%d\n", dwError)); }
dwError = ( GetLastError()); }
return ( dwError);
} // ReadFtpFile()
DWORD TestGetFileInOneThread(IN CHAR * pszServer, IN LPCSTR pszFileName, IN DWORD nIterations, IN DWORD sTimeout) { HINTERNET hinet; HINTERNET hFtp; DWORD NumSuccess = 0; CHAR rgchBuffer[300]; CHAR rgchUserName[100]; DWORD cbBuffer; DWORD dwError; DWORD iter; BOOL fReturn2;
hinet = InternetOpen( PSZ_APPLICATION_NAME, 0, NULL, 0, 0);
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, "InternetOpen()==> %08x\n", hinet)); }
if ( hinet == NULL) {
return (0); }
for( iter = 0 ; iter < nIterations; iter++) {
DWORD dwReadError = NO_ERROR;
IF_DEBUG( ITERATION) {
DBGPRINTF(( DBG_CONTEXT, "Iteration = %u\n", iter)); }
GenUserName( rgchUserName, "getFile", iter); hFtp = InternetConnect( hinet, pszServer, 0, "anonymous", rgchUserName, INTERNET_SERVICE_FTP, 0, NULL); IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetConnect()==> %08x\n", hFtp)); }
if ( hFtp == NULL) {
continue; }
dwReadError = ReadFtpFile( hFtp, pszFileName, sTimeout);
if ( dwReadError != NO_ERROR) {
cout << " Read File failed: Error = " << dwReadError << endl; }
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetGetLastResponse()\n")); }
cbBuffer = sizeof(rgchBuffer) - 1; if ( InternetGetLastResponseInfo( &dwError, rgchBuffer, &cbBuffer)) {
IF_DEBUG( RESPONSE) {
rgchBuffer[cbBuffer] = '\0'; cout << " ErrorCode = " << dwError << "\tResponse = " << rgchBuffer << endl; } }
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, " InternetCloseHandle(%08x)\n", hFtp)); }
if ( InternetCloseHandle(hFtp) && dwReadError == NO_ERROR) { NumSuccess++; } } // for()
IF_DEBUG( ENTRY) {
DBGPRINTF(( DBG_CONTEXT, "InternetCloseHandle(%08x)\n", hinet)); }
fReturn2 = InternetCloseHandle(hinet);
return ( NumSuccess);
} // TestGetFileInOneThread()
BOOL TestGetFile( int argc, char * argv[]) /*++
This function routinely establishes and throws away connections. It does not do any other work. This is used for testing logon and quit sequences of FTP server.
Arguments: argc count of arguments argv arguments argv[0] = "get" -- name of this test function argv[1] = # of thread to use for execution argv[2] = # of iterations for each thread. argv[3] = Name of file/path to get from server. (default = /readme.txt) argv[4] = Sleep time for enabling test of data transfer timeouts Units = seconds ( default = 0 ==> do not sleep).
--*/ { DWORD NumThreads = DEFAULT_NUMBER_OF_THREADS; DWORD NumIterations = DEFAULT_NUMBER_OF_ITERATIONS; DWORD NumSuccesses; LPSTR pszFileToGet = "/readme.txt"; DWORD sTimeout = 0; int i;
i = argc; // "i" is the running counter.
switch ( argc) {
case 5: --i; DBG_ASSERT( argv[i] != NULL); sTimeout = atoi(argv[i]);
// Fall Through
case 4: --i; DBG_ASSERT( argv[i] != NULL); pszFileToGet = argv[i];
// Fall Through
case 3: --i; DBG_ASSERT( argv[i] != NULL); NumIterations = atoi(argv[i]);
// Fall through
case 2: --i; DBG_ASSERT( argv[i] != NULL); NumThreads = atoi( argv[i]);
// Fall through
default: case 1: case 0: break; } // switch
// We will implement multithreading later on.
// for now just one thread is used. ( current thread)
NumSuccesses = TestGetFileInOneThread(g_lpszServerAddress, pszFileToGet, NumIterations, sTimeout);
cout << " Tested GetFile for Iterations: " << NumIterations << endl; cout << " Timeout for Sleep = " << sTimeout << " seconds" << endl; cout << " Successes = " << NumSuccesses; cout << " Failures = " << (NumIterations - NumSuccesses) << endl;
return ( NumSuccesses == NumIterations);
} // TestGetFile()
int __cdecl main( int argc, char * argv[]) {
DWORD err = NO_ERROR; char ** ppszArgv; // arguments for command functions
int cArgs; // arg count for command functions
char * pszCmdName; CmdStruct * pCmd; CMDFUNC pCmdFunc = NULL;
#ifndef _NO_TRACING_
CREATE_DEBUG_PRINT_OBJECT( "ftpstress", IisFtptestGuid); CREATE_INITIALIZE_DEBUG(); #else
CREATE_DEBUG_PRINT_OBJECT( "ftpstress"); SET_DEBUG_FLAGS( DEBUG_ITERATION); #endif
if ( argc < 3 || argv[1] == NULL ) {
// Insufficient arguments
GenUsageMessage( argc, argv); return ( 1); }
pszCmdName = argv[2]; if (( pCmd = DecodeCommand( pszCmdName)) == NULL || pCmd->cmdFunc == NULL) { printf( "Internal Error: Invalid Command %s\n", pszCmdName); GenUsageMessage( argc, argv); return ( 1); }
g_lpszServerAddress = argv[1]; // get server address
cArgs = argc - 2; ppszArgv = argv + 2;
if ( !(*pCmd->cmdFunc)( cArgs, ppszArgv)) { // call the test function
// Test function failed.
printf( "Command %s failed. Error = %d\n", pszCmdName, GetLastError()); return ( 1); }
printf( " Command %s succeeded\n", pszCmdName);
DELETE_DEBUG_PRINT_OBJECT();
return ( 0); // success
} // main()
/************************ End of File ***********************/
|