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_