mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1707 lines
No EOL
40 KiB
C
1707 lines
No EOL
40 KiB
C
// GameSpy Presence and Messaging SDK Stress Test
|
|
// Dan "Mr. Pants" Schoenblum
|
|
// Copyright 2000 GameSpy Industries, Inc
|
|
|
|
/*************
|
|
** INCLUDES **
|
|
*************/
|
|
#include <limits.h>
|
|
#include "../gp.h"
|
|
#include "../../common/gsAvailable.h"
|
|
|
|
/************
|
|
** DEFINES **
|
|
************/
|
|
//#define CONNECTION_MANAGER "localhost"
|
|
|
|
#define PROFILES_MAX 10000
|
|
|
|
#define LOG_FILE "gpstress.log"
|
|
|
|
#define NEXT_OP_TIME_MIN 2000000
|
|
#define NEXT_OP_TIME_MAX 2000000
|
|
|
|
#define IS_INSTANT_OP(op) (((op) >= FIRST_INSTANT_OP) && ((op) <= LAST_INSTANT_OP))
|
|
|
|
#define CONNECT_TIME_MIN 20000
|
|
#define CONNECT_TIME_MAX 20000
|
|
|
|
#define SHUTDOWN_DISCONNECTS_PER_SEC 50
|
|
|
|
#define DEFAULT_RUN_TIME (2 * 60 * 60 * 1000)
|
|
#define DEFAULT_MAX_CONNECTED 100
|
|
|
|
#define SHOW_INFO_TIME 1000
|
|
|
|
#define DEFAULT_CONNECTS_PER_SEC 15
|
|
|
|
#define MAX_OTHERS 20
|
|
|
|
#define PRODUCT_ID_MAX 18
|
|
|
|
#define VALIDATION_MAX_NICKS 512
|
|
|
|
#define MAX_OUTSTANDING_CONNECTIONS 1
|
|
|
|
/**********
|
|
** TYPES **
|
|
**********/
|
|
#ifndef __cplusplus
|
|
typedef enum
|
|
{
|
|
false,
|
|
true
|
|
} bool;
|
|
#endif
|
|
|
|
typedef enum
|
|
{
|
|
// No active operation.
|
|
///////////////////////
|
|
OpNull = -1,
|
|
|
|
// These operations all take a ceratin amount of time.
|
|
//////////////////////////////////////////////////////
|
|
OpConnect,
|
|
OpNewProfile,
|
|
OpGetInfo,
|
|
#ifdef TEST_SEARCH
|
|
OpProfileSearch,
|
|
OpFindPlayers,
|
|
#endif
|
|
|
|
// These are all instant operations.
|
|
////////////////////////////////////
|
|
#define FIRST_INSTANT_OP OpSetInfo
|
|
OpSetInfo,
|
|
OpBuddyRequest,
|
|
OpDeleteBuddy,
|
|
OpSetStatus1, // Do setstatus 5x as often as other ops
|
|
OpSetStatus2,
|
|
OpSetStatus3,
|
|
OpSetStatus4,
|
|
OpSetStatus5,
|
|
OpSendBuddyMessage,
|
|
OpSetInvitable,
|
|
#define LAST_INSTANT_OP OpSetInvitable
|
|
|
|
// The number of possible operations.
|
|
/////////////////////////////////////
|
|
NumOps
|
|
} Op;
|
|
|
|
typedef struct
|
|
{
|
|
// The index of this profile in the list.
|
|
/////////////////////////////////////////
|
|
int index;
|
|
|
|
// Loaded profile info.
|
|
///////////////////////
|
|
int userID;
|
|
char email[GP_EMAIL_LEN];
|
|
char password[GP_PASSWORD_LEN];
|
|
int profileID;
|
|
char nick[GP_NICK_LEN];
|
|
bool invalid;
|
|
|
|
// GP stuff.
|
|
////////////
|
|
GPConnection gp; // The profile's GP object.
|
|
bool gpInitialized; // False until gpInitialize is called for this profile.
|
|
unsigned long disconnectTime; // Disconnect at this time.
|
|
GPProfile others[MAX_OTHERS]; // Remote profiles that this profile knows about.
|
|
int numOthers; // The number of others.
|
|
unsigned long connectTime; // When the connect attempt was made.
|
|
bool connected; // True when gpConnect finished successfully.
|
|
|
|
// Op data.
|
|
///////////
|
|
Op activeOp; // The active operation, OpNull between operations.
|
|
unsigned long nextOpTime; // At this time, pick a new random operation.
|
|
int completedOps; // Total number of operations completed.
|
|
} Profile;
|
|
|
|
typedef struct
|
|
{
|
|
GPResult result;
|
|
char nicks[VALIDATION_MAX_NICKS][GP_NICK_LEN];
|
|
int numNicks;
|
|
Profile * profile;
|
|
} ValidationData;
|
|
|
|
/************
|
|
** GLOBALS **
|
|
************/
|
|
char profilesFile[MAX_PATH]; // The file from which to load the profiles.
|
|
Profile profiles[PROFILES_MAX]; // All of the loaded profiles.
|
|
int numProfiles; // The number of loaded profiles.
|
|
int numConnections; // The number of profiles that are initialized/connected.
|
|
int maxConnections; // The maximum number of connected profiles.
|
|
int highestConnections; // The highest number of connections.
|
|
int totalConnections; // The total number of connections.
|
|
int numConnected; // The number of profiles that are actually logged in.
|
|
int highestConnected; // The highest simultaneous connected.
|
|
int totalConnected; // The total number connected over the entire run.
|
|
int connectsPerSecond; // Number of connection attempts per second.
|
|
unsigned long lastConnectTime; // The last time there was a connect.
|
|
unsigned long startShutdownTime; // When to start shutting down.
|
|
bool shuttingDown; // True if we're in the process of shutting down.
|
|
unsigned long runTime; // How long to run for.
|
|
|
|
/********************
|
|
** PROFILE LOADING **
|
|
********************/
|
|
// This warning needs to be fixed for this file
|
|
// Disabling for now
|
|
#pragma warning ( disable: 4702 )
|
|
#pragma warning ( disable: 4127 )
|
|
bool ReadField(FILE * fp, char * field)
|
|
{
|
|
char * str = field;
|
|
int c;
|
|
*str = '\0';
|
|
while(1)
|
|
{
|
|
// Get a char.
|
|
//////////////
|
|
c = fgetc(fp);
|
|
|
|
// Check for end of field.
|
|
//////////////////////////
|
|
if((c == ',') || (c == '\n') || (c == -1))
|
|
{
|
|
// Check for no chars read.
|
|
///////////////////////////
|
|
if(field == str)
|
|
return false;
|
|
|
|
// Cap it off and return.
|
|
/////////////////////////
|
|
*str = '\0';
|
|
return true;
|
|
}
|
|
|
|
*str++ = (char)c;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ReadProfile(FILE * fp, Profile * profile)
|
|
{
|
|
char intBuffer[16];
|
|
|
|
// Read the user id.
|
|
////////////////////
|
|
if(!ReadField(fp, intBuffer))
|
|
return false;
|
|
profile->userID = atoi(intBuffer);
|
|
assert(profile->userID);
|
|
|
|
// Read the email.
|
|
//////////////////
|
|
ReadField(fp, profile->email);
|
|
|
|
// Read the password.
|
|
/////////////////////
|
|
ReadField(fp, profile->password);
|
|
|
|
// Read the profile id.
|
|
///////////////////////
|
|
ReadField(fp, intBuffer);
|
|
profile->profileID = atoi(intBuffer);
|
|
assert(profile->profileID);
|
|
|
|
// Read the nick.
|
|
/////////////////
|
|
ReadField(fp, profile->nick);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LoadProfiles(void)
|
|
{
|
|
#if 0
|
|
FILE * fp;
|
|
|
|
// Open the file.
|
|
/////////////////
|
|
fp = fopen(profilesFile, "rt");
|
|
if(!fp)
|
|
{
|
|
printf("Failed to open the profiles file (%s)!\n", profilesFile);
|
|
return false;
|
|
}
|
|
|
|
// Read the profiles.
|
|
/////////////////////
|
|
while(ReadProfile(fp, &profiles[numProfiles]))
|
|
{
|
|
// One more.
|
|
////////////
|
|
numProfiles++;
|
|
|
|
// Check for too many.
|
|
//////////////////////
|
|
if(numProfiles == PROFILES_MAX)
|
|
{
|
|
printf("Too many profiles in the profile file!\nIncrease PROFILES_MAX (%d)\n", PROFILES_MAX);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Close the file.
|
|
//////////////////
|
|
fclose(fp);
|
|
|
|
printf("Loaded %d profiles from %s\n", numProfiles, profilesFile);
|
|
#else
|
|
int i;
|
|
|
|
for(i = 0 ; i < maxConnections ; i++)
|
|
{
|
|
strcpy(profiles[i].nick, "gpstress");
|
|
sprintf(profiles[i].email, "gpstress%04d@gamespy.com", i);
|
|
strcpy(profiles[i].password, "gpstress");
|
|
}
|
|
|
|
numProfiles = i;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
/*********************
|
|
** RANDOM FUNCTIONS **
|
|
**********************/
|
|
char RandomChar(void)
|
|
{
|
|
static const char characters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789!@#$%^&*()_+-=~`<,>.?/:;\"'{[}]|\\";
|
|
int index;
|
|
|
|
index = (rand() % (sizeof(characters) - 1));
|
|
|
|
return characters[index];
|
|
}
|
|
|
|
char * RandomString(char * buffer)
|
|
{
|
|
int i;
|
|
int len;
|
|
|
|
// Random length.
|
|
/////////////////
|
|
len = ((rand() % 10) + 5);
|
|
|
|
// Set random chars.
|
|
////////////////////
|
|
for(i = 0 ; i < len ; i++)
|
|
buffer[i] = RandomChar();
|
|
buffer[i] = '\0';
|
|
|
|
return buffer;
|
|
}
|
|
|
|
// min & max are inclusive.
|
|
///////////////////////////
|
|
int RandomInt(int min, int max)
|
|
{
|
|
int range = ((max - min) + 1);
|
|
return (min + ((rand() * range) / (RAND_MAX + 1)));
|
|
}
|
|
|
|
bool RandomBool(void)
|
|
{
|
|
return (bool)RandomInt(0, 1);
|
|
}
|
|
|
|
GPProfile RandomOther(Profile * profile)
|
|
{
|
|
int nIndex;
|
|
|
|
assert(profile->numOthers > 0);
|
|
|
|
nIndex = RandomInt(0, profile->numOthers - 1);
|
|
assert(nIndex >= 0);
|
|
assert(nIndex < profile->numOthers);
|
|
|
|
return profile->others[nIndex];
|
|
}
|
|
|
|
void RandomServer(void)
|
|
{
|
|
#if 0
|
|
strcpy(GPConnectionManagerHostname, "mrpants");
|
|
#else
|
|
static const char * servers[] =
|
|
{
|
|
#if 1
|
|
"mrpants",
|
|
"mrpants1"
|
|
#else
|
|
"aphexgp1",
|
|
"aphexgp2"
|
|
#endif
|
|
};
|
|
|
|
const char * server = servers[RandomInt(0, (sizeof(servers) / sizeof(*servers)) - 1)];
|
|
strcpy(GPConnectionManagerHostname, server);
|
|
#endif
|
|
}
|
|
|
|
/************
|
|
** GENERAL **
|
|
************/
|
|
void MessageOther(Profile * profile, GPProfile other)
|
|
{
|
|
#if 1
|
|
int pid;
|
|
|
|
// Filter out certain profiles.
|
|
///////////////////////////////
|
|
gpIDFromProfile(&profile->gp, other, &pid);
|
|
switch(pid)
|
|
{
|
|
case 100001: // Mr. Pants@dan@gamespy.com
|
|
case 100002: // walla@bryan@gamespy.com
|
|
case 100013: // lumberjack@jason@gamespy.com
|
|
return;
|
|
}
|
|
|
|
gpSendBuddyMessage(&profile->gp, other, "STRESS-TEST");
|
|
#endif
|
|
}
|
|
|
|
void Log(const char * buffer)
|
|
{
|
|
FILE * fp;
|
|
|
|
static char timeBuffer[64];
|
|
time_t thetime;
|
|
struct tm *ltime;
|
|
time(&thetime);
|
|
ltime = localtime(&thetime);
|
|
sprintf(timeBuffer, "%-2.2d/%-2.2d/%-2.2d %-2.2d:%-2.2d:%-2.2d: ", ltime->tm_mon+1, ltime->tm_mday, ltime->tm_year % 100, ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
|
|
|
|
fp = fopen(LOG_FILE, "at");
|
|
if(fp)
|
|
{
|
|
fprintf(fp, "%s%s", timeBuffer, buffer);
|
|
fclose(fp);
|
|
}
|
|
|
|
OutputDebugString(timeBuffer);
|
|
OutputDebugString(buffer);
|
|
|
|
printf("%s%s", timeBuffer, buffer);
|
|
}
|
|
|
|
/************************
|
|
** GP GLOBAL CALLBACKS **
|
|
************************/
|
|
void GetInfoCallback(GPConnection * connnection, GPGetInfoResponseArg * arg, Profile * profile);
|
|
void AddOther(Profile * profile, GPProfile gpProfile);
|
|
void PrintOp(Profile * profile, const char * opString);
|
|
|
|
void ErrorCallback(GPConnection * connection, GPErrorArg * arg, Profile * profile)
|
|
{
|
|
char * errorCodeString;
|
|
char * resultString;
|
|
static char buffer[4098];
|
|
|
|
// Ignore errors that we're expecting to generate (due to randomness).
|
|
//////////////////////////////////////////////////////////////////////
|
|
switch(arg->errorCode)
|
|
{
|
|
case GP_ADDBUDDY_ALREADY_BUDDY:
|
|
case GP_BM_NOT_BUDDY:
|
|
return;
|
|
}
|
|
|
|
// Get a string for the result.
|
|
///////////////////////////////
|
|
#define RESULT(x) case x: resultString = #x; break;
|
|
switch(arg->result)
|
|
{
|
|
RESULT(GP_NO_ERROR)
|
|
RESULT(GP_MEMORY_ERROR)
|
|
RESULT(GP_PARAMETER_ERROR)
|
|
RESULT(GP_NETWORK_ERROR)
|
|
RESULT(GP_SERVER_ERROR)
|
|
default:
|
|
resultString = "Unknown result!\n";
|
|
}
|
|
|
|
// Get a string for the error code.
|
|
///////////////////////////////////
|
|
#define ERRORCODE(x) case x: errorCodeString = #x; break;
|
|
switch(arg->errorCode)
|
|
{
|
|
ERRORCODE(GP_GENERAL)
|
|
ERRORCODE(GP_PARSE)
|
|
ERRORCODE(GP_NOT_LOGGED_IN)
|
|
ERRORCODE(GP_BAD_SESSKEY)
|
|
ERRORCODE(GP_DATABASE)
|
|
ERRORCODE(GP_NETWORK)
|
|
ERRORCODE(GP_FORCED_DISCONNECT)
|
|
ERRORCODE(GP_CONNECTION_CLOSED)
|
|
ERRORCODE(GP_LOGIN)
|
|
ERRORCODE(GP_LOGIN_TIMEOUT)
|
|
ERRORCODE(GP_LOGIN_BAD_NICK)
|
|
ERRORCODE(GP_LOGIN_BAD_EMAIL)
|
|
ERRORCODE(GP_LOGIN_BAD_PASSWORD)
|
|
ERRORCODE(GP_LOGIN_BAD_PROFILE)
|
|
ERRORCODE(GP_LOGIN_PROFILE_DELETED)
|
|
ERRORCODE(GP_LOGIN_CONNECTION_FAILED)
|
|
ERRORCODE(GP_LOGIN_SERVER_AUTH_FAILED)
|
|
ERRORCODE(GP_LOGIN_BAD_UNIQUENICK)
|
|
ERRORCODE(GP_LOGIN_BAD_PREAUTH)
|
|
ERRORCODE(GP_NEWUSER)
|
|
ERRORCODE(GP_NEWUSER_BAD_NICK)
|
|
ERRORCODE(GP_NEWUSER_BAD_PASSWORD)
|
|
ERRORCODE(GP_NEWUSER_UNIQUENICK_INVALID)
|
|
ERRORCODE(GP_NEWUSER_UNIQUENICK_INUSE)
|
|
ERRORCODE(GP_UPDATEUI)
|
|
ERRORCODE(GP_UPDATEUI_BAD_EMAIL)
|
|
ERRORCODE(GP_NEWPROFILE)
|
|
ERRORCODE(GP_NEWPROFILE_BAD_NICK)
|
|
ERRORCODE(GP_NEWPROFILE_BAD_OLD_NICK)
|
|
ERRORCODE(GP_UPDATEPRO)
|
|
ERRORCODE(GP_UPDATEPRO_BAD_NICK)
|
|
ERRORCODE(GP_ADDBUDDY)
|
|
ERRORCODE(GP_ADDBUDDY_BAD_FROM)
|
|
ERRORCODE(GP_ADDBUDDY_BAD_NEW)
|
|
ERRORCODE(GP_ADDBUDDY_ALREADY_BUDDY)
|
|
ERRORCODE(GP_AUTHADD)
|
|
ERRORCODE(GP_AUTHADD_BAD_FROM)
|
|
ERRORCODE(GP_AUTHADD_BAD_SIG)
|
|
ERRORCODE(GP_STATUS)
|
|
ERRORCODE(GP_BM)
|
|
ERRORCODE(GP_BM_NOT_BUDDY)
|
|
ERRORCODE(GP_GETPROFILE)
|
|
ERRORCODE(GP_GETPROFILE_BAD_PROFILE)
|
|
ERRORCODE(GP_DELBUDDY)
|
|
ERRORCODE(GP_DELBUDDY_NOT_BUDDY)
|
|
ERRORCODE(GP_DELPROFILE)
|
|
ERRORCODE(GP_DELPROFILE_LAST_PROFILE)
|
|
ERRORCODE(GP_SEARCH)
|
|
ERRORCODE(GP_SEARCH_CONNECTION_FAILED)
|
|
ERRORCODE(GP_CHECK)
|
|
ERRORCODE(GP_CHECK_BAD_EMAIL)
|
|
ERRORCODE(GP_CHECK_BAD_NICK)
|
|
ERRORCODE(GP_CHECK_BAD_PASSWORD)
|
|
ERRORCODE(GP_REVOKE)
|
|
ERRORCODE(GP_REVOKE_NOT_BUDDY)
|
|
ERRORCODE(GP_REGISTERUNIQUENICK)
|
|
ERRORCODE(GP_REGISTERUNIQUENICK_TAKEN)
|
|
ERRORCODE(GP_REGISTERUNIQUENICK_RESERVED)
|
|
ERRORCODE(GP_REGISTERUNIQUENICK_BAD_NAMESPACE)
|
|
default:
|
|
errorCodeString = "Unknown error code!\n";
|
|
}
|
|
|
|
// Print out the info.
|
|
//////////////////////
|
|
if(arg->fatal)
|
|
sprintf(buffer, "%04d: FATAL ERROR", profile->index);
|
|
else
|
|
sprintf(buffer, "%04d: ERROR", profile->index);
|
|
sprintf(buffer + strlen(buffer), ", RESULT: %s (%d)", resultString, arg->result);
|
|
sprintf(buffer + strlen(buffer), ", ERROR CODE: %s (0x%X)", errorCodeString, arg->errorCode);
|
|
sprintf(buffer + strlen(buffer), ", ERROR STRING: %s\n", arg->errorString);
|
|
Log(buffer);
|
|
|
|
// Disconnect.
|
|
//////////////
|
|
profile->disconnectTime = 0;
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void RecvBuddyStatusCallback(GPConnection * connection, GPRecvBuddyStatusArg * arg, Profile * profile)
|
|
{
|
|
PrintOp(profile, "RecvBuddyStatusCallback");
|
|
|
|
#if 1
|
|
// Get info half the time.
|
|
//////////////////////////
|
|
if(RandomBool())
|
|
gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
|
|
// Send a message sometimes.
|
|
////////////////////////////
|
|
if(RandomInt(0, 9) == 0)
|
|
MessageOther(profile, arg->profile);
|
|
|
|
// Add the other.
|
|
/////////////////
|
|
AddOther(profile, arg->profile);
|
|
#endif
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
#if 1
|
|
void RecvBuddyRequestCallback(GPConnection * connection, GPRecvBuddyRequestArg * arg, Profile * profile)
|
|
{
|
|
PrintOp(profile, "RecvBuddyRequestCallback");
|
|
|
|
// Get info half the time.
|
|
//////////////////////////
|
|
if(RandomBool())
|
|
gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
|
|
// Accept it half the time.
|
|
///////////////////////////
|
|
if(RandomBool())
|
|
gpAuthBuddyRequest(&profile->gp, arg->profile);
|
|
|
|
// Add the other.
|
|
/////////////////
|
|
AddOther(profile, arg->profile);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void RecvBuddyMessageCallback(GPConnection * connection, GPRecvBuddyMessageArg * arg, Profile * profile)
|
|
{
|
|
PrintOp(profile, "RecvBuddyMessageCallback");
|
|
|
|
// Get info half the time.
|
|
//////////////////////////
|
|
if(RandomBool())
|
|
gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
|
|
// Reply sometimes.
|
|
///////////////////
|
|
if(RandomInt(0, 9) == 0)
|
|
MessageOther(profile, arg->profile);
|
|
|
|
// Add the other.
|
|
/////////////////
|
|
AddOther(profile, arg->profile);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void RecvGameInviteCallback(GPConnection * connection, GPRecvGameInviteArg * arg, Profile * profile)
|
|
{
|
|
PrintOp(profile, "RecvGameInviteCallback");
|
|
|
|
// Get info half the time.
|
|
//////////////////////////
|
|
if(RandomBool())
|
|
gpGetInfo(&profile->gp, arg->profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
|
|
// Send a message sometimes.
|
|
////////////////////////////
|
|
if(RandomInt(0, 9) == 0)
|
|
MessageOther(profile, arg->profile);
|
|
|
|
// Add the other.
|
|
/////////////////
|
|
AddOther(profile, arg->profile);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
#endif
|
|
|
|
/********************
|
|
** GP OP CALLBACKS **
|
|
********************/
|
|
void EndOp(Profile * profile);
|
|
|
|
const int RemoteAuthProfiles[] =
|
|
{
|
|
58214083,
|
|
58214074,
|
|
58214075,
|
|
58214076,
|
|
58214077,
|
|
58214078,
|
|
58214079,
|
|
58214080,
|
|
58214081,
|
|
58214082
|
|
};
|
|
|
|
void ConnectCallback(GPConnection * connection, GPConnectResponseArg * arg, Profile * profile)
|
|
{
|
|
if(arg->result == GP_NO_ERROR)
|
|
{
|
|
// Finished connecting.
|
|
///////////////////////
|
|
profile->connected = true;
|
|
numConnected++;
|
|
totalConnected++;
|
|
highestConnected = max(numConnected, highestConnected);
|
|
|
|
if(arg->profile != RemoteAuthProfiles[profile->index % 10])
|
|
{
|
|
char buffer[4096];
|
|
gsi_time ms = (current_time() - profile->connectTime);
|
|
sprintf(buffer, "%d: XXX Connection ProfileID Error (%d != %d) [%d]: %d.%03ds\n", totalConnected, arg->profile, RemoteAuthProfiles[profile->index % 10], (profile->index % 10), ms / 1000, ms % 1000);
|
|
Log(buffer);
|
|
}
|
|
|
|
#if 1
|
|
// log the connection
|
|
{
|
|
char buffer[256];
|
|
gsi_time ms = (current_time() - profile->connectTime);
|
|
sprintf(buffer, "%sConnected: %d time: %d.%03ds\n", (ms>=1000)?"XX ":"", totalConnected, ms / 1000, ms % 1000);
|
|
Log(buffer);
|
|
}
|
|
#endif
|
|
|
|
#if 1
|
|
// always disconnect right away
|
|
profile->disconnectTime = 0;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if 1
|
|
// log the error
|
|
{
|
|
char buffer[4096];
|
|
gsi_time ms = (current_time() - profile->connectTime);
|
|
sprintf(buffer, "%d: XXX Connection Failed [%d]: %d.%03ds\n", totalConnected, (profile->index % 10), ms / 1000, ms % 1000);
|
|
Log(buffer);
|
|
}
|
|
#endif
|
|
// Disconnect this profile.
|
|
///////////////////////////
|
|
profile->disconnectTime = 0;
|
|
}
|
|
|
|
// End the op.
|
|
//////////////
|
|
EndOp(profile);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void GetInfoCallback(GPConnection * connection, GPGetInfoResponseArg * arg, Profile * profile)
|
|
{
|
|
if(arg->result != GP_NO_ERROR)
|
|
{
|
|
printf("%04d: gpGetInfo failed\n", profile->index);
|
|
return;
|
|
}
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void FindPlayersCallback(GPConnection * connection, GPFindPlayersResponseArg * arg, Profile * profile)
|
|
{
|
|
int i;
|
|
|
|
if(arg->result != GP_NO_ERROR)
|
|
{
|
|
printf("%04d: gpFindPlayers failed\n", profile->index);
|
|
return;
|
|
}
|
|
|
|
// Get all of their info.
|
|
/////////////////////////
|
|
for(i = 0 ; i < arg->numMatches ; i++)
|
|
gpGetInfo(&profile->gp, arg->matches[i].profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
|
|
// Invite someone.
|
|
//////////////////
|
|
if(arg->numMatches > 0)
|
|
{
|
|
int index = RandomInt(0, arg->numMatches - 1);
|
|
int productID = RandomInt(1, PRODUCT_ID_MAX);
|
|
|
|
gpInvitePlayer(&profile->gp, arg->matches[index].profile, productID,NULL);
|
|
}
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void ProfileSearchCallback(GPConnection * connection, GPProfileSearchResponseArg * arg, Profile * profile)
|
|
{
|
|
int i;
|
|
|
|
if(arg->result != GP_NO_ERROR)
|
|
{
|
|
printf("%04d: gpProfileSearch failed\n", profile->index);
|
|
return;
|
|
}
|
|
|
|
// Get all of their info.
|
|
/////////////////////////
|
|
for(i = 0 ; i < arg->numMatches ; i++)
|
|
gpGetInfo(&profile->gp, arg->matches[i].profile, GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
/*****************
|
|
** OP FUNCTIONS **
|
|
*****************/
|
|
void AddOther(Profile * profile, GPProfile gpProfile)
|
|
{
|
|
int i;
|
|
|
|
// Check for full.
|
|
//////////////////
|
|
if(profile->numOthers == MAX_OTHERS)
|
|
return;
|
|
|
|
// Check if we already have this one.
|
|
/////////////////////////////////////
|
|
for(i = 0 ; i < profile->numOthers ; i++)
|
|
if(profile->others[i] == gpProfile)
|
|
return;
|
|
|
|
// Add it.
|
|
//////////
|
|
profile->others[profile->numOthers] = gpProfile;
|
|
profile->numOthers++;
|
|
}
|
|
|
|
unsigned long GetRandomOpTime(void)
|
|
{
|
|
// Between NEXT_OP_TIME_MIN and NEXT_OP_TIME_MAX.
|
|
/////////////////////////////////////////////////
|
|
return RandomInt(NEXT_OP_TIME_MIN, NEXT_OP_TIME_MAX);
|
|
}
|
|
|
|
Op GetRandomOp(void)
|
|
{
|
|
// Between 1 (skip OpConnect) and (NumOps - 1).
|
|
///////////////////////////////////////////////
|
|
Op op = (Op)(((rand() * (NumOps - 1)) / (RAND_MAX + 1)) + 1);
|
|
|
|
assert(op > OpConnect);
|
|
assert(op < NumOps);
|
|
|
|
return op;
|
|
}
|
|
|
|
void NewOp(Profile * profile)
|
|
{
|
|
// Is this the first op?
|
|
////////////////////////
|
|
if(profile->completedOps == 0)
|
|
{
|
|
// The first op is always connect.
|
|
//////////////////////////////////
|
|
profile->activeOp = OpConnect;
|
|
}
|
|
else
|
|
{
|
|
#if 1
|
|
// Pick a random op.
|
|
////////////////////
|
|
profile->activeOp = GetRandomOp();
|
|
#else
|
|
// Always do status.
|
|
////////////////////
|
|
profile->activeOp = OpSetStatus1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void EndOp(Profile * profile)
|
|
{
|
|
// No active op.
|
|
////////////////
|
|
profile->activeOp = OpNull;
|
|
|
|
// Set the next op time.
|
|
////////////////////////
|
|
profile->nextOpTime = (current_time() + GetRandomOpTime());
|
|
|
|
// One more op completed.
|
|
/////////////////////////
|
|
profile->completedOps++;
|
|
}
|
|
|
|
void PrintOp(Profile * profile, const char * opString)
|
|
{
|
|
#if 0
|
|
static char buffer[256];
|
|
sprintf(buffer, "%04d: %s\n", profile->index, opString);
|
|
OutputDebugString(buffer);
|
|
#endif
|
|
GSI_UNUSED(profile);
|
|
GSI_UNUSED(opString);
|
|
}
|
|
|
|
void StartOp(Profile * profile)
|
|
{
|
|
int i;
|
|
int num;
|
|
int intArray[16];
|
|
char string1[16];
|
|
char string2[16];
|
|
|
|
// Handle based on op.
|
|
//////////////////////
|
|
switch(profile->activeOp)
|
|
{
|
|
case OpNull:
|
|
assert(0);
|
|
printf("%04d: Tried to start null op\n", profile->index);
|
|
break;
|
|
|
|
case OpConnect:
|
|
PrintOp(profile, "OpConnect");
|
|
|
|
// Start the connect.
|
|
/////////////////////
|
|
#if 0
|
|
RandomServer();
|
|
#endif
|
|
#if 0
|
|
gpConnect(&profile->gp, profile->nick, profile->email, profile->password, (RandomInt(0, 9) == 0)?GP_FIREWALL:GP_NO_FIREWALL, GP_NON_BLOCKING, ConnectCallback, profile);
|
|
#else
|
|
{
|
|
const char * authtokens[] =
|
|
{
|
|
"GMT/61LHe4Yu+pHI0eDXu8GMdc51iXjsNvcz1GGoWJ9orpnbZIbp3CVBQddeSZOSq58",
|
|
"GMTcUM+iiQuzaw8crHxBFPCVV6J9V14KnSNHnHbQIXGwN6XpKv97yqSbOqxrgIWZCeZ",
|
|
"GMTxiKFKsnGdOeBaJxmJOQBNSqbm9zOjbu/cTiqpBJp1pqqOAnI1Jh81TPlWmFuvt0h",
|
|
"GMTqUg6QEerwnwi87fZQMcfzQ0xA/zNC96VCtx6GavTv7wzDtGpOWxJHUkm20qMxVsg",
|
|
"GMTV2uHalvcDgtvBsz62QF1ifbCJJ93QONO9TNGVGlDghs6ocL2qOiQVqNJS7LvTZ39",
|
|
"GMTq9Z7Tg/tkEMzqEODuQdNSQPgt5MdAwH26+lQGHliL9n3nH0b0D38fTFWRbkmk4K9",
|
|
"GMTwHyinDuomW0XmQswNyVpgdlQvnuGCR1it+kHCnUDmR5CG3svSufrDcjuHdlwfVON",
|
|
"GMTBZgPikENuiEON0by04RMR112ShZsDctzVbqljZ3ZufDvyugygztRlKIM9gyLwSdy",
|
|
"GMTmHNpmNufV9WuGIGET8E0Xd//56eYWO4mDaD+4KebWQWvc8CqWbqSeII6x9BxQMxQ",
|
|
"GMTyI447fNIYVh1vdI6aErka4TzJcYWctTU/Dzi2GK+4J3Vf/VAqQOs43R73I7dyX+u"
|
|
};
|
|
const char * partnerchallenges[] =
|
|
{
|
|
"WI[A)IuA",
|
|
"RNd$)q)0",
|
|
"LQTi;4#X",
|
|
"AOA)(57=",
|
|
"ob=0XiWJ",
|
|
"mRnTENJ@",
|
|
"9%@A+NKA",
|
|
"L=0O)Lg2",
|
|
"YR6[Zz%B",
|
|
"$kWZ%]~@"
|
|
};
|
|
int tokenIndex = (profile->index % 10);
|
|
gpConnectPreAuthenticated(&profile->gp, authtokens[tokenIndex], partnerchallenges[tokenIndex], GP_FIREWALL, GP_NON_BLOCKING, ConnectCallback, profile);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case OpNewProfile:
|
|
PrintOp(profile, "OpNewProfile");
|
|
|
|
// Pretend this op didn't happen, another will be picked next frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
profile->activeOp = OpNull;
|
|
break;
|
|
|
|
case OpGetInfo:
|
|
PrintOp(profile, "OpGetInfo");
|
|
|
|
// Do we know of any other profiles?
|
|
////////////////////////////////////
|
|
if(profile->numOthers > 0)
|
|
gpGetInfo(&profile->gp, RandomOther(profile), GP_DONT_CHECK_CACHE, GP_NON_BLOCKING, GetInfoCallback, profile);
|
|
else
|
|
profile->activeOp = OpNull;
|
|
break;
|
|
|
|
#ifdef TEST_SEARCH
|
|
case OpProfileSearch:
|
|
PrintOp(profile, "OpProfileSearch");
|
|
|
|
// Do a search.
|
|
///////////////
|
|
num = RandomInt(0, 3);
|
|
if(num == 0)
|
|
gpProfileSearch(&profile->gp, "pants", "dan@gamespy.com", NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile);
|
|
else if(num == 1)
|
|
gpProfileSearch(&profile->gp, "crt", NULL, NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile);
|
|
else
|
|
gpProfileSearch(&profile->gp, "STRESS-TEST", NULL, NULL, NULL, 0, GP_NON_BLOCKING, ProfileSearchCallback, profile);
|
|
break;
|
|
|
|
case OpFindPlayers:
|
|
PrintOp(profile, "OpFindPlayers");
|
|
|
|
// Find some players.
|
|
/////////////////////
|
|
gpFindPlayers(&profile->gp, RandomInt(1, PRODUCT_ID_MAX), GP_NON_BLOCKING, FindPlayersCallback, profile);
|
|
break;
|
|
#endif
|
|
|
|
case OpSetInfo:
|
|
PrintOp(profile, "OpSetInfo");
|
|
|
|
// Set some random info.
|
|
////////////////////////
|
|
gpSetInfos(&profile->gp, GP_FIRSTNAME, "STRESS-TEST");
|
|
gpSetInfos(&profile->gp, GP_LASTNAME, "STRESS-TEST");
|
|
gpSetInfoi(&profile->gp, GP_ICQUIN, RandomInt(100000, 40000000));
|
|
gpSetInfos(&profile->gp, GP_HOMEPAGE, "STRESS-TEST");
|
|
gpSetInfod(&profile->gp, GP_BIRTHDAY, RandomInt(1, 28), RandomInt(1, 12), RandomInt(1940, 1990));
|
|
break;
|
|
|
|
case OpBuddyRequest:
|
|
PrintOp(profile, "OpBuddyRequest");
|
|
|
|
#if 1
|
|
// Pretend this op didn't happen, another will be picked next frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
profile->activeOp = OpNull;
|
|
#else
|
|
// Send someone a buddy request.
|
|
////////////////////////////////
|
|
if(profile->numOthers > 0)
|
|
gpSendBuddyRequest(&profile->gp, RandomOther(profile), "STRESS-TEST");
|
|
#endif
|
|
break;
|
|
|
|
case OpDeleteBuddy:
|
|
PrintOp(profile, "OpDeleteBuddy");
|
|
|
|
// Pretend this op didn't happen, another will be picked next frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
profile->activeOp = OpNull;
|
|
break;
|
|
|
|
case OpSetStatus1:
|
|
case OpSetStatus2:
|
|
case OpSetStatus3:
|
|
case OpSetStatus4:
|
|
case OpSetStatus5:
|
|
PrintOp(profile, "OpSetStatus");
|
|
|
|
// Set the status to some random stuff.
|
|
///////////////////////////////////////
|
|
gpSetStatus(&profile->gp, GP_ONLINE, RandomString(string1), RandomString(string2));
|
|
break;
|
|
|
|
case OpSendBuddyMessage:
|
|
PrintOp(profile, "OpSendBuddyMessage");
|
|
|
|
// Send someone a message.
|
|
/////////////////////////
|
|
if(profile->numOthers > 0)
|
|
MessageOther(profile, RandomOther(profile));
|
|
break;
|
|
|
|
case OpSetInvitable:
|
|
PrintOp(profile, "OpSetInvitable");
|
|
|
|
// Get the num games.
|
|
/////////////////////
|
|
num = RandomInt(0, 10);
|
|
|
|
// Get the product ids.
|
|
///////////////////////
|
|
for(i = 0 ; i < num ; i++)
|
|
intArray[i] = RandomInt(1, PRODUCT_ID_MAX);
|
|
|
|
// Set the games.
|
|
/////////////////
|
|
gpSetInvitableGames(&profile->gp, num, intArray);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
printf("%04d: Tried to start unknown op: %d\n", profile->index, profile->activeOp);
|
|
break;
|
|
}
|
|
|
|
// Was this an instant op?
|
|
//////////////////////////
|
|
if(IS_INSTANT_OP(profile->activeOp))
|
|
{
|
|
// End it.
|
|
//////////
|
|
EndOp(profile);
|
|
}
|
|
}
|
|
|
|
/**********************
|
|
** PROFILE FUNCTIONS **
|
|
**********************/
|
|
void ProcessProfile(Profile * profile)
|
|
{
|
|
DWORD now = current_time();
|
|
|
|
// Is GP initialized?
|
|
/////////////////////
|
|
if(profile->gpInitialized)
|
|
{
|
|
// Do GP processing.
|
|
////////////////////
|
|
gpProcess(&profile->gp);
|
|
|
|
// Has a connection attempt been going for 2 minutes?
|
|
/////////////////////////////////////////////////////
|
|
if((profile->activeOp == OpConnect) && ((current_time() - profile->connectTime) > (200 * 60 * 1000)))
|
|
{
|
|
char buffer[256];
|
|
gsi_time ms = (current_time() - profile->connectTime);
|
|
sprintf(buffer, "%04d: XXX Excessive Connect Time: %d.%03ds\n", profile->index, ms / 1000, ms % 1000);
|
|
Log(buffer);
|
|
}
|
|
|
|
// Check for disconnect.
|
|
////////////////////////
|
|
if((now > profile->disconnectTime) && ((profile->activeOp != OpConnect) || shuttingDown))
|
|
{
|
|
// Cleanup GP for this profile.
|
|
///////////////////////////////
|
|
if(profile->connected)
|
|
{
|
|
numConnected--;
|
|
gpDisconnect(&profile->gp);
|
|
}
|
|
gpDestroy(&profile->gp);
|
|
|
|
// We're no longer initialized/connected.
|
|
/////////////////////////////////////////
|
|
profile->gpInitialized = false;
|
|
numConnections--;
|
|
}
|
|
// Is there no active op?
|
|
/////////////////////////
|
|
else if(!shuttingDown && (profile->activeOp == OpNull))
|
|
{
|
|
// Is it time for a new op?
|
|
///////////////////////////
|
|
#if 1
|
|
if(now > profile->nextOpTime)
|
|
#else
|
|
if((now > profile->nextOpTime) && (profile->completedOps == 0))
|
|
#endif
|
|
{
|
|
// Select a new op.
|
|
///////////////////
|
|
NewOp(profile);
|
|
|
|
// Start the op.
|
|
////////////////
|
|
StartOp(profile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Profile * GetUninitializedProfile(void)
|
|
{
|
|
int index;
|
|
|
|
// Loop until we get an uninitialized (and valid) profile.
|
|
//////////////////////////////////////////////////////////
|
|
do
|
|
{
|
|
// Get an index between 0 and (numProfiles - 1).
|
|
////////////////////////////////////////////////
|
|
index = ((rand() * numProfiles) / (RAND_MAX + 1));
|
|
assert(index >= 0);
|
|
assert(index < numProfiles);
|
|
}
|
|
while(profiles[index].gpInitialized || profiles[index].invalid);
|
|
|
|
return &profiles[index];
|
|
}
|
|
|
|
void InitializeProfile(Profile * profile)
|
|
{
|
|
GPResult result;
|
|
|
|
// Init the profile's GP object.
|
|
////////////////////////////////
|
|
result = gpInitialize(&profile->gp, 0, 0, GP_PARTNERID_GAMESPY);
|
|
if(result != GP_NO_ERROR)
|
|
{
|
|
printf("%04d: Failed to initialize GP for %s@%s\n", profile->index, profile->nick, profile->email);
|
|
return;
|
|
}
|
|
|
|
// Set the GP global callbacks.
|
|
///////////////////////////////
|
|
gpSetCallback(&profile->gp, GP_ERROR, ErrorCallback, profile);
|
|
gpSetCallback(&profile->gp, GP_RECV_BUDDY_STATUS, RecvBuddyStatusCallback, profile);
|
|
#if 1
|
|
gpSetCallback(&profile->gp, GP_RECV_BUDDY_REQUEST, RecvBuddyRequestCallback, profile);
|
|
gpSetCallback(&profile->gp, GP_RECV_BUDDY_MESSAGE, RecvBuddyMessageCallback, profile);
|
|
gpSetCallback(&profile->gp, GP_RECV_GAME_INVITE, RecvGameInviteCallback, profile);
|
|
#endif
|
|
|
|
// We're initialized.
|
|
/////////////////////
|
|
profile->gpInitialized = true;
|
|
|
|
// Not connected yet.
|
|
/////////////////////
|
|
profile->connected = false;
|
|
|
|
// Remember when we tried to connect.
|
|
/////////////////////////////////////
|
|
profile->connectTime = current_time();
|
|
|
|
// Haven't checked yet.
|
|
///////////////////////
|
|
profile->invalid = false;
|
|
|
|
// When to disconnect.
|
|
//////////////////////
|
|
profile->disconnectTime = current_time();
|
|
profile->disconnectTime += (((rand() * (CONNECT_TIME_MAX - CONNECT_TIME_MIN)) / RAND_MAX) + CONNECT_TIME_MIN);
|
|
|
|
// No others yet.
|
|
/////////////////
|
|
profile->numOthers = 0;
|
|
|
|
// Op stuff.
|
|
////////////
|
|
profile->activeOp = OpNull;
|
|
profile->nextOpTime = 0;
|
|
profile->completedOps = 0;
|
|
|
|
// It's a connection, but we're not connected.
|
|
//////////////////////////////////////////////
|
|
numConnections++;
|
|
totalConnections++;
|
|
highestConnections = max(highestConnections, numConnections);
|
|
}
|
|
|
|
/***************
|
|
** VALIDATION **
|
|
***************/
|
|
void GetUserNicksCallback(GPConnection * connection, GPGetUserNicksResponseArg * arg, ValidationData * validationData)
|
|
{
|
|
int i;
|
|
|
|
// Copy the result.
|
|
///////////////////
|
|
validationData->result = arg->result;
|
|
|
|
// Check for error.
|
|
///////////////////
|
|
if(arg->result != GP_NO_ERROR)
|
|
{
|
|
printf("%04d: gpGetUserNicks failed\n", validationData->profile->index);
|
|
return;
|
|
}
|
|
|
|
// Copy the nicks.
|
|
//////////////////
|
|
validationData->numNicks = min(arg->numNicks, VALIDATION_MAX_NICKS);
|
|
for(i = 0 ; i < arg->numNicks ; i++)
|
|
strcpy(validationData->nicks[i], arg->nicks[i]);
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void NewUserResponse(GPConnection * connection, GPNewUserResponseArg * arg, void * param)
|
|
{
|
|
GSI_UNUSED(connection);
|
|
GSI_UNUSED(arg);
|
|
GSI_UNUSED(param);
|
|
}
|
|
|
|
bool Validate(void)
|
|
{
|
|
int i;
|
|
GPConnection gp;
|
|
char email[GP_EMAIL_LEN] = "";
|
|
Profile * profile;
|
|
ValidationData validationData;
|
|
|
|
validationData.profile = NULL;
|
|
validationData.result = GP_NO_ERROR;
|
|
validationData.numNicks = 0;
|
|
// Set this here so ctrl-c can cancel the validation.
|
|
/////////////////////////////////////////////////////
|
|
startShutdownTime = ULONG_MAX;
|
|
|
|
// Init GP.
|
|
///////////
|
|
if(gpInitialize(&gp, 0, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR)
|
|
{
|
|
printf("Failed to initialize GP for validation\n");
|
|
return false;
|
|
}
|
|
/*
|
|
for(i = 41 ; i <= 1000 ; i++)
|
|
{
|
|
sprintf(email, "gpstress%04d@gamespy.com", i);
|
|
gpNewUser(&gp, "gpstress", email, "gpstress", GP_BLOCKING, NewUserResponse, NULL);
|
|
printf("%d\n", i);
|
|
}
|
|
*/
|
|
// Loop through all the profiles.
|
|
/////////////////////////////////
|
|
for(i = 0 ; i < numProfiles ; i++)
|
|
{
|
|
// Check for shutdown.
|
|
//////////////////////
|
|
if(current_time() > startShutdownTime)
|
|
return false;
|
|
|
|
// Cache the profile.
|
|
/////////////////////
|
|
profile = &profiles[i];
|
|
|
|
// Is the e-mail address different than the previous one?
|
|
/////////////////////////////////////////////////////////
|
|
if(strcmp(email, profile->email) != 0)
|
|
{
|
|
// Copy the e-mail.
|
|
///////////////////
|
|
strcpy(email, profile->email);
|
|
|
|
// Put the profile in the validation struct.
|
|
////////////////////////////////////////////
|
|
validationData.profile = profile;
|
|
|
|
// Show what we're doing.
|
|
/////////////////////////
|
|
printf("%04d: Getting nicks for: %s\n", profile->index, email);
|
|
|
|
// Get the nicks for this e-mail.
|
|
/////////////////////////////////
|
|
gpGetUserNicks(&gp, email, profile->password, GP_BLOCKING, GetUserNicksCallback, &validationData);
|
|
}
|
|
|
|
// Only do this if the validation succeeded.
|
|
////////////////////////////////////////////
|
|
if(validationData.result == GP_NO_ERROR)
|
|
{
|
|
int n;
|
|
bool match = false;
|
|
|
|
// Loop through the nicks.
|
|
//////////////////////////
|
|
for(n = 0 ; (n < validationData.numNicks) && !match ; n++)
|
|
{
|
|
// Does this nick match the one being validated?
|
|
////////////////////////////////////////////////
|
|
if(strcasecmp(profile->nick, validationData.nicks[n]) == 0)
|
|
match = true;
|
|
}
|
|
|
|
// Set invalid based on match.
|
|
//////////////////////////////
|
|
profile->invalid = !match;
|
|
}
|
|
else
|
|
{
|
|
// Probably invalid e-mail.
|
|
///////////////////////////
|
|
profile->invalid = true;
|
|
}
|
|
|
|
// Show if we got something invalid.
|
|
////////////////////////////////////
|
|
if(profile->invalid)
|
|
{
|
|
static char buffer[256];
|
|
sprintf(buffer, "%s (%d) : %04d: Invalid profile (%s@%s)\n", profilesFile, (profile->index + 1), profile->index, profile->nick, profile->email);
|
|
printf(buffer);
|
|
OutputDebugString(buffer);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*******************
|
|
** MAIN FUNCTIONS **
|
|
*******************/
|
|
#ifdef WIN32
|
|
BOOL WINAPI CtrlHandlerRoutine(DWORD dwCtrlType)
|
|
{
|
|
// Start shutting down soon.
|
|
////////////////////////////
|
|
startShutdownTime = 0;
|
|
|
|
GSI_UNUSED(dwCtrlType);
|
|
// Handled.
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
bool Initialize(void)
|
|
{
|
|
int i;
|
|
Profile * profile;
|
|
DWORD now;
|
|
GSIACResult aResult = GSIACWaiting;
|
|
|
|
// Seed the random number generator.
|
|
////////////////////////////////////
|
|
srand(time(NULL));
|
|
|
|
// Perform the availability check
|
|
GSIStartAvailableCheck("gmtest");
|
|
while(aResult == GSIACWaiting)
|
|
aResult = GSIAvailableCheckThink();
|
|
if (aResult != GSIACAvailable)
|
|
{
|
|
printf("Backend services are not available.\r\n");
|
|
return false;
|
|
}
|
|
|
|
|
|
#ifdef WIN32
|
|
// Set the ctrl-c handler.
|
|
//////////////////////////
|
|
SetConsoleCtrlHandler(CtrlHandlerRoutine, TRUE);
|
|
#endif
|
|
|
|
// Set our own hostname.
|
|
////////////////////////
|
|
#ifdef CONNECTION_MANAGER
|
|
if(CONNECTION_MANAGER[0])
|
|
strcpy(GPConnectionManagerHostname, CONNECTION_MANAGER);
|
|
#endif
|
|
|
|
// Load the profiles.
|
|
/////////////////////
|
|
if(!LoadProfiles())
|
|
return false;
|
|
|
|
// Cap off the max connected profiles.
|
|
//////////////////////////////////////
|
|
if(maxConnections > numProfiles)
|
|
maxConnections = numProfiles;
|
|
|
|
// Get the current time.
|
|
////////////////////////
|
|
now = current_time();
|
|
|
|
// Initalize profile stuff.
|
|
///////////////////////////
|
|
for(i = 0 ; i < numProfiles ; i++)
|
|
{
|
|
// Cache the profile pointer.
|
|
/////////////////////////////.
|
|
profile = &profiles[i];
|
|
|
|
// Set its index.
|
|
/////////////////
|
|
profile->index = i;
|
|
|
|
// No op yet.
|
|
/////////////
|
|
profile->activeOp = OpNull;
|
|
|
|
// Print out a message every 100.
|
|
/////////////////////////////////
|
|
#if 0
|
|
if(((i + 1) % 100) == 0)
|
|
{
|
|
printf("%d/%d profiles initialized\n", i + 1, numProfiles);
|
|
msleep(1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Shutdown(void)
|
|
{
|
|
int i;
|
|
|
|
// Cleanup all the GP objects.
|
|
//////////////////////////////
|
|
for(i = 0 ; i < numProfiles ; i++)
|
|
{
|
|
// Check if GP was intialized.
|
|
//////////////////////////////
|
|
if(profiles[i].gpInitialized)
|
|
{
|
|
// Destroy the GP object.
|
|
/////////////////////////
|
|
gpDestroy(&profiles[i].gp);
|
|
|
|
// Print out a message every 100.
|
|
/////////////////////////////////
|
|
if(((i + 1) % 100) == 0)
|
|
{
|
|
printf("%d/%d profiles destroyed\n", i + 1, numProfiles);
|
|
msleep(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StartShutdown(unsigned long now)
|
|
{
|
|
Profile * profile;
|
|
int i;
|
|
|
|
// Loop through all the profiles.
|
|
/////////////////////////////////
|
|
for(i = 0 ; i < numProfiles ; i++)
|
|
{
|
|
// Cache the profile pointer.
|
|
/////////////////////////////
|
|
profile = &profiles[i];
|
|
|
|
// Check if its GP object is initialized.
|
|
/////////////////////////////////////////
|
|
if(profile->gpInitialized)
|
|
{
|
|
#if 0
|
|
// Is it not actually connected yet?
|
|
////////////////////////////////////
|
|
if(!profile->connected)
|
|
{
|
|
char buffer[64];
|
|
|
|
// How long has it been waiting?
|
|
////////////////////////////////
|
|
sprintf(buffer, "%04d: Waiting %ds for connection attempt\n", profile->index, (current_time() - profile->connectTime) / 1000);
|
|
Log(buffer);
|
|
}
|
|
#endif
|
|
|
|
// Set when to disconnect,
|
|
//////////////////////////
|
|
profile->disconnectTime = (now + ((rand() * ((numConnections / SHUTDOWN_DISCONNECTS_PER_SEC) * 1000)) / RAND_MAX));
|
|
}
|
|
}
|
|
|
|
// We're shutting down, don't add new connections, etc.
|
|
///////////////////////////////////////////////////////
|
|
shuttingDown = true;
|
|
}
|
|
|
|
void Frame(unsigned long now)
|
|
{
|
|
int i;
|
|
|
|
// Is it time to connect a new profile?
|
|
///////////////////////////////////////
|
|
if(!shuttingDown && (numConnections < maxConnections) && ((numConnections - numConnected) < MAX_OUTSTANDING_CONNECTIONS))
|
|
{
|
|
Profile * profile;
|
|
unsigned long timeDiff;
|
|
int numConnects;
|
|
|
|
// How long since the last connect?
|
|
///////////////////////////////////
|
|
timeDiff = (now - lastConnectTime);
|
|
|
|
// How many connects should we do?
|
|
//////////////////////////////////
|
|
numConnects = ((timeDiff * connectsPerSecond) / 1000);
|
|
numConnects = min(numConnects, (MAX_OUTSTANDING_CONNECTIONS - (numConnections - numConnected)));
|
|
|
|
// Do the connects.
|
|
///////////////////
|
|
for(i = 0 ; i < numConnects ; i++)
|
|
{
|
|
// Need to check because it can change in the loop.
|
|
///////////////////////////////////////////////////
|
|
if(numConnections < maxConnections)
|
|
{
|
|
// Pick a random profile.
|
|
/////////////////////////
|
|
profile = GetUninitializedProfile();
|
|
|
|
// Init it.
|
|
///////////
|
|
InitializeProfile(profile);
|
|
|
|
// Remember when we did the connect(s).
|
|
///////////////////////////////////////
|
|
lastConnectTime = now;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop through all the profiles.
|
|
/////////////////////////////////
|
|
for(i = 0 ; i < numProfiles ; i++)
|
|
{
|
|
// Process the profile.
|
|
///////////////////////
|
|
ProcessProfile(&profiles[i]);
|
|
}
|
|
}
|
|
|
|
void Run(void)
|
|
{
|
|
bool done;
|
|
unsigned long now;
|
|
#if 0
|
|
unsigned long nextInfoTime = 0;
|
|
#endif
|
|
// Get the current time.
|
|
////////////////////////
|
|
now = current_time();
|
|
|
|
// Set when to shut down.
|
|
/////////////////////////
|
|
startShutdownTime = (now + runTime);
|
|
|
|
// Make up the last connect time.
|
|
/////////////////////////////////
|
|
lastConnectTime = (now - 100);
|
|
|
|
// Loop until we're done.
|
|
/////////////////////////
|
|
for(done = false ; !done ; )
|
|
{
|
|
// Get the current time.
|
|
////////////////////////
|
|
now = current_time();
|
|
|
|
// Are we shutting down?
|
|
////////////////////////
|
|
if(shuttingDown)
|
|
{
|
|
// Are we done?
|
|
///////////////
|
|
if(numConnections == 0)
|
|
{
|
|
done = true;
|
|
}
|
|
}
|
|
else if(now > startShutdownTime)
|
|
{
|
|
// Time to start shutting down.
|
|
///////////////////////////////
|
|
StartShutdown(now);
|
|
}
|
|
|
|
#if 0
|
|
// Is it time to print some info?
|
|
/////////////////////////////////
|
|
if(now > nextInfoTime)
|
|
{
|
|
static char buffer[256];
|
|
|
|
// Set when to next show info.
|
|
//////////////////////////////
|
|
nextInfoTime = (now + SHOW_INFO_TIME);
|
|
|
|
// Show the connection numbers.
|
|
///////////////////////////////
|
|
sprintf(buffer, "INFO: Connections: %d current, %d highest, %d total\n", numConnections, highestConnections, totalConnections);
|
|
Log(buffer);
|
|
|
|
// Show the connected numbers.
|
|
//////////////////////////////
|
|
sprintf(buffer, "INFO: Connected: %d current, %d highest, %d total\n", numConnected, highestConnected, totalConnected);
|
|
Log(buffer);
|
|
|
|
// Show that we're shutting down, or when we're shutting down.
|
|
//////////////////////////////////////////////////////////////
|
|
if(shuttingDown)
|
|
sprintf(buffer, "INFO: Shutting down\n");
|
|
else
|
|
{
|
|
unsigned long totalSeconds = ((startShutdownTime - now) / 1000);
|
|
unsigned long hours, minutes, seconds;
|
|
seconds = (totalSeconds % 60);
|
|
minutes = (totalSeconds / 60 % 60);
|
|
hours = (totalSeconds / 60 / 60);
|
|
sprintf(buffer, "INFO: Shut down in %d:%02d:%02d\n", hours, minutes, seconds);
|
|
}
|
|
Log(buffer);
|
|
}
|
|
#endif
|
|
|
|
// Run a frame.
|
|
///////////////
|
|
Frame(now);
|
|
|
|
// Take a break.
|
|
////////////////
|
|
msleep(10);
|
|
}
|
|
}
|
|
|
|
bool ParseArgs(int argc, char ** argv)
|
|
{
|
|
int i;
|
|
/*
|
|
// Check for the file index.
|
|
////////////////////////////
|
|
if(argc < 2)
|
|
{
|
|
printf("Usage: %s <index 0-9>\n", argv[0]);
|
|
return false;
|
|
}
|
|
sprintf(profilesFile, "stress%d.txt", atoi(argv[1]));
|
|
*/
|
|
// Set defaults.
|
|
////////////////
|
|
maxConnections = DEFAULT_MAX_CONNECTED;
|
|
runTime = DEFAULT_RUN_TIME;
|
|
connectsPerSecond = DEFAULT_CONNECTS_PER_SEC;
|
|
|
|
// Check args.
|
|
//////////////
|
|
for(i = 1 ; i < argc ; i++)
|
|
{
|
|
// Check for max connected profiles.
|
|
////////////////////////////////////
|
|
if(strcasecmp(argv[i], "-m") == 0)
|
|
{
|
|
if(++i < argc)
|
|
{
|
|
maxConnections = atoi(argv[i]);
|
|
if(maxConnections <= 0)
|
|
maxConnections = DEFAULT_MAX_CONNECTED;
|
|
}
|
|
}
|
|
// Check for how long to run.
|
|
/////////////////////////////
|
|
else if(strcasecmp(argv[i], "-t") == 0)
|
|
{
|
|
if(++i < argc)
|
|
{
|
|
runTime = (atoi(argv[i]) * 1000);
|
|
if(runTime <= 0)
|
|
runTime = DEFAULT_RUN_TIME;
|
|
}
|
|
}
|
|
// Check for connections per second.
|
|
////////////////////////////////////
|
|
else if(strcasecmp(argv[i], "-s") == 0)
|
|
{
|
|
if(++i < argc)
|
|
{
|
|
connectsPerSecond = atoi(argv[i]);
|
|
if(connectsPerSecond <= 0)
|
|
connectsPerSecond = DEFAULT_CONNECTS_PER_SEC;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int main(int argc, char ** argv)
|
|
{
|
|
// Parse args.
|
|
//////////////
|
|
if(!ParseArgs(argc, argv))
|
|
return 1;
|
|
|
|
// Initialize.
|
|
//////////////
|
|
if(!Initialize())
|
|
return 1;
|
|
|
|
#if 0
|
|
// Validate the loaded profiles.
|
|
////////////////////////////////
|
|
if(!Validate())
|
|
return 1;
|
|
#endif
|
|
|
|
// Do all that stuff.
|
|
/////////////////////
|
|
Run();
|
|
|
|
// Cleanup.
|
|
///////////
|
|
Shutdown();
|
|
|
|
return 0;
|
|
} |