You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
11 KiB
336 lines
11 KiB
//========= 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
|