2013-07-29 12:13:03 +01:00
// Connection.cpp
// Interfaces to the cConnection class representing a single pair of connected sockets
#include "Globals.h"
#include "Connection.h"
#include "Server.h"
#include <iostream>
#ifdef _DEBUG
#define DebugSleep Sleep
#else
#define DebugSleep(X)
#endif // else _DEBUG
#define HANDLE_CLIENT_PACKET_READ(Proc, Type, Var) \
Type Var; \
{ \
if (!m_ClientBuffer.Proc(Var)) \
{ \
return false; \
} \
}
#define HANDLE_SERVER_PACKET_READ(Proc, Type, Var) \
Type Var; \
{ \
if (!m_ServerBuffer.Proc(Var)) \
{ \
return false; \
} \
}
#define CLIENTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client")
#define SERVERSEND(...) SendData(m_ServerSocket, __VA_ARGS__, "Server")
#define CLIENTENCRYPTSEND(...) SendEncryptedData(m_ClientSocket, m_ClientEncryptor, __VA_ARGS__, "Client")
#define SERVERENCRYPTSEND(...) SendEncryptedData(m_ServerSocket, m_ServerEncryptor, __VA_ARGS__, "Server")
#define COPY_TO_SERVER() \
{ \
AString ToServer; \
m_ClientBuffer.ReadAgain(ToServer); \
switch (m_ServerState) \
{ \
case csUnencrypted: \
{ \
SERVERSEND(ToServer.data(), ToServer.size()); \
break; \
} \
case csEncryptedUnderstood: \
case csEncryptedUnknown: \
{ \
SERVERENCRYPTSEND(ToServer.data(), ToServer.size()); \
break; \
} \
case csWaitingForEncryption: \
{ \
Log("Waiting for server encryption, queued %u bytes", ToServer.size()); \
m_ServerEncryptionBuffer.append(ToServer.data(), ToServer.size()); \
break; \
} \
} \
DebugSleep(50); \
}
#define COPY_TO_CLIENT() \
{ \
AString ToClient; \
m_ServerBuffer.ReadAgain(ToClient); \
switch (m_ClientState) \
{ \
case csUnencrypted: \
{ \
CLIENTSEND(ToClient.data(), ToClient.size()); \
break; \
} \
case csEncryptedUnderstood: \
case csEncryptedUnknown: \
{ \
CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
break; \
} \
case csWaitingForEncryption: \
{ \
Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \
m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \
break; \
} \
} \
DebugSleep(50); \
}
#define HANDLE_CLIENT_READ(Proc) \
{ \
if (!Proc()) \
{ \
AString Leftover; \
m_ClientBuffer.ReadAgain(Leftover); \
DataLog(Leftover.data(), Leftover.size(), "Leftover data after client packet parsing, %d bytes:", Leftover.size()); \
m_ClientBuffer.ResetRead(); \
return true; \
} \
}
#define HANDLE_SERVER_READ(Proc) \
{ \
if (!Proc()) \
{ \
m_ServerBuffer.ResetRead(); \
return true; \
} \
}
#define MAX_ENC_LEN 1024
typedef unsigned char Byte ;
enum
{
PACKET_KEEPALIVE = 0x00 ,
PACKET_LOGIN = 0x01 ,
PACKET_HANDSHAKE = 0x02 ,
PACKET_CHAT_MESSAGE = 0x03 ,
PACKET_TIME_UPDATE = 0x04 ,
PACKET_ENTITY_EQUIPMENT = 0x05 ,
PACKET_COMPASS = 0x06 ,
PACKET_USE_ENTITY = 0x07 ,
PACKET_UPDATE_HEALTH = 0x08 ,
PACKET_PLAYER_ON_GROUND = 0x0a ,
PACKET_PLAYER_POSITION = 0x0b ,
PACKET_PLAYER_LOOK = 0x0c ,
PACKET_PLAYER_POSITION_LOOK = 0x0d ,
PACKET_BLOCK_DIG = 0x0e ,
PACKET_BLOCK_PLACE = 0x0f ,
PACKET_SLOT_SELECT = 0x10 ,
PACKET_PLAYER_ANIMATION = 0x12 ,
PACKET_ENTITY_ACTION = 0x13 ,
PACKET_SPAWN_NAMED_ENTITY = 0x14 ,
PACKET_SPAWN_PICKUP = 0x15 ,
PACKET_COLLECT_PICKUP = 0x16 ,
PACKET_SPAWN_OBJECT_VEHICLE = 0x17 ,
PACKET_SPAWN_MOB = 0x18 ,
PACKET_SPAWN_PAINTING = 0x19 ,
PACKET_SPAWN_EXPERIENCE_ORB = 0x1a ,
PACKET_ENTITY_VELOCITY = 0x1c ,
PACKET_DESTROY_ENTITIES = 0x1d ,
PACKET_ENTITY = 0x1e ,
PACKET_ENTITY_RELATIVE_MOVE = 0x1f ,
PACKET_ENTITY_LOOK = 0x20 ,
PACKET_ENTITY_RELATIVE_MOVE_LOOK = 0x21 ,
PACKET_ENTITY_TELEPORT = 0x22 ,
PACKET_ENTITY_HEAD_LOOK = 0x23 ,
PACKET_ENTITY_STATUS = 0x26 ,
PACKET_ATTACH_ENTITY = 0x27 ,
PACKET_ENTITY_METADATA = 0x28 ,
PACKET_ENTITY_EFFECT = 0x29 ,
PACKET_ENTITY_EFFECT_REMOVE = 0x2a ,
PACKET_SET_EXPERIENCE = 0x2b ,
PACKET_ENTITY_PROPERTIES = 0x2c ,
PACKET_MAP_CHUNK = 0x33 ,
PACKET_MULTI_BLOCK_CHANGE = 0x34 ,
PACKET_BLOCK_CHANGE = 0x35 ,
PACKET_BLOCK_ACTION = 0x36 ,
PACKET_MAP_CHUNK_BULK = 0x38 ,
PACKET_SOUND_EFFECT = 0x3d ,
PACKET_NAMED_SOUND_EFFECT = 0x3e ,
PACKET_CHANGE_GAME_STATE = 0x46 ,
PACKET_WINDOW_OPEN = 0x64 ,
PACKET_WINDOW_CLOSE = 0x65 ,
PACKET_WINDOW_CLICK = 0x66 ,
PACKET_SET_SLOT = 0x67 ,
PACKET_WINDOW_CONTENTS = 0x68 ,
PACKET_CREATIVE_INVENTORY_ACTION = 0x6b ,
PACKET_UPDATE_SIGN = 0x82 ,
PACKET_UPDATE_TILE_ENTITY = 0x84 ,
PACKET_PLAYER_LIST_ITEM = 0xc9 ,
PACKET_PLAYER_ABILITIES = 0xca ,
PACKET_INCREMENT_STATISTIC = 0xc8 ,
2013-07-31 14:32:05 +02:00
PACKET_TAB_COMPLETION = 0xcb ,
2013-07-29 12:13:03 +01:00
PACKET_LOCALE_AND_VIEW = 0xcc ,
PACKET_CLIENT_STATUSES = 0xcd ,
PACKET_PLUGIN_MESSAGE = 0xfa ,
PACKET_ENCRYPTION_KEY_RESPONSE = 0xfc ,
PACKET_ENCRYPTION_KEY_REQUEST = 0xfd ,
PACKET_PING = 0xfe ,
PACKET_KICK = 0xff ,
2013-08-25 21:57:12 +02:00
// Synonyms:
PACKET_DISCONNECT = PACKET_KICK ,
2013-07-29 12:13:03 +01:00
} ;
enum
{
OBJECT_BOAT = 1 ,
OBJECT_MINECART = 10 ,
OBJECT_MINECART_STORAGE = 11 ,
OBJECT_MINECART_POWERED = 12 ,
2013-08-16 11:23:24 +01:00
OBJECT_MINECART_TNT = 13 ,
OBJECT_MINECART_HOPPER = 14 ,
2013-07-29 12:13:03 +01:00
OBJECT_TNT = 50 ,
OBJECT_ENDERCRYSTAL = 51 ,
OBJECT_ARROW = 60 ,
OBJECT_SNOWBALL = 61 ,
OBJECT_EGG = 62 ,
OBJECT_FALLING_BLOCK = 70 ,
OBJECT_EYE_OF_ENDER = 72 ,
OBJECT_DRAGON_EGG = 74 ,
OBJECT_FISHING_FLOAT = 90 ,
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cConnection:
cConnection :: cConnection ( SOCKET a_ClientSocket , cServer & a_Server ) :
m_ItemIdx ( 0 ),
m_LogFile ( NULL ),
m_Server ( a_Server ),
m_ClientSocket ( a_ClientSocket ),
m_ServerSocket ( - 1 ),
2013-08-30 10:10:56 +02:00
m_BeginTick ( m_Timer . GetNowTime ()),
2013-07-29 12:13:03 +01:00
m_ClientState ( csUnencrypted ),
m_ServerState ( csUnencrypted ),
m_Nonce ( 0 ),
m_ClientBuffer ( 1024 KiB ),
m_ServerBuffer ( 1024 KiB ),
m_HasClientPinged ( false )
{
Printf ( m_LogNameBase , "Log_%d" , ( int ) time ( NULL ));
AString fnam ( m_LogNameBase );
fnam . append ( ".log" );
m_LogFile = fopen ( fnam . c_str (), "w" );
Log ( "Log file created" );
printf ( "Connection is logged to file \" %s \"\n " , fnam . c_str ());
}
cConnection ::~ cConnection ()
{
fclose ( m_LogFile );
}
void cConnection :: Run ( void )
{
if ( ! ConnectToServer ())
{
Log ( "Cannot connect to server; aborting" );
return ;
}
while ( true )
{
fd_set ReadFDs ;
FD_ZERO ( & ReadFDs );
FD_SET ( m_ServerSocket , & ReadFDs );
FD_SET ( m_ClientSocket , & ReadFDs );
int res = select ( 2 , & ReadFDs , NULL , NULL , NULL );
if ( res <= 0 )
{
printf ( "select() failed: %d; aborting client" , WSAGetLastError ());
break ;
}
if ( FD_ISSET ( m_ServerSocket , & ReadFDs ))
{
if ( ! RelayFromServer ())
{
break ;
}
}
if ( FD_ISSET ( m_ClientSocket , & ReadFDs ))
{
if ( ! RelayFromClient ())
{
break ;
}
}
}
Log ( "Relaying ended, closing sockets" );
closesocket ( m_ServerSocket );
closesocket ( m_ClientSocket );
}
void cConnection :: Log ( const char * a_Format , ...)
{
va_list args ;
va_start ( args , a_Format );
AString msg ;
AppendVPrintf ( msg , a_Format , args );
va_end ( args );
AString FullMsg ;
Printf ( FullMsg , "[%5.3f] %s \n " , GetRelativeTime (), msg . c_str ());
// Log to file:
cCSLock Lock ( m_CSLog );
fputs ( FullMsg . c_str (), m_LogFile );
// Log to screen:
// std::cout << FullMsg;
}
void cConnection :: DataLog ( const void * a_Data , int a_Size , const char * a_Format , ...)
{
va_list args ;
va_start ( args , a_Format );
AString msg ;
AppendVPrintf ( msg , a_Format , args );
va_end ( args );
AString FullMsg ;
AString Hex ;
Printf ( FullMsg , "[%5.3f] %s \n %s \n " , GetRelativeTime (), msg . c_str (), CreateHexDump ( Hex , a_Data , a_Size , 16 ). c_str ());
// Log to file:
cCSLock Lock ( m_CSLog );
fputs ( FullMsg . c_str (), m_LogFile );
/*
// Log to screen:
std::cout << FullMsg;
//*/
}
void cConnection :: LogFlush ( void )
{
fflush ( m_LogFile );
}
bool cConnection :: ConnectToServer ( void )
{
m_ServerSocket = socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP );
if ( m_ServerSocket == INVALID_SOCKET )
{
return false ;
}
sockaddr_in localhost ;
localhost . sin_family = AF_INET ;
localhost . sin_port = htons ( m_Server . GetConnectPort ());
localhost . sin_addr . s_addr = htonl ( 0x7f000001 ); // localhost
if ( connect ( m_ServerSocket , ( sockaddr * ) & localhost , sizeof ( localhost )) != 0 )
{
printf ( "connection to server failed: %d \n " , WSAGetLastError ());
return false ;
}
Log ( "Connected to SERVER" );
return true ;
}
bool cConnection :: RelayFromServer ( void )
{
char Buffer [ 64 KiB ];
int res = recv ( m_ServerSocket , Buffer , sizeof ( Buffer ), 0 );
if ( res <= 0 )
{
Log ( "Server closed the socket: %d; %d; aborting connection" , res , WSAGetLastError ());
return false ;
}
DataLog ( Buffer , res , "Received %d bytes from the SERVER" , res );
switch ( m_ServerState )
{
case csUnencrypted :
case csWaitingForEncryption :
{
return DecodeServersPackets ( Buffer , res );
}
case csEncryptedUnderstood :
{
m_ServerDecryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
DataLog ( Buffer , res , "Decrypted %d bytes from the SERVER" , res );
return DecodeServersPackets ( Buffer , res );
}
case csEncryptedUnknown :
{
m_ServerDecryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
DataLog ( Buffer , res , "Decrypted %d bytes from the SERVER" , res );
m_ClientEncryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
return CLIENTSEND ( Buffer , res );
}
}
return true ;
}
bool cConnection :: RelayFromClient ( void )
{
char Buffer [ 64 KiB ];
int res = recv ( m_ClientSocket , Buffer , sizeof ( Buffer ), 0 );
if ( res <= 0 )
{
Log ( "Client closed the socket: %d; %d; aborting connection" , res , WSAGetLastError ());
return false ;
}
DataLog ( Buffer , res , "Received %d bytes from the CLIENT" , res );
switch ( m_ClientState )
{
case csUnencrypted :
case csWaitingForEncryption :
{
return DecodeClientsPackets ( Buffer , res );
}
case csEncryptedUnderstood :
{
m_ClientDecryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
DataLog ( Buffer , res , "Decrypted %d bytes from the CLIENT" , res );
return DecodeClientsPackets ( Buffer , res );
}
case csEncryptedUnknown :
{
m_ClientDecryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
DataLog ( Buffer , res , "Decrypted %d bytes from the CLIENT" , res );
m_ServerEncryptor . ProcessData (( byte * ) Buffer , ( byte * ) Buffer , res );
return SERVERSEND ( Buffer , res );
}
}
return true ;
}
double cConnection :: GetRelativeTime ( void )
{
2013-08-30 10:10:56 +02:00
return ( double )( m_Timer . GetNowTime () - m_BeginTick ) / 1000 ;
2013-07-29 12:13:03 +01:00
}
bool cConnection :: SendData ( SOCKET a_Socket , const char * a_Data , int a_Size , const char * a_Peer )
{
DataLog ( a_Data , a_Size , "Sending data to %s" , a_Peer );
int res = send ( a_Socket , a_Data , a_Size , 0 );
if ( res <= 0 )
{
Log ( "%s closed the socket: %d, %d; aborting connection" , a_Peer , res , WSAGetLastError ());
return false ;
}
return true ;
}
bool cConnection :: SendData ( SOCKET a_Socket , cByteBuffer & a_Data , const char * a_Peer )
{
AString All ;
a_Data . ReadAll ( All );
a_Data . CommitRead ();
return SendData ( a_Socket , All . data (), All . size (), a_Peer );
}
bool cConnection :: SendEncryptedData ( SOCKET a_Socket , Encryptor & a_Encryptor , const char * a_Data , int a_Size , const char * a_Peer )
{
DataLog ( a_Data , a_Size , "Encrypting %d bytes to %s" , a_Size , a_Peer );
const byte * Data = ( const byte * ) a_Data ;
while ( a_Size > 0 )
{
byte Buffer [ 64 KiB ];
int NumBytes = ( a_Size > sizeof ( Buffer )) ? sizeof ( Buffer ) : a_Size ;
a_Encryptor . ProcessData ( Buffer , Data , NumBytes );
bool res = SendData ( a_Socket , ( const char * ) Buffer , NumBytes , a_Peer );
if ( ! res )
{
return false ;
}
Data += NumBytes ;
a_Size -= NumBytes ;
}
return true ;
}
bool cConnection :: SendEncryptedData ( SOCKET a_Socket , Encryptor & a_Encryptor , cByteBuffer & a_Data , const char * a_Peer )
{
AString All ;
a_Data . ReadAll ( All );
a_Data . CommitRead ();
return SendEncryptedData ( a_Socket , a_Encryptor , All . data (), All . size (), a_Peer );
}
bool cConnection :: DecodeClientsPackets ( const char * a_Data , int a_Size )
{
if ( ! m_ClientBuffer . Write ( a_Data , a_Size ))
{
Log ( "Too much queued data for the server, aborting connection" );
return false ;
}
while ( m_ClientBuffer . CanReadBytes ( 1 ))
{
unsigned char PacketType ;
m_ClientBuffer . ReadByte ( PacketType );
2013-08-30 10:15:54 +02:00
Log ( "Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%02x" , m_ClientBuffer . GetReadableSpace (), PacketType );
2013-07-29 12:13:03 +01:00
switch ( PacketType )
{
case PACKET_BLOCK_DIG : HANDLE_CLIENT_READ ( HandleClientBlockDig ); break ;
case PACKET_BLOCK_PLACE : HANDLE_CLIENT_READ ( HandleClientBlockPlace ); break ;
case PACKET_CHAT_MESSAGE : HANDLE_CLIENT_READ ( HandleClientChatMessage ); break ;
case PACKET_CLIENT_STATUSES : HANDLE_CLIENT_READ ( HandleClientClientStatuses ); break ;
case PACKET_CREATIVE_INVENTORY_ACTION : HANDLE_CLIENT_READ ( HandleClientCreativeInventoryAction ); break ;
2013-08-25 21:57:12 +02:00
case PACKET_DISCONNECT : HANDLE_CLIENT_READ ( HandleClientDisconnect ); break ;
2013-07-29 12:13:03 +01:00
case PACKET_ENCRYPTION_KEY_RESPONSE : HANDLE_CLIENT_READ ( HandleClientEncryptionKeyResponse ); break ;
case PACKET_ENTITY_ACTION : HANDLE_CLIENT_READ ( HandleClientEntityAction ); break ;
case PACKET_HANDSHAKE : HANDLE_CLIENT_READ ( HandleClientHandshake ); break ;
case PACKET_KEEPALIVE : HANDLE_CLIENT_READ ( HandleClientKeepAlive ); break ;
case PACKET_LOCALE_AND_VIEW : HANDLE_CLIENT_READ ( HandleClientLocaleAndView ); break ;
case PACKET_PING : HANDLE_CLIENT_READ ( HandleClientPing ); break ;
case PACKET_PLAYER_ABILITIES : HANDLE_CLIENT_READ ( HandleClientPlayerAbilities ); break ;
case PACKET_PLAYER_ANIMATION : HANDLE_CLIENT_READ ( HandleClientAnimation ); break ;
case PACKET_PLAYER_LOOK : HANDLE_CLIENT_READ ( HandleClientPlayerLook ); break ;
case PACKET_PLAYER_ON_GROUND : HANDLE_CLIENT_READ ( HandleClientPlayerOnGround ); break ;
case PACKET_PLAYER_POSITION : HANDLE_CLIENT_READ ( HandleClientPlayerPosition ); break ;
case PACKET_PLAYER_POSITION_LOOK : HANDLE_CLIENT_READ ( HandleClientPlayerPositionLook ); break ;
case PACKET_PLUGIN_MESSAGE : HANDLE_CLIENT_READ ( HandleClientPluginMessage ); break ;
case PACKET_SLOT_SELECT : HANDLE_CLIENT_READ ( HandleClientSlotSelect ); break ;
2013-07-31 14:32:05 +02:00
case PACKET_TAB_COMPLETION : HANDLE_CLIENT_READ ( HandleClientTabCompletion ); break ;
2013-07-29 12:13:03 +01:00
case PACKET_UPDATE_SIGN : HANDLE_CLIENT_READ ( HandleClientUpdateSign ); break ;
case PACKET_USE_ENTITY : HANDLE_CLIENT_READ ( HandleClientUseEntity ); break ;
case PACKET_WINDOW_CLICK : HANDLE_CLIENT_READ ( HandleClientWindowClick ); break ;
case PACKET_WINDOW_CLOSE : HANDLE_CLIENT_READ ( HandleClientWindowClose ); break ;
default :
{
if ( m_ClientState == csEncryptedUnderstood )
{
Log ( "****************** Unknown packet 0x%02x from the client while encrypted; continuing to relay blind only" , PacketType );
AString Data ;
m_ClientBuffer . ResetRead ();
m_ClientBuffer . ReadAll ( Data );
DataLog ( Data . data (), Data . size (), "Current data in the client packet queue: %d bytes" , Data . size ());
m_ClientState = csEncryptedUnknown ;
m_ClientBuffer . ResetRead ();
if ( m_ServerState == csUnencrypted )
{
SERVERSEND ( m_ClientBuffer );
}
else
{
SERVERENCRYPTSEND ( m_ClientBuffer );
}
return true ;
}
else
{
Log ( "Unknown packet 0x%02x from the client while unencrypted; aborting connection" , PacketType );
return false ;
}
}
} // switch (PacketType)
m_ClientBuffer . CommitRead ();
} // while (CanReadBytes(1))
return true ;
}
bool cConnection :: DecodeServersPackets ( const char * a_Data , int a_Size )
{
if ( ! m_ServerBuffer . Write ( a_Data , a_Size ))
{
Log ( "Too much queued data for the client, aborting connection" );
return false ;
}
if (
( m_ServerState == csEncryptedUnderstood ) &&
( m_ClientState == csUnencrypted )
)
{
// Client hasn't finished encryption handshake yet, don't send them any data yet
}
while ( m_ServerBuffer . CanReadBytes ( 1 ))
{
unsigned char PacketType ;
m_ServerBuffer . ReadByte ( PacketType );
2013-08-30 10:15:54 +02:00
Log ( "Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%02x" , m_ServerBuffer . GetReadableSpace (), PacketType );
2013-07-29 12:13:03 +01:00
LogFlush ();
switch ( PacketType )
{
case PACKET_ATTACH_ENTITY : HANDLE_SERVER_READ ( HandleServerAttachEntity ); break ;
case PACKET_BLOCK_ACTION : HANDLE_SERVER_READ ( HandleServerBlockAction ); break ;
case PACKET_BLOCK_CHANGE : HANDLE_SERVER_READ ( HandleServerBlockChange ); break ;
case PACKET_CHANGE_GAME_STATE : HANDLE_SERVER_READ ( HandleServerChangeGameState ); break ;
case PACKET_CHAT_MESSAGE : HANDLE_SERVER_READ ( HandleServerChatMessage ); break ;
case PACKET_COLLECT_PICKUP : HANDLE_SERVER_READ ( HandleServerCollectPickup ); break ;
case PACKET_COMPASS : HANDLE_SERVER_READ ( HandleServerCompass ); break ;
case PACKET_DESTROY_ENTITIES : HANDLE_SERVER_READ ( HandleServerDestroyEntities ); break ;
case PACKET_ENCRYPTION_KEY_REQUEST : HANDLE_SERVER_READ ( HandleServerEncryptionKeyRequest ); break ;
case PACKET_ENCRYPTION_KEY_RESPONSE : HANDLE_SERVER_READ ( HandleServerEncryptionKeyResponse ); break ;
case PACKET_ENTITY : HANDLE_SERVER_READ ( HandleServerEntity ); break ;
case PACKET_ENTITY_EQUIPMENT : HANDLE_SERVER_READ ( HandleServerEntityEquipment ); break ;
case PACKET_ENTITY_HEAD_LOOK : HANDLE_SERVER_READ ( HandleServerEntityHeadLook ); break ;
case PACKET_ENTITY_LOOK : HANDLE_SERVER_READ ( HandleServerEntityLook ); break ;
case PACKET_ENTITY_METADATA : HANDLE_SERVER_READ ( HandleServerEntityMetadata ); break ;
case PACKET_ENTITY_PROPERTIES : HANDLE_SERVER_READ ( HandleServerEntityProperties ); break ;
case PACKET_ENTITY_RELATIVE_MOVE : HANDLE_SERVER_READ ( HandleServerEntityRelativeMove ); break ;
case PACKET_ENTITY_RELATIVE_MOVE_LOOK : HANDLE_SERVER_READ ( HandleServerEntityRelativeMoveLook ); break ;
case PACKET_ENTITY_STATUS : HANDLE_SERVER_READ ( HandleServerEntityStatus ); break ;
case PACKET_ENTITY_TELEPORT : HANDLE_SERVER_READ ( HandleServerEntityTeleport ); break ;
case PACKET_ENTITY_VELOCITY : HANDLE_SERVER_READ ( HandleServerEntityVelocity ); break ;
case PACKET_INCREMENT_STATISTIC : HANDLE_SERVER_READ ( HandleServerIncrementStatistic ); break ;
case PACKET_KEEPALIVE : HANDLE_SERVER_READ ( HandleServerKeepAlive ); break ;
case PACKET_KICK : HANDLE_SERVER_READ ( HandleServerKick ); break ;
case PACKET_LOGIN : HANDLE_SERVER_READ ( HandleServerLogin ); break ;
case PACKET_MAP_CHUNK : HANDLE_SERVER_READ ( HandleServerMapChunk ); break ;
case PACKET_MAP_CHUNK_BULK : HANDLE_SERVER_READ ( HandleServerMapChunkBulk ); break ;
case PACKET_MULTI_BLOCK_CHANGE : HANDLE_SERVER_READ ( HandleServerMultiBlockChange ); break ;
case PACKET_NAMED_SOUND_EFFECT : HANDLE_SERVER_READ ( HandleServerNamedSoundEffect ); break ;
case PACKET_PLAYER_ABILITIES : HANDLE_SERVER_READ ( HandleServerPlayerAbilities ); break ;
case PACKET_PLAYER_ANIMATION : HANDLE_SERVER_READ ( HandleServerPlayerAnimation ); break ;
case PACKET_PLAYER_LIST_ITEM : HANDLE_SERVER_READ ( HandleServerPlayerListItem ); break ;
case PACKET_PLAYER_POSITION_LOOK : HANDLE_SERVER_READ ( HandleServerPlayerPositionLook ); break ;
case PACKET_PLUGIN_MESSAGE : HANDLE_SERVER_READ ( HandleServerPluginMessage ); break ;
case PACKET_SET_EXPERIENCE : HANDLE_SERVER_READ ( HandleServerSetExperience ); break ;
case PACKET_SET_SLOT : HANDLE_SERVER_READ ( HandleServerSetSlot ); break ;
case PACKET_SLOT_SELECT : HANDLE_SERVER_READ ( HandleServerSlotSelect ); break ;
case PACKET_SOUND_EFFECT : HANDLE_SERVER_READ ( HandleServerSoundEffect ); break ;
case PACKET_SPAWN_MOB : HANDLE_SERVER_READ ( HandleServerSpawnMob ); break ;
case PACKET_SPAWN_NAMED_ENTITY : HANDLE_SERVER_READ ( HandleServerSpawnNamedEntity ); break ;
case PACKET_SPAWN_OBJECT_VEHICLE : HANDLE_SERVER_READ ( HandleServerSpawnObjectVehicle ); break ;
case PACKET_SPAWN_PAINTING : HANDLE_SERVER_READ ( HandleServerSpawnPainting ); break ;
case PACKET_SPAWN_PICKUP : HANDLE_SERVER_READ ( HandleServerSpawnPickup ); break ;
2013-07-31 14:32:05 +02:00
case PACKET_TAB_COMPLETION : HANDLE_SERVER_READ ( HandleServerTabCompletion ); break ;
2013-07-29 12:13:03 +01:00
case PACKET_TIME_UPDATE : HANDLE_SERVER_READ ( HandleServerTimeUpdate ); break ;
case PACKET_UPDATE_HEALTH : HANDLE_SERVER_READ ( HandleServerUpdateHealth ); break ;
case PACKET_UPDATE_SIGN : HANDLE_SERVER_READ ( HandleServerUpdateSign ); break ;
case PACKET_UPDATE_TILE_ENTITY : HANDLE_SERVER_READ ( HandleServerUpdateTileEntity ); break ;
case PACKET_WINDOW_CLOSE : HANDLE_SERVER_READ ( HandleServerWindowClose ); break ;
case PACKET_WINDOW_CONTENTS : HANDLE_SERVER_READ ( HandleServerWindowContents ); break ;
case PACKET_WINDOW_OPEN : HANDLE_SERVER_READ ( HandleServerWindowOpen ); break ;
default :
{
if ( m_ServerState == csEncryptedUnderstood )
{
Log ( "********************** Unknown packet 0x%02x from the server while encrypted; continuing to relay blind only" , PacketType );
AString Data ;
m_ServerBuffer . ResetRead ();
m_ServerBuffer . ReadAll ( Data );
DataLog ( Data . data (), Data . size (), "Current data in the server packet queue: %d bytes" , Data . size ());
m_ServerState = csEncryptedUnknown ;
m_ServerBuffer . ResetRead ();
if ( m_ClientState == csUnencrypted )
{
CLIENTSEND ( m_ServerBuffer );
}
else
{
CLIENTENCRYPTSEND ( m_ServerBuffer );
}
return true ;
}
else
{
Log ( "Unknown packet 0x%02x from the server while unencrypted; aborting connection" , PacketType );
return false ;
}
}
} // switch (PacketType)
m_ServerBuffer . CommitRead ();
} // while (CanReadBytes(1))
return true ;
}
bool cConnection :: HandleClientAnimation ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , Animation );
Log ( "Received a PACKET_ANIMATION from the client:" );
Log ( " EntityID: %d" , EntityID );
Log ( " Animation: %d" , Animation );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientBlockDig ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , Status );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , BlockY );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , BlockFace );
Log ( "Received a PACKET_BLOCK_DIG from the client:" );
Log ( " Status = %d" , Status );
Log ( " Pos = <%d, %d, %d>" , BlockX , BlockY , BlockZ );
Log ( " BlockFace = %d" , BlockFace );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientBlockPlace ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , BlockY );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , Face );
AString Desc ;
if ( ! ParseSlot ( m_ClientBuffer , Desc ))
{
return false ;
}
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , CursorX );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , CursorY );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , CursorZ );
Log ( "Received a PACKET_BLOCK_PLACE from the client:" );
Log ( " Block = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Face = %d" , Face );
Log ( " Item = %s" , Desc . c_str ());
Log ( " Cursor = <%d, %d, %d>" , CursorX , CursorY , CursorZ );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientChatMessage ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Message );
Log ( "Received a PACKET_CHAT_MESSAGE from the client:" );
Log ( " Message = \" %s \" " , Message . c_str ());
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientClientStatuses ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , Statuses );
Log ( "Received a PACKET_CLIENT_STATUSES from the CLIENT:" );
Log ( " Statuses = %d" , Statuses );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientCreativeInventoryAction ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , SlotNum );
AString Item ;
if ( ! ParseSlot ( m_ClientBuffer , Item ))
{
return false ;
}
Log ( "Received a PACKET_CREATIVE_INVENTORY_ACTION from the client:" );
Log ( " SlotNum = %d" , SlotNum );
Log ( " Item = %s" , Item . c_str ());
COPY_TO_SERVER ();
return true ;
}
2013-08-25 21:57:12 +02:00
bool cConnection :: HandleClientDisconnect ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Reason );
Log ( "Received a PACKET_DISCONNECT from the client:" );
Log ( " Reason = \" %s \" " , Reason . c_str ());
COPY_TO_SERVER ();
return true ;
}
2013-07-29 12:13:03 +01:00
bool cConnection :: HandleClientEncryptionKeyResponse ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , EncKeyLength );
AString EncKey ;
if ( ! m_ClientBuffer . ReadString ( EncKey , EncKeyLength ))
{
return true ;
}
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , EncNonceLength );
AString EncNonce ;
if ( ! m_ClientBuffer . ReadString ( EncNonce , EncNonceLength ))
{
return true ;
}
if (( EncKeyLength > MAX_ENC_LEN ) || ( EncNonceLength > MAX_ENC_LEN ))
{
Log ( "Client: Too long encryption params" );
return true ;
}
StartClientEncryption ( EncKey , EncNonce );
return true ;
}
bool cConnection :: HandleClientEntityAction ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , PlayerID );
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , ActionType );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , UnknownHorseVal );
Log ( "Received a PACKET_ENTITY_ACTION from the client:" );
Log ( " PlayerID = %d" , PlayerID );
Log ( " ActionType = %d" , ActionType );
Log ( " UnknownHorseVal = %d (0x%08x)" , UnknownHorseVal , UnknownHorseVal );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientHandshake ( void )
{
// Read the packet from the client:
HANDLE_CLIENT_PACKET_READ ( ReadByte , Byte , ProtocolVersion );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Username );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , ServerHost );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , ServerPort );
m_ClientBuffer . CommitRead ();
Log ( "Received a PACKET_HANDSHAKE from the client:" );
Log ( " ProtocolVersion = %d" , ProtocolVersion );
Log ( " Username = \" %s \" " , Username . c_str ());
Log ( " ServerHost = \" %s \" " , ServerHost . c_str ());
Log ( " ServerPort = %d" , ServerPort );
// Send the same packet to the server, but with our port:
cByteBuffer ToServer ( 512 );
ToServer . WriteByte ( PACKET_HANDSHAKE );
ToServer . WriteByte ( ProtocolVersion );
ToServer . WriteBEUTF16String16 ( Username );
ToServer . WriteBEUTF16String16 ( ServerHost );
ToServer . WriteBEInt ( m_Server . GetConnectPort ());
SERVERSEND ( ToServer );
return true ;
}
bool cConnection :: HandleClientKeepAlive ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , ID );
Log ( "Received a PACKET_KEEPALIVE from the client" );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientLocaleAndView ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Locale );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , ViewDistance );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , ChatFlags );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , Difficulty );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , ShowCape );
Log ( "Received a PACKET_LOCALE_AND_VIEW from the client" );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPing ( void )
{
m_HasClientPinged = true ;
Log ( "Received a PACKET_PING from the client" );
m_ClientBuffer . ResetRead ();
SERVERSEND ( m_ClientBuffer );
return true ;
}
bool cConnection :: HandleClientPlayerAbilities ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , Flags );
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , FlyingSpeed );
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , WalkingSpeed );
Log ( "Receives a PACKET_PLAYER_ABILITIES from the client:" );
Log ( " Flags = %d (0x%02x)" , Flags , Flags );
Log ( " FlyingSpeed = %f" , FlyingSpeed );
Log ( " WalkingSpeed = %f" , WalkingSpeed );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPlayerLook ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , Yaw );
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , Pitch );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , OnGround );
Log ( "Received a PACKET_PLAYER_LOOK from the client" );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPlayerOnGround ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , OnGround );
Log ( "Received a PACKET_PLAYER_ON_GROUND from the client" );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPlayerPosition ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosX );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , Stance );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosY );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosZ );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , IsOnGround );
Log ( "Received a PACKET_PLAYER_POSITION from the client" );
// TODO: list packet contents
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPlayerPositionLook ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosX );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , Stance );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosY );
HANDLE_CLIENT_PACKET_READ ( ReadBEDouble , double , PosZ );
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , Yaw );
HANDLE_CLIENT_PACKET_READ ( ReadBEFloat , float , Pitch );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , IsOnGround );
Log ( "Received a PACKET_PLAYER_POSITION_LOOK from the client" );
Log ( " Pos = {%.03f, %.03f, %.03f}" , PosX , PosY , PosZ );
Log ( " Stance = %.03f" , Stance );
Log ( " Y, P = %.03f, %.03f" , Yaw , Pitch );
Log ( " IsOnGround = %s" , IsOnGround ? "true" : "false" );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientPluginMessage ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , ChannelName );
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , Length );
AString Data ;
if ( ! m_ClientBuffer . ReadString ( Data , Length ))
{
return false ;
}
Log ( "Received a PACKET_PLUGIN_MESSAGE from the client" );
Log ( " ChannelName = \" %s \" " , ChannelName . c_str ());
DataLog ( Data . data (), Length , " Data: %d bytes" , Length );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientSlotSelect ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , SlotNum );
Log ( "Received a PACKET_SLOT_SELECT from the client" );
Log ( " SlotNum = %d" , SlotNum );
COPY_TO_SERVER ();
return true ;
}
2013-07-31 14:32:05 +02:00
bool cConnection :: HandleClientTabCompletion ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Query );
Log ( "Received a PACKET_TAB_COMPLETION query from the client" );
Log ( " Query = \" %s \" " , Query . c_str ());
COPY_TO_SERVER ();
return true ;
}
2013-07-29 12:13:03 +01:00
bool cConnection :: HandleClientUpdateSign ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , BlockY );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Line1 );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Line2 );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Line3 );
HANDLE_CLIENT_PACKET_READ ( ReadBEUTF16String16 , AString , Line4 );
Log ( "Received a PACKET_UPDATE_SIGN from the client:" );
Log ( " Block = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Lines = \" %s \" , \" %s \" , \" %s \" , \" %s \" " , Line1 . c_str (), Line2 . c_str (), Line3 . c_str (), Line4 . c_str ());
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientUseEntity ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , PlayerID );
HANDLE_CLIENT_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , MouseButton );
Log ( "Received a PACKET_USE_ENTITY from the client:" );
Log ( " PlayerID = %d" , PlayerID );
Log ( " EntityID = %d" , EntityID );
Log ( " MouseButton = %d" , MouseButton );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientWindowClick ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , WindowID );
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , SlotNum );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , IsRightClick );
HANDLE_CLIENT_PACKET_READ ( ReadBEShort , short , TransactionID );
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , IsShiftClick );
AString Item ;
if ( ! ParseSlot ( m_ClientBuffer , Item ))
{
return false ;
}
Log ( "Received a PACKET_WINDOW_CLICK from the client" );
Log ( " WindowID = %d" , WindowID );
Log ( " SlotNum = %d" , SlotNum );
Log ( " IsRclk = %d, IsShift = %d" , IsRightClick , IsShiftClick );
Log ( " TransactionID = 0x%x" , TransactionID );
Log ( " ClickedItem = %s" , Item . c_str ());
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleClientWindowClose ( void )
{
HANDLE_CLIENT_PACKET_READ ( ReadChar , char , WindowID );
Log ( "Received a PACKET_WINDOW_CLOSE from the client:" );
Log ( " WindowID = %d" , WindowID );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleServerAttachEntity ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , VehicleID );
HANDLE_SERVER_PACKET_READ ( ReadBool , bool , Leash );
Log ( "Received a PACKET_ATTACH_ENTITY from the server:" );
Log ( " EntityID = %d (0x%x)" , EntityID , EntityID );
Log ( " VehicleID = %d (0x%x)" , VehicleID , VehicleID );
Log ( " Leash = %s" , Leash ? "true" : "false" );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerBlockAction ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , BlockY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Byte1 );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Byte2 );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , BlockID );
Log ( "Received a PACKET_BLOCK_ACTION from the server:" );
Log ( " Pos = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Bytes = (%d, %d) == (0x%x, 0x%x)" , Byte1 , Byte2 , Byte1 , Byte2 );
Log ( " BlockID = %d" , BlockID );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerBlockChange ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , BlockY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , BlockType );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , BlockMeta );
Log ( "Received a PACKET_BLOCK_CHANGE from the server" );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerChangeGameState ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Reason );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Data );
Log ( "Received a PACKET_CHANGE_GAME_STATE from the server:" );
Log ( " Reason = %d" , Reason );
Log ( " Data = %d" , Data );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerChatMessage ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Message );
Log ( "Received a PACKET_CHAT_MESSAGE from the server:" );
Log ( " Message = \" %s \" " , Message . c_str ());
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerCollectPickup ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , CollectedID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , CollectorID );
Log ( "Received a PACKET_COLLECT_PICKUP from the server:" );
Log ( " CollectedID = %d" , CollectedID );
Log ( " CollectorID = %d" , CollectorID );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerCompass ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , SpawnX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , SpawnY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , SpawnZ );
Log ( "Received PACKET_COMPASS from the server:" );
Log ( " Spawn = {%d, %d, %d}" , SpawnX , SpawnY , SpawnZ );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerDestroyEntities ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , NumEntities );
if ( ! m_ServerBuffer . SkipRead (( int ) NumEntities * 4 ))
{
return false ;
}
Log ( "Received PACKET_DESTROY_ENTITIES from the server:" );
Log ( " NumEntities = %d" , NumEntities );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEncryptionKeyRequest ( void )
{
// Read the packet from the server:
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , ServerID );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , PublicKeyLength );
AString PublicKey ;
if ( ! m_ServerBuffer . ReadString ( PublicKey , PublicKeyLength ))
{
return false ;
}
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , NonceLength );
AString Nonce ;
if ( ! m_ServerBuffer . ReadString ( Nonce , NonceLength ))
{
return false ;
}
Log ( "Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:" );
Log ( " ServerID = %s" , ServerID . c_str ());
// Reply to the server:
SendEncryptionKeyResponse ( PublicKey , Nonce );
// Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD to the client, using our own key:
Log ( "Sending PACKET_ENCRYPTION_KEY_REQUEST to the CLIENT" );
AString key ;
StringSink sink ( key ); // GCC won't allow inline instantiation in the following line, damned temporary refs
m_Server . GetPublicKey (). Save ( sink );
cByteBuffer ToClient ( 512 );
ToClient . WriteByte ( PACKET_ENCRYPTION_KEY_REQUEST );
ToClient . WriteBEUTF16String16 ( ServerID );
ToClient . WriteBEShort (( short ) key . size ());
ToClient . WriteBuf ( key . data (), key . size ());
ToClient . WriteBEShort ( 4 );
ToClient . WriteBEInt ( m_Nonce ); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
CLIENTSEND ( ToClient );
return true ;
}
bool cConnection :: HandleServerEntity ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
Log ( "Received a PACKET_ENTITY from the server:" );
Log ( " EntityID = %d" , EntityID );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityEquipment ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SlotNum );
AString Item ;
if ( ! ParseSlot ( m_ServerBuffer , Item ))
{
return false ;
}
Log ( "Received a PACKET_ENTITY_EQUIPMENT from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " SlotNum = %d" , SlotNum );
Log ( " Item = %s" , Item . c_str ());
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityHeadLook ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , HeadYaw );
Log ( "Received a PACKET_ENTITY_HEAD_LOOK from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " HeadYaw = %d" , HeadYaw );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityLook ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
Log ( "Received a PACKET_ENTITY_LOOK from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Yaw = %d" , Yaw );
Log ( " Pitch = %d" , Pitch );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityMetadata ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
AString Metadata ;
if ( ! ParseMetadata ( m_ServerBuffer , Metadata ))
{
return false ;
}
AString HexDump ;
CreateHexDump ( HexDump , Metadata . data (), Metadata . size (), 32 );
Log ( "Received a PACKET_ENTITY_METADATA from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Metadata, length = %d (0x%x): \n %s" , Metadata . length (), Metadata . length (), HexDump . c_str ());
LogMetadata ( Metadata , 4 );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityProperties ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , Count );
Log ( "Received a PACKET_ENTITY_PROPERTIES from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Count = %d" , Count );
for ( int i = 0 ; i < Count ; i ++ )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Key );
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , Value );
Log ( " \" %s \" = %f" , Key . c_str (), Value );
} // for i
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , ListLength );
Log ( " ListLength = %d" , ListLength );
for ( int i = 0 ; i < ListLength ; i ++ )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt64 , Int64 , UUIDHi );
HANDLE_SERVER_PACKET_READ ( ReadBEInt64 , Int64 , UUIDLo );
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , DblVal );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , ByteVal );
Log ( " [%d] = {0x%08llx%08llx, %f, %i}" , i , UUIDHi , UUIDLo , DblVal , ByteVal );
} // for i
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityRelativeMove ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dx );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dy );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dz );
Log ( "Received a PACKET_ENTITY_RELATIVE_MOVE from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " RelMove = <%d, %d, %d>" , dx , dy , dz );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityRelativeMoveLook ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dx );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dy );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , dz );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
Log ( "Received a PACKET_ENTITY_RELATIVE_MOVE_LOOK from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " RelMove = <%d, %d, %d>" , dx , dy , dz );
Log ( " Yaw = %d" , Yaw );
Log ( " Pitch = %d" , Pitch );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityStatus ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Status );
Log ( "Received a PACKET_ENTITY_STATUS from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Status = %d" , Status );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityTeleport ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
Log ( "Received a PACKET_ENTITY_TELEPORT from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Pos = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Yaw = %d" , Yaw );
Log ( " Pitch = %d" , Pitch );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerEntityVelocity ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityY );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityZ );
Log ( "Received a PACKET_ENTITY_VELOCITY from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Velocity = <%d, %d, %d>" , VelocityX , VelocityY , VelocityZ );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerIncrementStatistic ( void )
{
// 0xc8
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , StatisticID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , Amount );
Log ( "Received a PACKET_INCREMENT_STATISTIC from the server:" );
Log ( " StatisticID = %d (0x%x)" , StatisticID , StatisticID );
Log ( " Amount = %d" , Amount );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerKeepAlive ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PingID );
Log ( "Received a PACKET_KEEP_ALIVE from the server:" );
Log ( " ID = %d" , PingID );
COPY_TO_CLIENT ()
return true ;
}
bool cConnection :: HandleServerEncryptionKeyResponse ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , Lengths );
if ( Lengths != 0 )
{
Log ( "Lengths are not zero!" );
return true ;
}
Log ( "Server communication is now encrypted" );
m_ServerState = csEncryptedUnderstood ;
DataLog ( m_ServerEncryptionBuffer . data (), m_ServerEncryptionBuffer . size (), "Sending the queued data to server (%u bytes):" , m_ServerEncryptionBuffer . size ());
SERVERENCRYPTSEND ( m_ServerEncryptionBuffer . data (), m_ServerEncryptionBuffer . size ());
m_ServerEncryptionBuffer . clear ();
return true ;
}
bool cConnection :: HandleServerKick ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Reason );
Log ( "Received PACKET_KICK from the SERVER:" );
if ( m_HasClientPinged )
{
Log ( " This was a std reply to client's PING" );
AStringVector Split ;
// Split by NULL chars (StringSplit() won't work here):
size_t Last = 0 ;
for ( size_t i = 0 ; i < Reason . size (); i ++ )
{
if ( Reason [ i ] == 0 )
{
Split . push_back ( Reason . substr ( Last , i - Last ));
Last = i + 1 ;
}
}
if ( Split . size () == 5 )
{
Log ( " Protocol version: \" %s \" " , Split [ 0 ]. c_str ());
Log ( " Server version: \" %s \" " , Split [ 1 ]. c_str ());
Log ( " MOTD: \" %s \" " , Split [ 2 ]. c_str ());
Log ( " Cur players: \" %s \" " , Split [ 3 ]. c_str ());
Log ( " Max players: \" %s \" " , Split [ 4 ]. c_str ());
}
else
{
DataLog ( Reason . data (), Reason . size (), " Unknown reply format, dumping hex:" );
}
}
else
{
Log ( " Reason = \" %s \" " , Reason . c_str ());
}
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerLogin ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , LevelType );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , GameMode );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Dimension );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Difficulty );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Unused );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , MaxPlayers );
Log ( "Received a PACKET_LOGIN from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " LevelType = \" %s \" " , LevelType . c_str ());
Log ( " GameMode = %d" , GameMode );
Log ( " Dimension = %d" , Dimension );
Log ( " Difficulty = %d" , Difficulty );
Log ( " Unused = %d" , Unused );
Log ( " MaxPlayers = %d" , MaxPlayers );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerMapChunk ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , ChunkX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , ChunkZ );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , IsContiguous );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , PrimaryBitmap );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , AdditionalBitmap );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , CompressedSize );
AString CompressedData ;
if ( ! m_ServerBuffer . ReadString ( CompressedData , CompressedSize ))
{
return false ;
}
Log ( "Received a PACKET_MAP_CHUNK from the server:" );
Log ( " ChunkPos = [%d, %d]" , ChunkX , ChunkZ );
Log ( " Compressed size = %d (0x%x)" , CompressedSize , CompressedSize );
// TODO: Save the compressed data into a file for later analysis
COPY_TO_CLIENT ()
return true ;
}
bool cConnection :: HandleServerMapChunkBulk ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , ChunkCount );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , CompressedSize );
HANDLE_SERVER_PACKET_READ ( ReadBool , bool , IsSkyLightSent );
AString CompressedData ;
if ( ! m_ServerBuffer . ReadString ( CompressedData , CompressedSize ))
{
return false ;
}
AString Meta ;
if ( ! m_ServerBuffer . ReadString ( Meta , ChunkCount * 12 ))
{
return false ;
}
Log ( "Received a PACKET_MAP_CHUNK_BULK from the server:" );
Log ( " ChunkCount = %d" , ChunkCount );
Log ( " Compressed size = %d (0x%x)" , CompressedSize , CompressedSize );
Log ( " IsSkyLightSent = %s" , IsSkyLightSent ? "true" : "false" );
// TODO: Save the compressed data into a file for later analysis
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerMultiBlockChange ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , ChunkX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , ChunkZ );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , NumBlocks );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , DataSize );
AString BlockChangeData ;
if ( ! m_ServerBuffer . ReadString ( BlockChangeData , DataSize ))
{
return false ;
}
Log ( "Received a PACKET_MULTI_BLOCK_CHANGE packet from the server:" );
Log ( " Chunk = [%d, %d]" , ChunkX , ChunkZ );
Log ( " NumBlocks = %d" , NumBlocks );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerNamedSoundEffect ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , SoundName );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , Volume );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
Log ( "Received a PACKET_NAMED_SOUND_EFFECT from the server:" );
Log ( " SoundName = \" %s \" " , SoundName . c_str ());
Log ( " Pos = (%d, %d, %d) ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 8 , PosY / 8 , PosZ / 8 );
Log ( " Volume = %f" , Volume );
Log ( " Pitch = %d" , Pitch );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerPlayerAbilities ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , Flags );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , FlyingSpeed );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , WalkingSpeed );
Log ( "Received a PACKET_PLAYER_ABILITIES from the server:" );
Log ( " Flags = %d (0x%02x)" , Flags , Flags );
Log ( " FlyingSpeed = %f" , FlyingSpeed );
Log ( " WalkingSpeed = %f" , WalkingSpeed );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerPlayerAnimation ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PlayerID );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , AnimationID );
Log ( "Received a PACKET_PLAYER_ANIMATION from the server:" );
Log ( " PlayerID: %d (0x%x)" , PlayerID , PlayerID );
Log ( " Animation: %d" , AnimationID );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerPlayerListItem ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , PlayerName );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , IsOnline );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , Ping );
Log ( "Received a PACKET_PLAYERLIST_ITEM from the server:" );
Log ( " PlayerName = \" %s \" " , PlayerName . c_str ());
Log ( " Ping = %d" , Ping );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerPlayerPositionLook ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , Stance );
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEDouble , double , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , Pitch );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , IsOnGround );
Log ( "Received a PACKET_PLAYER_POSITION_LOOK from the server" );
// TODO: list packet contents
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerPluginMessage ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , ChannelName );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , Length );
AString Data ;
if ( ! m_ServerBuffer . ReadString ( Data , Length ))
{
return false ;
}
Log ( "Received a PACKET_PLUGIN_MESSAGE from the server" );
Log ( " ChannelName = \" %s \" " , ChannelName . c_str ());
DataLog ( Data . data (), Length , " Data: %d bytes" , Length );
COPY_TO_SERVER ();
return true ;
}
bool cConnection :: HandleServerSetExperience ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , ExperienceBar );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , Level );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , TotalExperience );
Log ( "Received a PACKET_SET_EXPERIENCE from the server:" );
Log ( " ExperienceBar = %.05f" , ExperienceBar );
Log ( " Level = %d" , Level );
Log ( " TotalExperience = %d" , TotalExperience );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSetSlot ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , WindowID );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SlotNum );
AString Item ;
if ( ! ParseSlot ( m_ServerBuffer , Item ))
{
return false ;
}
Log ( "Received a PACKET_SET_SLOT from the server:" );
Log ( " WindowID = %d" , WindowID );
Log ( " SlotNum = %d" , SlotNum );
Log ( " Item = %s" , Item . c_str ());
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSlotSelect ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SlotNum );
Log ( "Received a PACKET_SLOT_SELECT from the server:" );
Log ( " SlotNum = %d" , SlotNum );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSoundEffect ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EffectID );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , Data );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , NoVolumeDecrease );
Log ( "Received a PACKET_SOUND_EFFECT from the server:" );
Log ( " EffectID = %d" , EffectID );
Log ( " Pos = {%d, %d, %d}" , PosX , PosY , PosZ );
Log ( " Data = %d" , Data );
Log ( " NoVolumeDecrease = %d" , NoVolumeDecrease );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSpawnMob ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , MobType );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , HeadYaw );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityY );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , VelocityZ );
AString Metadata ;
if ( ! ParseMetadata ( m_ServerBuffer , Metadata ))
{
return false ;
}
AString HexDump ;
CreateHexDump ( HexDump , Metadata . data (), Metadata . size (), 32 );
Log ( "Received a PACKET_SPAWN_MOB from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " MobType = %d" , MobType );
Log ( " Pos = <%d, %d, %d> ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 32 , PosY / 32 , PosZ / 32 );
Log ( " Angles = [%d, %d, %d]" , Yaw , Pitch , HeadYaw );
Log ( " Velocity = <%d, %d, %d>" , VelocityX , VelocityY , VelocityZ );
Log ( " Metadata, length = %d (0x%x): \n %s" , Metadata . length (), Metadata . length (), HexDump . c_str ());
LogMetadata ( Metadata , 4 );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSpawnNamedEntity ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , EntityName );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , CurrentItem );
AString Metadata ;
if ( ! ParseMetadata ( m_ServerBuffer , Metadata ))
{
return false ;
}
AString HexDump ;
CreateHexDump ( HexDump , Metadata . data (), Metadata . size (), 32 );
Log ( "Received a PACKET_SPAWN_NAMED_ENTITY from the server:" );
Log ( " EntityID = %d (0x%x)" , EntityID , EntityID );
Log ( " Name = %s" , EntityName . c_str ());
Log ( " Pos = <%d, %d, %d> ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 32 , PosY / 32 , PosZ / 32 );
Log ( " Rotation = <yaw %d, pitch %d>" , Yaw , Pitch );
Log ( " CurrentItem = %d" , CurrentItem );
Log ( " Metadata, length = %d (0x%x): \n %s" , Metadata . length (), Metadata . length (), HexDump . c_str ());
LogMetadata ( Metadata , 4 );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSpawnObjectVehicle ( void )
{
#ifdef _DEBUG
// DEBUG:
// This packet is still troublesome when DataIndicator != 0
AString Buffer ;
m_ServerBuffer . ResetRead ();
m_ServerBuffer . ReadAll ( Buffer );
m_ServerBuffer . ResetRead ();
m_ServerBuffer . SkipRead ( 1 );
if ( Buffer . size () > 128 )
{
// Only log up to 128 bytes
Buffer . erase ( 128 , AString :: npos );
}
DataLog ( Buffer . data (), Buffer . size (), "Buffer while parsing the PACKET_SPAWN_OBJECT_VEHICLE packet (%d bytes):" , Buffer . size ());
#endif // _DEBUG
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , ObjType );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Yaw );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , DataIndicator );
AString ExtraData ;
short VelocityX , VelocityY , VelocityZ ;
if ( DataIndicator != 0 )
{
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SpeedX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SpeedY );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , SpeedZ );
VelocityX = SpeedX ; VelocityY = SpeedY ; VelocityZ = SpeedZ ; // Speed vars are local to this scope, but we need them available later
/*
// This doesn't seem to work - for a falling block I'm getting no extra data at all
int ExtraLen = 0;
switch (ObjType)
{
case OBJECT_FALLING_BLOCK: ExtraLen = 4; break; // int: BlockType | (BlockMeta << 12)
case OBJECT_ARROW:
case OBJECT_SNOWBALL:
case OBJECT_EGG:
case OBJECT_EYE_OF_ENDER:
case OBJECT_DRAGON_EGG:
case OBJECT_FISHING_FLOAT:
{
ExtraLen = 4; break; // int: EntityID of the thrower
}
// TODO: Splash potions
}
if ((ExtraLen > 0) && !m_ServerBuffer.ReadString(ExtraData, ExtraLen))
{
return false;
}
*/
}
Log ( "Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:" );
Log ( " EntityID = %d (0x%x)" , EntityID , EntityID );
Log ( " ObjType = %d (0x%x)" , ObjType , ObjType );
Log ( " Pos = <%d, %d, %d> ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 32 , PosY / 32 , PosZ / 32 );
Log ( " Rotation = <yaw %d, pitch %d>" , Yaw , Pitch );
Log ( " DataIndicator = %d (0x%x)" , DataIndicator , DataIndicator );
if ( DataIndicator != 0 )
{
Log ( " Velocity = <%d, %d, %d>" , VelocityX , VelocityY , VelocityZ );
DataLog ( ExtraData . data (), ExtraData . size (), " ExtraData size = %d:" , ExtraData . size ());
}
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSpawnPainting ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , ImageName );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , Direction );
Log ( "Received a PACKET_SPAWN_PAINTING from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " ImageName = \" %s \" " , ImageName . c_str ());
Log ( " Pos = <%d, %d, %d> ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 32 , PosY / 32 , PosZ / 32 );
Log ( " Direction = %d" , Direction );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerSpawnPickup ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , EntityID );
AString ItemDesc ;
if ( ! ParseSlot ( m_ServerBuffer , ItemDesc ))
{
return false ;
}
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosX );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , PosZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Rotation );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Pitch );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Roll );
Log ( "Received a PACKET_SPAWN_PICKUP from the server:" );
Log ( " EntityID = %d" , EntityID );
Log ( " Item = %s" , ItemDesc . c_str ());
Log ( " Pos = <%d, %d, %d> ~ {%d, %d, %d}" , PosX , PosY , PosZ , PosX / 32 , PosY / 32 , PosZ / 32 );
Log ( " Angles = [%d, %d, %d]" , Rotation , Pitch , Roll );
COPY_TO_CLIENT ();
return true ;
}
2013-07-31 14:32:05 +02:00
bool cConnection :: HandleServerTabCompletion ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Results );
Log ( "Received a PACKET_TAB_COMPLETION from the server, results given:" );
// Parse the zero-terminated list of results:
size_t len = Results . size ();
size_t last = 0 ;
for ( size_t i = 0 ; i < len ; i ++ )
{
if ( Results [ i ] == 0 )
{
Log ( " \" %s \" " , Results . substr ( last , i - last ). c_str ());
last = i + 1 ;
}
}
2013-07-31 14:35:48 +02:00
if ( last < len )
{
Log ( " \" %s \" " , Results . substr ( last , len - last ). c_str ());
}
2013-07-31 14:32:05 +02:00
COPY_TO_CLIENT ();
return true ;
}
2013-07-29 12:13:03 +01:00
bool cConnection :: HandleServerTimeUpdate ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt64 , Int64 , WorldAge );
HANDLE_SERVER_PACKET_READ ( ReadBEInt64 , Int64 , TimeOfDay );
Log ( "Received a PACKET_TIME_UPDATE from the server" );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerUpdateHealth ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , Health );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , Food );
HANDLE_SERVER_PACKET_READ ( ReadBEFloat , float , Saturation );
Log ( "Received a PACKET_UPDATE_HEALTH from the server" );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerUpdateSign ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , BlockY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Line1 );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Line2 );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Line3 );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Line4 );
Log ( "Received a PACKET_UPDATE_SIGN from the server:" );
Log ( " Block = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Lines = \" %s \" , \" %s \" , \" %s \" , \" %s \" " , Line1 . c_str (), Line2 . c_str (), Line3 . c_str (), Line4 . c_str ());
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerUpdateTileEntity ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockX );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , BlockY );
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , BlockZ );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , Action );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , DataLength );
AString Data ;
if (( DataLength > 0 ) && ! m_ServerBuffer . ReadString ( Data , DataLength ))
{
return false ;
}
Log ( "Received a PACKET_UPDATE_TILE_ENTITY from the server:" );
Log ( " Block = {%d, %d, %d}" , BlockX , BlockY , BlockZ );
Log ( " Action = %d" , Action );
DataLog ( Data . data (), Data . size (), " Data (%d bytes)" , Data . size ());
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerWindowClose ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , WindowID );
Log ( "Received a PACKET_WINDOW_CLOSE from the server:" );
Log ( " WindowID = %d" , WindowID );
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerWindowContents ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , WindowID );
HANDLE_SERVER_PACKET_READ ( ReadBEShort , short , NumSlots );
Log ( "Received a PACKET_WINDOW_CONTENTS from the server:" );
Log ( " WindowID = %d" , WindowID );
Log ( " NumSlots = %d" , NumSlots );
AStringVector Items ;
for ( short i = 0 ; i < NumSlots ; i ++ )
{
AString Item ;
if ( ! ParseSlot ( m_ServerBuffer , Item ))
{
return false ;
}
Log ( " %d: %s" , i , Item . c_str ());
}
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: HandleServerWindowOpen ( void )
{
HANDLE_SERVER_PACKET_READ ( ReadChar , char , WindowID );
HANDLE_SERVER_PACKET_READ ( ReadChar , char , WindowType );
HANDLE_SERVER_PACKET_READ ( ReadBEUTF16String16 , AString , Title );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , NumSlots );
HANDLE_SERVER_PACKET_READ ( ReadByte , Byte , UseProvidedTitle );
int HorseInt = 0 ;
if ( WindowType == 11 ) // Horse / Donkey / Mule
{
HANDLE_SERVER_PACKET_READ ( ReadBEInt , int , intHorseInt );
HorseInt = intHorseInt ;
}
Log ( "Received a PACKET_WINDOW_OPEN from the server:" );
Log ( " WindowID = %d" , WindowID );
Log ( " WindowType = %d" , WindowType );
Log ( " Title = \" %s \" , Use = %d" , Title . c_str (), UseProvidedTitle );
Log ( " NumSlots = %d" , NumSlots );
if ( WindowType == 11 )
{
Log ( " HorseInt = %d (0x%08x)" , HorseInt , HorseInt );
}
COPY_TO_CLIENT ();
return true ;
}
bool cConnection :: ParseSlot ( cByteBuffer & a_Buffer , AString & a_ItemDesc )
{
short ItemType ;
if ( ! a_Buffer . ReadBEShort ( ItemType ))
{
return false ;
}
if ( ItemType <= 0 )
{
a_ItemDesc = "<empty>" ;
return true ;
}
if ( ! a_Buffer . CanReadBytes ( 5 ))
{
return false ;
}
char ItemCount ;
short ItemDamage ;
short MetadataLength ;
a_Buffer . ReadChar ( ItemCount );
a_Buffer . ReadBEShort ( ItemDamage );
a_Buffer . ReadBEShort ( MetadataLength );
Printf ( a_ItemDesc , "%d:%d * %d" , ItemType , ItemDamage , ItemCount );
if ( MetadataLength <= 0 )
{
return true ;
}
AString Metadata ;
Metadata . resize ( MetadataLength );
if ( ! a_Buffer . ReadBuf (( void * ) Metadata . data (), MetadataLength ))
{
return false ;
}
AString MetaHex ;
CreateHexDump ( MetaHex , Metadata . data (), Metadata . size (), 16 );
AppendPrintf ( a_ItemDesc , "; %d bytes of meta: \n %s" , MetadataLength , MetaHex . c_str ());
// Save metadata to a file:
AString fnam ;
Printf ( fnam , "%s_item_%08x.nbt" , m_LogNameBase . c_str (), m_ItemIdx ++ );
FILE * f = fopen ( fnam . c_str (), "wb" );
if ( f != NULL )
{
fwrite ( Metadata . data (), 1 , Metadata . size (), f );
fclose ( f );
AppendPrintf ( a_ItemDesc , " \n (saved to file \" %s \" )" , fnam . c_str ());
}
return true ;
}
bool cConnection :: ParseMetadata ( cByteBuffer & a_Buffer , AString & a_Metadata )
{
char x ;
if ( ! a_Buffer . ReadChar ( x ))
{
return false ;
}
a_Metadata . push_back ( x );
while ( x != 0x7f )
{
int Index = (( unsigned )(( unsigned char ) x )) & 0x1f ; // Lower 5 bits = index
int Type = (( unsigned )(( unsigned char ) x )) >> 5 ; // Upper 3 bits = type
int Length = 0 ;
switch ( Type )
{
case 0 : Length = 1 ; break ; // byte
case 1 : Length = 2 ; break ; // short
case 2 : Length = 4 ; break ; // int
case 3 : Length = 4 ; break ; // float
case 4 : // string16
{
short Len = 0 ;
if ( ! a_Buffer . ReadBEShort ( Len ))
{
return false ;
}
short NetLen = htons ( Len );
a_Metadata . append (( char * ) & NetLen , 2 );
Length = Len ;
break ;
}
case 5 :
{
int Before = a_Buffer . GetReadableSpace ();
AString ItemDesc ;
if ( ! ParseSlot ( a_Buffer , ItemDesc ))
{
return false ;
}
int After = a_Buffer . GetReadableSpace ();
a_Buffer . ResetRead ();
a_Buffer . SkipRead ( a_Buffer . GetReadableSpace () - Before );
Length = Before - After ;
break ;
}
case 6 : Length = 12 ; break ; // 3 * int
default :
{
ASSERT ( ! "Unknown metadata type" );
break ;
}
} // switch (Type)
AString data ;
if ( ! a_Buffer . ReadString ( data , Length ))
{
return false ;
}
a_Metadata . append ( data );
if ( ! a_Buffer . ReadChar ( x ))
{
return false ;
}
a_Metadata . push_back ( x );
} // while (x != 0x7f)
return true ;
}
void cConnection :: LogMetadata ( const AString & a_Metadata , size_t a_IndentCount )
{
AString Indent ( a_IndentCount , ' ' );
int pos = 0 ;
while ( a_Metadata [ pos ] != 0x7f )
{
int Index = (( unsigned )(( unsigned char ) a_Metadata [ pos ])) & 0x1f ; // Lower 5 bits = index
int Type = (( unsigned )(( unsigned char ) a_Metadata [ pos ])) >> 5 ; // Upper 3 bits = type
int Length = 0 ;
switch ( Type )
{
case 0 :
{
Log ( "%sbyte[%d] = %d" , Indent . c_str (), Index , a_Metadata [ pos + 1 ]);
pos += 1 ;
break ;
}
case 1 :
{
Log ( "%sshort[%d] = %d" , Indent . c_str (), Index , ( a_Metadata [ pos + 1 ] << 8 ) | a_Metadata [ pos + 2 ]);
pos += 2 ;
break ;
}
case 2 :
{
Log ( "%sint[%d] = %d" , Indent . c_str (), Index , ( a_Metadata [ pos + 1 ] << 24 ) | ( a_Metadata [ pos + 2 ] << 16 ) | ( a_Metadata [ pos + 3 ] << 8 ) | a_Metadata [ pos + 4 ]);
pos += 4 ;
break ;
}
case 3 :
{
Log ( "%sfloat[%d] = 0x%x" , Indent . c_str (), Index , ( a_Metadata [ pos + 1 ] << 24 ) | ( a_Metadata [ pos + 2 ] << 16 ) | ( a_Metadata [ pos + 3 ] << 8 ) | a_Metadata [ pos + 4 ]);
pos += 4 ;
break ;
}
case 4 : // string16
{
short Length = ( a_Metadata [ pos + 1 ] << 8 ) | a_Metadata [ pos + 2 ];
Log ( "%sstring[%d] = \" %*s \" " , Indent . c_str (), Index , Length , a_Metadata . c_str () + pos + 3 );
pos += Length + 2 ;
break ;
}
case 5 :
{
int BytesLeft = a_Metadata . size () - pos - 1 ;
cByteBuffer bb ( BytesLeft );
bb . Write ( a_Metadata . data () + pos + 1 , BytesLeft );
AString ItemDesc ;
if ( ! ParseSlot ( bb , ItemDesc ))
{
ASSERT ( ! "Cannot parse item description from metadata" );
return ;
}
int After = bb . GetReadableSpace ();
int BytesConsumed = BytesLeft - bb . GetReadableSpace ();
Log ( "%sslot[%d] = %s (%d bytes)" , Indent . c_str (), Index , ItemDesc . c_str (), BytesConsumed );
pos += BytesConsumed ;
break ;
}
case 6 :
{
Log ( "%spos[%d] = <%d, %d, %d>" , Indent . c_str (), Index ,
( a_Metadata [ pos + 1 ] << 24 ) | ( a_Metadata [ pos + 2 ] << 16 ) | ( a_Metadata [ pos + 3 ] << 8 ) | a_Metadata [ pos + 4 ],
( a_Metadata [ pos + 5 ] << 24 ) | ( a_Metadata [ pos + 6 ] << 16 ) | ( a_Metadata [ pos + 7 ] << 8 ) | a_Metadata [ pos + 8 ],
( a_Metadata [ pos + 9 ] << 24 ) | ( a_Metadata [ pos + 10 ] << 16 ) | ( a_Metadata [ pos + 11 ] << 8 ) | a_Metadata [ pos + 12 ]
);
pos += 12 ;
break ;
}
default :
{
ASSERT ( ! "Unknown metadata type" );
break ;
}
} // switch (Type)
pos += 1 ;
} // while (x != 0x7f)
}
void cConnection :: SendEncryptionKeyResponse ( const AString & a_ServerPublicKey , const AString & a_Nonce )
{
// Generate the shared secret and encrypt using the server's public key
byte SharedSecret [ 16 ];
byte EncryptedSecret [ 128 ];
memset ( SharedSecret , 0 , sizeof ( SharedSecret )); // Use all zeroes for the initial secret
RSA :: PublicKey pk ;
CryptoPP :: StringSource src ( a_ServerPublicKey , true );
ByteQueue bq ;
src . TransferTo ( bq );
bq . MessageEnd ();
pk . Load ( bq );
RSAES < PKCS1v15 >:: Encryptor rsaEncryptor ( pk );
RandomPool rng ;
time_t CurTime = time ( NULL );
rng . Put (( const byte * ) & CurTime , sizeof ( CurTime ));
int EncryptedLength = rsaEncryptor . FixedCiphertextLength ();
ASSERT ( EncryptedLength <= sizeof ( EncryptedSecret ));
rsaEncryptor . Encrypt ( rng , SharedSecret , sizeof ( SharedSecret ), EncryptedSecret );
m_ServerEncryptor . SetKey ( SharedSecret , 16 , MakeParameters ( Name :: IV (), ConstByteArrayParameter ( SharedSecret , 16 ))( Name :: FeedbackSize (), 1 ));
m_ServerDecryptor . SetKey ( SharedSecret , 16 , MakeParameters ( Name :: IV (), ConstByteArrayParameter ( SharedSecret , 16 ))( Name :: FeedbackSize (), 1 ));
// Encrypt the nonce:
byte EncryptedNonce [ 128 ];
rsaEncryptor . Encrypt ( rng , ( const byte * )( a_Nonce . data ()), a_Nonce . size (), EncryptedNonce );
// Send the packet to the server:
Log ( "Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER" );
cByteBuffer ToServer ( 1024 );
ToServer . WriteByte ( PACKET_ENCRYPTION_KEY_RESPONSE );
ToServer . WriteBEShort ( EncryptedLength );
ToServer . WriteBuf ( EncryptedSecret , EncryptedLength );
ToServer . WriteBEShort ( EncryptedLength );
ToServer . WriteBuf ( EncryptedNonce , EncryptedLength );
SERVERSEND ( ToServer );
m_ServerState = csWaitingForEncryption ;
}
void cConnection :: StartClientEncryption ( const AString & a_EncKey , const AString & a_EncNonce )
{
// Decrypt EncNonce using privkey
RSAES < PKCS1v15 >:: Decryptor rsaDecryptor ( m_Server . GetPrivateKey ());
time_t CurTime = time ( NULL );
RandomPool rng ;
rng . Put (( const byte * ) & CurTime , sizeof ( CurTime ));
byte DecryptedNonce [ MAX_ENC_LEN ];
DecodingResult res = rsaDecryptor . Decrypt ( rng , ( const byte * ) a_EncNonce . data (), a_EncNonce . size (), DecryptedNonce );
if ( ! res . isValidCoding || ( res . messageLength != 4 ))
{
Log ( "Client: Bad nonce length" );
return ;
}
if ( ntohl ( * (( int * ) DecryptedNonce )) != m_Nonce )
{
Log ( "Bad nonce value" );
return ;
}
// Decrypt the symmetric encryption key using privkey:
byte SharedSecret [ MAX_ENC_LEN ];
res = rsaDecryptor . Decrypt ( rng , ( const byte * ) a_EncKey . data (), a_EncKey . size (), SharedSecret );
if ( ! res . isValidCoding || ( res . messageLength != 16 ))
{
Log ( "Bad key length" );
return ;
}
// Send encryption key response:
cByteBuffer ToClient ( 6 );
ToClient . WriteByte (( char ) 0xfc );
ToClient . WriteBEShort ( 0 );
ToClient . WriteBEShort ( 0 );
CLIENTSEND ( ToClient );
// Start the encryption:
m_ClientEncryptor . SetKey ( SharedSecret , 16 , MakeParameters ( Name :: IV (), ConstByteArrayParameter ( SharedSecret , 16 ))( Name :: FeedbackSize (), 1 ));
m_ClientDecryptor . SetKey ( SharedSecret , 16 , MakeParameters ( Name :: IV (), ConstByteArrayParameter ( SharedSecret , 16 ))( Name :: FeedbackSize (), 1 ));
Log ( "Client connection is now encrypted" );
m_ClientState = csEncryptedUnderstood ;
// Send the queued data:
DataLog ( m_ClientEncryptionBuffer . data (), m_ClientEncryptionBuffer . size (), "Sending the queued data to client (%u bytes):" , m_ClientEncryptionBuffer . size ());
CLIENTENCRYPTSEND ( m_ClientEncryptionBuffer . data (), m_ClientEncryptionBuffer . size ());
m_ClientEncryptionBuffer . clear ();
// Handle all postponed server data
DecodeServersPackets ( NULL , 0 );
}