2015-09-24 22:52:02 +02:00
/*
2018-07-30 04:07:02 +02:00
* This is the source code of tgnet library v . 1.1
2015-09-24 22:52:02 +02:00
* It is licensed under GNU GPL v . 2 or later .
* You should have received a copy of the license in this archive ( see LICENSE ) .
*
2018-07-30 04:07:02 +02:00
* Copyright Nikolai Kudashov , 2015 - 2018.
2015-09-24 22:52:02 +02:00
*/
2016-03-06 02:49:31 +01:00
# include <openssl/rand.h>
# include <stdlib.h>
2018-07-30 04:07:02 +02:00
# include <cstring>
# include <openssl/sha.h>
2019-08-22 01:53:26 +02:00
# include <algorithm>
2015-09-24 22:52:02 +02:00
# include "Connection.h"
# include "ConnectionsManager.h"
# include "BuffersStorage.h"
# include "FileLog.h"
# include "Timer.h"
# include "Datacenter.h"
# include "NativeByteBuffer.h"
2018-07-30 04:07:02 +02:00
# include "ByteArray.h"
2015-09-24 22:52:02 +02:00
2018-07-30 04:07:02 +02:00
thread_local static uint32_t lastConnectionToken = 1 ;
2015-09-24 22:52:02 +02:00
2018-07-30 04:07:02 +02:00
Connection : : Connection ( Datacenter * datacenter , ConnectionType type , int8_t num ) : ConnectionSession ( datacenter - > instanceNum ) , ConnectionSocket ( datacenter - > instanceNum ) {
2015-09-24 22:52:02 +02:00
currentDatacenter = datacenter ;
2018-07-30 04:07:02 +02:00
connectionNum = num ;
2015-09-24 22:52:02 +02:00
connectionType = type ;
genereateNewSessionId ( ) ;
connectionState = TcpConnectionStageIdle ;
2018-07-30 04:07:02 +02:00
reconnectTimer = new Timer ( datacenter - > instanceNum , [ & ] {
2015-09-24 22:52:02 +02:00
reconnectTimer - > stop ( ) ;
2018-07-30 04:07:02 +02:00
waitForReconnectTimer = false ;
2015-09-24 22:52:02 +02:00
connect ( ) ;
} ) ;
}
Connection : : ~ Connection ( ) {
if ( reconnectTimer ! = nullptr ) {
reconnectTimer - > stop ( ) ;
delete reconnectTimer ;
reconnectTimer = nullptr ;
}
}
void Connection : : suspendConnection ( ) {
2017-12-08 18:35:59 +01:00
suspendConnection ( false ) ;
}
void Connection : : suspendConnection ( bool idle ) {
2015-09-24 22:52:02 +02:00
reconnectTimer - > stop ( ) ;
2018-07-30 04:07:02 +02:00
waitForReconnectTimer = false ;
2015-09-24 22:52:02 +02:00
if ( connectionState = = TcpConnectionStageIdle | | connectionState = = TcpConnectionStageSuspended ) {
return ;
}
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) suspend " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType ) ;
2017-12-08 18:35:59 +01:00
connectionState = idle ? TcpConnectionStageIdle : TcpConnectionStageSuspended ;
2015-09-24 22:52:02 +02:00
dropConnection ( ) ;
2018-07-30 04:07:02 +02:00
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionClosed ( this , 0 ) ;
2015-09-24 22:52:02 +02:00
firstPacketSent = false ;
if ( restOfTheData ! = nullptr ) {
restOfTheData - > reuse ( ) ;
restOfTheData = nullptr ;
}
lastPacketLength = 0 ;
connectionToken = 0 ;
wasConnected = false ;
}
void Connection : : onReceivedData ( NativeByteBuffer * buffer ) {
2016-03-16 13:26:32 +01:00
AES_ctr128_encrypt ( buffer - > bytes ( ) , buffer - > bytes ( ) , buffer - > limit ( ) , & decryptKey , decryptIv , decryptCount , & decryptNum ) ;
2016-03-06 02:49:31 +01:00
2015-09-24 22:52:02 +02:00
failedConnectionCount = 0 ;
2019-01-23 18:03:33 +01:00
if ( connectionType = = ConnectionTypeGeneric | | connectionType = = ConnectionTypeTemp | | connectionType = = ConnectionTypeGenericMedia ) {
receivedDataAmount + = buffer - > limit ( ) ;
if ( receivedDataAmount > = 512 * 1024 ) {
if ( currentTimeout > 4 ) {
currentTimeout - = 2 ;
setTimeout ( currentTimeout ) ;
}
receivedDataAmount = 0 ;
}
}
2015-09-24 22:52:02 +02:00
NativeByteBuffer * parseLaterBuffer = nullptr ;
if ( restOfTheData ! = nullptr ) {
if ( lastPacketLength = = 0 ) {
if ( restOfTheData - > capacity ( ) - restOfTheData - > position ( ) > = buffer - > limit ( ) ) {
restOfTheData - > limit ( restOfTheData - > position ( ) + buffer - > limit ( ) ) ;
restOfTheData - > writeBytes ( buffer ) ;
buffer = restOfTheData ;
} else {
NativeByteBuffer * newBuffer = BuffersStorage : : getInstance ( ) . getFreeBuffer ( restOfTheData - > limit ( ) + buffer - > limit ( ) ) ;
restOfTheData - > rewind ( ) ;
newBuffer - > writeBytes ( restOfTheData ) ;
newBuffer - > writeBytes ( buffer ) ;
buffer = newBuffer ;
restOfTheData - > reuse ( ) ;
restOfTheData = newBuffer ;
}
} else {
uint32_t len ;
if ( lastPacketLength - restOfTheData - > position ( ) < = buffer - > limit ( ) ) {
len = lastPacketLength - restOfTheData - > position ( ) ;
} else {
len = buffer - > limit ( ) ;
}
uint32_t oldLimit = buffer - > limit ( ) ;
buffer - > limit ( len ) ;
restOfTheData - > writeBytes ( buffer ) ;
buffer - > limit ( oldLimit ) ;
if ( restOfTheData - > position ( ) = = lastPacketLength ) {
parseLaterBuffer = buffer - > hasRemaining ( ) ? buffer : nullptr ;
buffer = restOfTheData ;
} else {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) received packet size less(%u) then message size(%u) " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , restOfTheData - > position ( ) , lastPacketLength ) ;
2015-09-24 22:52:02 +02:00
return ;
}
}
}
buffer - > rewind ( ) ;
while ( buffer - > hasRemaining ( ) ) {
if ( ! hasSomeDataSinceLastConnect ) {
currentDatacenter - > storeCurrentAddressAndPortNum ( ) ;
isTryingNextPort = false ;
2018-07-30 04:07:02 +02:00
if ( connectionType = = ConnectionTypeProxy ) {
setTimeout ( 5 ) ;
} else if ( connectionType = = ConnectionTypePush ) {
2015-09-24 22:52:02 +02:00
setTimeout ( 60 * 15 ) ;
2018-07-30 04:07:02 +02:00
} else if ( connectionType = = ConnectionTypeUpload ) {
if ( ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . networkSlow ) {
setTimeout ( 40 ) ;
} else {
setTimeout ( 25 ) ;
}
2019-01-23 18:03:33 +01:00
} else if ( connectionType = = ConnectionTypeDownload ) {
2015-09-24 22:52:02 +02:00
setTimeout ( 25 ) ;
2019-01-23 18:03:33 +01:00
} else {
setTimeout ( currentTimeout ) ;
2015-09-24 22:52:02 +02:00
}
}
hasSomeDataSinceLastConnect = true ;
uint32_t currentPacketLength = 0 ;
uint32_t mark = buffer - > position ( ) ;
2018-07-30 04:07:02 +02:00
uint32_t len ;
2015-09-24 22:52:02 +02:00
2018-07-30 04:07:02 +02:00
if ( currentProtocolType = = ProtocolTypeEF ) {
uint8_t fByte = buffer - > readByte ( nullptr ) ;
if ( ( fByte & ( 1 < < 7 ) ) ! = 0 ) {
buffer - > position ( mark ) ;
if ( buffer - > remaining ( ) < 4 ) {
NativeByteBuffer * reuseLater = restOfTheData ;
restOfTheData = BuffersStorage : : getInstance ( ) . getFreeBuffer ( 16384 ) ;
restOfTheData - > writeBytes ( buffer ) ;
restOfTheData - > limit ( restOfTheData - > position ( ) ) ;
lastPacketLength = 0 ;
if ( reuseLater ! = nullptr ) {
reuseLater - > reuse ( ) ;
}
break ;
2015-09-24 22:52:02 +02:00
}
2018-07-30 04:07:02 +02:00
int32_t ackId = buffer - > readBigInt32 ( nullptr ) & ( ~ ( 1 < < 31 ) ) ;
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionQuickAckReceived ( this , ackId ) ;
continue ;
}
if ( fByte ! = 0x7f ) {
currentPacketLength = ( ( uint32_t ) fByte ) * 4 ;
} else {
buffer - > position ( mark ) ;
if ( buffer - > remaining ( ) < 4 ) {
if ( restOfTheData = = nullptr | | ( restOfTheData ! = nullptr & & restOfTheData - > position ( ) ! = 0 ) ) {
NativeByteBuffer * reuseLater = restOfTheData ;
restOfTheData = BuffersStorage : : getInstance ( ) . getFreeBuffer ( 16384 ) ;
restOfTheData - > writeBytes ( buffer ) ;
restOfTheData - > limit ( restOfTheData - > position ( ) ) ;
lastPacketLength = 0 ;
if ( reuseLater ! = nullptr ) {
reuseLater - > reuse ( ) ;
}
} else {
restOfTheData - > position ( restOfTheData - > limit ( ) ) ;
}
break ;
}
currentPacketLength = ( ( uint32_t ) buffer - > readInt32 ( nullptr ) > > 8 ) * 4 ;
2015-09-24 22:52:02 +02:00
}
2018-07-30 04:07:02 +02:00
len = currentPacketLength + ( fByte ! = 0x7f ? 1 : 4 ) ;
2015-09-24 22:52:02 +02:00
} else {
if ( buffer - > remaining ( ) < 4 ) {
if ( restOfTheData = = nullptr | | ( restOfTheData ! = nullptr & & restOfTheData - > position ( ) ! = 0 ) ) {
NativeByteBuffer * reuseLater = restOfTheData ;
restOfTheData = BuffersStorage : : getInstance ( ) . getFreeBuffer ( 16384 ) ;
restOfTheData - > writeBytes ( buffer ) ;
restOfTheData - > limit ( restOfTheData - > position ( ) ) ;
lastPacketLength = 0 ;
if ( reuseLater ! = nullptr ) {
reuseLater - > reuse ( ) ;
}
} else {
restOfTheData - > position ( restOfTheData - > limit ( ) ) ;
}
break ;
}
2018-07-30 04:07:02 +02:00
uint32_t fInt = buffer - > readUint32 ( nullptr ) ;
if ( ( fInt & ( 0x80000000 ) ) ! = 0 ) {
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionQuickAckReceived ( this , fInt & ( ~ ( 1 < < 31 ) ) ) ;
continue ;
}
currentPacketLength = fInt ;
len = currentPacketLength + 4 ;
2015-09-24 22:52:02 +02:00
}
2019-08-22 01:53:26 +02:00
if ( currentProtocolType ! = ProtocolTypeDD & & currentProtocolType ! = ProtocolTypeTLS & & currentPacketLength % 4 ! = 0 | | currentPacketLength > 2 * 1024 * 1024 ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) received invalid packet length " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType ) ;
2015-09-24 22:52:02 +02:00
reconnect ( ) ;
return ;
}
if ( currentPacketLength < buffer - > remaining ( ) ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) received message len %u but packet larger %u " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , currentPacketLength , buffer - > remaining ( ) ) ;
2015-09-24 22:52:02 +02:00
} else if ( currentPacketLength = = buffer - > remaining ( ) ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) received message len %u equal to packet size " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , currentPacketLength ) ;
2015-09-24 22:52:02 +02:00
} else {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) received packet size less(%u) then message size(%u) " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , buffer - > remaining ( ) , currentPacketLength ) ;
2015-09-24 22:52:02 +02:00
NativeByteBuffer * reuseLater = nullptr ;
2018-07-30 04:07:02 +02:00
2015-09-24 22:52:02 +02:00
if ( restOfTheData ! = nullptr & & restOfTheData - > capacity ( ) < len ) {
reuseLater = restOfTheData ;
restOfTheData = nullptr ;
}
if ( restOfTheData = = nullptr ) {
buffer - > position ( mark ) ;
restOfTheData = BuffersStorage : : getInstance ( ) . getFreeBuffer ( len ) ;
restOfTheData - > writeBytes ( buffer ) ;
} else {
restOfTheData - > position ( restOfTheData - > limit ( ) ) ;
restOfTheData - > limit ( len ) ;
}
lastPacketLength = len ;
if ( reuseLater ! = nullptr ) {
reuseLater - > reuse ( ) ;
}
return ;
}
uint32_t old = buffer - > limit ( ) ;
buffer - > limit ( buffer - > position ( ) + currentPacketLength ) ;
2018-07-30 04:07:02 +02:00
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionDataReceived ( this , buffer , currentPacketLength ) ;
2015-09-24 22:52:02 +02:00
buffer - > position ( buffer - > limit ( ) ) ;
buffer - > limit ( old ) ;
if ( restOfTheData ! = nullptr ) {
if ( ( lastPacketLength ! = 0 & & restOfTheData - > position ( ) = = lastPacketLength ) | | ( lastPacketLength = = 0 & & ! restOfTheData - > hasRemaining ( ) ) ) {
restOfTheData - > reuse ( ) ;
restOfTheData = nullptr ;
} else {
restOfTheData - > compact ( ) ;
restOfTheData - > limit ( restOfTheData - > position ( ) ) ;
restOfTheData - > position ( 0 ) ;
}
}
if ( parseLaterBuffer ! = nullptr ) {
buffer = parseLaterBuffer ;
parseLaterBuffer = nullptr ;
}
}
}
void Connection : : connect ( ) {
2018-07-30 04:07:02 +02:00
if ( waitForReconnectTimer ) {
return ;
}
if ( ! ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . isNetworkAvailable ( ) ) {
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionClosed ( this , 0 ) ;
2015-09-24 22:52:02 +02:00
return ;
}
2018-07-30 04:07:02 +02:00
if ( connectionState = = TcpConnectionStageConnected | | connectionState = = TcpConnectionStageConnecting ) {
2015-09-24 22:52:02 +02:00
return ;
}
2019-05-14 14:08:05 +02:00
connectionInProcess = true ;
2015-09-24 22:52:02 +02:00
connectionState = TcpConnectionStageConnecting ;
2018-07-30 04:07:02 +02:00
isMediaConnection = false ;
uint32_t ipv6 = ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . isIpv6Enabled ( ) ? TcpAddressFlagIpv6 : 0 ;
uint32_t isStatic = connectionType = = ConnectionTypeProxy | | ! ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . proxyAddress . empty ( ) ? TcpAddressFlagStatic : 0 ;
TcpAddress * tcpAddress = nullptr ;
if ( isMediaConnectionType ( connectionType ) ) {
2017-07-08 18:32:04 +02:00
currentAddressFlags = TcpAddressFlagDownload | isStatic ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags | ipv6 ) ;
if ( tcpAddress = = nullptr ) {
2017-07-08 18:32:04 +02:00
currentAddressFlags = isStatic ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags | ipv6 ) ;
} else {
isMediaConnection = true ;
2015-09-24 22:52:02 +02:00
}
2018-07-30 04:07:02 +02:00
if ( tcpAddress = = nullptr & & ipv6 ) {
2017-07-08 18:32:04 +02:00
ipv6 = 0 ;
currentAddressFlags = TcpAddressFlagDownload | isStatic ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags ) ;
if ( tcpAddress = = nullptr ) {
2017-07-08 18:32:04 +02:00
currentAddressFlags = isStatic ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags ) ;
} else {
isMediaConnection = true ;
2015-09-24 22:52:02 +02:00
}
}
2018-07-30 04:07:02 +02:00
} else if ( connectionType = = ConnectionTypeTemp ) {
currentAddressFlags = TcpAddressFlagTemp ;
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags ) ;
2019-12-31 14:08:08 +01:00
ipv6 = 0 ;
2015-09-24 22:52:02 +02:00
} else {
2017-07-08 18:32:04 +02:00
currentAddressFlags = isStatic ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags | ipv6 ) ;
if ( tcpAddress = = nullptr & & ipv6 ) {
2017-07-08 18:32:04 +02:00
ipv6 = 0 ;
2018-07-30 04:07:02 +02:00
tcpAddress = currentDatacenter - > getCurrentAddress ( currentAddressFlags ) ;
2015-09-24 22:52:02 +02:00
}
}
2018-07-30 04:07:02 +02:00
if ( tcpAddress = = nullptr ) {
hostAddress = " " ;
} else {
hostAddress = tcpAddress - > address ;
secret = tcpAddress - > secret ;
}
if ( tcpAddress ! = nullptr & & isStatic ) {
hostPort = ( uint16_t ) tcpAddress - > port ;
} else {
hostPort = ( uint16_t ) currentDatacenter - > getCurrentPort ( currentAddressFlags ) ;
}
2015-09-24 22:52:02 +02:00
reconnectTimer - > stop ( ) ;
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) connecting (%s:%hu) " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , hostAddress . c_str ( ) , hostPort ) ;
2015-09-24 22:52:02 +02:00
firstPacketSent = false ;
if ( restOfTheData ! = nullptr ) {
restOfTheData - > reuse ( ) ;
restOfTheData = nullptr ;
}
lastPacketLength = 0 ;
wasConnected = false ;
hasSomeDataSinceLastConnect = false ;
2019-08-22 01:53:26 +02:00
openConnection ( hostAddress , hostPort , secret , ipv6 ! = 0 , ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . currentNetworkType ) ;
2018-07-30 04:07:02 +02:00
if ( connectionType = = ConnectionTypeProxy ) {
setTimeout ( 5 ) ;
} else if ( connectionType = = ConnectionTypePush ) {
2015-09-24 22:52:02 +02:00
if ( isTryingNextPort ) {
setTimeout ( 20 ) ;
} else {
setTimeout ( 30 ) ;
}
2018-07-30 04:07:02 +02:00
} else if ( connectionType = = ConnectionTypeUpload ) {
if ( ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . networkSlow ) {
setTimeout ( 40 ) ;
} else {
setTimeout ( 25 ) ;
}
2015-09-24 22:52:02 +02:00
} else {
if ( isTryingNextPort ) {
setTimeout ( 8 ) ;
} else {
2018-07-30 04:07:02 +02:00
setTimeout ( 12 ) ;
2015-09-24 22:52:02 +02:00
}
}
2019-05-14 14:08:05 +02:00
connectionInProcess = false ;
2015-09-24 22:52:02 +02:00
}
void Connection : : reconnect ( ) {
2018-07-30 04:07:02 +02:00
if ( connectionType = = ConnectionTypeProxy ) {
suspendConnection ( false ) ;
} else {
forceNextPort = true ;
suspendConnection ( true ) ;
connect ( ) ;
}
2015-09-24 22:52:02 +02:00
}
2017-07-08 18:32:04 +02:00
bool Connection : : hasUsefullData ( ) {
2018-07-30 04:07:02 +02:00
int64_t time = ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . getCurrentTimeMonotonicMillis ( ) ;
if ( usefullData & & llabs ( time - usefullDataReceiveTime ) < 4 * 1000L ) {
return false ;
}
2017-07-08 18:32:04 +02:00
return usefullData ;
}
2018-07-30 04:07:02 +02:00
bool Connection : : isSuspended ( ) {
return connectionState = = TcpConnectionStageSuspended ;
}
bool Connection : : isMediaConnectionType ( ConnectionType type ) {
return ( type & ConnectionTypeGenericMedia ) ! = 0 | | ( type & ConnectionTypeDownload ) ! = 0 ;
}
2017-07-08 18:32:04 +02:00
void Connection : : setHasUsefullData ( ) {
2018-07-30 04:07:02 +02:00
if ( ! usefullData ) {
usefullDataReceiveTime = ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . getCurrentTimeMonotonicMillis ( ) ;
usefullData = true ;
lastReconnectTimeout = 50 ;
}
}
bool Connection : : allowsCustomPadding ( ) {
2019-08-22 01:53:26 +02:00
return currentProtocolType = = ProtocolTypeTLS | | currentProtocolType = = ProtocolTypeDD | | currentProtocolType = = ProtocolTypeEF ;
2017-07-08 18:32:04 +02:00
}
2018-07-30 04:07:02 +02:00
void Connection : : sendData ( NativeByteBuffer * buff , bool reportAck , bool encrypted ) {
2015-09-24 22:52:02 +02:00
if ( buff = = nullptr ) {
return ;
}
buff - > rewind ( ) ;
if ( connectionState = = TcpConnectionStageIdle | | connectionState = = TcpConnectionStageReconnecting | | connectionState = = TcpConnectionStageSuspended ) {
connect ( ) ;
}
if ( isDisconnected ( ) ) {
buff - > reuse ( ) ;
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) disconnected, don't send data " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType ) ;
2015-09-24 22:52:02 +02:00
return ;
}
uint32_t bufferLen = 0 ;
2018-07-30 04:07:02 +02:00
uint32_t packetLength ;
2015-09-24 22:52:02 +02:00
2018-07-30 04:07:02 +02:00
uint8_t useSecret = 0 ;
if ( ! firstPacketSent ) {
if ( ! overrideProxyAddress . empty ( ) ) {
if ( ! overrideProxySecret . empty ( ) ) {
useSecret = 1 ;
} else if ( ! secret . empty ( ) ) {
useSecret = 2 ;
}
} else if ( ! ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . proxyAddress . empty ( ) & & ! ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . proxySecret . empty ( ) ) {
useSecret = 1 ;
} else if ( ! secret . empty ( ) ) {
useSecret = 2 ;
}
if ( useSecret ! = 0 ) {
std : : string * currentSecret = getCurrentSecret ( useSecret ) ;
2019-08-22 01:53:26 +02:00
if ( currentSecret - > length ( ) > = 17 & & ( * currentSecret ) [ 0 ] = = ' \xdd ' ) {
2018-07-30 04:07:02 +02:00
currentProtocolType = ProtocolTypeDD ;
2019-08-22 01:53:26 +02:00
} else if ( currentSecret - > length ( ) > 17 & & ( * currentSecret ) [ 0 ] = = ' \xee ' ) {
currentProtocolType = ProtocolTypeTLS ;
2018-07-30 04:07:02 +02:00
} else {
currentProtocolType = ProtocolTypeEF ;
}
} else {
currentProtocolType = ProtocolTypeEF ;
}
}
uint32_t additinalPacketSize = 0 ;
if ( currentProtocolType = = ProtocolTypeEF ) {
packetLength = buff - > limit ( ) / 4 ;
if ( packetLength < 0x7f ) {
bufferLen + + ;
} else {
bufferLen + = 4 ;
}
2015-09-24 22:52:02 +02:00
} else {
2018-07-30 04:07:02 +02:00
packetLength = buff - > limit ( ) ;
2019-08-22 01:53:26 +02:00
if ( currentProtocolType = = ProtocolTypeDD | | currentProtocolType = = ProtocolTypeTLS ) {
2018-07-30 04:07:02 +02:00
RAND_bytes ( ( uint8_t * ) & additinalPacketSize , 4 ) ;
if ( ! encrypted ) {
additinalPacketSize = additinalPacketSize % 257 ;
} else {
additinalPacketSize = additinalPacketSize % 16 ;
}
packetLength + = additinalPacketSize ;
} else {
RAND_bytes ( ( uint8_t * ) & additinalPacketSize , 4 ) ;
if ( ! encrypted ) {
additinalPacketSize = additinalPacketSize % 257 ;
uint32_t additionalSize = additinalPacketSize % 4 ;
if ( additionalSize ! = 0 ) {
additinalPacketSize + = ( 4 - additionalSize ) ;
}
}
packetLength + = additinalPacketSize ;
}
2015-09-24 22:52:02 +02:00
bufferLen + = 4 ;
}
2018-07-30 04:07:02 +02:00
2015-09-24 22:52:02 +02:00
if ( ! firstPacketSent ) {
2016-03-06 02:49:31 +01:00
bufferLen + = 64 ;
2015-09-24 22:52:02 +02:00
}
NativeByteBuffer * buffer = BuffersStorage : : getInstance ( ) . getFreeBuffer ( bufferLen ) ;
2018-07-30 04:07:02 +02:00
NativeByteBuffer * buffer2 ;
if ( additinalPacketSize > 0 ) {
buffer2 = BuffersStorage : : getInstance ( ) . getFreeBuffer ( additinalPacketSize ) ;
RAND_bytes ( buffer2 - > bytes ( ) , additinalPacketSize ) ;
} else {
buffer2 = nullptr ;
}
2016-03-06 02:49:31 +01:00
uint8_t * bytes = buffer - > bytes ( ) ;
2018-07-30 04:07:02 +02:00
2015-09-24 22:52:02 +02:00
if ( ! firstPacketSent ) {
2016-03-06 02:49:31 +01:00
buffer - > position ( 64 ) ;
while ( true ) {
RAND_bytes ( bytes , 64 ) ;
uint32_t val = ( bytes [ 3 ] < < 24 ) | ( bytes [ 2 ] < < 16 ) | ( bytes [ 1 ] < < 8 ) | ( bytes [ 0 ] ) ;
uint32_t val2 = ( bytes [ 7 ] < < 24 ) | ( bytes [ 6 ] < < 16 ) | ( bytes [ 5 ] < < 8 ) | ( bytes [ 4 ] ) ;
2019-08-22 01:53:26 +02:00
if ( currentProtocolType = = ProtocolTypeTLS | | bytes [ 0 ] ! = 0xef & & val ! = 0x44414548 & & val ! = 0x54534f50 & & val ! = 0x20544547 & & val ! = 0x4954504f & & val ! = 0xeeeeeeee & & val ! = 0xdddddddd & & val ! = 0x02010316 & & val2 ! = 0x00000000 ) {
2018-07-30 04:07:02 +02:00
if ( currentProtocolType = = ProtocolTypeEF ) {
bytes [ 56 ] = bytes [ 57 ] = bytes [ 58 ] = bytes [ 59 ] = 0xef ;
2019-08-22 01:53:26 +02:00
} else if ( currentProtocolType = = ProtocolTypeDD | | currentProtocolType = = ProtocolTypeTLS ) {
2018-07-30 04:07:02 +02:00
bytes [ 56 ] = bytes [ 57 ] = bytes [ 58 ] = bytes [ 59 ] = 0xdd ;
} else if ( currentProtocolType = = ProtocolTypeEE ) {
bytes [ 56 ] = bytes [ 57 ] = bytes [ 58 ] = bytes [ 59 ] = 0xee ;
}
if ( useSecret ! = 0 ) {
int16_t datacenterId ;
2019-12-31 14:08:08 +01:00
if ( isMediaConnection ) {
2018-07-30 04:07:02 +02:00
if ( ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . testBackend ) {
datacenterId = - ( int16_t ) ( 10000 + currentDatacenter - > getDatacenterId ( ) ) ;
} else {
datacenterId = - ( int16_t ) currentDatacenter - > getDatacenterId ( ) ;
}
} else {
if ( ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . testBackend ) {
datacenterId = ( int16_t ) ( 10000 + currentDatacenter - > getDatacenterId ( ) ) ;
} else {
datacenterId = ( int16_t ) currentDatacenter - > getDatacenterId ( ) ;
}
}
bytes [ 60 ] = ( uint8_t ) ( datacenterId & 0xff ) ;
bytes [ 61 ] = ( uint8_t ) ( ( datacenterId > > 8 ) & 0xff ) ;
}
2016-03-06 02:49:31 +01:00
break ;
}
}
2018-07-30 04:07:02 +02:00
2016-03-06 02:49:31 +01:00
encryptNum = decryptNum = 0 ;
memset ( encryptCount , 0 , 16 ) ;
memset ( decryptCount , 0 , 16 ) ;
2018-07-30 04:07:02 +02:00
for ( int32_t a = 0 ; a < 48 ; a + + ) {
temp [ a ] = bytes [ a + 8 ] ;
}
encryptKeyWithSecret ( temp , useSecret ) ;
if ( AES_set_encrypt_key ( temp , 256 , & encryptKey ) < 0 ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_E ( " unable to set encryptKey " ) ;
2016-03-06 02:49:31 +01:00
exit ( 1 ) ;
}
2018-07-30 04:07:02 +02:00
memcpy ( encryptIv , temp + 32 , 16 ) ;
for ( int32_t a = 0 ; a < 48 ; a + + ) {
temp [ a ] = bytes [ 55 - a ] ;
}
encryptKeyWithSecret ( temp , useSecret ) ;
2016-03-06 02:49:31 +01:00
if ( AES_set_encrypt_key ( temp , 256 , & decryptKey ) < 0 ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_E ( " unable to set decryptKey " ) ;
2016-03-06 02:49:31 +01:00
exit ( 1 ) ;
}
memcpy ( decryptIv , temp + 32 , 16 ) ;
AES_ctr128_encrypt ( bytes , temp , 64 , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
2016-03-16 13:26:32 +01:00
memcpy ( bytes + 56 , temp + 56 , 8 ) ;
2016-03-06 02:49:31 +01:00
2015-09-24 22:52:02 +02:00
firstPacketSent = true ;
}
2018-07-30 04:07:02 +02:00
if ( currentProtocolType = = ProtocolTypeEF ) {
if ( packetLength < 0x7f ) {
if ( reportAck ) {
packetLength | = ( 1 < < 7 ) ;
}
buffer - > writeByte ( ( uint8_t ) packetLength ) ;
bytes + = ( buffer - > limit ( ) - 1 ) ;
AES_ctr128_encrypt ( bytes , bytes , 1 , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
} else {
packetLength = ( packetLength < < 8 ) + 0x7f ;
if ( reportAck ) {
packetLength | = ( 1 < < 7 ) ;
}
buffer - > writeInt32 ( packetLength ) ;
bytes + = ( buffer - > limit ( ) - 4 ) ;
AES_ctr128_encrypt ( bytes , bytes , 4 , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
2015-09-24 22:52:02 +02:00
}
} else {
if ( reportAck ) {
2018-07-30 04:07:02 +02:00
packetLength | = 0x80000000 ;
2015-09-24 22:52:02 +02:00
}
buffer - > writeInt32 ( packetLength ) ;
2016-03-06 02:49:31 +01:00
bytes + = ( buffer - > limit ( ) - 4 ) ;
2016-03-16 13:26:32 +01:00
AES_ctr128_encrypt ( bytes , bytes , 4 , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
2015-09-24 22:52:02 +02:00
}
buffer - > rewind ( ) ;
writeBuffer ( buffer ) ;
buff - > rewind ( ) ;
2016-03-16 13:26:32 +01:00
AES_ctr128_encrypt ( buff - > bytes ( ) , buff - > bytes ( ) , buff - > limit ( ) , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
2015-09-24 22:52:02 +02:00
writeBuffer ( buff ) ;
2018-07-30 04:07:02 +02:00
if ( buffer2 ! = nullptr ) {
AES_ctr128_encrypt ( buffer2 - > bytes ( ) , buffer2 - > bytes ( ) , buffer2 - > limit ( ) , & encryptKey , encryptIv , encryptCount , & encryptNum ) ;
writeBuffer ( buffer2 ) ;
}
2015-09-24 22:52:02 +02:00
}
2018-07-30 04:07:02 +02:00
inline std : : string * Connection : : getCurrentSecret ( uint8_t secretType ) {
if ( secretType = = 2 ) {
return & secret ;
} else if ( ! overrideProxySecret . empty ( ) ) {
return & overrideProxySecret ;
} else {
return & ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . proxySecret ;
}
}
inline void Connection : : encryptKeyWithSecret ( uint8_t * bytes , uint8_t secretType ) {
if ( secretType = = 0 ) {
return ;
}
std : : string * currentSecret = getCurrentSecret ( secretType ) ;
size_t a = 0 ;
2019-08-22 01:53:26 +02:00
size_t size = std : : min ( ( size_t ) 16 , currentSecret - > length ( ) ) ;
if ( currentSecret - > length ( ) > = 17 & & ( ( * currentSecret ) [ 0 ] = = ' \xdd ' | | ( * currentSecret ) [ 0 ] = = ' \xee ' ) ) {
2018-07-30 04:07:02 +02:00
a = 1 ;
2019-08-22 01:53:26 +02:00
size = 17 ;
2018-07-30 04:07:02 +02:00
}
SHA256_CTX sha256Ctx ;
SHA256_Init ( & sha256Ctx ) ;
SHA256_Update ( & sha256Ctx , bytes , 32 ) ;
char b [ 1 ] ;
2019-08-22 01:53:26 +02:00
for ( ; a < size ; a + + ) {
b [ 0 ] = ( char ) ( * currentSecret ) [ a ] ;
2018-07-30 04:07:02 +02:00
SHA256_Update ( & sha256Ctx , b , 1 ) ;
}
SHA256_Final ( bytes , & sha256Ctx ) ;
}
2019-05-14 14:08:05 +02:00
void Connection : : onDisconnectedInternal ( int32_t reason , int32_t error ) {
2015-09-24 22:52:02 +02:00
reconnectTimer - > stop ( ) ;
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) disconnected with reason %d " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , reason ) ;
bool switchToNextPort = reason = = 2 & & wasConnected & & ( ! hasSomeDataSinceLastConnect | | currentDatacenter - > isCustomPort ( currentAddressFlags ) ) | | forceNextPort ;
if ( connectionType = = ConnectionTypeGeneric | | connectionType = = ConnectionTypeTemp | | connectionType = = ConnectionTypeGenericMedia ) {
if ( wasConnected & & reason = = 2 & & currentTimeout < 16 ) {
currentTimeout + = 2 ;
}
}
2015-09-24 22:52:02 +02:00
firstPacketSent = false ;
if ( restOfTheData ! = nullptr ) {
restOfTheData - > reuse ( ) ;
restOfTheData = nullptr ;
}
lastPacketLength = 0 ;
2019-01-23 18:03:33 +01:00
receivedDataAmount = 0 ;
2015-09-24 22:52:02 +02:00
wasConnected = false ;
if ( connectionState ! = TcpConnectionStageSuspended & & connectionState ! = TcpConnectionStageIdle ) {
connectionState = TcpConnectionStageIdle ;
}
2018-07-30 04:07:02 +02:00
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionClosed ( this , reason ) ;
connectionToken = 0 ;
2015-09-24 22:52:02 +02:00
uint32_t datacenterId = currentDatacenter - > getDatacenterId ( ) ;
2017-12-08 18:35:59 +01:00
if ( connectionState = = TcpConnectionStageIdle ) {
2015-09-24 22:52:02 +02:00
connectionState = TcpConnectionStageReconnecting ;
failedConnectionCount + + ;
if ( failedConnectionCount = = 1 ) {
2018-07-30 04:07:02 +02:00
if ( hasUsefullData ( ) ) {
2017-12-08 18:35:59 +01:00
willRetryConnectCount = 3 ;
2015-09-24 22:52:02 +02:00
} else {
willRetryConnectCount = 1 ;
}
}
2019-05-14 14:08:05 +02:00
if ( ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . isNetworkAvailable ( ) & & connectionType ! = ConnectionTypeProxy ) {
2015-09-24 22:52:02 +02:00
isTryingNextPort = true ;
if ( failedConnectionCount > willRetryConnectCount | | switchToNextPort ) {
currentDatacenter - > nextAddressOrPort ( currentAddressFlags ) ;
failedConnectionCount = 0 ;
}
}
2018-07-30 04:07:02 +02:00
if ( error = = 0x68 | | error = = 0x71 ) {
if ( connectionType ! = ConnectionTypeProxy ) {
waitForReconnectTimer = true ;
reconnectTimer - > setTimeout ( lastReconnectTimeout , false ) ;
lastReconnectTimeout * = 2 ;
if ( lastReconnectTimeout > 400 ) {
lastReconnectTimeout = 400 ;
}
reconnectTimer - > start ( ) ;
}
} else {
waitForReconnectTimer = false ;
if ( connectionType = = ConnectionTypeGenericMedia & & currentDatacenter - > isHandshaking ( true ) | | connectionType = = ConnectionTypeGeneric & & ( currentDatacenter - > isHandshaking ( false ) | | datacenterId = = ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . currentDatacenterId | | datacenterId = = ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . movingToDatacenterId ) ) {
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) reconnect %s:%hu " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , hostAddress . c_str ( ) , hostPort ) ;
2018-07-30 04:07:02 +02:00
reconnectTimer - > setTimeout ( 1000 , false ) ;
reconnectTimer - > start ( ) ;
}
2017-12-08 18:35:59 +01:00
}
2015-09-24 22:52:02 +02:00
}
2017-12-08 18:35:59 +01:00
usefullData = false ;
2015-09-24 22:52:02 +02:00
}
2019-05-14 14:08:05 +02:00
void Connection : : onDisconnected ( int32_t reason , int32_t error ) {
if ( connectionInProcess ) {
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . scheduleTask ( [ & , reason , error ] {
onDisconnectedInternal ( reason , error ) ;
} ) ;
} else {
onDisconnectedInternal ( reason , error ) ;
}
}
2015-09-24 22:52:02 +02:00
void Connection : : onConnected ( ) {
connectionState = TcpConnectionStageConnected ;
connectionToken = lastConnectionToken + + ;
wasConnected = true ;
2019-01-23 18:03:33 +01:00
if ( LOGS_ENABLED ) DEBUG_D ( " connection(%p, account%u, dc%u, type %d) connected to %s:%hu " , this , currentDatacenter - > instanceNum , currentDatacenter - > getDatacenterId ( ) , connectionType , hostAddress . c_str ( ) , hostPort ) ;
2018-07-30 04:07:02 +02:00
ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . onConnectionConnected ( this ) ;
2015-09-24 22:52:02 +02:00
}
2019-01-23 18:03:33 +01:00
bool Connection : : hasPendingRequests ( ) {
return ConnectionsManager : : getInstance ( currentDatacenter - > instanceNum ) . hasPendingRequestsForConnection ( this ) ;
}
2015-09-24 22:52:02 +02:00
Datacenter * Connection : : getDatacenter ( ) {
return currentDatacenter ;
}
ConnectionType Connection : : getConnectionType ( ) {
return connectionType ;
}
2018-07-30 04:07:02 +02:00
int8_t Connection : : getConnectionNum ( ) {
return connectionNum ;
}
2015-09-24 22:52:02 +02:00
uint32_t Connection : : getConnectionToken ( ) {
return connectionToken ;
}