/************************************************************************/ /* BattlEye Client code */ /************************************************************************/ #include "../client/client.h" #include "winquake.h" #ifdef BATTLEYE static qbyte newBEPacket[BE_MAX_PACKET_SIZE]; static short newBEPacketLen = 0; /* short GetBEPacket(void*, short) (1st parameter for Run()): This function first checks if cls.runBattlEye = true - if not, it returns -1. Then it checks if there is a new/last packet - if not, it returns 0. If there is one, it checks if its length is <= buffer length (2nd parameter) (fits into the buffer pointed to by the 1st parameter) - if not, the server tries to illegally flood the client with impossibly huge BE packets and thus it should disconnect immediately; after doing this, it returns -1. Otherwise it copies the last BE packet into the buffer and returns its length/size. The (last) packet data and length are stored globally (variable(s): e.g. a BYTE[1024] buffer for the data and an int for the length; or a wsw msg structure?) each time the engine receives a packet starting with the unique BE header (e.g. "BE"; note: store the packet/length globally without/minus it). After doing this, the function clears/cleans up/whatever the global lastBEPacket data and length (e.g. fills them with 0), so the function later knows and returns that there is no new BE packet when called by BE/Run() immediately again. BE/Run() calls this function very frequently (in its loop) to check for new incoming packets. */ static short GetBEPacket(void* buf, short len) { short thisPacketLen; // may we run and thus perform this action ? if(!cls.runBattlEye) return -1; // no new packet if(newBEPacketLen == 0) return 0; // illegally huge packets if(newBEPacketLen > len) { Com_Error( ERR_DROP, "Invalid BattlEye packet size from server" ); return -1; } thisPacketLen = newBEPacketLen; memcpy(buf, newBEPacket, thisPacketLen); newBEPacketLen = 0; return thisPacketLen; } /* short SendBEPacket(void*, short) (2nd parameter for Run()): This function first checks if cls.runBattlEye = true - if not, it returns -1. Otherwise it simply sends a BE packet to the connected server. It appends the unique BE header in front of the packet/buffer pointed to by the 1st parameter and sends a packet of [2nd parameter]+2 (2 for "BE" as the header) bytes. If the packet was sent successfully, it returns 0, otherwise -1. BE/Run() calls this function to send BE packets to the server. */ static short SendBEPacket(void* buf, short len) { // may we run and thus perform this action ? if(!cls.runBattlEye) return -1; memcpy(cls.BE.packets[cls.BE.headPacket & BE_UPDATE_MASK], buf, len); cls.BE.packetLens[cls.BE.headPacket & BE_UPDATE_MASK] = len; cls.BE.headPacket++; return 0; } static DWORD WINAPI BattlEyeThread(LPVOID lpParameter) { HMODULE BEModule; while(BEModule=LoadLibrary("BattlEye.dll")) { // the BE "Run" export typedef qbyte (*BE_RUN)(short (*)(void*, short), short (*)(void*, short)); BE_RUN BERun; qbyte Result = qfalse; if (BERun = (BE_RUN)GetProcAddress(BEModule, "Run")) { Com_Printf("BattlEye started\n"); Result = BERun(&GetBEPacket, &SendBEPacket); } else Cbuf_ExecuteText(EXEC_APPEND, "disconnect;menu_msgbox \"Failed to get BattlEye.dll procedure\""); // note: Run() is like an application (has its own "infinite" loop) - // it returns only when the below happens FreeLibrary(BEModule); // unload the module each time Run() returns // (or if GetProcAddress() fails) // if Result = true, everything is ok, BE just wants to be reloaded // (used after auto-updating/downloading) ... // if Result = false, BE is done (most likely GetBEPacket failed due to closed connection), // so quit the thread if (!Result) return 0; } // this code is reached only if LoadLibrary() failed Cbuf_ExecuteText(EXEC_APPEND, "disconnect;menu_msgbox \"Failed to load BattlEye.dll\""); return 0; } void CL_BE_Start(void) { // static variable holding the handle to the current/last BE thread - it is initially set to NULL static HANDLE BEThread=NULL; DWORD BEThreadID; if(BEThread!=NULL) { WaitForSingleObject(BEThread, INFINITE); CloseHandle(BEThread); BEThread=NULL; } cls.runBattlEye=qtrue; // create the thread BEThread=CreateThread(NULL, 0, BattlEyeThread, NULL, 0, &BEThreadID); } void CL_BE_NewIncomingPacket(void* buf, int len) { memcpy(newBEPacket, buf, len); newBEPacketLen = len; } #endif // BATTLEYE