Another gamedata cleanup sponsored by an r=pred (bug 3351).

This commit is contained in:
David Anderson 2008-12-26 23:26:21 -05:00
parent cb41fa6de4
commit 4daca3c5ba
6 changed files with 231 additions and 212 deletions

View File

@ -44,6 +44,7 @@
#define INVALID_SOCKET -1 #define INVALID_SOCKET -1
#define closesocket close #define closesocket close
#define WSAGetLastError() errno
#endif #endif
#include "sh_vector.h" #include "sh_vector.h"
@ -61,6 +62,7 @@
#include "TimerSys.h" #include "TimerSys.h"
#include "compat_wrappers.h" #include "compat_wrappers.h"
#include "sm_stringutil.h" #include "sm_stringutil.h"
#include "md5.h"
#define QUERY_MAX_LENGTH 1024 #define QUERY_MAX_LENGTH 1024
@ -73,9 +75,9 @@ bool g_disableGameDataUpdate = false;
bool g_restartAfterUpdate = false; bool g_restartAfterUpdate = false;
int g_serverPort = 6500; int g_serverPort = 6500;
char g_serverAddress[100] = "hayate.alliedmods.net"; char g_serverAddress[100] = "smupdate.alliedmods.net";
void FetcherThread::RunThread( IThreadHandle *pHandle ) void FetcherThread::RunThread(IThreadHandle *pHandle)
{ {
char lock_path[PLATFORM_MAX_PATH]; char lock_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp"); g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
@ -127,9 +129,7 @@ void FetcherThread::RunThread( IThreadHandle *pHandle )
if (g_disableGameDataUpdate) if (g_disableGameDataUpdate)
{ {
#ifdef DEBUG
g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true"); g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true");
#endif
fclose(logfile); fclose(logfile);
unlink(lock_path); unlink(lock_path);
@ -148,13 +148,15 @@ void FetcherThread::RunThread( IThreadHandle *pHandle )
int sent = SendData(socketDescriptor, query, len); int sent = SendData(socketDescriptor, query, len);
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Sent Query!"); g_Logger.LogToOpenFile(logfile, "Sent gamedata query");
#endif ENDIF_DEBUG_SPEW
if (sent == 0) if (sent == 0)
{ {
IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Failed to send gamedata query data to remote host"); g_Logger.LogToOpenFile(logfile, "Failed to send gamedata query data to remote host");
ENDIF_DEBUG_SPEW
closesocket(socketDescriptor); closesocket(socketDescriptor);
fclose(logfile); fclose(logfile);
@ -170,12 +172,12 @@ void FetcherThread::RunThread( IThreadHandle *pHandle )
unlink(lock_path); unlink(lock_path);
} }
void FetcherThread::OnTerminate( IThreadHandle *pHandle, bool cancel ) void FetcherThread::OnTerminate(IThreadHandle *pHandle, bool cancel)
{ {
g_blockGameDataLoad = false; g_blockGameDataLoad = false;
} }
int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen ) int FetcherThread::BuildGameDataQuery(char *buffer, int maxlen)
{ {
char gamedata_path[PLATFORM_MAX_PATH]; char gamedata_path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata"); g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
@ -204,41 +206,39 @@ int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
{ {
const char *name = dir->GetEntryName(); const char *name = dir->GetEntryName();
size_t len = strlen(name); size_t len = strlen(name);
if (len >= 4 if (len >= 4 && strcmp(&name[len-4], ".txt") == 0)
&& strcmp(&name[len-4], ".txt") == 0)
{ {
MD5 md5;
SMCError err;
SMCStates states;
unsigned char raw[16];
char file[PLATFORM_MAX_PATH]; char file[PLATFORM_MAX_PATH];
g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name); g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
SMCStates states; g_MD5Builder.checksum = &md5;
if (g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states) == SMCError_Okay) if ((err = g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states)) == SMCError_Okay)
{
unsigned char *md5 = g_MD5Builder.GetMD5();
if (md5 != NULL)
{ {
md5.raw_digest(raw);
(uint8_t)buffer[10]++; //Increment the file counter (uint8_t)buffer[10]++; //Increment the file counter
Writer.WriteBytes(md5, 16); Writer.WriteBytes(raw, 16);
g_Logger.LogToOpenFile(logfile, "%s - \"%s\"", file, g_MD5Builder.GetMD5String());
FileData *data = new FileData(); FileData *data = new FileData();
data->filename = new SourceHook::String(file); data->filename = new SourceHook::String(file);
memcpy(data->checksum, g_MD5Builder.GetMD5String(), 33); md5.hex_digest(data->checksum);
filenames.push_back(data); filenames.push_back(data);
IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Parsed file: %s as %s", file, data->checksum);
ENDIF_DEBUG_SPEW
} }
else else
{ {
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "%s no md5?", file); const char *error = g_TextParser.GetSMCErrorString(err);
#endif g_Logger.LogToOpenFile(logfile, "Parsing of file %s failed: %s", file, error);
} ENDIF_DEBUG_SPEW
}
else
{
#ifdef DEBUG
g_Logger.LogToOpenFile(logfile, "%s failed!", file);
#endif
} }
} }
} }
@ -251,17 +251,16 @@ int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
int FetcherThread::ConnectSocket() int FetcherThread::ConnectSocket()
{ {
struct protoent *ptrp; #if defined PLATFORM_WINDOWS
ptrp = getprotobyname("tcp");
#ifdef WIN32
WSADATA wsaData; WSADATA wsaData;
WSAStartup(0x0101, &wsaData); WSAStartup(0x0101, &wsaData);
#endif #endif
if (ptrp == NULL) struct protoent *ptrp;
if ((ptrp = getprotobyname("tcp")) == NULL)
{ {
g_Logger.LogToOpenFile(logfile, "Failed to find TCP"); g_Logger.LogToOpenFile(logfile, "Error: Failed to find TCP protocol");
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -269,12 +268,9 @@ int FetcherThread::ConnectSocket()
if (socketDescriptor == INVALID_SOCKET) if (socketDescriptor == INVALID_SOCKET)
{ {
//bugger aye? char error[255];
#ifdef WIN32 g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
g_Logger.LogToOpenFile(logfile, "Failed to create a new socket - Error %i", WSAGetLastError()); g_Logger.LogToOpenFile(logfile, "Error: Failed to create socket: %s", error);
#else
g_Logger.LogToOpenFile(logfile, "Failed to create a new socket - Error %i", errno);
#endif
closesocket(socketDescriptor); closesocket(socketDescriptor);
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -291,7 +287,7 @@ int FetcherThread::ConnectSocket()
{ {
if ((local_addr.sin_addr.s_addr = inet_addr(g_serverAddress)) == INADDR_NONE) if ((local_addr.sin_addr.s_addr = inet_addr(g_serverAddress)) == INADDR_NONE)
{ {
g_Logger.LogToOpenFile(logfile, "Couldn't locate address"); g_Logger.LogToOpenFile(logfile, "Couldn't locate address: %s", g_serverAddress);
closesocket(socketDescriptor); closesocket(socketDescriptor);
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -303,11 +299,9 @@ int FetcherThread::ConnectSocket()
if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
{ {
#ifdef WIN32 char error[255];
g_Logger.LogToOpenFile(logfile, "Couldn't connect - Error %i", WSAGetLastError()); g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
#else g_Logger.LogToOpenFile(logfile, "Couldn't connect to %s: %s", g_serverAddress, error);
g_Logger.LogToOpenFile(logfile, "Couldn't connect - Error %i", errno);
#endif
closesocket(socketDescriptor); closesocket(socketDescriptor);
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -318,35 +312,34 @@ int FetcherThread::ConnectSocket()
void FetcherThread::ProcessGameDataQuery(int socketDescriptor) void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
{ {
char buffer[50]; char buffer[50];
#ifdef DEBUG
IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Waiting for reply!"); g_Logger.LogToOpenFile(logfile, "Waiting for reply!");
#endif ENDIF_DEBUG_SPEW
//Read in the header bytes //Read in the header bytes
int returnLen = RecvData(socketDescriptor, buffer, 12); int returnLen = RecvData(socketDescriptor, buffer, 12);
#ifdef DEBUG
g_Logger.LogToOpenFile(logfile, "Recv Completed");
#endif
if (returnLen == 0) if (returnLen == 0)
{ {
#ifdef DEBUG char error[255];
g_Logger.LogToOpenFile(logfile, ",but it failed."); g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
#endif g_Logger.LogToOpenFile(logfile, "Did not receive reply: %s", error);
/* Timeout or fail? */
return; return;
} }
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Received Header!"); g_Logger.LogToOpenFile(logfile, "Received Header!");
#endif ENDIF_DEBUG_SPEW
bf_read Reader = bf_read("GameDataQuery", buffer, 12); bf_read Reader = bf_read("GameDataQuery", buffer, 12);
if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G') if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
{ {
IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Unknown Query Response"); g_Logger.LogToOpenFile(logfile, "Unknown Query Response");
ENDIF_DEBUG_SPEW
return; return;
} }
@ -359,17 +352,23 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
build[2] = Reader.ReadShort(); build[2] = Reader.ReadShort();
build[3] = Reader.ReadShort(); build[3] = Reader.ReadShort();
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Update Status: %i - Latest %i.%i.%i.%i", updateStatus, build[0], build[1], build[2], build[3]); g_Logger.LogToOpenFile(logfile,
#endif "Update Status: %i - Latest %i.%i.%i.%i",
updateStatus,
build[0],
build[1],
build[2],
build[3]);
ENDIF_DEBUG_SPEW
HandleUpdateStatus(updateStatus, build); HandleUpdateStatus(updateStatus, build);
int changedFiles = Reader.ReadByte(); int changedFiles = Reader.ReadByte();
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles); g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles);
#endif ENDIF_DEBUG_SPEW
for (int i=0; i<changedFiles; i++) for (int i=0; i<changedFiles; i++)
{ {
@ -387,9 +386,9 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
int index = Reader.ReadByte(); int index = Reader.ReadByte();
int tempLen = Reader.ReadUBitLong(32); int tempLen = Reader.ReadUBitLong(32);
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen); g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen);
#endif ENDIF_DEBUG_SPEW
void *memPtr; void *memPtr;
memtable->CreateMem(tempLen+1, &memPtr); memtable->CreateMem(tempLen+1, &memPtr);
@ -397,9 +396,9 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
//Read the contents of our file into the memtable //Read the contents of our file into the memtable
returnLen = RecvData(socketDescriptor, (char *)memPtr, tempLen); returnLen = RecvData(socketDescriptor, (char *)memPtr, tempLen);
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Recieved %i bytes", returnLen); g_Logger.LogToOpenFile(logfile, "Received %i bytes", returnLen);
#endif ENDIF_DEBUG_SPEW
if (returnLen == 0) if (returnLen == 0)
{ {
@ -410,7 +409,7 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
((unsigned char *)memPtr)[tempLen] = '\0'; ((unsigned char *)memPtr)[tempLen] = '\0';
FileData *data = filenames.at(index); FileData *data = filenames.at(index);
const char* filename; const char *filename;
if (data != NULL) if (data != NULL)
{ {
filename = data->filename->c_str(); filename = data->filename->c_str();
@ -419,12 +418,12 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
if (fp) if (fp)
{ {
fprintf(fp, (const char *)memPtr); fprintf(fp, "%s", (const char *)memPtr);
fclose(fp); fclose(fp);
} }
else else
{ {
g_Logger.LogToOpenFile(logfile, "Failed to open file \"%s\"", filename); g_Logger.LogToOpenFile(logfile, "Failed to open file \"%s\" for writing", filename);
} }
} }
else else
@ -434,14 +433,13 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
memtable->Reset(); memtable->Reset();
#ifdef DEBUG
g_Logger.LogToOpenFile(logfile, "Updated File %s", filename); g_Logger.LogToOpenFile(logfile, "Updated file: %s", filename);
#endif
} }
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "File Downloads Completed!"); g_Logger.LogToOpenFile(logfile, "File Downloads Completed!");
#endif ENDIF_DEBUG_SPEW
bool needsRestart = false; bool needsRestart = false;
@ -456,8 +454,9 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
if (returnLen == 0) if (returnLen == 0)
{ {
/* Timeout or fail? */ char error[255];
g_Logger.LogToOpenFile(logfile, "Failed to receive unknown count"); g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
g_Logger.LogToOpenFile(logfile, "Did not receive count reply: %s", error);
return; return;
} }
@ -465,28 +464,27 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
changedFiles = Reader.ReadByte(); changedFiles = Reader.ReadByte();
if (changedFiles == 0) if (changedFiles < 1)
{ {
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done"); g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done");
#endif ENDIF_DEBUG_SPEW
return; return;
} }
char *changedFileIndexes = new char[changedFiles]; char *changedFileIndexes = new char[changedFiles];
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles); g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles);
#endif ENDIF_DEBUG_SPEW
returnLen = RecvData(socketDescriptor, changedFileIndexes, changedFiles); returnLen = RecvData(socketDescriptor, changedFileIndexes, changedFiles);
if (returnLen == 0) if (returnLen == 0)
{ {
/* Timeout or fail? */ char error[255];
#ifdef DEBUG g_LibSys.GetPlatformErrorEx(WSAGetLastError(), error, sizeof(error));
g_Logger.LogToOpenFile(logfile, "Failed to receive unknown list"); g_Logger.LogToOpenFile(logfile, "Did not receive list reply: %s", error);
#endif
return; return;
} }
@ -509,21 +507,22 @@ void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
} }
g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname); g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
#ifdef DEBUG IF_DEBUG_SPEW
g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName); g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName);
#endif ENDIF_DEBUG_SPEW
} }
delete [] changedFileIndexes; delete [] changedFileIndexes;
if (needsRestart && g_restartAfterUpdate) if (needsRestart && g_restartAfterUpdate)
{ {
/* :TODO: none of this is thread safe. */
g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!"); g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!");
engine->ServerCommand("quit\n"); engine->ServerCommand("quit\n");
} }
} }
int FetcherThread::RecvData( int socketDescriptor, char *buffer, int len ) int FetcherThread::RecvData(int socketDescriptor, char *buffer, int len)
{ {
fd_set fds; fd_set fds;
struct timeval tv; struct timeval tv;
@ -562,7 +561,7 @@ int FetcherThread::RecvData( int socketDescriptor, char *buffer, int len )
return bytesReceivedTotal; return bytesReceivedTotal;
} }
int FetcherThread::SendData( int socketDescriptor, char *buffer, int len ) int FetcherThread::SendData(int socketDescriptor, char *buffer, int len)
{ {
fd_set fds; fd_set fds;
struct timeval tv; struct timeval tv;
@ -597,7 +596,7 @@ int FetcherThread::SendData( int socketDescriptor, char *buffer, int len )
return sentBytesTotal; return sentBytesTotal;
} }
void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] ) void FetcherThread::HandleUpdateStatus(UpdateStatus status, short version[4])
{ {
switch (status) switch (status)
{ {
@ -609,14 +608,12 @@ void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
case Update_NewBuild: case Update_NewBuild:
{ {
g_Logger.LogMessage("SourceMod Update: A new Mercurial build is available from sourcemod.net");
g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
break; break;
} }
case Update_MinorAvailable: case Update_MinorAvailable:
{ {
g_Logger.LogMessage("SourceMod Update: An incremental minor release of SourceMod is now available from sourcemod.net"); g_Logger.LogMessage("SourceMod Update: A new release of SourceMod is now available from sourcemod.net");
g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]); g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
break; break;
} }
@ -630,8 +627,8 @@ void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
case Update_CriticalAvailable: case Update_CriticalAvailable:
{ {
g_Logger.LogError("SourceMod Update: A new critical release of SourceMod is now available from sourcemod.net. It is strongly recommended that you update"); g_Logger.LogError("SourceMod Update: A critical SourceMod release is available from sourcemod.net. It is strongly recommended that you update!");
g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]); g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
break; break;
} }
} }
@ -665,14 +662,14 @@ public:
char *error, char *error,
size_t maxlength) size_t maxlength)
{ {
if (strcmp(key, "DisableAutoUpdate") == 0) if (strcasecmp(key, "DisableAutoUpdate") == 0)
{ {
if (strcmp(value, "yes") == 0) if (strcasecmp(value, "yes") == 0)
{ {
g_disableGameDataUpdate = true; g_disableGameDataUpdate = true;
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(value, "no") == 0) else if (strcasecmp(value, "no") == 0)
{ {
g_disableGameDataUpdate = false; g_disableGameDataUpdate = false;
return ConfigResult_Accept; return ConfigResult_Accept;
@ -681,14 +678,14 @@ public:
return ConfigResult_Reject; return ConfigResult_Reject;
} }
if (strcmp(key, "ForceRestartAfterUpdate") == 0) if (strcasecmp(key, "ForceRestartAfterUpdate") == 0)
{ {
if (strcmp(value, "yes") == 0) if (strcasecmp(value, "yes") == 0)
{ {
g_restartAfterUpdate = true; g_restartAfterUpdate = true;
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcmp(value, "no") == 0) else if (strcasecmp(value, "no") == 0)
{ {
g_restartAfterUpdate = false; g_restartAfterUpdate = false;
return ConfigResult_Accept; return ConfigResult_Accept;
@ -697,14 +694,14 @@ public:
return ConfigResult_Reject; return ConfigResult_Reject;
} }
if (strcmp(key, "AutoUpdateServer") == 0) if (strcasecmp(key, "AutoUpdateServer") == 0)
{ {
UTIL_Format(g_serverAddress, sizeof(g_serverAddress), "%s", value); UTIL_Format(g_serverAddress, sizeof(g_serverAddress), "%s", value);
return ConfigResult_Accept; return ConfigResult_Accept;
} }
if (strcmp(key, "AutoUpdatePort") == 0) if (strcasecmp(key, "AutoUpdatePort") == 0)
{ {
int port = atoi(value); int port = atoi(value);
@ -722,6 +719,55 @@ public:
} }
} g_InitFetch; } g_InitFetch;
BuildMD5ableBuffer::BuildMD5ableBuffer()
{
stringTable = new BaseStringTable(2048);
}
BuildMD5ableBuffer::~BuildMD5ableBuffer()
{
delete stringTable;
}
void BuildMD5ableBuffer::ReadSMC_ParseStart()
{
stringTable->Reset();
}
SMCResult BuildMD5ableBuffer::ReadSMC_KeyValue(const SMCStates *states,
const char *key,
const char *value)
{
stringTable->AddString(key);
stringTable->AddString(value);
return SMCResult_Continue;
}
SMCResult BuildMD5ableBuffer::ReadSMC_NewSection(const SMCStates *states, const char *name)
{
stringTable->AddString(name);
return SMCResult_Continue;
}
void BuildMD5ableBuffer::ReadSMC_ParseEnd(bool halted, bool failed)
{
if (halted || failed)
{
return;
}
void *data = stringTable->GetMemTable()->GetAddress(0);
if (data != NULL)
{
checksum->update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed());
}
checksum->finalize();
}
CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file") CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
{ {
#if !defined ORANGEBOX_BUILD #if !defined ORANGEBOX_BUILD
@ -764,3 +810,25 @@ CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
g_SMAPI->ConPrint("File not found!\n"); g_SMAPI->ConPrint("File not found!\n");
} }
FetcherThread::~FetcherThread()
{
//delete filenames;
SourceHook::CVector<FileData *>::iterator iter = filenames.begin();
FileData *curData;
while (iter != filenames.end())
{
curData = (*iter);
delete curData->filename;
delete curData;
iter = filenames.erase(iter);
}
}
FetcherThread::FetcherThread()
{
memtable = new BaseMemTable(4096);
}

View File

@ -38,7 +38,6 @@
#include "Logger.h" #include "Logger.h"
#include "LibrarySys.h" #include "LibrarySys.h"
#include "ThreadSupport.h" #include "ThreadSupport.h"
#include "md5.h"
#include "sm_memtable.h" #include "sm_memtable.h"
enum UpdateStatus enum UpdateStatus
@ -51,127 +50,44 @@ enum UpdateStatus
Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */ Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */
}; };
class MD5;
class BuildMD5ableBuffer : public ITextListener_SMC class BuildMD5ableBuffer : public ITextListener_SMC
{ {
public: public:
BuildMD5ableBuffer();
BuildMD5ableBuffer() ~BuildMD5ableBuffer();
{ void ReadSMC_ParseStart();
stringTable = new BaseStringTable(2048); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
md5[0] = 0; SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
md5String[0] = 0; void ReadSMC_ParseEnd(bool halted, bool failed);
} public:
MD5 *checksum;
~BuildMD5ableBuffer()
{
delete stringTable;
}
void ReadSMC_ParseStart()
{
checksum = MD5();
}
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
{
stringTable->AddString(key);
stringTable->AddString(value);
return SMCResult_Continue;
}
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
{
stringTable->AddString(name);
return SMCResult_Continue;
}
void ReadSMC_ParseEnd(bool halted, bool failed)
{
if (halted || failed)
{
return;
}
void *data = stringTable->GetMemTable()->GetAddress(0);
if (data != NULL)
{
checksum.update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed());
}
checksum.finalize();
checksum.hex_digest(md5String);
checksum.raw_digest(md5);
stringTable->Reset();
}
unsigned char * GetMD5()
{
return md5;
}
unsigned char * GetMD5String()
{
return (unsigned char *)&md5String[0];
}
private: private:
MD5 checksum;
unsigned char md5[16];
char md5String[33];
BaseStringTable *stringTable; BaseStringTable *stringTable;
}; };
struct FileData struct FileData
{ {
SourceHook::String *filename; SourceHook::String *filename;
unsigned char checksum[33]; char checksum[33];
}; };
class FetcherThread : public IThread class FetcherThread : public IThread
{ {
public: public:
FetcherThread() FetcherThread();
{ ~FetcherThread();
//filenames = new BaseStringTable(200); public:
memtable = new BaseMemTable(4096);
}
~FetcherThread()
{
//delete filenames;
SourceHook::CVector<FileData *>::iterator iter = filenames.begin();
FileData *curData;
while (iter != filenames.end())
{
curData = (*iter);
delete curData->filename;
delete curData;
iter = filenames.erase(iter);
}
}
void RunThread(IThreadHandle *pHandle); void RunThread(IThreadHandle *pHandle);
void OnTerminate(IThreadHandle *pHandle, bool cancel); void OnTerminate(IThreadHandle *pHandle, bool cancel);
private: private:
int BuildGameDataQuery(char *buffer, int maxlen); int BuildGameDataQuery(char *buffer, int maxlen);
void ProcessGameDataQuery(int SocketDescriptor); void ProcessGameDataQuery(int SocketDescriptor);
int RecvData(int socketDescriptor, char *buffer, int len); int RecvData(int socketDescriptor, char *buffer, int len);
int SendData(int socketDescriptor, char *buffer, int len); int SendData(int socketDescriptor, char *buffer, int len);
int ConnectSocket(); int ConnectSocket();
void HandleUpdateStatus(UpdateStatus status, short version[4]); void HandleUpdateStatus(UpdateStatus status, short version[4]);
public: public:
SourceHook::CVector<FileData *> filenames; SourceHook::CVector<FileData *> filenames;
private: private:
@ -182,3 +98,4 @@ extern BuildMD5ableBuffer g_MD5Builder;
extern bool g_blockGameDataLoad; extern bool g_blockGameDataLoad;
#endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_ #endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_

View File

@ -272,21 +272,35 @@ IDirectory *LibrarySystem::OpenDirectory(const char *path)
} }
void LibrarySystem::GetPlatformError(char *error, size_t maxlength) void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
{
#if defined PLATFORM_WINDOWS
return GetPlatformErrorEx(GetLastError(), error, maxlength);
#elif defined PLATFORM_POSIX
return GetPlatformErrorEx(errno, error, maxlength);
#endif
}
void LibrarySystem::GetPlatformErrorEx(int code, char *error, size_t maxlength)
{ {
if (error && maxlength) if (error && maxlength)
{ {
#if defined PLATFORM_WINDOWS #if defined PLATFORM_WINDOWS
DWORD dw = GetLastError();
FormatMessageA( FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, NULL,
dw, (DWORD)code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)error, (LPSTR)error,
maxlength, maxlength,
NULL); NULL);
#elif defined PLATFORM_LINUX
const char *ae = strerror_r(code, error, maxlength);
if (ae != error)
{
UTIL_Format(error, maxlength, "%s", ae);
}
#elif defined PLATFORM_POSIX #elif defined PLATFORM_POSIX
UTIL_Format(error, maxlength, "%s", strerror(errno)); strerror_r(code, error, maxlength);
#endif #endif
} }
} }

View File

@ -90,6 +90,7 @@ public:
bool IsPathFile(const char *path); bool IsPathFile(const char *path);
bool IsPathDirectory(const char *path); bool IsPathDirectory(const char *path);
void GetPlatformError(char *error, size_t maxlength); void GetPlatformError(char *error, size_t maxlength);
void GetPlatformErrorEx(int code, char *error, size_t maxlength);
size_t PathFormat(char *buffer, size_t len, const char *fmt, ...); size_t PathFormat(char *buffer, size_t len, const char *fmt, ...);
const char *GetFileExtension(const char *filename); const char *GetFileExtension(const char *filename);
bool CreateFolder(const char *path); bool CreateFolder(const char *path);

View File

@ -63,6 +63,7 @@ ISourcePawnEngine2 *g_pSourcePawn2 = NULL;
IdentityToken_t *g_pCoreIdent = NULL; IdentityToken_t *g_pCoreIdent = NULL;
IForward *g_pOnMapEnd = NULL; IForward *g_pOnMapEnd = NULL;
bool g_Loaded = false; bool g_Loaded = false;
bool sm_show_debug_spew = false;
typedef ISourcePawnEngine *(*GET_SP_V1)(); typedef ISourcePawnEngine *(*GET_SP_V1)();
typedef ISourcePawnEngine2 *(*GET_SP_V2)(); typedef ISourcePawnEngine2 *(*GET_SP_V2)();
@ -115,6 +116,12 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key,
return ConfigResult_Accept; return ConfigResult_Accept;
} }
else if (strcasecmp(key, "DebugSpew") == 0)
{
sm_show_debug_spew = (strcasecmp(value, "yes") == 0) ? true : false;
return ConfigResult_Accept;
}
return ConfigResult_Ignore; return ConfigResult_Ignore;
} }

View File

@ -40,6 +40,17 @@
using namespace SourceHook; using namespace SourceHook;
#if defined _DEBUG
# define IF_DEBUG_SPEW
# define ENDIF_DEBUG_SPEW
#else
# define IF_DEBUG_SPEW \
if (sm_show_debug_spew) \
{
# define ENDIF_DEBUG_SPEW \
}
#endif
/** /**
* @brief Implements SourceMod's global overall management, API, and logic * @brief Implements SourceMod's global overall management, API, and logic
*/ */
@ -132,6 +143,7 @@ private:
}; };
extern bool g_Loaded; extern bool g_Loaded;
extern bool sm_show_debug_spew;
extern SourceModBase g_SourceMod; extern SourceModBase g_SourceMod;
extern HandleType_t g_WrBitBufType; //:TODO: find a better place for this extern HandleType_t g_WrBitBufType; //:TODO: find a better place for this
extern HandleType_t g_RdBitBufType; //:TODO: find a better place for this extern HandleType_t g_RdBitBufType; //:TODO: find a better place for this