csgo-2018-source/common/netmessages.cpp

337 lines
11 KiB
C++
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//========= Copyright <20> 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