2019-07-17 13:37:18 -04:00
# include <algorithm>
# include <log/LogUtils.h>
# include <misc/memtracker.h>
# include <protocol/Packet.h>
# include <ThreadPool/Timer.h>
2020-07-30 05:40:03 -04:00
# include "../../server/VoiceServer.h"
# include "./VoiceClientConnection.h"
# include "./VoiceClient.h"
2019-07-17 13:37:18 -04:00
//#define LOG_AUTO_ACK_AUTORESPONSE
//#define FUZZING_TESTING_INCOMMING
//#define FUZZING_TESTING_OUTGOING
2020-01-26 20:21:39 -05:00
//#define FIZZING_TESTING_DISABLE_HANDSHAKE
# define FUZZING_TESTING_DROP 8
2019-07-17 13:37:18 -04:00
# define FUZZING_TESTING_DROP_MAX 10
//#define CONNECTION_NO_STATISTICS
# define QLZ_COMPRESSION_LEVEL 1
# include "qlz/QuickLZ.h"
using namespace std ;
using namespace std : : chrono ;
using namespace ts ;
using namespace ts : : connection ;
using namespace ts : : protocol ;
using namespace ts : : server ;
2020-07-29 13:05:38 -04:00
VoiceClientConnection : : VoiceClientConnection ( VoiceClient * client )
2020-07-29 16:53:40 -04:00
: current_client { client } ,
crypt_handler { } ,
packet_decoder_ { & this - > crypt_handler } ,
packet_encoder_ { & this - > crypt_handler , & this - > packet_statistics_ } ,
crypt_setup_handler_ { this } {
2020-01-23 20:57:58 -05:00
memtrack : : allocated < VoiceClientConnection > ( this ) ;
2019-07-17 13:37:18 -04:00
2020-07-29 13:05:38 -04:00
this - > packet_decoder_ . callback_argument = this ;
this - > packet_decoder_ . callback_decoded_packet = VoiceClientConnection : : callback_packet_decoded ;
this - > packet_decoder_ . callback_decoded_command = VoiceClientConnection : : callback_command_decoded ;
this - > packet_decoder_ . callback_send_acknowledge = VoiceClientConnection : : callback_send_acknowledge ;
this - > packet_encoder_ . callback_data = this ;
this - > packet_encoder_ . callback_request_write = VoiceClientConnection : : callback_request_write ;
this - > packet_encoder_ . callback_crypt_error = VoiceClientConnection : : callback_encode_crypt_error ;
this - > packet_encoder_ . callback_resend_failed = VoiceClientConnection : : callback_resend_failed ;
this - > packet_encoder_ . callback_resend_stats = VoiceClientConnection : : callback_resend_statistics ;
this - > packet_encoder_ . callback_connection_stats = VoiceClientConnection : : callback_outgoing_connection_statistics ;
2020-04-24 16:04:07 -04:00
2020-07-29 16:53:40 -04:00
this - > ping_handler_ . callback_argument = this ;
this - > ping_handler_ . callback_send_ping = VoiceClientConnection : : callback_ping_send ;
this - > ping_handler_ . callback_send_recovery_command = VoiceClientConnection : : callback_ping_send_recovery ;
this - > ping_handler_ . callback_time_outed = VoiceClientConnection : : callback_ping_timeout ;
this - > virtual_server_id_ = client - > getServerId ( ) ;
2020-01-23 20:57:58 -05:00
debugMessage ( client - > getServer ( ) - > getServerId ( ) , " Allocated new voice client connection at {} " , ( void * ) this ) ;
2019-07-17 13:37:18 -04:00
}
VoiceClientConnection : : ~ VoiceClientConnection ( ) {
2020-04-24 16:04:07 -04:00
this - > reset ( ) ;
2020-07-29 16:53:40 -04:00
this - > current_client = nullptr ;
2020-01-23 20:57:58 -05:00
memtrack : : freed < VoiceClientConnection > ( this ) ;
2019-07-17 13:37:18 -04:00
}
2020-07-29 16:53:40 -04:00
std : : string VoiceClientConnection : : log_prefix ( ) {
auto client = this - > getCurrentClient ( ) ;
if ( ! client ) return " [unknown / unknown] " ; /* FIXME: Get the IP address here! */
return CLIENT_STR_LOG_PREFIX_ ( client ) ;
}
2019-07-17 13:37:18 -04:00
void VoiceClientConnection : : triggerWrite ( ) {
2020-07-29 16:53:40 -04:00
if ( this - > current_client - > voice_server )
this - > current_client - > voice_server - > triggerWrite ( dynamic_pointer_cast < VoiceClient > ( this - > current_client - > _this . lock ( ) ) ) ;
2019-07-17 13:37:18 -04:00
}
2020-01-26 20:21:39 -05:00
void VoiceClientConnection : : handle_incoming_datagram ( const pipes : : buffer_view & buffer ) {
2020-02-15 08:03:46 -05:00
ClientPacketParser packet_parser { buffer } ;
2020-07-29 13:05:38 -04:00
if ( ! packet_parser . valid ( ) )
2020-01-23 20:57:58 -05:00
return ;
2020-04-08 07:01:41 -04:00
# ifndef CONNECTION_NO_STATISTICS
2020-07-29 16:53:40 -04:00
if ( this - > current_client ) {
auto stats = this - > current_client - > connectionStatistics ;
2020-04-08 07:01:41 -04:00
stats - > logIncomingPacket ( stats : : ConnectionStatistics : : category : : from_type ( packet_parser . type ( ) ) , buffer . length ( ) + 96 ) ; /* 96 for the UDP packet overhead */
}
this - > packet_statistics ( ) . received_packet ( ( protocol : : PacketType ) packet_parser . type ( ) , packet_parser . full_packet_id ( ) ) ;
# endif
2020-07-29 13:05:38 -04:00
std : : string error { } ;
auto result = this - > packet_decoder_ . process_incoming_data ( packet_parser , error ) ;
using PacketProcessResult = server : : server : : udp : : PacketProcessResult ;
switch ( result ) {
case PacketProcessResult : : SUCCESS :
case PacketProcessResult : : FUZZ_DROPPED : /* maybe some kind of log? */
case PacketProcessResult : : DECRYPT_FAILED : /* Silently drop this packet */
case PacketProcessResult : : DUPLICATED_PACKET : /* no action needed, acknowledge should be send already */
break ;
case PacketProcessResult : : DECRYPT_KEY_GEN_FAILED :
/* no action needed, acknowledge should be send */
2020-07-29 16:53:40 -04:00
logCritical ( this - > virtual_server_id_ , " {} Failed to generate decrypt key. Dropping packet. " , this - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
break ;
case PacketProcessResult : : BUFFER_OVERFLOW :
case PacketProcessResult : : BUFFER_UNDERFLOW :
2020-07-29 16:53:40 -04:00
debugMessage ( this - > virtual_server_id_ , " {} Dropping command packet because command assembly buffer has an {}: {} " ,
this - > log_prefix ( ) ,
2020-07-29 13:05:38 -04:00
result = = PacketProcessResult : : BUFFER_UNDERFLOW ? " underflow " : " overflow " ,
error
) ;
break ;
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
case PacketProcessResult : : UNKNOWN_ERROR :
2020-07-29 16:53:40 -04:00
logCritical ( this - > virtual_server_id_ , " {} Having an unknown error while processing a incoming packet: {} " ,
this - > log_prefix ( ) ,
2020-07-29 13:05:38 -04:00
error
) ;
goto disconnect_client ;
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
case PacketProcessResult : : COMMAND_BUFFER_OVERFLOW :
2020-07-29 16:53:40 -04:00
debugMessage ( this - > virtual_server_id_ , " {} Having a command buffer overflow. This might cause the client to drop. " , this - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
break ;
2020-01-23 20:57:58 -05:00
2020-07-29 13:05:38 -04:00
case PacketProcessResult : : COMMAND_DECOMPRESS_FAILED :
2020-07-29 16:53:40 -04:00
logWarning ( this - > virtual_server_id_ , " {} Failed to decompress a command packet. Dropping command. " , this - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
break ;
2020-01-23 20:57:58 -05:00
2020-07-29 13:05:38 -04:00
case PacketProcessResult : : COMMAND_TOO_LARGE :
2020-07-29 16:53:40 -04:00
logWarning ( this - > virtual_server_id_ , " {} Received a too large command. Dropping client. " , this - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
goto disconnect_client ;
case PacketProcessResult : : COMMAND_SEQUENCE_LENGTH_TOO_LONG :
2020-07-29 16:53:40 -04:00
logWarning ( this - > virtual_server_id_ , " {} Received a too long command sequence. Dropping client. " , this - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
goto disconnect_client ;
default :
assert ( false ) ;
break ;
2020-01-23 20:57:58 -05:00
}
2020-07-29 13:05:38 -04:00
return ;
2020-01-23 20:57:58 -05:00
2020-07-29 13:05:38 -04:00
disconnect_client : ;
/* FIXME: Disconnect the client */
}
2020-01-23 20:57:58 -05:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_send_acknowledge ( void * ptr_this , uint16_t packet_id , bool command_low ) {
2020-07-29 16:53:40 -04:00
reinterpret_cast < VoiceClientConnection * > ( ptr_this ) - > packet_encoder_ . send_packet_acknowledge ( packet_id , command_low ) ;
2020-07-29 13:05:38 -04:00
}
2020-01-26 20:21:39 -05:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_packet_decoded ( void * ptr_this , const ts : : protocol : : ClientPacketParser & packet ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
switch ( packet . type ( ) ) {
case protocol : : VOICE :
2020-07-29 16:53:40 -04:00
connection - > handlePacketVoice ( packet ) ;
2020-07-29 13:05:38 -04:00
break ;
case protocol : : VOICE_WHISPER :
2020-07-29 16:53:40 -04:00
connection - > handlePacketVoiceWhisper ( packet ) ;
2020-07-29 13:05:38 -04:00
break ;
case protocol : : ACK :
2020-07-29 16:53:40 -04:00
connection - > handlePacketAck ( packet ) ;
break ;
2020-07-29 13:05:38 -04:00
case protocol : : ACK_LOW :
2020-07-29 16:53:40 -04:00
connection - > handlePacketAckLow ( packet ) ;
2020-07-29 13:05:38 -04:00
break ;
case protocol : : PING :
2020-07-29 16:53:40 -04:00
connection - > handlePacketPing ( packet ) ;
break ;
2020-07-29 13:05:38 -04:00
case protocol : : PONG :
2020-07-29 16:53:40 -04:00
connection - > handlePacketPong ( packet ) ;
2020-07-29 13:05:38 -04:00
break ;
default :
assert ( false ) ;
2020-07-29 16:53:40 -04:00
logError ( connection - > virtual_server_id_ , " {} Received hand decoded packet, but we've no method to handle it. Dropping packet. " , connection - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
break ;
}
}
2020-01-26 20:21:39 -05:00
2020-07-29 16:53:40 -04:00
void VoiceClientConnection : : callback_command_decoded ( void * ptr_this , ReassembledCommand * & command ) {
2020-07-29 13:05:38 -04:00
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
2020-01-26 20:21:39 -05:00
2020-07-29 13:05:38 -04:00
/* we're exchanging the command so we're taking the ownership */
2020-07-29 16:53:40 -04:00
connection - > handlePacketCommand ( std : : exchange ( command , nullptr ) ) ;
2020-07-29 13:05:38 -04:00
}
2020-01-23 20:57:58 -05:00
2020-07-29 13:05:38 -04:00
bool VoiceClientConnection : : verify_encryption ( const pipes : : buffer_view & buffer /* incl. mac etc */ ) {
return this - > packet_decoder_ . verify_encryption ( buffer ) ;
}
2019-07-17 13:37:18 -04:00
2020-07-29 16:53:40 -04:00
std : : shared_ptr < ts : : server : : VoiceClient > VoiceClientConnection : : getCurrentClient ( ) {
if ( ! this - > current_client ) return nullptr ;
return std : : dynamic_pointer_cast < server : : VoiceClient > ( this - > current_client - > ref ( ) ) ;
2019-07-17 13:37:18 -04:00
}
bool VoiceClientConnection : : wait_empty_write_and_prepare_queue ( chrono : : time_point < chrono : : system_clock > until ) {
2020-07-29 13:05:38 -04:00
return this - > packet_encoder_ . wait_empty_write_and_prepare_queue ( until ) ;
2019-07-17 13:37:18 -04:00
}
void VoiceClientConnection : : reset ( ) {
2020-07-29 13:05:38 -04:00
this - > crypt_handler . reset ( ) ;
2020-07-29 16:53:40 -04:00
this - > ping_handler_ . reset ( ) ;
2020-07-29 13:05:38 -04:00
this - > packet_decoder_ . reset ( ) ;
this - > packet_encoder_ . reset ( ) ;
2019-07-17 13:37:18 -04:00
}
2020-01-26 20:21:39 -05:00
2020-07-30 05:40:03 -04:00
void VoiceClientConnection : : reset_remote_address ( ) {
memset ( & this - > remote_address_ , 0 , sizeof ( this - > remote_address_ ) ) ;
memset ( & this - > remote_address_info_ , 0 , sizeof ( this - > remote_address_info_ ) ) ;
}
2020-04-24 16:04:07 -04:00
void VoiceClientConnection : : send_packet ( protocol : : PacketType type , protocol : : PacketFlag : : PacketFlags flag , const void * payload , size_t payload_size ) {
2020-07-29 16:53:40 -04:00
this - > packet_encoder_ . send_packet ( type , flag , payload , payload_size ) ;
2020-04-24 16:04:07 -04:00
}
2020-11-07 07:17:51 -05:00
void VoiceClientConnection : : send_packet ( protocol : : OutgoingServerPacket * packet ) {
this - > packet_encoder_ . send_packet ( packet ) ;
}
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : send_command ( const std : : string_view & cmd , bool b , std : : unique_ptr < threads : : Future < bool > > cb ) {
this - > packet_encoder_ . send_command ( cmd , b , std : : move ( cb ) ) ;
}
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_encode_crypt_error ( void * ptr_this ,
const PacketEncoder : : CryptError & error ,
const std : : string & detail ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
switch ( error ) {
case PacketEncoder : : CryptError : : ENCRYPT_FAILED :
2020-07-29 16:53:40 -04:00
logError ( connection - > virtual_server_id_ , " {} Failed to encrypt packet. Error: {} " , connection - > log_prefix ( ) , detail ) ;
2020-07-29 13:05:38 -04:00
break ;
case PacketEncoder : : CryptError : : KEY_GENERATION_FAILED :
2020-07-29 16:53:40 -04:00
logError ( connection - > virtual_server_id_ , " {} Failed to generate crypt key/nonce for sending a packet. This should never happen! Dropping packet. " , connection - > log_prefix ( ) ) ;
2020-07-29 13:05:38 -04:00
break ;
default :
assert ( false ) ;
2020-04-24 16:04:07 -04:00
return ;
}
2020-07-29 13:05:38 -04:00
}
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_request_write ( void * ptr_this ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
connection - > triggerWrite ( ) ;
}
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_resend_failed ( void * ptr_this , const shared_ptr < AcknowledgeManager : : Entry > & entry ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
2020-04-24 16:04:07 -04:00
2020-07-29 16:53:40 -04:00
debugMessage ( connection - > virtual_server_id_ , " {} Failed to execute packet resend of packet {}. Dropping connection. " , connection - > log_prefix ( ) , entry - > packet_full_id ) ;
auto client = connection - > getCurrentClient ( ) ;
assert ( client ) ; /* TIXME! */
if ( client - > state = = ConnectionState : : CONNECTED ) {
client - > disconnect ( ViewReasonId : : VREASON_TIMEOUT , config : : messages : : timeout : : packet_resend_failed , nullptr , true ) ;
2020-04-24 16:04:07 -04:00
} else {
2020-07-29 16:53:40 -04:00
client - > close_connection ( system_clock : : now ( ) + seconds ( 1 ) ) ;
2020-04-24 16:04:07 -04:00
}
2020-07-29 13:05:38 -04:00
}
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_resend_statistics ( void * ptr_this , size_t send_count ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
2020-04-24 16:04:07 -04:00
2020-07-29 16:53:40 -04:00
logTrace ( connection - > virtual_server_id_ , " {} Resending {} packets. " , connection - > log_prefix ( ) , send_count ) ;
2020-07-29 13:05:38 -04:00
}
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
void VoiceClientConnection : : callback_outgoing_connection_statistics ( void * ptr_this ,
ts : : stats : : ConnectionStatistics : : category : : value category ,
size_t send_count ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
2020-07-29 16:53:40 -04:00
auto client = connection - > getCurrentClient ( ) ;
if ( ! client ) return ;
auto statistics = client - > connectionStatistics ;
2020-07-29 13:05:38 -04:00
if ( ! statistics ) return ;
2020-04-24 16:04:07 -04:00
2020-07-29 13:05:38 -04:00
statistics - > logOutgoingPacket ( category , send_count ) ;
2020-07-29 16:53:40 -04:00
}
void VoiceClientConnection : : callback_ping_send ( void * ptr_this , uint16_t & id ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
auto packet = protocol : : allocate_outgoing_packet ( 0 ) ;
packet - > ref ( ) ;
packet - > type_and_flags = ( uint8_t ) PacketType : : PING | ( uint8_t ) PacketFlag : : Unencrypted ;
connection - > packet_encoder_ . send_packet ( packet ) ;
id = packet - > packet_id ( ) ;
packet - > unref ( ) ;
}
void VoiceClientConnection : : callback_ping_send_recovery ( void * ptr_this ) {
auto connection = reinterpret_cast < VoiceClientConnection * > ( ptr_this ) ;
connection - > send_command ( " notifyconnectioninforequest invokerids=0 " , false , nullptr ) ;
}
void VoiceClientConnection : : callback_ping_timeout ( void * ptr_this ) {
2020-07-30 05:40:03 -04:00
( void ) ptr_this ;
2020-07-29 16:53:40 -04:00
/* doing nothing a packet resend failed will cause the client to disconnect */
2020-01-26 20:21:39 -05:00
}