|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "netmessages.h"
#include "bitbuf.h"
#include "const.h"
#include "../engine/net_chan.h"
#include "mathlib/mathlib.h"
#include "networkstringtabledefs.h"
#include "../engine/audio/public/sound.h"
#include "../engine/event_system.h"
#include "../engine/dt.h"
#include "mathlib/IceKey.H"
#include "tier0/vprof.h"
static char s_text[1024];
const char *g_MostCommonPathIDs[] = { "GAME", "MOD" };
const char *g_MostCommonPrefixes[] = { "materials", "models", "sounds", "scripts" };
static int FindCommonPathID( const char *pPathID ) { for ( int i = 0; i < ARRAYSIZE( g_MostCommonPathIDs ); i++ ) { if ( V_stricmp( pPathID, g_MostCommonPathIDs[i] ) == 0 ) return i; } return -1; }
static int FindCommonPrefix( const char *pStr ) { for ( int i = 0; i < ARRAYSIZE( g_MostCommonPrefixes ); i++ ) { if ( V_stristr( pStr, g_MostCommonPrefixes[i] ) == pStr ) { int iNextChar = V_strlen( g_MostCommonPrefixes[i] ); if ( pStr[iNextChar] == '/' || pStr[iNextChar] == '\\' ) return i; } } return -1; }
void CCLCMsg_FileCRCCheck_t::SetPath( CCLCMsg_FileCRCCheck& msg, const char *path ) { int iCode = FindCommonPathID( path ); if ( iCode == -1 ) { msg.set_code_path( -1 ); msg.set_path( path ); } else { msg.set_code_path( iCode ); } }
const char *CCLCMsg_FileCRCCheck_t::GetPath( const CCLCMsg_FileCRCCheck& msg ) { int iCode = msg.code_path(); if( ( iCode >= 0 ) && ( iCode < ARRAYSIZE( g_MostCommonPathIDs ) ) ) { return g_MostCommonPathIDs[ iCode ]; }
Assert( msg.code_path() == -1 ); return msg.path().c_str(); }
void CCLCMsg_FileCRCCheck_t::SetFileName( CCLCMsg_FileCRCCheck& msg, const char *fileName ) { int iCode = FindCommonPrefix( fileName ); if ( iCode == -1 ) { msg.set_code_filename( -1 ); msg.set_filename( fileName ); } else { msg.set_code_filename( iCode ); msg.set_filename( &fileName[ V_strlen( g_MostCommonPrefixes[ iCode ] ) + 1 ] ); } }
const char *CCLCMsg_FileCRCCheck_t::GetFileName( const CCLCMsg_FileCRCCheck& msg ) { int iCode = msg.code_filename(); if( ( iCode >= 0 ) && ( iCode < ARRAYSIZE( g_MostCommonPrefixes ) ) ) { return va( "%s%c%s", g_MostCommonPrefixes[ iCode ], CORRECT_PATH_SEPARATOR, msg.filename().c_str() ); }
Assert( msg.code_filename() == -1 ); return msg.filename().c_str(); }
void CmdKeyValuesHelper::CLCMsg_SetKeyValues( CCLCMsg_CmdKeyValues& msg, const KeyValues *keyValues ) { CUtlBuffer bufData; keyValues->WriteAsBinary( bufData ); int numBytes = bufData.TellPut(); msg.set_keyvalues( bufData.Base(), numBytes ); }
KeyValues *CmdKeyValuesHelper::CLCMsg_GetKeyValues ( const CCLCMsg_CmdKeyValues& msg ) { KeyValues *pKeyValues = new KeyValues( "" );
const std::string& msgStr = msg.keyvalues(); int numBytes = msgStr.size();
CUtlBuffer bufRead( msgStr.data(), numBytes, CUtlBuffer::READ_ONLY ); if ( !pKeyValues->ReadAsBinary( bufRead, 90 ) ) // we are expecting very few nest levels of keyvalues here!
{ Assert( false ); }
return pKeyValues; }
void CmdKeyValuesHelper::SVCMsg_SetKeyValues( CSVCMsg_CmdKeyValues& msg, const KeyValues *keyValues ) { CUtlBuffer bufData; keyValues->WriteAsBinary( bufData ); int numBytes = bufData.TellPut(); msg.set_keyvalues( bufData.Base(), numBytes ); }
KeyValues *CmdKeyValuesHelper::SVCMsg_GetKeyValues ( const CSVCMsg_CmdKeyValues& msg ) { KeyValues *pKeyValues = new KeyValues( "" );
const std::string& msgStr = msg.keyvalues(); int numBytes = msgStr.size();
CUtlBuffer bufRead( msgStr.data(), numBytes, CUtlBuffer::READ_ONLY ); if ( !pKeyValues->ReadAsBinary( bufRead ) ) { Assert( false ); }
return pKeyValues; }
/*
bool CmdEncryptedDataMessageCodec::SVCMsg_EncryptedData_EncryptMessage( CSVCMsg_EncryptedData_t &msgEncryptedResult, const ::google::protobuf::Message &msgPlaintextInput ) { static char const *szEncryptedTag = "[[ENCRYPTED_DATA]]"; static size_t nEncryptedLen = Q_strlen( szEncryptedTag ); int32 const numBytesWritten = msgPlaintextInput.ByteSize(); msgEncryptedResult.mutable_encrypted()->resize( nEncryptedLen + sizeof( int32 ) + numBytesWritten );
Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at(0), szEncryptedTag, nEncryptedLen ); int32 const numBytesWrittenWire = BigLong( numBytesWritten ); // byteswap for the wire
Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at( nEncryptedLen ), &numBytesWrittenWire, sizeof( numBytesWrittenWire ) ); return msgPlaintextInput.SerializeWithCachedSizesToArray( ( uint8 * ) &msgEncryptedResult.mutable_encrypted()->at( nEncryptedLen + sizeof( int32 ) ) ); } */
bool CmdEncryptedDataMessageCodec::SVCMsg_EncryptedData_EncryptMessage( CSVCMsg_EncryptedData_t &msgEncryptedResult, INetMessage *pMsgPlaintextInput, char const *key ) { // Prepare encryption key
IceKey iceKey( 2 ); if ( iceKey.keySize() != Q_strlen( key ) ) { Warning( "CmdEncryptedDataMessageCodec key size is %d, but %d is expected!\n", Q_strlen( key ), iceKey.keySize() ); return false; // we cannot encrypt with the supplied key
} iceKey.set( ( const unsigned char * ) key );
// supporting smaller stack
net_scratchbuffer_t scratch; bf_write msg( "SVCMsg_EncryptedData_EncryptMessage", scratch.GetBuffer(), scratch.Size() ); if ( !pMsgPlaintextInput->WriteToBuffer( msg ) ) return false; int32 const numBytesWritten = msg.GetNumBytesWritten(); // Generate some random fudge, ICE operates on 64-bit blocks, so make sure our total size is a multiple of 8 bytes
int numRandomFudgeBytes = RandomInt( 16, 72 ); int numTotalEncryptedBytes = 1 + numRandomFudgeBytes + sizeof( int32 ) + numBytesWritten; numRandomFudgeBytes += iceKey.blockSize() - ( numTotalEncryptedBytes % iceKey.blockSize() ); numTotalEncryptedBytes = 1 + numRandomFudgeBytes + sizeof( int32 ) + numBytesWritten;
char *pchRandomFudgeBytes = ( char * ) stackalloc( numRandomFudgeBytes ); for ( int k = 0; k < numRandomFudgeBytes; ++ k ) pchRandomFudgeBytes[k] = RandomInt( 16, 250 ); msgEncryptedResult.mutable_encrypted()->resize( numTotalEncryptedBytes );
msgEncryptedResult.mutable_encrypted()->at(0) = numRandomFudgeBytes; Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at(1), pchRandomFudgeBytes, numRandomFudgeBytes ); int32 const numBytesWrittenWire = BigLong( numBytesWritten ); // byteswap for the wire
Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at( 1 + numRandomFudgeBytes ), &numBytesWrittenWire, sizeof( numBytesWrittenWire ) ); Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at( 1 + numRandomFudgeBytes + sizeof( int32 ) ), msg.GetBasePointer(), numBytesWritten );
// Encrypt the message
unsigned char *pchCryptoBuffer = ( unsigned char * ) stackalloc( iceKey.blockSize() ); for ( int k = 0; k < numTotalEncryptedBytes; k += iceKey.blockSize() ) { iceKey.encrypt( ( const unsigned char * ) &msgEncryptedResult.mutable_encrypted()->at(k), pchCryptoBuffer ); Q_memcpy( &msgEncryptedResult.mutable_encrypted()->at(k), pchCryptoBuffer, iceKey.blockSize() ); } return true; }
bool CmdEncryptedDataMessageCodec::SVCMsg_EncryptedData_Process( CSVCMsg_EncryptedData const &msgEncryptedInput, INetChannel *pProcessingChannelInterface, char const *key ) { CNetChan *pProcessingChannel = ( CNetChan * ) pProcessingChannelInterface; if ( !pProcessingChannel ) return false;
if ( !msgEncryptedInput.has_encrypted() ) return true;
if ( !key || !*key ) return true; // key is not supplied, so ignore the message
// Decrypt the message
IceKey iceKey( 2 ); if ( iceKey.keySize() != Q_strlen( key ) ) return true; // we cannot decrypt with the supplied key
iceKey.set( ( const unsigned char * ) key ); if ( msgEncryptedInput.encrypted().size() % iceKey.blockSize() ) return true; // message malformed, cannot decrypt
if ( msgEncryptedInput.encrypted().size() > NET_MAX_PAYLOAD ) return true; // size too large, cannot decrypt
net_scratchbuffer_t scratch; byte *buffer = scratch.GetBuffer(); unsigned char *pchCryptoBuffer = ( unsigned char * ) stackalloc( iceKey.blockSize() ); for ( int k = 0; k < ( int ) msgEncryptedInput.encrypted().size(); k += iceKey.blockSize() ) { iceKey.decrypt( ( const unsigned char * ) &msgEncryptedInput.encrypted().at(k), pchCryptoBuffer ); Q_memcpy( &buffer[k], pchCryptoBuffer, iceKey.blockSize() ); }
// Check how much random fudge we have
int numRandomFudgeBytes = *buffer; if ( ( numRandomFudgeBytes > 0 ) && ( numRandomFudgeBytes + 1 + sizeof( int32 ) < msgEncryptedInput.encrypted().size() ) ) { // Fetch the size of the encrypted message
int32 numBytesWrittenWire = 0; Q_memcpy( &numBytesWrittenWire, &buffer[ 1 + numRandomFudgeBytes ], sizeof( int32 ) ); int32 const numBytesWritten = BigLong( numBytesWrittenWire ); // byteswap from the wire
// Make sure the total size of the message matches the expectations
if ( numRandomFudgeBytes + 1 + sizeof( int32 ) + numBytesWritten == msgEncryptedInput.encrypted().size() ) { bf_read bufRead( &buffer[ 1 + numRandomFudgeBytes + sizeof( int32 ) ], numBytesWritten ); unsigned char cmd = bufRead.ReadVarInt32();
// See if the netchan has the required binder registered
int iMsgHandler = 0; INetMessageBinder *pMsgBind = pProcessingChannel->FindMessageBinder( cmd, iMsgHandler++ ); if ( pMsgBind ) { int startbit = bufRead.GetNumBitsRead();
INetMessage *pEmbeddedMessage = pMsgBind->CreateFromBuffer( bufRead ); if ( !pEmbeddedMessage ) { Msg( "CmdEncryptedDataMessageCodec failed to parse embedded message" ); Assert( 0 ); return false; } pEmbeddedMessage->SetReliable( pProcessingChannel->WasLastMessageReliable() );
pProcessingChannel->UpdateMessageStats( pEmbeddedMessage->GetGroup(), bufRead.GetNumBitsRead() - startbit );
do { bool bRet = pMsgBind->Process( *pEmbeddedMessage ); if ( !bRet ) { ConDMsg( "CmdEncryptedDataMessageCodec: netchannel failed processing embedded message %s.\n", pEmbeddedMessage->GetName() ); Assert ( 0 ); delete pEmbeddedMessage; return false; }
// Move to another binder
pMsgBind = pProcessingChannel->FindMessageBinder( cmd, iMsgHandler++ ); } while ( pMsgBind );
delete pEmbeddedMessage; } } }
return true; }
CTSPool< net_scratchbuffer_t::buffer_t > net_scratchbuffer_t::sm_NetScratchBuffers;
#if defined( REPLAY_ENABLED )
bool CLC_SaveReplay::WriteToBuffer( bf_write &buffer ) const { buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); buffer.WriteString( m_szFilename ); buffer.WriteUBitLong( m_nStartSendByte, sizeof( m_nStartSendByte ) ); buffer.WriteFloat( m_flPostDeathRecordTime ); return !buffer.IsOverflowed(); }
bool CLC_SaveReplay::ReadFromBuffer( bf_read &buffer ) { buffer.ReadString( m_szFilename, sizeof( m_szFilename ) ); m_nStartSendByte = buffer.ReadUBitLong( sizeof( m_nStartSendByte ) ); m_flPostDeathRecordTime = buffer.ReadFloat(); return !buffer.IsOverflowed(); }
const char *CLC_SaveReplay::ToString() const { V_snprintf( s_text, sizeof( s_text ), "%s: filename: %s, start byte: %i, post death record time: %f", GetName(), m_szFilename, m_nStartSendByte, m_flPostDeathRecordTime ); return s_text; } #endif
|