And the most important piece: Import of experimental gamedata autoupdater. Also new debug command "sm_gamedata_md5 <filename>"
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402323
This commit is contained in:
		
							parent
							
								
									f3f46fc126
								
							
						
					
					
						commit
						a513a2a6f8
					
				@ -88,4 +88,18 @@
 | 
			
		||||
	 * "off"	- Translate using default server's language
 | 
			
		||||
	 */
 | 
			
		||||
	"AllowClLanguageVar"		"On"
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Enables or Disables SourceMod's automatic gamedata updating.
 | 
			
		||||
	 *
 | 
			
		||||
	 * The default value is "no". A value of "yes" will block the Auto Updater.
 | 
			
		||||
	 */
 | 
			
		||||
	"DisableAutoUpdate"		"no"
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Enables or disables automatic restarting of the server after a successful update.
 | 
			
		||||
	 *
 | 
			
		||||
	 * The default value is "no". A value of "yes" will let the server automatically restart.
 | 
			
		||||
	 */
 | 
			
		||||
	"ForceRestartAfterUpdate"		"no"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,7 @@
 | 
			
		||||
#include "LibrarySys.h"
 | 
			
		||||
#include "HandleSys.h"
 | 
			
		||||
#include "sm_crc32.h"
 | 
			
		||||
#include "GameDataFetcher.h"
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_LINUX
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
@ -630,6 +631,13 @@ void GameConfigManager::OnSourceModAllShutdown()
 | 
			
		||||
 | 
			
		||||
bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
 | 
			
		||||
{
 | 
			
		||||
	/* A crash was detected during last load - We block the gamedata loading so it hopefully won't happen again */
 | 
			
		||||
	if (g_blockGameDataLoad)
 | 
			
		||||
	{
 | 
			
		||||
		UTIL_Format(error, maxlength, "GameData loaded blocked due to detected crash");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CGameConfig *pConfig;
 | 
			
		||||
 | 
			
		||||
	if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										682
									
								
								core/GameDataFetcher.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										682
									
								
								core/GameDataFetcher.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,682 @@
 | 
			
		||||
/**
 | 
			
		||||
* vim: set ts=4 :
 | 
			
		||||
* =============================================================================
 | 
			
		||||
* SourceMod
 | 
			
		||||
* Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
 | 
			
		||||
* =============================================================================
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or modify it under
 | 
			
		||||
* the terms of the GNU General Public License, version 3.0, as published by the
 | 
			
		||||
* Free Software Foundation.
 | 
			
		||||
* 
 | 
			
		||||
* This program is distributed in the hope that it will be useful, but WITHOUT
 | 
			
		||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
			
		||||
* FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
			
		||||
* details.
 | 
			
		||||
*
 | 
			
		||||
* You should have received a copy of the GNU General Public License along with
 | 
			
		||||
* this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*
 | 
			
		||||
* As a special exception, AlliedModders LLC gives you permission to link the
 | 
			
		||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
 | 
			
		||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 | 
			
		||||
* by the Valve Corporation.  You must obey the GNU General Public License in
 | 
			
		||||
* all respects for all other code used.  Additionally, AlliedModders LLC grants
 | 
			
		||||
* this exception to all derivative works.  AlliedModders LLC defines further
 | 
			
		||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 | 
			
		||||
* or <http://www.sourcemod.net/license.php>.
 | 
			
		||||
*
 | 
			
		||||
* Version: $Id$
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "GameDataFetcher.h"
 | 
			
		||||
#include "bitbuf.h"
 | 
			
		||||
 | 
			
		||||
#ifdef PLATFORM_WINDOWS
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#define INVALID_SOCKET -1
 | 
			
		||||
#define closesocket close
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "sh_vector.h"
 | 
			
		||||
#include "sh_string.h"
 | 
			
		||||
#include "sm_version.h"
 | 
			
		||||
 | 
			
		||||
#ifdef ORANGEBOX_BUILD
 | 
			
		||||
#include "convar_sm_ob.h"
 | 
			
		||||
#else
 | 
			
		||||
#include "convar_sm.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "sourcemm_api.h"
 | 
			
		||||
#include "time.h"
 | 
			
		||||
#include "TimerSys.h"
 | 
			
		||||
 | 
			
		||||
#define QUERY_MAX_LENGTH 1024
 | 
			
		||||
 | 
			
		||||
BuildMD5ableBuffer g_MD5Builder;
 | 
			
		||||
FetcherThread g_FetchThread;
 | 
			
		||||
 | 
			
		||||
FILE *logfile = NULL;
 | 
			
		||||
 | 
			
		||||
bool g_disableGameDataUpdate = false;
 | 
			
		||||
bool g_restartAfterUpdate = false;
 | 
			
		||||
 | 
			
		||||
void FetcherThread::RunThread( IThreadHandle *pHandle )
 | 
			
		||||
{
 | 
			
		||||
	char lock_path[PLATFORM_MAX_PATH];
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
 | 
			
		||||
	g_LibSys.CreateFolder(lock_path);
 | 
			
		||||
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogMessage("Starting experimental gamedata update fetcher... please report problems to bugs.alliedmods.net");
 | 
			
		||||
 | 
			
		||||
	char log_path[PLATFORM_MAX_PATH];
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata");
 | 
			
		||||
 | 
			
		||||
	g_LibSys.CreateFolder(log_path);
 | 
			
		||||
 | 
			
		||||
	time_t t;
 | 
			
		||||
	GetAdjustedTime(&t);
 | 
			
		||||
	tm *curtime = localtime(&t);
 | 
			
		||||
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday);
 | 
			
		||||
 | 
			
		||||
	logfile = fopen(log_path, "a");
 | 
			
		||||
 | 
			
		||||
	if (!logfile)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogError("Failed to create GameData log file");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Create a blank lock file
 | 
			
		||||
	FILE *fp = fopen(lock_path, "w");
 | 
			
		||||
	if (fp)
 | 
			
		||||
	{
 | 
			
		||||
		fclose(fp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create a new socket for this connection */
 | 
			
		||||
	int socketDescriptor = ConnectSocket();
 | 
			
		||||
 | 
			
		||||
	if (socketDescriptor == INVALID_SOCKET)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char query[QUERY_MAX_LENGTH];
 | 
			
		||||
 | 
			
		||||
	/* Check for updated gamedata files */
 | 
			
		||||
	int len = BuildGameDataQuery(query, QUERY_MAX_LENGTH);
 | 
			
		||||
 | 
			
		||||
	if (len == 0)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Query Writing failed");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (g_disableGameDataUpdate)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int sent = NonBlockingSend(socketDescriptor, query, len);
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Sent Query!");
 | 
			
		||||
 | 
			
		||||
	if (sent == 0)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Failed to send data");
 | 
			
		||||
		closesocket(socketDescriptor);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ProcessGameDataQuery(socketDescriptor);
 | 
			
		||||
 | 
			
		||||
	/* And we're done! */
 | 
			
		||||
	closesocket(socketDescriptor);
 | 
			
		||||
 | 
			
		||||
	fclose(logfile);
 | 
			
		||||
 | 
			
		||||
	// Delete our lock
 | 
			
		||||
	unlink(lock_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FetcherThread::OnTerminate( IThreadHandle *pHandle, bool cancel )
 | 
			
		||||
{
 | 
			
		||||
	//delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
 | 
			
		||||
{
 | 
			
		||||
	char gamedata_path[PLATFORM_MAX_PATH];
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
 | 
			
		||||
 | 
			
		||||
	IDirectory *dir = g_LibSys.OpenDirectory(gamedata_path);
 | 
			
		||||
 | 
			
		||||
	if (dir == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bf_write Writer = bf_write("GameDataQuery", buffer, maxlen);
 | 
			
		||||
 | 
			
		||||
	Writer.WriteByte('A'); //Generic Header char
 | 
			
		||||
	Writer.WriteByte('G'); //G for gamedata query, or green, like my hat.
 | 
			
		||||
 | 
			
		||||
	short build[4] = { SVN_FILE_VERSION };
 | 
			
		||||
 | 
			
		||||
	Writer.WriteBytes(&build[0], 8);
 | 
			
		||||
 | 
			
		||||
	Writer.WriteByte(0); // Initialize the file counter - Index 10
 | 
			
		||||
 | 
			
		||||
	while (dir->MoreFiles())
 | 
			
		||||
	{
 | 
			
		||||
		if (dir->IsEntryFile())
 | 
			
		||||
		{
 | 
			
		||||
			const char *name = dir->GetEntryName();
 | 
			
		||||
			size_t len = strlen(name);
 | 
			
		||||
			if (len >= 4
 | 
			
		||||
				&& strcmp(&name[len-4], ".txt") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				char file[PLATFORM_MAX_PATH];
 | 
			
		||||
 | 
			
		||||
				g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
 | 
			
		||||
 | 
			
		||||
				SMCStates states;
 | 
			
		||||
				if (g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states) == SMCError_Okay)
 | 
			
		||||
				{
 | 
			
		||||
					unsigned char *md5 = g_MD5Builder.GetMD5();
 | 
			
		||||
					if (md5 != NULL)
 | 
			
		||||
					{
 | 
			
		||||
						(uint8_t)buffer[10]++; //Increment the file counter
 | 
			
		||||
						Writer.WriteBytes(md5, 16);
 | 
			
		||||
 | 
			
		||||
						g_Logger.LogToOpenFile(logfile, "%s - \"%s\"", file, g_MD5Builder.GetMD5String());
 | 
			
		||||
 | 
			
		||||
						FileData *data = new FileData();
 | 
			
		||||
						data->filename = new SourceHook::String(file);
 | 
			
		||||
						memcpy(data->checksum, g_MD5Builder.GetMD5String(), 33);
 | 
			
		||||
						filenames.push_back(data);
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						g_Logger.LogToOpenFile(logfile, "%s no md5?", file);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					g_Logger.LogToOpenFile(logfile, "%s failed!", file);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dir->NextEntry();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Writer.GetNumBytesWritten();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int FetcherThread::ConnectSocket()
 | 
			
		||||
{
 | 
			
		||||
	struct protoent *ptrp;
 | 
			
		||||
	ptrp = getprotobyname("tcp");
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	WSADATA wsaData;
 | 
			
		||||
	WSAStartup(0x0101, &wsaData);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (ptrp == NULL) 
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Failed to find TCP");
 | 
			
		||||
		return INVALID_SOCKET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int socketDescriptor = socket(AF_INET, SOCK_STREAM, ptrp->p_proto);
 | 
			
		||||
 | 
			
		||||
	if (socketDescriptor == INVALID_SOCKET)
 | 
			
		||||
	{
 | 
			
		||||
		//bugger aye?
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Failed to create a new socket");
 | 
			
		||||
		closesocket(socketDescriptor);
 | 
			
		||||
		return INVALID_SOCKET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct hostent *he;
 | 
			
		||||
	struct sockaddr_in local_addr;
 | 
			
		||||
 | 
			
		||||
	local_addr.sin_family = AF_INET;
 | 
			
		||||
	local_addr.sin_port = htons((u_short)6500);
 | 
			
		||||
 | 
			
		||||
	he = gethostbyname("hayate.alliedmods.net");
 | 
			
		||||
 | 
			
		||||
	if (!he)
 | 
			
		||||
	{
 | 
			
		||||
		if ((local_addr.sin_addr.s_addr = inet_addr("hayate.alliedmods.net")) == INADDR_NONE)
 | 
			
		||||
		{
 | 
			
		||||
			g_Logger.LogToOpenFile(logfile, "Couldnt locate address");
 | 
			
		||||
			closesocket(socketDescriptor);
 | 
			
		||||
			return INVALID_SOCKET;
 | 
			
		||||
		}
 | 
			
		||||
	} 
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		memcpy(&local_addr.sin_addr, (struct in_addr *)he->h_addr, he->h_length);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Couldn't connect");
 | 
			
		||||
		closesocket(socketDescriptor);
 | 
			
		||||
		return INVALID_SOCKET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return socketDescriptor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[50];
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Waiting for reply!");
 | 
			
		||||
 | 
			
		||||
	//Read in the header bytes
 | 
			
		||||
	int returnLen = NonBlockingRecv(socketDescriptor, buffer, 12);
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Recv Completed");
 | 
			
		||||
 | 
			
		||||
	if (returnLen == 0)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, ",but it failed.");
 | 
			
		||||
		/* Timeout or fail? */
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Received Header!");
 | 
			
		||||
 | 
			
		||||
	bf_read Reader = bf_read("GameDataQuery", buffer, 12);
 | 
			
		||||
 | 
			
		||||
	if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Invalid Query to handle");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	UpdateStatus updateStatus = (UpdateStatus)Reader.ReadByte();
 | 
			
		||||
 | 
			
		||||
	short build[4] = {0,0,0,0};
 | 
			
		||||
 | 
			
		||||
	build[0] = Reader.ReadShort();
 | 
			
		||||
	build[1] = Reader.ReadShort();
 | 
			
		||||
	build[2] = Reader.ReadShort();
 | 
			
		||||
	build[3] = Reader.ReadShort();
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Update Status: %i - Latest %i.%i.%i.%i", updateStatus, build[0], build[1], build[2], build[3]);
 | 
			
		||||
 | 
			
		||||
	HandleUpdateStatus(updateStatus, build);
 | 
			
		||||
 | 
			
		||||
	int changedFiles = Reader.ReadByte();
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles);
 | 
			
		||||
 | 
			
		||||
	for (int i=0; i<changedFiles; i++)
 | 
			
		||||
	{
 | 
			
		||||
		//Read in the file index and byte count
 | 
			
		||||
		returnLen = NonBlockingRecv(socketDescriptor, buffer, 5);
 | 
			
		||||
 | 
			
		||||
		if (returnLen == 0)
 | 
			
		||||
		{
 | 
			
		||||
			/* Timeout or fail? */
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Reader.StartReading(buffer, 5);
 | 
			
		||||
 | 
			
		||||
		int index = Reader.ReadByte();
 | 
			
		||||
		int tempLen = Reader.ReadUBitLong(32);
 | 
			
		||||
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen);
 | 
			
		||||
 | 
			
		||||
		void *memPtr;
 | 
			
		||||
		memtable->CreateMem(tempLen+1, &memPtr);
 | 
			
		||||
 | 
			
		||||
		//Read the contents of our file into the memtable
 | 
			
		||||
		returnLen = NonBlockingRecv(socketDescriptor, (char *)memPtr, tempLen);
 | 
			
		||||
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Recieved %i bytes", returnLen);
 | 
			
		||||
 | 
			
		||||
		if (returnLen == 0)
 | 
			
		||||
		{
 | 
			
		||||
			/* Timeout or fail? */
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		((unsigned char *)memPtr)[tempLen] = '\0';
 | 
			
		||||
 | 
			
		||||
		FileData *data = filenames.at(index);
 | 
			
		||||
		const char* filename;
 | 
			
		||||
		if (data != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			filename = data->filename->c_str();
 | 
			
		||||
 | 
			
		||||
			FILE *fp = fopen(filename, "w");
 | 
			
		||||
 | 
			
		||||
			if (fp)
 | 
			
		||||
			{
 | 
			
		||||
				fprintf(fp, (const char *)memPtr);
 | 
			
		||||
				fclose(fp);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			filename = "";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		memtable->Reset();
 | 
			
		||||
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Updated File %s", filename);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "File Downloads Completed!");
 | 
			
		||||
 | 
			
		||||
	bool needsRestart = false;
 | 
			
		||||
 | 
			
		||||
	if (changedFiles > 0)
 | 
			
		||||
	{
 | 
			
		||||
		needsRestart = true;
 | 
			
		||||
		g_Logger.LogMessage("New GameData Files have been downloaded to your gamedata directory. Please restart your server for these to take effect");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Read changed file count
 | 
			
		||||
	returnLen = NonBlockingRecv(socketDescriptor, buffer, 1);
 | 
			
		||||
 | 
			
		||||
	if (returnLen == 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* Timeout or fail? */
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Failed to receive unknown count");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Reader.StartReading(buffer, 1);
 | 
			
		||||
 | 
			
		||||
	changedFiles = Reader.ReadByte();
 | 
			
		||||
 | 
			
		||||
	if (changedFiles == 0)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char *changedFileIndexes = new char[changedFiles];
 | 
			
		||||
	
 | 
			
		||||
	g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles);
 | 
			
		||||
	
 | 
			
		||||
	returnLen = NonBlockingRecv(socketDescriptor, changedFileIndexes, changedFiles);
 | 
			
		||||
 | 
			
		||||
	if (returnLen == 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* Timeout or fail? */
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Failed to receive unknown list");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Reader.StartReading(changedFileIndexes, changedFiles);
 | 
			
		||||
 | 
			
		||||
	for (int i=0; i<changedFiles; i++)
 | 
			
		||||
	{
 | 
			
		||||
		int index = Reader.ReadByte();
 | 
			
		||||
		char fileName[30];
 | 
			
		||||
 | 
			
		||||
		FileData *data = filenames.at(index);
 | 
			
		||||
		const char* pathname;
 | 
			
		||||
		if (data != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			pathname = data->filename->c_str();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			pathname = "";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
 | 
			
		||||
 | 
			
		||||
		g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete [] changedFileIndexes;
 | 
			
		||||
 | 
			
		||||
	if (needsRestart && g_restartAfterUpdate)
 | 
			
		||||
	{
 | 
			
		||||
		g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!");
 | 
			
		||||
		engine->ServerCommand("quit\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int FetcherThread::NonBlockingRecv( int socketDescriptor, char *buffer, int len )
 | 
			
		||||
{
 | 
			
		||||
	fd_set fds;
 | 
			
		||||
	struct timeval tv;
 | 
			
		||||
 | 
			
		||||
	/* Create a 10 Second Timeout */
 | 
			
		||||
	tv.tv_sec = 10;
 | 
			
		||||
	tv.tv_usec = 0;
 | 
			
		||||
 | 
			
		||||
	/* Add our socket to a socket set */
 | 
			
		||||
	FD_ZERO(&fds);
 | 
			
		||||
	FD_SET(socketDescriptor, &fds);
 | 
			
		||||
 | 
			
		||||
	/* Wait max of 10 seconds for recv to become available */
 | 
			
		||||
	select(socketDescriptor+1, &fds, NULL, NULL, &tv);
 | 
			
		||||
 | 
			
		||||
	int bytesReceived = 0;
 | 
			
		||||
 | 
			
		||||
	/* Is there a limit on how much we can receive? Some site said 1024 bytes, which will be well short of a file */
 | 
			
		||||
	if (FD_ISSET(socketDescriptor, &fds))
 | 
			
		||||
	{
 | 
			
		||||
		bytesReceived = recv(socketDescriptor, buffer, len, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bytesReceived == 0 || bytesReceived == -1)
 | 
			
		||||
	{
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bytesReceived < len)
 | 
			
		||||
	{
 | 
			
		||||
		return bytesReceived + NonBlockingRecv(socketDescriptor, buffer+bytesReceived, len-bytesReceived);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bytesReceived;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int FetcherThread::NonBlockingSend( int socketDescriptor, char *buffer, int len )
 | 
			
		||||
{
 | 
			
		||||
	fd_set fds;
 | 
			
		||||
	struct timeval tv;
 | 
			
		||||
 | 
			
		||||
	tv.tv_sec = 10;
 | 
			
		||||
	tv.tv_usec = 0;
 | 
			
		||||
 | 
			
		||||
	FD_ZERO(&fds);
 | 
			
		||||
	FD_SET(socketDescriptor, &fds);
 | 
			
		||||
 | 
			
		||||
	select(socketDescriptor+1, NULL, &fds, NULL, &tv);
 | 
			
		||||
 | 
			
		||||
	int sentBytes = 0;
 | 
			
		||||
 | 
			
		||||
	if (FD_ISSET(socketDescriptor, &fds))
 | 
			
		||||
	{
 | 
			
		||||
		sentBytes = send(socketDescriptor, buffer, len, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sentBytes == 0 || sentBytes == -1)
 | 
			
		||||
	{
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sentBytes < len)
 | 
			
		||||
	{
 | 
			
		||||
		return sentBytes + NonBlockingSend(socketDescriptor, buffer+sentBytes, len-sentBytes);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sentBytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
 | 
			
		||||
{
 | 
			
		||||
	switch (status)
 | 
			
		||||
	{
 | 
			
		||||
		case Update_Unknown:
 | 
			
		||||
		case Update_Current:
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case Update_NewBuild:
 | 
			
		||||
		{
 | 
			
		||||
			g_Logger.LogMessage("SourceMod Update: A new SVN 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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case Update_MinorAvailable:
 | 
			
		||||
		{
 | 
			
		||||
			g_Logger.LogMessage("SourceMod Update: An incremental minor 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]);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case Update_MajorAvailable:
 | 
			
		||||
		{
 | 
			
		||||
			g_Logger.LogMessage("SourceMod Update: An major 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]);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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.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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool g_blockGameDataLoad = false;
 | 
			
		||||
 | 
			
		||||
class InitFetch : public SMGlobalClass
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	void OnSourceModAllInitialized_Post()
 | 
			
		||||
	{
 | 
			
		||||
		char lock_path[PLATFORM_MAX_PATH];
 | 
			
		||||
		g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
 | 
			
		||||
 | 
			
		||||
		if (g_LibSys.IsPathFile(lock_path) && g_LibSys.PathExists(lock_path))
 | 
			
		||||
		{
 | 
			
		||||
			g_Logger.LogError("sourcemod/data/temp/gamedata.lock file detected. This is most likely due to a crash during GameData updating - Blocking GameData loading");
 | 
			
		||||
			g_Logger.LogError("If this error persists delete the file manually");
 | 
			
		||||
			g_blockGameDataLoad = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ThreadParams fetchThreadParams = ThreadParams();
 | 
			
		||||
		fetchThreadParams.prio = ThreadPrio_Low;
 | 
			
		||||
		g_pThreader->MakeThread(&g_FetchThread, &fetchThreadParams);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ConfigResult OnSourceModConfigChanged(const char *key, 
 | 
			
		||||
		const char *value, 
 | 
			
		||||
		ConfigSource source,
 | 
			
		||||
		char *error, 
 | 
			
		||||
		size_t maxlength)
 | 
			
		||||
	{
 | 
			
		||||
		if (strcmp(key, "DisableAutoUpdate") == 0)
 | 
			
		||||
		{
 | 
			
		||||
			if (strcmp(value, "yes") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				g_disableGameDataUpdate = true;
 | 
			
		||||
				return ConfigResult_Accept;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(value, "no") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				g_disableGameDataUpdate = false;
 | 
			
		||||
				return ConfigResult_Accept;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return ConfigResult_Reject;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (strcmp(key, "ForceRestartAfterUpdate") == 0)
 | 
			
		||||
		{
 | 
			
		||||
			if (strcmp(value, "yes") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				g_restartAfterUpdate = true;
 | 
			
		||||
				return ConfigResult_Accept;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(value, "no") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				g_restartAfterUpdate = false;
 | 
			
		||||
				return ConfigResult_Accept;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return ConfigResult_Reject;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return ConfigResult_Ignore;
 | 
			
		||||
	}
 | 
			
		||||
} g_InitFetch;
 | 
			
		||||
 | 
			
		||||
CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
 | 
			
		||||
{
 | 
			
		||||
#if !defined ORANGEBOX_BUILD
 | 
			
		||||
	CCommand args;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (args.ArgC() < 2)
 | 
			
		||||
	{
 | 
			
		||||
		g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const char *file = args.Arg(1);
 | 
			
		||||
	if (!file || file[0] == '\0')
 | 
			
		||||
	{
 | 
			
		||||
		g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SourceHook::CVector<FileData *>::iterator iter = g_FetchThread.filenames.begin();
 | 
			
		||||
 | 
			
		||||
	FileData *curData;
 | 
			
		||||
 | 
			
		||||
	while (iter != g_FetchThread.filenames.end())
 | 
			
		||||
	{
 | 
			
		||||
		curData = (*iter);
 | 
			
		||||
 | 
			
		||||
		char fileName[30];
 | 
			
		||||
 | 
			
		||||
		g_LibSys.GetFileFromPath(fileName, sizeof(fileName), curData->filename->c_str());
 | 
			
		||||
 | 
			
		||||
		if (strcmpi(fileName, file) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			g_SMAPI->ConPrintf("MD5 Sum: %s\n", curData->checksum);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iter++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_SMAPI->ConPrint("File not found!\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										185
									
								
								core/GameDataFetcher.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								core/GameDataFetcher.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,185 @@
 | 
			
		||||
/**
 | 
			
		||||
* vim: set ts=4 :
 | 
			
		||||
* =============================================================================
 | 
			
		||||
* SourceMod
 | 
			
		||||
* Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
 | 
			
		||||
* =============================================================================
 | 
			
		||||
*
 | 
			
		||||
* This program is free software; you can redistribute it and/or modify it under
 | 
			
		||||
* the terms of the GNU General Public License, version 3.0, as published by the
 | 
			
		||||
* Free Software Foundation.
 | 
			
		||||
* 
 | 
			
		||||
* This program is distributed in the hope that it will be useful, but WITHOUT
 | 
			
		||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
			
		||||
* FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
			
		||||
* details.
 | 
			
		||||
*
 | 
			
		||||
* You should have received a copy of the GNU General Public License along with
 | 
			
		||||
* this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*
 | 
			
		||||
* As a special exception, AlliedModders LLC gives you permission to link the
 | 
			
		||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
 | 
			
		||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 | 
			
		||||
* by the Valve Corporation.  You must obey the GNU General Public License in
 | 
			
		||||
* all respects for all other code used.  Additionally, AlliedModders LLC grants
 | 
			
		||||
* this exception to all derivative works.  AlliedModders LLC defines further
 | 
			
		||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 | 
			
		||||
* or <http://www.sourcemod.net/license.php>.
 | 
			
		||||
*
 | 
			
		||||
* Version: $Id$
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
 | 
			
		||||
#define _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
 | 
			
		||||
 | 
			
		||||
#include "sourcemod.h"
 | 
			
		||||
#include "TextParsers.h"
 | 
			
		||||
#include "IThreader.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
#include "LibrarySys.h"
 | 
			
		||||
#include "ThreadSupport.h"
 | 
			
		||||
#include "md5.h"
 | 
			
		||||
#include "sm_memtable.h"
 | 
			
		||||
 | 
			
		||||
enum UpdateStatus
 | 
			
		||||
{ 
 | 
			
		||||
	Update_Unknown = 0,				/* Version wasn't recognised or version querying is unsupported */
 | 
			
		||||
	Update_Current = 1,				/* Server is running latest version */
 | 
			
		||||
	Update_NewBuild = 2,			/* Server is on a svn release and a newer version is available */
 | 
			
		||||
	Update_MinorAvailable = 3,		/* Server is on a release and a minor release has superceeded it */
 | 
			
		||||
	Update_MajorAvailable = 4,		/* Server is on a release and a major release has superceeded it */
 | 
			
		||||
	Update_CriticalAvailable = 5,	/* A critical update has been released (security fixes etc) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BuildMD5ableBuffer : public ITextListener_SMC
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
	BuildMD5ableBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		stringTable = new BaseStringTable(2048);
 | 
			
		||||
		md5[0] = 0;
 | 
			
		||||
		md5String[0] = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~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:
 | 
			
		||||
	MD5 checksum;
 | 
			
		||||
	unsigned char md5[16];
 | 
			
		||||
	char md5String[33];
 | 
			
		||||
	BaseStringTable *stringTable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FileData
 | 
			
		||||
{
 | 
			
		||||
	SourceHook::String *filename;
 | 
			
		||||
	unsigned char checksum[33];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FetcherThread : public IThread
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	FetcherThread() 
 | 
			
		||||
	{
 | 
			
		||||
		//filenames = new BaseStringTable(200);
 | 
			
		||||
		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 OnTerminate(IThreadHandle *pHandle, bool cancel);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int BuildGameDataQuery(char *buffer, int maxlen);
 | 
			
		||||
	void ProcessGameDataQuery(int SocketDescriptor);
 | 
			
		||||
 | 
			
		||||
	/* These names are a lie. It's really NoMoreBlockingThan10Seconds */
 | 
			
		||||
	int NonBlockingRecv(int socketDescriptor, char *buffer, int len);
 | 
			
		||||
	int NonBlockingSend(int socketDescriptor, char *buffer, int len);
 | 
			
		||||
 | 
			
		||||
	int ConnectSocket();
 | 
			
		||||
 | 
			
		||||
	void HandleUpdateStatus(UpdateStatus status, short version[4]);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	SourceHook::CVector<FileData *> filenames;
 | 
			
		||||
private:
 | 
			
		||||
	BaseMemTable *memtable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern BuildMD5ableBuffer g_MD5Builder;
 | 
			
		||||
extern bool g_blockGameDataLoad;
 | 
			
		||||
 | 
			
		||||
#endif // _INCLUDE_SOURCEMOD_GAMEDATAFETCHER_H_
 | 
			
		||||
@ -19,7 +19,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC
 | 
			
		||||
	sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
 | 
			
		||||
	MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp sm_crc32.cpp \
 | 
			
		||||
	frame_hooks.cpp concmd_cleaner.cpp Profiler.cpp PhraseCollection.cpp NextMap.cpp \
 | 
			
		||||
	NativeOwner.cpp
 | 
			
		||||
	NativeOwner.cpp GameDataFetcher.cpp md5.cpp
 | 
			
		||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
 | 
			
		||||
	smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
 | 
			
		||||
	smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp \
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										485
									
								
								core/md5.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										485
									
								
								core/md5.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,485 @@
 | 
			
		||||
// MD5.CC - source code for the C++/object oriented translation and 
 | 
			
		||||
//          modification of MD5.
 | 
			
		||||
 | 
			
		||||
// Translation and modification (c) 1995 by Mordechai T. Abzug 
 | 
			
		||||
 | 
			
		||||
// This translation/ modification is provided "as is," without express or 
 | 
			
		||||
// implied warranty of any kind.
 | 
			
		||||
 | 
			
		||||
// The translator/ modifier does not claim (1) that MD5 will do what you think 
 | 
			
		||||
// it does; (2) that this translation/ modification is accurate; or (3) that 
 | 
			
		||||
// this software is "merchantible."  (Language for this disclaimer partially 
 | 
			
		||||
// copied from the disclaimer below).
 | 
			
		||||
 | 
			
		||||
/* based on:
 | 
			
		||||
 | 
			
		||||
   MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
 | 
			
		||||
   MDDRIVER.C - test driver for MD2, MD4 and MD5
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
 | 
			
		||||
rights reserved.
 | 
			
		||||
 | 
			
		||||
License to copy and use this software is granted provided that it
 | 
			
		||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
 | 
			
		||||
Algorithm" in all material mentioning or referencing this software
 | 
			
		||||
or this function.
 | 
			
		||||
 | 
			
		||||
License is also granted to make and use derivative works provided
 | 
			
		||||
that such works are identified as "derived from the RSA Data
 | 
			
		||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
 | 
			
		||||
mentioning or referencing the derived work.
 | 
			
		||||
 | 
			
		||||
RSA Data Security, Inc. makes no representations concerning either
 | 
			
		||||
the merchantability of this software or the suitability of this
 | 
			
		||||
software for any particular purpose. It is provided "as is"
 | 
			
		||||
without express or implied warranty of any kind.
 | 
			
		||||
 | 
			
		||||
These notices must be retained in any copies of any part of this
 | 
			
		||||
documentation and/or software.
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "md5.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
// MD5 simple initialization method
 | 
			
		||||
 | 
			
		||||
MD5::MD5(){
 | 
			
		||||
 | 
			
		||||
  init();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// MD5 block update operation. Continues an MD5 message-digest
 | 
			
		||||
// operation, processing another message block, and updating the
 | 
			
		||||
// context.
 | 
			
		||||
 | 
			
		||||
void MD5::update (uint1 *input, uint4 input_length) {
 | 
			
		||||
 | 
			
		||||
  uint4 input_index, buffer_index;
 | 
			
		||||
  uint4 buffer_space;                // how much space is left in buffer
 | 
			
		||||
 | 
			
		||||
  if (finalized){  // so we can't update!
 | 
			
		||||
    /*cerr << "MD5::update:  Can't update a finalized digest!" << endl;*/
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Compute number of bytes mod 64
 | 
			
		||||
  buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
 | 
			
		||||
 | 
			
		||||
  // Update number of bits
 | 
			
		||||
  if (  (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
 | 
			
		||||
    count[1]++;
 | 
			
		||||
 | 
			
		||||
  count[1] += ((uint4)input_length >> 29);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  buffer_space = 64 - buffer_index;  // how much space is left in buffer
 | 
			
		||||
 | 
			
		||||
  // Transform as many times as possible.
 | 
			
		||||
  if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
 | 
			
		||||
    // fill the rest of the buffer and transform
 | 
			
		||||
    memcpy (buffer + buffer_index, input, buffer_space);
 | 
			
		||||
    transform (buffer);
 | 
			
		||||
 | 
			
		||||
    // now, transform each 64-byte piece of the input, bypassing the buffer
 | 
			
		||||
    for (input_index = buffer_space; input_index + 63 < input_length; 
 | 
			
		||||
	 input_index += 64)
 | 
			
		||||
      transform (input+input_index);
 | 
			
		||||
 | 
			
		||||
    buffer_index = 0;  // so we can buffer remaining
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    input_index=0;     // so we can buffer the whole input
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // and here we do the buffering:
 | 
			
		||||
  memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// MD5 update for files.
 | 
			
		||||
// Like above, except that it works on files (and uses above as a primitive.)
 | 
			
		||||
 | 
			
		||||
void MD5::update(FILE *file){
 | 
			
		||||
 | 
			
		||||
  unsigned char buffer[1024];
 | 
			
		||||
  int len;
 | 
			
		||||
 | 
			
		||||
  while ((len=fread(buffer, 1, 1024, file)))
 | 
			
		||||
    update(buffer, len);
 | 
			
		||||
 | 
			
		||||
  fclose (file);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
 | 
			
		||||
// the message digest and zeroizing the context.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MD5::finalize (){
 | 
			
		||||
 | 
			
		||||
  unsigned char bits[8];
 | 
			
		||||
  unsigned int index, padLen;
 | 
			
		||||
  static uint1 PADDING[64]={
 | 
			
		||||
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  if (finalized){
 | 
			
		||||
   /* cerr << "MD5::finalize:  Already finalized this digest!" << endl;*/
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Save number of bits
 | 
			
		||||
  encode (bits, count, 8);
 | 
			
		||||
 | 
			
		||||
  // Pad out to 56 mod 64.
 | 
			
		||||
  index = (uint4) ((count[0] >> 3) & 0x3f);
 | 
			
		||||
  padLen = (index < 56) ? (56 - index) : (120 - index);
 | 
			
		||||
  update (PADDING, padLen);
 | 
			
		||||
 | 
			
		||||
  // Append length (before padding)
 | 
			
		||||
  update (bits, 8);
 | 
			
		||||
 | 
			
		||||
  // Store state in digest
 | 
			
		||||
  encode (digest, state, 16);
 | 
			
		||||
 | 
			
		||||
  // Zeroize sensitive information
 | 
			
		||||
  memset (buffer, 0, sizeof(*buffer));
 | 
			
		||||
 | 
			
		||||
  finalized=1;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MD5::MD5(FILE *file){
 | 
			
		||||
 | 
			
		||||
  init();  // must be called be all constructors
 | 
			
		||||
  update(file);
 | 
			
		||||
  finalize ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char *MD5::raw_digest(){
 | 
			
		||||
 | 
			
		||||
  uint1 *s = new uint1[16];
 | 
			
		||||
 | 
			
		||||
  if (!finalized){
 | 
			
		||||
/*    cerr << "MD5::raw_digest:  Can't get digest if you haven't "<<
 | 
			
		||||
      "finalized the digest!" <<endl;*/
 | 
			
		||||
    return ( (unsigned char*) "");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  memcpy(s, digest, 16);
 | 
			
		||||
  return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char *MD5::raw_digest(unsigned char buffer[16])
 | 
			
		||||
{
 | 
			
		||||
	if (!finalized)
 | 
			
		||||
	{
 | 
			
		||||
		return ( (unsigned char*) "");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	 memcpy(buffer, digest, 16);
 | 
			
		||||
	 return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char *MD5::hex_digest(){
 | 
			
		||||
 | 
			
		||||
  int i;
 | 
			
		||||
  char *s= new char[33];
 | 
			
		||||
 | 
			
		||||
  if (!finalized){
 | 
			
		||||
/*    cerr << "MD5::hex_digest:  Can't get digest if you haven't "<<
 | 
			
		||||
      "finalized the digest!" <<endl;*/
 | 
			
		||||
    return "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (i=0; i<16; i++)
 | 
			
		||||
    sprintf(s+i*2, "%02x", digest[i]);
 | 
			
		||||
 | 
			
		||||
  s[32]='\0';
 | 
			
		||||
 | 
			
		||||
  return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char *MD5::hex_digest(char buffer[33]){
 | 
			
		||||
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (!finalized)
 | 
			
		||||
  {
 | 
			
		||||
	 /* cerr << "MD5::hex_digest:  Can't get digest if you haven't "<<
 | 
			
		||||
      "finalized the digest!" <<endl;*/
 | 
			
		||||
    return "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (i=0; i<16; i++)
 | 
			
		||||
    sprintf(buffer+i*2, "%02x", digest[i]);
 | 
			
		||||
 | 
			
		||||
  buffer[32]='\0';
 | 
			
		||||
 | 
			
		||||
  return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// PRIVATE METHODS:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MD5::init(){
 | 
			
		||||
  finalized=0;  // we just started!
 | 
			
		||||
 | 
			
		||||
  // Nothing counted, so count=0
 | 
			
		||||
  count[0] = 0;
 | 
			
		||||
  count[1] = 0;
 | 
			
		||||
 | 
			
		||||
  // Load magic initialization constants.
 | 
			
		||||
  state[0] = 0x67452301;
 | 
			
		||||
  state[1] = 0xefcdab89;
 | 
			
		||||
  state[2] = 0x98badcfe;
 | 
			
		||||
  state[3] = 0x10325476;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Constants for MD5Transform routine.
 | 
			
		||||
// Although we could use C++ style constants, defines are actually better,
 | 
			
		||||
// since they let us easily evade scope clashes.
 | 
			
		||||
 | 
			
		||||
#define S11 7
 | 
			
		||||
#define S12 12
 | 
			
		||||
#define S13 17
 | 
			
		||||
#define S14 22
 | 
			
		||||
#define S21 5
 | 
			
		||||
#define S22 9
 | 
			
		||||
#define S23 14
 | 
			
		||||
#define S24 20
 | 
			
		||||
#define S31 4
 | 
			
		||||
#define S32 11
 | 
			
		||||
#define S33 16
 | 
			
		||||
#define S34 23
 | 
			
		||||
#define S41 6
 | 
			
		||||
#define S42 10
 | 
			
		||||
#define S43 15
 | 
			
		||||
#define S44 21
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// MD5 basic transformation. Transforms state based on block.
 | 
			
		||||
void MD5::transform (uint1 block[64]){
 | 
			
		||||
 | 
			
		||||
  uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
 | 
			
		||||
 | 
			
		||||
  decode (x, block, 64);
 | 
			
		||||
 | 
			
		||||
  assert(!finalized);  // not just a user error, since the method is private
 | 
			
		||||
 | 
			
		||||
  /* Round 1 */
 | 
			
		||||
  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
 | 
			
		||||
  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
 | 
			
		||||
  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
 | 
			
		||||
  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
 | 
			
		||||
  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
 | 
			
		||||
  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
 | 
			
		||||
  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
 | 
			
		||||
  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
 | 
			
		||||
  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
 | 
			
		||||
  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
 | 
			
		||||
  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
 | 
			
		||||
  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
 | 
			
		||||
  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
 | 
			
		||||
  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
 | 
			
		||||
  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
 | 
			
		||||
  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
 | 
			
		||||
 | 
			
		||||
 /* Round 2 */
 | 
			
		||||
  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
 | 
			
		||||
  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
 | 
			
		||||
  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
 | 
			
		||||
  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
 | 
			
		||||
  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
 | 
			
		||||
  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
 | 
			
		||||
  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
 | 
			
		||||
  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
 | 
			
		||||
  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
 | 
			
		||||
  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
 | 
			
		||||
  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
 | 
			
		||||
  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
 | 
			
		||||
  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
 | 
			
		||||
  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
 | 
			
		||||
  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
 | 
			
		||||
  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
 | 
			
		||||
 | 
			
		||||
  /* Round 3 */
 | 
			
		||||
  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
 | 
			
		||||
  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
 | 
			
		||||
  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
 | 
			
		||||
  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
 | 
			
		||||
  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
 | 
			
		||||
  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
 | 
			
		||||
  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
 | 
			
		||||
  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
 | 
			
		||||
  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
 | 
			
		||||
  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
 | 
			
		||||
  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
 | 
			
		||||
  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
 | 
			
		||||
  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
 | 
			
		||||
  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
 | 
			
		||||
  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
 | 
			
		||||
  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
 | 
			
		||||
 | 
			
		||||
  /* Round 4 */
 | 
			
		||||
  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
 | 
			
		||||
  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
 | 
			
		||||
  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
 | 
			
		||||
  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
 | 
			
		||||
  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
 | 
			
		||||
  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
 | 
			
		||||
  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
 | 
			
		||||
  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
 | 
			
		||||
  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
 | 
			
		||||
  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
 | 
			
		||||
  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
 | 
			
		||||
  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
 | 
			
		||||
  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
 | 
			
		||||
  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
 | 
			
		||||
  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
 | 
			
		||||
  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
 | 
			
		||||
 | 
			
		||||
  state[0] += a;
 | 
			
		||||
  state[1] += b;
 | 
			
		||||
  state[2] += c;
 | 
			
		||||
  state[3] += d;
 | 
			
		||||
 | 
			
		||||
  // Zeroize sensitive information.
 | 
			
		||||
  memset ( (uint1 *) x, 0, sizeof(x));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Encodes input (UINT4) into output (unsigned char). Assumes len is
 | 
			
		||||
// a multiple of 4.
 | 
			
		||||
void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
 | 
			
		||||
 | 
			
		||||
  unsigned int i, j;
 | 
			
		||||
 | 
			
		||||
  for (i = 0, j = 0; j < len; i++, j += 4) {
 | 
			
		||||
    output[j]   = (uint1)  (input[i] & 0xff);
 | 
			
		||||
    output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
 | 
			
		||||
    output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
 | 
			
		||||
    output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Decodes input (unsigned char) into output (UINT4). Assumes len is
 | 
			
		||||
// a multiple of 4.
 | 
			
		||||
void MD5::decode (uint4 *output, uint1 *input, uint4 len){
 | 
			
		||||
 | 
			
		||||
  unsigned int i, j;
 | 
			
		||||
 | 
			
		||||
  for (i = 0, j = 0; j < len; i++, j += 4)
 | 
			
		||||
    output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
 | 
			
		||||
      (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Note: Replace "for loop" with standard memcpy if possible.
 | 
			
		||||
void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
 | 
			
		||||
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < len; i++)
 | 
			
		||||
    output[i] = input[i];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Note: Replace "for loop" with standard memset if possible.
 | 
			
		||||
void MD5::memset (uint1 *output, uint1 value, uint4 len){
 | 
			
		||||
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < len; i++)
 | 
			
		||||
    output[i] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ROTATE_LEFT rotates x left n bits.
 | 
			
		||||
 | 
			
		||||
inline unsigned int MD5::rotate_left  (uint4 x, uint4 n){
 | 
			
		||||
  return (x << n) | (x >> (32-n))  ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// F, G, H and I are basic MD5 functions.
 | 
			
		||||
 | 
			
		||||
inline unsigned int MD5::F            (uint4 x, uint4 y, uint4 z){
 | 
			
		||||
  return (x & y) | (~x & z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline unsigned int MD5::G            (uint4 x, uint4 y, uint4 z){
 | 
			
		||||
  return (x & z) | (y & ~z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline unsigned int MD5::H            (uint4 x, uint4 y, uint4 z){
 | 
			
		||||
  return x ^ y ^ z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline unsigned int MD5::I            (uint4 x, uint4 y, uint4 z){
 | 
			
		||||
  return y ^ (x | ~z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
 | 
			
		||||
// Rotation is separate from addition to prevent recomputation.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
		    uint4  s, uint4 ac){
 | 
			
		||||
 a += F(b, c, d) + x + ac;
 | 
			
		||||
 a = rotate_left (a, s) +b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
		    uint4 s, uint4 ac){
 | 
			
		||||
 a += G(b, c, d) + x + ac;
 | 
			
		||||
 a = rotate_left (a, s) +b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
		    uint4 s, uint4 ac){
 | 
			
		||||
 a += H(b, c, d) + x + ac;
 | 
			
		||||
 a = rotate_left (a, s) +b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
			     uint4 s, uint4 ac){
 | 
			
		||||
 a += I(b, c, d) + x + ac;
 | 
			
		||||
 a = rotate_left (a, s) +b;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								core/md5.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								core/md5.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
			
		||||
// MD5.CC - source code for the C++/object oriented translation and 
 | 
			
		||||
//          modification of MD5.
 | 
			
		||||
 | 
			
		||||
// Translation and modification (c) 1995 by Mordechai T. Abzug 
 | 
			
		||||
 | 
			
		||||
// This translation/ modification is provided "as is," without express or 
 | 
			
		||||
// implied warranty of any kind.
 | 
			
		||||
 | 
			
		||||
// The translator/ modifier does not claim (1) that MD5 will do what you think 
 | 
			
		||||
// it does; (2) that this translation/ modification is accurate; or (3) that 
 | 
			
		||||
// this software is "merchantible."  (Language for this disclaimer partially 
 | 
			
		||||
// copied from the disclaimer below).
 | 
			
		||||
 | 
			
		||||
/* based on:
 | 
			
		||||
 | 
			
		||||
   MD5.H - header file for MD5C.C
 | 
			
		||||
   MDDRIVER.C - test driver for MD2, MD4 and MD5
 | 
			
		||||
 | 
			
		||||
   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
 | 
			
		||||
rights reserved.
 | 
			
		||||
 | 
			
		||||
License to copy and use this software is granted provided that it
 | 
			
		||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
 | 
			
		||||
Algorithm" in all material mentioning or referencing this software
 | 
			
		||||
or this function.
 | 
			
		||||
 | 
			
		||||
License is also granted to make and use derivative works provided
 | 
			
		||||
that such works are identified as "derived from the RSA Data
 | 
			
		||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
 | 
			
		||||
mentioning or referencing the derived work.
 | 
			
		||||
 | 
			
		||||
RSA Data Security, Inc. makes no representations concerning either
 | 
			
		||||
the merchantability of this software or the suitability of this
 | 
			
		||||
software for any particular purpose. It is provided "as is"
 | 
			
		||||
without express or implied warranty of any kind.
 | 
			
		||||
 | 
			
		||||
These notices must be retained in any copies of any part of this
 | 
			
		||||
documentation and/or software.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
//#include <fstream.h>
 | 
			
		||||
//#include <iostream.h>
 | 
			
		||||
 | 
			
		||||
class MD5 {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
// methods for controlled operation:
 | 
			
		||||
  MD5              ();  // simple initializer
 | 
			
		||||
  void  update     (unsigned char *input, unsigned int input_length);
 | 
			
		||||
  void  update     (FILE *file);
 | 
			
		||||
  void  finalize   ();
 | 
			
		||||
 | 
			
		||||
// constructors for special circumstances.  All these constructors finalize
 | 
			
		||||
// the MD5 context.
 | 
			
		||||
  MD5              (unsigned char *string); // digest string, finalize
 | 
			
		||||
  MD5              (FILE *file);            // digest file, close, finalize
 | 
			
		||||
 | 
			
		||||
// methods to acquire finalized result
 | 
			
		||||
  unsigned char    *raw_digest ();  // digest as a 16-byte binary array
 | 
			
		||||
  unsigned char		*raw_digest(unsigned char buffer[16]);
 | 
			
		||||
  char *            hex_digest ();  // digest as a 33-byte ascii-hex string
 | 
			
		||||
  char *			hex_digest (char buffer[33]); //same as above, passing buffer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
// first, some types:
 | 
			
		||||
  typedef unsigned       int uint4; // assumes integer is 4 words long
 | 
			
		||||
  typedef unsigned short int uint2; // assumes short integer is 2 words long
 | 
			
		||||
  typedef unsigned      char uint1; // assumes char is 1 word long
 | 
			
		||||
 | 
			
		||||
// next, the private data:
 | 
			
		||||
  uint4 state[4];
 | 
			
		||||
  uint4 count[2];     // number of *bits*, mod 2^64
 | 
			
		||||
  uint1 buffer[64];   // input buffer
 | 
			
		||||
  uint1 digest[16];
 | 
			
		||||
  uint1 finalized;
 | 
			
		||||
 | 
			
		||||
// last, the private methods, mostly static:
 | 
			
		||||
  void init             ();               // called by all constructors
 | 
			
		||||
  void transform        (uint1 *buffer);  // does the real update work.  Note 
 | 
			
		||||
                                          // that length is implied to be 64.
 | 
			
		||||
 | 
			
		||||
  static void encode    (uint1 *dest, uint4 *src, uint4 length);
 | 
			
		||||
  static void decode    (uint4 *dest, uint1 *src, uint4 length);
 | 
			
		||||
  static void memcpy    (uint1 *dest, uint1 *src, uint4 length);
 | 
			
		||||
  static void memset    (uint1 *start, uint1 val, uint4 length);
 | 
			
		||||
 | 
			
		||||
  static inline uint4  rotate_left (uint4 x, uint4 n);
 | 
			
		||||
  static inline uint4  F           (uint4 x, uint4 y, uint4 z);
 | 
			
		||||
  static inline uint4  G           (uint4 x, uint4 y, uint4 z);
 | 
			
		||||
  static inline uint4  H           (uint4 x, uint4 y, uint4 z);
 | 
			
		||||
  static inline uint4  I           (uint4 x, uint4 y, uint4 z);
 | 
			
		||||
  static inline void   FF  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
			    uint4 s, uint4 ac);
 | 
			
		||||
  static inline void   GG  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
			    uint4 s, uint4 ac);
 | 
			
		||||
  static inline void   HH  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
			    uint4 s, uint4 ac);
 | 
			
		||||
  static inline void   II  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
 | 
			
		||||
			    uint4 s, uint4 ac);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
@ -869,6 +869,10 @@
 | 
			
		||||
				RelativePath="..\GameConfigs.cpp"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\GameDataFetcher.cpp"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\HalfLife2.cpp"
 | 
			
		||||
				>
 | 
			
		||||
@ -877,6 +881,10 @@
 | 
			
		||||
				RelativePath="..\Logger.cpp"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\md5.cpp"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\MemoryUtils.cpp"
 | 
			
		||||
				>
 | 
			
		||||
@ -1043,6 +1051,10 @@
 | 
			
		||||
				RelativePath="..\GameConfigs.h"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\GameDataFetcher.h"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\HalfLife2.h"
 | 
			
		||||
				>
 | 
			
		||||
@ -1051,6 +1063,10 @@
 | 
			
		||||
				RelativePath="..\Logger.h"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\md5.h"
 | 
			
		||||
				>
 | 
			
		||||
			</File>
 | 
			
		||||
			<File
 | 
			
		||||
				RelativePath="..\MemoryUtils.h"
 | 
			
		||||
				>
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,11 @@ public:
 | 
			
		||||
		return size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline unsigned int GetActualMemUsed()
 | 
			
		||||
	{
 | 
			
		||||
		return tail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	unsigned char *membase;
 | 
			
		||||
	unsigned int size;
 | 
			
		||||
 | 
			
		||||
@ -186,6 +186,11 @@ void CForwardManager::ReleaseForward(IForward *forward)
 | 
			
		||||
 | 
			
		||||
void CForwardManager::ForwardFree(CForward *fwd)
 | 
			
		||||
{
 | 
			
		||||
	if (fwd == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_FreeForwards.push(fwd);
 | 
			
		||||
	m_managed.remove(fwd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user