dvander@2168: /** dvander@2168: * vim: set ts=4 : dvander@2168: * ============================================================================= dvander@2168: * SourceMod dvander@2168: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. dvander@2168: * ============================================================================= dvander@2168: * dvander@2168: * This program is free software; you can redistribute it and/or modify it under dvander@2168: * the terms of the GNU General Public License, version 3.0, as published by the dvander@2168: * Free Software Foundation. dvander@2168: * dvander@2168: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@2168: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@2168: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@2168: * details. dvander@2168: * dvander@2168: * You should have received a copy of the GNU General Public License along with dvander@2168: * this program. If not, see . dvander@2168: * dvander@2168: * As a special exception, AlliedModders LLC gives you permission to link the dvander@2168: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@2168: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@2168: * by the Valve Corporation. You must obey the GNU General Public License in dvander@2168: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@2168: * this exception to all derivative works. AlliedModders LLC defines further dvander@2168: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@2168: * or . dvander@2168: * dvander@2168: * Version: $Id$ dvander@2168: */ dvander@2168: dvander@2168: #ifndef _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_ dvander@2168: #define _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_ dvander@2168: dvander@2168: #include "sourcemod.h" dvander@2168: #include "TextParsers.h" dvander@2168: #include "IThreader.h" dvander@2168: #include "Logger.h" dvander@2168: #include "LibrarySys.h" dvander@2168: #include "ThreadSupport.h" dvander@2168: #include "md5.h" dvander@2168: #include "sm_memtable.h" dvander@2168: dvander@2168: enum UpdateStatus dvander@2168: { dvander@2168: Update_Unknown = 0, /* Version wasn't recognised or version querying is unsupported */ dvander@2168: Update_Current = 1, /* Server is running latest version */ dvander@2168: Update_NewBuild = 2, /* Server is on a svn release and a newer version is available */ dvander@2168: Update_MinorAvailable = 3, /* Server is on a release and a minor release has superceeded it */ dvander@2168: Update_MajorAvailable = 4, /* Server is on a release and a major release has superceeded it */ dvander@2168: Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */ dvander@2168: }; dvander@2168: dvander@2168: class BuildMD5ableBuffer : public ITextListener_SMC dvander@2168: { dvander@2168: public: dvander@2168: dvander@2168: BuildMD5ableBuffer() dvander@2168: { dvander@2168: stringTable = new BaseStringTable(2048); dvander@2168: md5[0] = 0; dvander@2168: md5String[0] = 0; dvander@2168: } dvander@2168: dvander@2168: ~BuildMD5ableBuffer() dvander@2168: { dvander@2168: delete stringTable; dvander@2168: } dvander@2168: dvander@2168: void ReadSMC_ParseStart() dvander@2168: { dvander@2168: checksum = MD5(); dvander@2168: } dvander@2168: dvander@2168: SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) dvander@2168: { dvander@2168: stringTable->AddString(key); dvander@2168: stringTable->AddString(value); dvander@2168: dvander@2168: return SMCResult_Continue; dvander@2168: } dvander@2168: dvander@2168: SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name) dvander@2168: { dvander@2168: stringTable->AddString(name); dvander@2168: dvander@2168: return SMCResult_Continue; dvander@2168: } dvander@2168: dvander@2168: void ReadSMC_ParseEnd(bool halted, bool failed) dvander@2168: { dvander@2168: if (halted || failed) dvander@2168: { dvander@2168: return; dvander@2168: } dvander@2168: dvander@2168: void *data = stringTable->GetMemTable()->GetAddress(0); dvander@2168: dvander@2168: if (data != NULL) dvander@2168: { dvander@2168: checksum.update((unsigned char *)data, stringTable->GetMemTable()->GetActualMemUsed()); dvander@2168: } dvander@2168: dvander@2168: checksum.finalize(); dvander@2168: dvander@2168: checksum.hex_digest(md5String); dvander@2168: checksum.raw_digest(md5); dvander@2168: dvander@2168: stringTable->Reset(); dvander@2168: } dvander@2168: dvander@2168: unsigned char * GetMD5() dvander@2168: { dvander@2168: return md5; dvander@2168: } dvander@2168: dvander@2168: unsigned char * GetMD5String() dvander@2168: { dvander@2168: return (unsigned char *)&md5String[0]; dvander@2168: } dvander@2168: dvander@2168: private: dvander@2168: MD5 checksum; dvander@2168: unsigned char md5[16]; dvander@2168: char md5String[33]; dvander@2168: BaseStringTable *stringTable; dvander@2168: }; dvander@2168: dvander@2168: struct FileData dvander@2168: { dvander@2168: SourceHook::String *filename; dvander@2168: unsigned char checksum[33]; dvander@2168: }; dvander@2168: dvander@2168: dvander@2168: class FetcherThread : public IThread dvander@2168: { dvander@2168: public: dvander@2168: FetcherThread() dvander@2168: { dvander@2168: //filenames = new BaseStringTable(200); dvander@2168: memtable = new BaseMemTable(4096); dvander@2168: } dvander@2168: dvander@2168: ~FetcherThread() dvander@2168: { dvander@2168: //delete filenames; dvander@2168: SourceHook::CVector::iterator iter = filenames.begin(); dvander@2168: dvander@2168: FileData *curData; dvander@2168: dvander@2168: while (iter != filenames.end()) dvander@2168: { dvander@2168: curData = (*iter); dvander@2168: delete curData->filename; dvander@2168: delete curData; dvander@2168: iter = filenames.erase(iter); dvander@2168: } dvander@2168: } dvander@2168: dvander@2168: void RunThread(IThreadHandle *pHandle); dvander@2168: void OnTerminate(IThreadHandle *pHandle, bool cancel); dvander@2168: dvander@2168: private: dvander@2168: int BuildGameDataQuery(char *buffer, int maxlen); dvander@2168: void ProcessGameDataQuery(int SocketDescriptor); dvander@2168: dvander@2168: /* These names are a lie. It's really NoMoreBlockingThan10Seconds */ dvander@2168: int NonBlockingRecv(int socketDescriptor, char *buffer, int len); dvander@2168: int NonBlockingSend(int socketDescriptor, char *buffer, int len); dvander@2168: dvander@2168: int ConnectSocket(); dvander@2168: dvander@2168: void HandleUpdateStatus(UpdateStatus status, short version[4]); dvander@2168: dvander@2168: public: dvander@2168: SourceHook::CVector filenames; dvander@2168: private: dvander@2168: BaseMemTable *memtable; dvander@2168: }; dvander@2168: dvander@2168: extern BuildMD5ableBuffer g_MD5Builder; dvander@2168: extern bool g_blockGameDataLoad; dvander@2168: dvander@2168: #endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_