2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2018-01-03 13:23:14 +03:00
the official desktop application for the Telegram messaging service .
2014-05-30 12:53:19 +04:00
2018-01-03 13:23:14 +03:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2014-05-30 12:53:19 +04:00
*/
2016-03-23 21:43:12 +03:00
# include "mtproto/connection.h"
2016-03-23 21:12:07 +03:00
2017-12-18 16:40:15 +04:00
# include "mtproto/session.h"
2017-06-26 20:38:16 +03:00
# include "mtproto/rsa_public_key.h"
# include "mtproto/rpc_sender.h"
# include "mtproto/dc_options.h"
# include "mtproto/connection_abstract.h"
# include "zlib.h"
2019-01-21 17:42:21 +04:00
# include "core/application.h"
2018-06-03 22:52:23 +03:00
# include "core/launcher.h"
2017-06-26 20:38:16 +03:00
# include "lang/lang_keys.h"
# include "base/openssl_help.h"
2018-04-24 23:09:20 +04:00
# include "base/qthelp_url.h"
2018-06-06 15:16:21 +03:00
extern " C " {
2016-03-23 21:12:07 +03:00
# include <openssl/bn.h>
# include <openssl/err.h>
# include <openssl/aes.h>
# include <openssl/sha.h>
# include <openssl/md5.h>
2014-05-30 12:53:19 +04:00
# include <openssl/rand.h>
2018-06-06 15:16:21 +03:00
} // extern "C"
2016-03-23 21:12:07 +03:00
2019-02-07 19:36:30 +03:00
# ifdef small
# undef small
# endif // small
2016-03-23 21:12:07 +03:00
namespace MTP {
namespace internal {
2016-03-24 11:57:11 +03:00
namespace {
2017-02-25 19:44:02 +03:00
constexpr auto kRecreateKeyId = AuthKey : : KeyId ( 0xFFFFFFFFFFFFFFFFULL ) ;
2017-02-27 12:51:03 +03:00
constexpr auto kIntSize = static_cast < int > ( sizeof ( mtpPrime ) ) ;
2017-04-24 15:16:38 +03:00
constexpr auto kMaxModExpSize = 256 ;
2019-02-19 10:57:53 +04:00
constexpr auto kWaitForBetterTimeout = crl : : time ( 2000 ) ;
constexpr auto kMinConnectedTimeout = crl : : time ( 1000 ) ;
constexpr auto kMaxConnectedTimeout = crl : : time ( 8000 ) ;
constexpr auto kMinReceiveTimeout = crl : : time ( 4000 ) ;
constexpr auto kMaxReceiveTimeout = crl : : time ( 64000 ) ;
constexpr auto kMarkConnectionOldTimeout = crl : : time ( 192000 ) ;
2018-04-24 23:09:20 +04:00
constexpr auto kPingDelayDisconnect = 60 ;
2019-02-19 10:57:53 +04:00
constexpr auto kPingSendAfter = crl : : time ( 30000 ) ;
constexpr auto kPingSendAfterForce = crl : : time ( 45000 ) ;
2018-05-17 22:58:00 +03:00
constexpr auto kTestModeDcIdShift = 10000 ;
2017-04-24 15:16:38 +03:00
2018-04-24 11:21:19 +04:00
// If we can't connect for this time we will ask _instance to update config.
2019-02-19 10:57:53 +04:00
constexpr auto kRequestConfigTimeout = crl : : time ( 8000 ) ;
2018-04-24 11:21:19 +04:00
2016-12-31 12:58:56 +04:00
// Don't try to handle messages larger than this size.
constexpr auto kMaxMessageLength = 16 * 1024 * 1024 ;
2017-12-11 18:45:29 +04:00
QString LogIdsVector ( const QVector < MTPlong > & ids ) {
if ( ! ids . size ( ) ) return " [] " ;
auto idsStr = QString ( " [%1 " ) . arg ( ids . cbegin ( ) - > v ) ;
for ( const auto & id : ids ) {
idsStr + = QString ( " , %2 " ) . arg ( id . v ) ;
}
return idsStr + " ] " ;
}
2018-08-10 22:19:46 +03:00
bool IsGoodModExpFirst (
const openssl : : BigNum & modexp ,
const openssl : : BigNum & prime ) {
const auto diff = openssl : : BigNum : : Sub ( prime , modexp ) ;
2017-04-24 15:16:38 +03:00
if ( modexp . failed ( ) | | prime . failed ( ) | | diff . failed ( ) ) {
return false ;
}
constexpr auto kMinDiffBitsCount = 2048 - 64 ;
2018-08-10 22:19:46 +03:00
if ( diff . isNegative ( )
| | diff . bitsSize ( ) < kMinDiffBitsCount
| | modexp . bitsSize ( ) < kMinDiffBitsCount
| | modexp . bytesSize ( ) > kMaxModExpSize ) {
2017-04-24 15:16:38 +03:00
return false ;
}
return true ;
}
bool IsPrimeAndGoodCheck ( const openssl : : BigNum & prime , int g ) {
constexpr auto kGoodPrimeBitsCount = 2048 ;
if ( prime . failed ( ) | | prime . isNegative ( ) | | prime . bitsSize ( ) ! = kGoodPrimeBitsCount ) {
LOG ( ( " MTP Error: Bad prime bits count %1, expected %2. " ) . arg ( prime . bitsSize ( ) ) . arg ( kGoodPrimeBitsCount ) ) ;
return false ;
}
openssl : : Context context ;
if ( ! prime . isPrime ( context ) ) {
LOG ( ( " MTP Error: Bad prime. " ) ) ;
return false ;
}
switch ( g ) {
case 2 : {
auto mod8 = prime . modWord ( 8 ) ;
if ( mod8 ! = 7 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod8: %2 " ) . arg ( g ) . arg ( mod8 ) ) ;
return false ;
}
} break ;
case 3 : {
auto mod3 = prime . modWord ( 3 ) ;
if ( mod3 ! = 2 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod3: %2 " ) . arg ( g ) . arg ( mod3 ) ) ;
return false ;
}
} break ;
case 4 : break ;
case 5 : {
auto mod5 = prime . modWord ( 5 ) ;
if ( mod5 ! = 1 & & mod5 ! = 4 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod5: %2 " ) . arg ( g ) . arg ( mod5 ) ) ;
return false ;
}
} break ;
case 6 : {
auto mod24 = prime . modWord ( 24 ) ;
if ( mod24 ! = 19 & & mod24 ! = 23 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod24: %2 " ) . arg ( g ) . arg ( mod24 ) ) ;
return false ;
}
} break ;
case 7 : {
auto mod7 = prime . modWord ( 7 ) ;
if ( mod7 ! = 3 & & mod7 ! = 5 & & mod7 ! = 6 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod7: %2 " ) . arg ( g ) . arg ( mod7 ) ) ;
return false ;
}
} break ;
default : {
LOG ( ( " BigNum PT Error: bad g value: %1 " ) . arg ( g ) ) ;
return false ;
} break ;
}
auto primeSubOneDivTwo = prime ;
primeSubOneDivTwo . setSubWord ( 1 ) ;
primeSubOneDivTwo . setDivWord ( 2 ) ;
if ( ! primeSubOneDivTwo . isPrime ( context ) ) {
LOG ( ( " MTP Error: Bad (prime - 1) / 2. " ) ) ;
return false ;
}
return true ;
}
2018-03-27 16:16:00 +04:00
bool IsPrimeAndGood ( bytes : : const_span primeBytes , int g ) {
2017-04-24 15:16:38 +03:00
static constexpr unsigned char GoodPrime [ ] = {
0xC7 , 0x1C , 0xAE , 0xB9 , 0xC6 , 0xB1 , 0xC9 , 0x04 , 0x8E , 0x6C , 0x52 , 0x2F , 0x70 , 0xF1 , 0x3F , 0x73 ,
0x98 , 0x0D , 0x40 , 0x23 , 0x8E , 0x3E , 0x21 , 0xC1 , 0x49 , 0x34 , 0xD0 , 0x37 , 0x56 , 0x3D , 0x93 , 0x0F ,
0x48 , 0x19 , 0x8A , 0x0A , 0xA7 , 0xC1 , 0x40 , 0x58 , 0x22 , 0x94 , 0x93 , 0xD2 , 0x25 , 0x30 , 0xF4 , 0xDB ,
0xFA , 0x33 , 0x6F , 0x6E , 0x0A , 0xC9 , 0x25 , 0x13 , 0x95 , 0x43 , 0xAE , 0xD4 , 0x4C , 0xCE , 0x7C , 0x37 ,
0x20 , 0xFD , 0x51 , 0xF6 , 0x94 , 0x58 , 0x70 , 0x5A , 0xC6 , 0x8C , 0xD4 , 0xFE , 0x6B , 0x6B , 0x13 , 0xAB ,
0xDC , 0x97 , 0x46 , 0x51 , 0x29 , 0x69 , 0x32 , 0x84 , 0x54 , 0xF1 , 0x8F , 0xAF , 0x8C , 0x59 , 0x5F , 0x64 ,
0x24 , 0x77 , 0xFE , 0x96 , 0xBB , 0x2A , 0x94 , 0x1D , 0x5B , 0xCD , 0x1D , 0x4A , 0xC8 , 0xCC , 0x49 , 0x88 ,
0x07 , 0x08 , 0xFA , 0x9B , 0x37 , 0x8E , 0x3C , 0x4F , 0x3A , 0x90 , 0x60 , 0xBE , 0xE6 , 0x7C , 0xF9 , 0xA4 ,
0xA4 , 0xA6 , 0x95 , 0x81 , 0x10 , 0x51 , 0x90 , 0x7E , 0x16 , 0x27 , 0x53 , 0xB5 , 0x6B , 0x0F , 0x6B , 0x41 ,
0x0D , 0xBA , 0x74 , 0xD8 , 0xA8 , 0x4B , 0x2A , 0x14 , 0xB3 , 0x14 , 0x4E , 0x0E , 0xF1 , 0x28 , 0x47 , 0x54 ,
0xFD , 0x17 , 0xED , 0x95 , 0x0D , 0x59 , 0x65 , 0xB4 , 0xB9 , 0xDD , 0x46 , 0x58 , 0x2D , 0xB1 , 0x17 , 0x8D ,
0x16 , 0x9C , 0x6B , 0xC4 , 0x65 , 0xB0 , 0xD6 , 0xFF , 0x9C , 0xA3 , 0x92 , 0x8F , 0xEF , 0x5B , 0x9A , 0xE4 ,
0xE4 , 0x18 , 0xFC , 0x15 , 0xE8 , 0x3E , 0xBE , 0xA0 , 0xF8 , 0x7F , 0xA9 , 0xFF , 0x5E , 0xED , 0x70 , 0x05 ,
0x0D , 0xED , 0x28 , 0x49 , 0xF4 , 0x7B , 0xF9 , 0x59 , 0xD9 , 0x56 , 0x85 , 0x0C , 0xE9 , 0x29 , 0x85 , 0x1F ,
0x0D , 0x81 , 0x15 , 0xF6 , 0x35 , 0xB1 , 0x05 , 0xEE , 0x2E , 0x4E , 0x15 , 0xD0 , 0x4B , 0x24 , 0x54 , 0xBF ,
0x6F , 0x4F , 0xAD , 0xF0 , 0x34 , 0xB1 , 0x04 , 0x03 , 0x11 , 0x9C , 0xD8 , 0xE3 , 0xB9 , 0x2F , 0xCC , 0x5B } ;
2018-03-27 16:16:00 +04:00
if ( ! bytes : : compare ( bytes : : make_span ( GoodPrime ) , primeBytes ) ) {
2017-04-24 15:16:38 +03:00
if ( g = = 3 | | g = = 4 | | g = = 5 | | g = = 7 ) {
return true ;
}
}
return IsPrimeAndGoodCheck ( openssl : : BigNum ( primeBytes ) , g ) ;
}
2018-03-27 16:16:00 +04:00
bytes : : vector CreateAuthKey (
bytes : : const_span firstBytes ,
bytes : : const_span randomBytes ,
bytes : : const_span primeBytes ) {
2017-04-24 15:16:38 +03:00
using openssl : : BigNum ;
BigNum first ( firstBytes ) ;
BigNum prime ( primeBytes ) ;
if ( ! IsGoodModExpFirst ( first , prime ) ) {
LOG ( ( " AuthKey Error: Bad first prime in CreateAuthKey(). " ) ) ;
2018-03-27 16:16:00 +04:00
return { } ;
2017-04-24 15:16:38 +03:00
}
return BigNum : : ModExp ( first , BigNum ( randomBytes ) , prime ) . getBytes ( ) ;
}
2017-12-07 09:34:11 +04:00
ModExpFirst CreateModExp (
int g ,
2018-03-27 16:16:00 +04:00
bytes : : const_span primeBytes ,
bytes : : const_span randomSeed ) {
2017-04-24 15:16:38 +03:00
Expects ( randomSeed . size ( ) = = ModExpFirst : : kRandomPowerSize ) ;
using namespace openssl ;
BigNum prime ( primeBytes ) ;
2018-03-27 16:16:00 +04:00
auto result = ModExpFirst ( ) ;
result . randomPower . resize ( ModExpFirst : : kRandomPowerSize ) ;
2018-08-10 22:19:46 +03:00
while ( true ) {
2018-04-24 12:46:27 +04:00
bytes : : set_random ( result . randomPower ) ;
2017-04-24 15:16:38 +03:00
for ( auto i = 0 ; i ! = ModExpFirst : : kRandomPowerSize ; + + i ) {
result . randomPower [ i ] ^ = randomSeed [ i ] ;
}
2018-08-10 22:19:46 +03:00
const auto modexp = BigNum : : ModExp (
BigNum ( g ) ,
BigNum ( result . randomPower ) ,
prime ) ;
2017-04-24 15:16:38 +03:00
if ( IsGoodModExpFirst ( modexp , prime ) ) {
result . modexp = modexp . getBytes ( ) ;
2018-08-10 22:19:46 +03:00
return result ;
2017-04-24 15:16:38 +03:00
}
}
}
2017-02-25 19:44:02 +03:00
2018-06-25 19:55:27 +01:00
void wrapInvokeAfter ( SecureRequest & to , const SecureRequest & from , const RequestMap & haveSent , int32 skipBeforeRequest = 0 ) {
const auto afterId = * ( mtpMsgId * ) ( from - > after - > data ( ) + 4 ) ;
const auto i = afterId ? haveSent . constFind ( afterId ) : haveSent . cend ( ) ;
2017-02-24 20:15:41 +03:00
int32 size = to - > size ( ) , lenInInts = ( from . innerLength ( ) > > 2 ) , headlen = 4 , fulllen = headlen + lenInInts ;
if ( i = = haveSent . constEnd ( ) ) { // no invoke after or such msg was not sent or was completed recently
to - > resize ( size + fulllen + skipBeforeRequest ) ;
if ( skipBeforeRequest ) {
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , headlen * sizeof ( mtpPrime ) ) ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest , from - > constData ( ) + 4 + headlen , lenInInts * sizeof ( mtpPrime ) ) ;
} else {
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , fulllen * sizeof ( mtpPrime ) ) ;
}
} else {
to - > resize ( size + fulllen + skipBeforeRequest + 3 ) ;
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , headlen * sizeof ( mtpPrime ) ) ;
( * to ) [ size + 3 ] + = 3 * sizeof ( mtpPrime ) ;
* ( ( mtpTypeId * ) & ( ( * to ) [ size + headlen + skipBeforeRequest ] ) ) = mtpc_invokeAfterMsg ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest + 1 , & afterId , 2 * sizeof ( mtpPrime ) ) ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest + 3 , from - > constData ( ) + 4 + headlen , lenInInts * sizeof ( mtpPrime ) ) ;
if ( size + 3 ! = 7 ) ( * to ) [ 7 ] + = 3 * sizeof ( mtpPrime ) ;
}
}
2017-03-10 22:46:28 +03:00
bool parsePQ ( const QByteArray & pqStr , QByteArray & pStr , QByteArray & qStr ) {
2016-03-23 21:12:07 +03:00
if ( pqStr . length ( ) > 8 ) return false ; // more than 64 bit pq
uint64 pq = 0 , p , q ;
2017-03-10 22:46:28 +03:00
const uchar * pqChars = ( const uchar * ) pqStr . constData ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 , l = pqStr . length ( ) ; i < l ; + + i ) {
pq < < = 8 ;
pq | = ( uint64 ) pqChars [ i ] ;
}
uint64 pqSqrt = ( uint64 ) sqrtl ( ( long double ) pq ) , ySqr , y ;
while ( pqSqrt * pqSqrt > pq ) - - pqSqrt ;
while ( pqSqrt * pqSqrt < pq ) + + pqSqrt ;
for ( ySqr = pqSqrt * pqSqrt - pq ; ; + + pqSqrt , ySqr = pqSqrt * pqSqrt - pq ) {
y = ( uint64 ) sqrtl ( ( long double ) ySqr ) ;
while ( y * y > ySqr ) - - y ;
while ( y * y < ySqr ) + + y ;
if ( ! ySqr | | y + pqSqrt > = pq ) return false ;
if ( y * y = = ySqr ) {
p = pqSqrt + y ;
q = ( pqSqrt > y ) ? ( pqSqrt - y ) : ( y - pqSqrt ) ;
break ;
}
}
2016-03-28 20:15:17 +03:00
if ( p > q ) std : : swap ( p , q ) ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
pStr . resize ( 4 ) ;
2017-03-10 22:46:28 +03:00
uchar * pChars = ( uchar * ) pStr . data ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( pChars + 3 - i ) = ( uchar ) ( p & 0xFF ) ;
p > > = 8 ;
}
qStr . resize ( 4 ) ;
2017-03-10 22:46:28 +03:00
uchar * qChars = ( uchar * ) qStr . data ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( qChars + 3 - i ) = ( uchar ) ( q & 0xFF ) ;
q > > = 8 ;
}
return true ;
}
2016-03-24 11:57:11 +03:00
} // namespace
2016-03-23 21:12:07 +03:00
2018-04-24 23:09:20 +04:00
Connection : : Connection ( not_null < Instance * > instance ) : _instance ( instance ) {
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
void Connection : : start ( SessionData * sessionData , ShiftedDcId shiftedDcId ) {
2018-04-24 23:09:20 +04:00
Expects ( _thread = = nullptr & & _private = = nullptr ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
_thread = std : : make_unique < Thread > ( ) ;
auto newData = std : : make_unique < ConnectionPrivate > (
_instance ,
_thread . get ( ) ,
this ,
sessionData ,
shiftedDcId ) ;
2016-02-29 19:53:26 +03:00
2017-02-25 19:44:02 +03:00
// will be deleted in the thread::finished signal
2018-04-24 23:09:20 +04:00
_private = newData . release ( ) ;
_thread - > start ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void Connection : : kill ( ) {
2018-04-24 23:09:20 +04:00
Expects ( _private ! = nullptr & & _thread ! = nullptr ) ;
_private - > stop ( ) ;
_private = nullptr ;
_thread - > quit ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void Connection : : waitTillFinish ( ) {
2018-04-24 23:09:20 +04:00
Expects ( _private = = nullptr & & _thread ! = nullptr ) ;
2016-02-29 19:53:26 +03:00
2016-03-01 05:36:23 +03:00
DEBUG_LOG ( ( " Waiting for connectionThread to finish " ) ) ;
2018-04-24 23:09:20 +04:00
_thread - > wait ( ) ;
_thread . reset ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
int32 Connection : : state ( ) const {
2018-04-24 23:09:20 +04:00
Expects ( _private ! = nullptr & & _thread ! = nullptr ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
return _private - > getState ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
QString Connection : : transport ( ) const {
2018-04-24 23:09:20 +04:00
Expects ( _private ! = nullptr & & _thread ! = nullptr ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
return _private - > transport ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
Connection : : ~ Connection ( ) {
2018-04-24 23:09:20 +04:00
Expects ( _private = = nullptr ) ;
2018-04-24 12:46:27 +04:00
2018-04-24 23:09:20 +04:00
if ( _thread ) {
2017-02-24 20:15:41 +03:00
waitTillFinish ( ) ;
}
2016-02-29 19:53:26 +03:00
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : appendTestConnection (
DcOptions : : Variants : : Protocol protocol ,
const QString & ip ,
int port ,
const bytes : : vector & protocolSecret ) {
QWriteLocker lock ( & stateConnMutex ) ;
const auto priority = ( qthelp : : is_ipv6 ( ip ) ? 0 : 1 )
2018-04-25 13:24:48 +04:00
+ ( protocol = = DcOptions : : Variants : : Tcp ? 1 : 0 )
+ ( protocolSecret . empty ( ) ? 0 : 1 ) ;
2018-04-24 23:09:20 +04:00
_testConnections . push_back ( {
2018-05-17 22:58:00 +03:00
AbstractConnection : : Create (
_instance ,
protocol ,
thread ( ) ,
2019-07-05 09:54:53 +02:00
protocolSecret ,
2018-05-17 22:58:00 +03:00
_connectionOptions - > proxy ) ,
2018-04-24 23:09:20 +04:00
priority
} ) ;
auto weak = _testConnections . back ( ) . data . get ( ) ;
connect ( weak , & AbstractConnection : : error , [ = ] ( int errorCode ) {
onError ( weak , errorCode ) ;
} ) ;
connect ( weak , & AbstractConnection : : receivedSome , [ = ] {
onReceivedSome ( ) ;
} ) ;
2014-05-30 12:53:19 +04:00
firstSentAt = 0 ;
2018-04-24 23:09:20 +04:00
if ( _oldConnection ) {
_oldConnection = false ;
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " This connection marked as not old! " ) ) ;
}
2018-04-24 23:09:20 +04:00
_oldConnectionTimer . callOnce ( kMarkConnectionOldTimeout ) ;
connect ( weak , & AbstractConnection : : connected , [ = ] {
onConnected ( weak ) ;
} ) ;
connect ( weak , & AbstractConnection : : disconnected , [ = ] {
onDisconnected ( weak ) ;
} ) ;
2014-05-30 12:53:19 +04:00
2018-05-17 22:58:00 +03:00
InvokeQueued ( _testConnections . back ( ) . data , [ = ] {
weak - > connectToServer ( ip , port , protocolSecret , getProtocolDcId ( ) ) ;
} ) ;
}
int16 ConnectionPrivate : : getProtocolDcId ( ) const {
2018-06-11 21:35:27 +03:00
const auto dcId = BareDcId ( _shiftedDcId ) ;
const auto simpleDcId = isTemporaryDcId ( dcId )
? getRealIdFromTemporaryDcId ( dcId )
2018-05-02 22:27:03 +03:00
: dcId ;
2018-05-17 22:58:00 +03:00
const auto testedDcId = cTestMode ( )
? ( kTestModeDcIdShift + simpleDcId )
2018-05-02 22:27:03 +03:00
: simpleDcId ;
2018-05-17 22:58:00 +03:00
return ( _dcType = = DcType : : MediaDownload )
? - testedDcId
: testedDcId ;
2018-04-23 14:24:03 +04:00
}
2015-06-29 15:25:28 +03:00
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : destroyAllConnections ( ) {
_waitForBetterTimer . cancel ( ) ;
_waitForReceivedTimer . cancel ( ) ;
_waitForConnectedTimer . cancel ( ) ;
_testConnections . clear ( ) ;
_connection = nullptr ;
}
ConnectionPrivate : : ConnectionPrivate (
not_null < Instance * > instance ,
not_null < QThread * > thread ,
not_null < Connection * > owner ,
not_null < SessionData * > data ,
ShiftedDcId shiftedDcId )
: QObject ( nullptr )
2017-02-24 20:15:41 +03:00
, _instance ( instance )
2016-03-24 11:57:11 +03:00
, _state ( DisconnectedState )
2017-02-25 19:44:02 +03:00
, _shiftedDcId ( shiftedDcId )
2016-02-29 19:53:26 +03:00
, _owner ( owner )
2018-04-24 23:09:20 +04:00
, _retryTimer ( thread , [ = ] { retryByTimer ( ) ; } )
, _oldConnectionTimer ( thread , [ = ] { markConnectionOld ( ) ; } )
, _waitForConnectedTimer ( thread , [ = ] { waitConnectedFailed ( ) ; } )
, _waitForReceivedTimer ( thread , [ = ] { waitReceivedFailed ( ) ; } )
, _waitForBetterTimer ( thread , [ = ] { waitBetterFailed ( ) ; } )
, _waitForReceived ( kMinReceiveTimeout )
, _waitForConnected ( kMinConnectedTimeout )
, _pingSender ( thread , [ = ] { sendPingByTimer ( ) ; } )
2016-12-07 16:32:25 +03:00
, sessionData ( data ) {
2017-03-23 19:11:35 +03:00
Expects ( _shiftedDcId ! = 0 ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
moveToThread ( thread ) ;
connect ( thread , & QThread : : started , this , [ = ] { connectToServer ( ) ; } ) ;
connect ( thread , & QThread : : finished , this , [ = ] { finishAndDestroy ( ) ; } ) ;
2017-02-24 20:15:41 +03:00
connect ( this , SIGNAL ( finished ( internal : : Connection * ) ) , _instance , SLOT ( connectionFinished ( internal : : Connection * ) ) , Qt : : QueuedConnection ) ;
2014-05-30 12:53:19 +04:00
2014-11-24 16:21:27 +03:00
connect ( sessionData - > owner ( ) , SIGNAL ( authKeyCreated ( ) ) , this , SLOT ( updateAuthKey ( ) ) , Qt : : QueuedConnection ) ;
connect ( sessionData - > owner ( ) , SIGNAL ( needToRestart ( ) ) , this , SLOT ( restartNow ( ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( needToReceive ( ) ) , sessionData - > owner ( ) , SLOT ( tryToReceive ( ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( stateChanged ( qint32 ) ) , sessionData - > owner ( ) , SLOT ( onConnectionStateChange ( qint32 ) ) , Qt : : QueuedConnection ) ;
connect ( sessionData - > owner ( ) , SIGNAL ( needToSend ( ) ) , this , SLOT ( tryToSend ( ) ) , Qt : : QueuedConnection ) ;
2015-04-16 17:59:42 +03:00
connect ( sessionData - > owner ( ) , SIGNAL ( needToPing ( ) ) , this , SLOT ( onPingSendForce ( ) ) , Qt : : QueuedConnection ) ;
2014-11-24 16:21:27 +03:00
connect ( this , SIGNAL ( sessionResetDone ( ) ) , sessionData - > owner ( ) , SLOT ( onResetDone ( ) ) , Qt : : QueuedConnection ) ;
2014-11-25 15:15:29 +03:00
static bool _registered = false ;
if ( ! _registered ) {
_registered = true ;
2016-12-07 16:32:25 +03:00
qRegisterMetaType < QVector < quint64 > > ( " QVector<quint64> " ) ;
2014-11-25 15:15:29 +03:00
}
2014-12-05 16:44:27 +03:00
connect ( this , SIGNAL ( needToSendAsync ( ) ) , sessionData - > owner ( ) , SLOT ( needToResumeAndSend ( ) ) , Qt : : QueuedConnection ) ;
2016-12-01 22:20:33 +03:00
connect ( this , SIGNAL ( sendAnythingAsync ( qint64 ) ) , sessionData - > owner ( ) , SLOT ( sendAnything ( qint64 ) ) , Qt : : QueuedConnection ) ;
2015-03-12 13:28:10 +03:00
connect ( this , SIGNAL ( sendHttpWaitAsync ( ) ) , sessionData - > owner ( ) , SLOT ( sendAnything ( ) ) , Qt : : QueuedConnection ) ;
2014-11-25 15:15:29 +03:00
connect ( this , SIGNAL ( sendPongAsync ( quint64 , quint64 ) ) , sessionData - > owner ( ) , SLOT ( sendPong ( quint64 , quint64 ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( sendMsgsStateInfoAsync ( quint64 , QByteArray ) ) , sessionData - > owner ( ) , SLOT ( sendMsgsStateInfo ( quint64 , QByteArray ) ) , Qt : : QueuedConnection ) ;
2016-12-01 22:20:33 +03:00
connect ( this , SIGNAL ( resendAsync ( quint64 , qint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resend ( quint64 , qint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( resendManyAsync ( QVector < quint64 > , qint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resendMany ( QVector < quint64 > , qint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
2018-06-02 17:29:21 +03:00
connect ( this , SIGNAL ( resendAllAsync ( ) ) , sessionData - > owner ( ) , SLOT ( resendAll ( ) ) , Qt : : QueuedConnection ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onConfigLoaded ( ) {
2017-03-23 19:11:35 +03:00
connectToServer ( true ) ;
}
void ConnectionPrivate : : onCDNConfigLoaded ( ) {
restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
int32 ConnectionPrivate : : getShiftedDcId ( ) const {
return _shiftedDcId ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
int32 ConnectionPrivate : : getState ( ) const {
2015-06-25 21:04:40 +03:00
QReadLocker lock ( & stateConnMutex ) ;
2014-05-30 12:53:19 +04:00
int32 result = _state ;
if ( _state < 0 ) {
2018-04-24 23:09:20 +04:00
if ( _retryTimer . isActive ( ) ) {
2019-02-19 10:57:53 +04:00
result = int32 ( crl : : now ( ) - _retryWillFinish ) ;
2014-05-30 12:53:19 +04:00
if ( result > = 0 ) {
result = - 1 ;
}
}
}
return result ;
}
2016-03-24 11:57:11 +03:00
QString ConnectionPrivate : : transport ( ) const {
2015-06-25 21:04:40 +03:00
QReadLocker lock ( & stateConnMutex ) ;
2018-04-24 23:09:20 +04:00
if ( ! _connection | | ( _state < 0 ) ) {
2014-05-30 12:53:19 +04:00
return QString ( ) ;
}
2018-04-24 12:46:27 +04:00
Assert ( _connectionOptions ! = nullptr ) ;
2018-04-24 23:09:20 +04:00
return _connection - > transport ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
bool ConnectionPrivate : : setState ( int32 state , int32 ifState ) {
if ( ifState ! = Connection : : UpdateAlways ) {
2015-06-25 21:04:40 +03:00
QReadLocker lock ( & stateConnMutex ) ;
2014-05-30 12:53:19 +04:00
if ( _state ! = ifState ) return false ;
}
2015-06-25 21:04:40 +03:00
QWriteLocker lock ( & stateConnMutex ) ;
2014-05-30 12:53:19 +04:00
if ( _state = = state ) return false ;
_state = state ;
if ( state < 0 ) {
2018-04-24 23:09:20 +04:00
_retryTimeout = - state ;
_retryTimer . callOnce ( _retryTimeout ) ;
2019-02-19 10:57:53 +04:00
_retryWillFinish = crl : : now ( ) + _retryTimeout ;
2014-05-30 12:53:19 +04:00
}
emit stateChanged ( state ) ;
return true ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : resetSession ( ) { // recreate all msg_id and msg_seqno
2014-08-01 15:09:46 +04:00
_needSessionReset = false ;
QWriteLocker locker1 ( sessionData - > haveSentMutex ( ) ) ;
QWriteLocker locker2 ( sessionData - > toResendMutex ( ) ) ;
QWriteLocker locker3 ( sessionData - > toSendMutex ( ) ) ;
QWriteLocker locker4 ( sessionData - > wereAckedMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & haveSent = sessionData - > haveSentMap ( ) ;
auto & toResend = sessionData - > toResendMap ( ) ;
auto & toSend = sessionData - > toSendMap ( ) ;
auto & wereAcked = sessionData - > wereAckedMap ( ) ;
auto newId = msgid ( ) ;
auto setSeqNumbers = RequestMap ( ) ;
auto replaces = QMap < mtpMsgId , mtpMsgId > ( ) ;
for ( auto i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) {
if ( ! i . value ( ) . isSentContainer ( ) ) {
2014-08-01 15:09:46 +04:00
if ( ! * ( mtpMsgId * ) ( i . value ( ) - > constData ( ) + 4 ) ) continue ;
mtpMsgId id = i . key ( ) ;
if ( id > newId ) {
while ( true ) {
if ( toResend . constFind ( newId ) = = toResend . cend ( ) & & wereAcked . constFind ( newId ) = = wereAcked . cend ( ) & & haveSent . constFind ( newId ) = = haveSent . cend ( ) ) {
break ;
}
mtpMsgId m = msgid ( ) ;
if ( m < = newId ) break ; // wtf
newId = m ;
}
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
2014-08-01 15:09:46 +04:00
replaces . insert ( id , newId ) ;
id = newId ;
* ( mtpMsgId * ) ( i . value ( ) - > data ( ) + 4 ) = id ;
}
setSeqNumbers . insert ( id , i . value ( ) ) ;
}
}
2018-06-25 19:55:27 +01:00
for ( auto i = toResend . cbegin ( ) , e = toResend . cend ( ) ; i ! = e ; + + i ) { // collect all non-container requests
const auto j = toSend . constFind ( i . value ( ) ) ;
2014-08-01 15:09:46 +04:00
if ( j = = toSend . cend ( ) ) continue ;
2018-06-25 19:55:27 +01:00
if ( ! j . value ( ) . isSentContainer ( ) ) {
2014-08-01 15:09:46 +04:00
if ( ! * ( mtpMsgId * ) ( j . value ( ) - > constData ( ) + 4 ) ) continue ;
mtpMsgId id = i . key ( ) ;
if ( id > newId ) {
while ( true ) {
if ( toResend . constFind ( newId ) = = toResend . cend ( ) & & wereAcked . constFind ( newId ) = = wereAcked . cend ( ) & & haveSent . constFind ( newId ) = = haveSent . cend ( ) ) {
break ;
}
mtpMsgId m = msgid ( ) ;
if ( m < = newId ) break ; // wtf
newId = m ;
}
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
2014-08-01 15:09:46 +04:00
replaces . insert ( id , newId ) ;
id = newId ;
* ( mtpMsgId * ) ( j . value ( ) - > data ( ) + 4 ) = id ;
}
setSeqNumbers . insert ( id , j . value ( ) ) ;
}
}
2016-03-24 13:12:18 +03:00
uint64 session = rand_value < uint64 > ( ) ;
2014-08-01 15:09:46 +04:00
DEBUG_LOG ( ( " MTP Info: creating new session after bad_msg_notification, setting random server_session %1 " ) . arg ( session ) ) ;
sessionData - > setSession ( session ) ;
2018-06-25 19:55:27 +01:00
for ( auto i = setSeqNumbers . cbegin ( ) , e = setSeqNumbers . cend ( ) ; i ! = e ; + + i ) { // generate new seq_numbers
2014-08-01 15:09:46 +04:00
bool wasNeedAck = ( * ( i . value ( ) - > data ( ) + 6 ) & 1 ) ;
* ( i . value ( ) - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( wasNeedAck ) ;
}
if ( ! replaces . isEmpty ( ) ) {
2018-06-25 19:55:27 +01:00
for ( auto i = replaces . cbegin ( ) , e = replaces . cend ( ) ; i ! = e ; + + i ) { // replace msgIds keys in all data structs
const auto j = haveSent . find ( i . key ( ) ) ;
2014-08-01 15:09:46 +04:00
if ( j ! = haveSent . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto req = j . value ( ) ;
2014-08-01 15:09:46 +04:00
haveSent . erase ( j ) ;
haveSent . insert ( i . value ( ) , req ) ;
}
2018-06-25 19:55:27 +01:00
const auto k = toResend . find ( i . key ( ) ) ;
2014-08-01 15:09:46 +04:00
if ( k ! = toResend . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto req = k . value ( ) ;
2014-08-01 15:09:46 +04:00
toResend . erase ( k ) ;
toResend . insert ( i . value ( ) , req ) ;
}
2018-06-25 19:55:27 +01:00
const auto l = wereAcked . find ( i . key ( ) ) ;
if ( l ! = wereAcked . cend ( ) ) {
const auto req = l . value ( ) ;
wereAcked . erase ( l ) ;
2014-08-01 15:09:46 +04:00
wereAcked . insert ( i . value ( ) , req ) ;
}
}
2018-06-25 19:55:27 +01:00
for ( auto i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) { // replace msgIds in saved containers
if ( i . value ( ) . isSentContainer ( ) ) {
mtpMsgId * ids = ( mtpMsgId * ) ( i . value ( ) - > data ( ) + 8 ) ;
2014-08-01 15:09:46 +04:00
for ( uint32 j = 0 , l = ( i . value ( ) - > size ( ) - 8 ) > > 1 ; j < l ; + + j ) {
2018-06-25 19:55:27 +01:00
const auto k = replaces . constFind ( ids [ j ] ) ;
2014-08-01 15:09:46 +04:00
if ( k ! = replaces . cend ( ) ) {
ids [ j ] = k . value ( ) ;
}
}
}
}
}
2014-08-01 22:49:43 +04:00
2014-11-05 20:43:32 +03:00
ackRequestData . clear ( ) ;
resendRequestData . clear ( ) ;
{
QWriteLocker locker5 ( sessionData - > stateRequestMutex ( ) ) ;
sessionData - > stateRequestMap ( ) . clear ( ) ;
}
2014-08-01 22:49:43 +04:00
emit sessionResetDone ( ) ;
2014-08-01 15:09:46 +04:00
}
2018-06-25 19:55:27 +01:00
mtpMsgId ConnectionPrivate : : prepareToSend ( SecureRequest & request , mtpMsgId currentLastId ) {
2014-05-30 12:53:19 +04:00
if ( request - > size ( ) < 9 ) return 0 ;
mtpMsgId msgId = * ( mtpMsgId * ) ( request - > constData ( ) + 4 ) ;
if ( msgId ) { // resending this request
QWriteLocker locker ( sessionData - > toResendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & toResend = sessionData - > toResendMap ( ) ;
const auto i = toResend . find ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( i ! = toResend . cend ( ) ) {
toResend . erase ( i ) ;
}
} else {
2014-08-01 15:09:46 +04:00
msgId = * ( mtpMsgId * ) ( request - > data ( ) + 4 ) = currentLastId ;
2018-06-25 19:55:27 +01:00
* ( request - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( request . needAck ( ) ) ;
2014-05-30 12:53:19 +04:00
}
return msgId ;
}
2018-06-25 19:55:27 +01:00
mtpMsgId ConnectionPrivate : : replaceMsgId ( SecureRequest & request , mtpMsgId newId ) {
2014-08-01 15:09:46 +04:00
if ( request - > size ( ) < 9 ) return 0 ;
mtpMsgId oldMsgId = * ( mtpMsgId * ) ( request - > constData ( ) + 4 ) ;
if ( oldMsgId ! = newId ) {
if ( oldMsgId ) {
QWriteLocker locker ( sessionData - > toResendMutex ( ) ) ;
// haveSentMutex() and wereAckedMutex() were locked in tryToSend()
2018-06-25 19:55:27 +01:00
auto & toResend = sessionData - > toResendMap ( ) ;
auto & wereAcked = sessionData - > wereAckedMap ( ) ;
auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-08-01 15:09:46 +04:00
while ( true ) {
if ( toResend . constFind ( newId ) = = toResend . cend ( ) & & wereAcked . constFind ( newId ) = = wereAcked . cend ( ) & & haveSent . constFind ( newId ) = = haveSent . cend ( ) ) {
break ;
}
2018-06-25 19:55:27 +01:00
const auto m = msgid ( ) ;
2014-08-01 15:09:46 +04:00
if ( m < = newId ) break ; // wtf
2016-01-11 23:43:29 +08:00
2014-08-01 15:09:46 +04:00
newId = m ;
}
2018-06-25 19:55:27 +01:00
const auto i = toResend . find ( oldMsgId ) ;
2014-08-01 15:09:46 +04:00
if ( i ! = toResend . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto req = i . value ( ) ;
2014-08-01 15:09:46 +04:00
toResend . erase ( i ) ;
toResend . insert ( newId , req ) ;
}
2018-06-25 19:55:27 +01:00
const auto j = wereAcked . find ( oldMsgId ) ;
2014-08-01 15:09:46 +04:00
if ( j ! = wereAcked . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto req = j . value ( ) ;
2014-08-01 15:09:46 +04:00
wereAcked . erase ( j ) ;
wereAcked . insert ( newId , req ) ;
}
2018-06-25 19:55:27 +01:00
const auto k = haveSent . find ( oldMsgId ) ;
2014-08-01 15:09:46 +04:00
if ( k ! = haveSent . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto req = k . value ( ) ;
2014-08-01 15:09:46 +04:00
haveSent . erase ( k ) ;
haveSent . insert ( newId , req ) ;
}
2018-06-25 19:55:27 +01:00
for ( auto l = haveSent . begin ( ) ; l ! = haveSent . cend ( ) ; + + l ) {
const auto req = l . value ( ) ;
if ( req . isSentContainer ( ) ) {
const auto ids = ( mtpMsgId * ) ( req - > data ( ) + 8 ) ;
2014-08-01 15:09:46 +04:00
for ( uint32 i = 0 , l = ( req - > size ( ) - 8 ) > > 1 ; i < l ; + + i ) {
if ( ids [ i ] = = oldMsgId ) {
ids [ i ] = newId ;
}
}
}
}
} else {
2018-06-25 19:55:27 +01:00
* ( request - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( request . needAck ( ) ) ;
2014-08-01 15:09:46 +04:00
}
* ( mtpMsgId * ) ( request - > data ( ) + 4 ) = newId ;
}
return newId ;
}
2018-06-25 19:55:27 +01:00
mtpMsgId ConnectionPrivate : : placeToContainer ( SecureRequest & toSendRequest , mtpMsgId & bigMsgId , mtpMsgId * & haveSentArr , SecureRequest & req ) {
2014-11-05 20:43:32 +03:00
mtpMsgId msgId = prepareToSend ( req , bigMsgId ) ;
if ( msgId > bigMsgId ) msgId = replaceMsgId ( req , bigMsgId ) ;
if ( msgId > = bigMsgId ) bigMsgId = msgid ( ) ;
* ( haveSentArr + + ) = msgId ;
2018-06-25 19:55:27 +01:00
uint32 from = toSendRequest - > size ( ) , len = req . messageSize ( ) ;
2014-11-05 20:43:32 +03:00
toSendRequest - > resize ( from + len ) ;
memcpy ( toSendRequest - > data ( ) + from , req - > constData ( ) + 4 , len * sizeof ( mtpPrime ) ) ;
return msgId ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : tryToSend ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
2018-04-24 23:09:20 +04:00
if ( ! sessionData | | ! _connection ) {
2014-11-13 14:27:10 +03:00
return ;
}
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
auto needsLayer = ! _connectionOptions - > inited ;
auto state = getState ( ) ;
auto prependOnly = ( state ! = ConnectedState ) ;
auto pingRequest = SecureRequest ( ) ;
2018-06-11 21:35:27 +03:00
if ( _shiftedDcId = = BareDcId ( _shiftedDcId ) ) { // main session
2019-02-19 10:57:53 +04:00
if ( ! prependOnly & & ! _pingIdToSend & & ! _pingId & & _pingSendAt < = crl : : now ( ) ) {
2016-03-24 13:12:18 +03:00
_pingIdToSend = rand_value < mtpPingId > ( ) ;
2015-03-12 13:28:10 +03:00
}
}
if ( _pingIdToSend ) {
2018-06-11 21:35:27 +03:00
if ( prependOnly | | _shiftedDcId ! = BareDcId ( _shiftedDcId ) ) {
2018-06-25 19:55:27 +01:00
pingRequest = SecureRequest : : Serialize ( MTPPing (
MTP_long ( _pingIdToSend )
) ) ;
DEBUG_LOG ( ( " MTP Info: sending ping, ping_id: %1 "
) . arg ( _pingIdToSend ) ) ;
2015-03-12 13:28:10 +03:00
} else {
2018-06-25 19:55:27 +01:00
pingRequest = SecureRequest : : Serialize ( MTPPing_delay_disconnect (
MTP_long ( _pingIdToSend ) ,
MTP_int ( kPingDelayDisconnect ) ) ) ;
DEBUG_LOG ( ( " MTP Info: sending ping_delay_disconnect, "
" ping_id: %1 " ) . arg ( _pingIdToSend ) ) ;
2015-03-12 13:28:10 +03:00
}
2014-05-30 12:53:19 +04:00
2019-02-19 10:57:53 +04:00
pingRequest - > msDate = crl : : now ( ) ; // > 0 - can send without container
2018-04-24 23:09:20 +04:00
_pingSendAt = pingRequest - > msDate + kPingSendAfter ;
2014-11-05 20:43:32 +03:00
pingRequest - > requestId = 0 ; // dont add to haveSent / wereAcked maps
2014-05-30 12:53:19 +04:00
2018-06-11 21:35:27 +03:00
if ( _shiftedDcId = = BareDcId ( _shiftedDcId ) & & ! prependOnly ) { // main session
2018-04-24 23:09:20 +04:00
_pingSender . callOnce ( kPingSendAfterForce ) ;
2015-03-12 13:28:10 +03:00
}
_pingId = _pingIdToSend ;
_pingIdToSend = 0 ;
2014-05-30 12:53:19 +04:00
} else {
2015-03-12 13:28:10 +03:00
if ( prependOnly ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: dc %1 not sending, waiting for Connected state, state: %2 " ) . arg ( _shiftedDcId ) . arg ( state ) ) ;
2014-05-30 12:53:19 +04:00
return ; // just do nothing, if is not connected yet
2015-03-12 13:28:10 +03:00
} else {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: dc %1 trying to send after ping, state: %2 " ) . arg ( _shiftedDcId ) . arg ( state ) ) ;
2014-05-30 12:53:19 +04:00
}
}
2018-06-25 19:55:27 +01:00
SecureRequest ackRequest , resendRequest , stateRequest , httpWaitRequest ;
2014-11-05 20:43:32 +03:00
if ( ! prependOnly & & ! ackRequestData . isEmpty ( ) ) {
2018-06-25 19:55:27 +01:00
ackRequest = SecureRequest : : Serialize ( MTPMsgsAck (
MTP_msgs_ack ( MTP_vector < MTPlong > ( ackRequestData ) ) ) ) ;
2019-02-19 10:57:53 +04:00
ackRequest - > msDate = crl : : now ( ) ; // > 0 - can send without container
2014-11-05 20:43:32 +03:00
ackRequest - > requestId = 0 ; // dont add to haveSent / wereAcked maps
ackRequestData . clear ( ) ;
}
if ( ! prependOnly & & ! resendRequestData . isEmpty ( ) ) {
2018-06-25 19:55:27 +01:00
resendRequest = SecureRequest : : Serialize ( MTPMsgResendReq (
MTP_msg_resend_req ( MTP_vector < MTPlong > ( resendRequestData ) ) ) ) ;
2019-02-19 10:57:53 +04:00
resendRequest - > msDate = crl : : now ( ) ; // > 0 - can send without container
2014-11-05 20:43:32 +03:00
resendRequest - > requestId = 0 ; // dont add to haveSent / wereAcked maps
resendRequestData . clear ( ) ;
}
if ( ! prependOnly ) {
QVector < MTPlong > stateReq ;
{
QWriteLocker locker ( sessionData - > stateRequestMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & ids = sessionData - > stateRequestMap ( ) ;
2014-11-05 20:43:32 +03:00
if ( ! ids . isEmpty ( ) ) {
stateReq . reserve ( ids . size ( ) ) ;
2018-06-25 19:55:27 +01:00
for ( auto i = ids . cbegin ( ) , e = ids . cend ( ) ; i ! = e ; + + i ) {
2014-11-05 20:43:32 +03:00
stateReq . push_back ( MTP_long ( i . key ( ) ) ) ;
}
}
ids . clear ( ) ;
}
if ( ! stateReq . isEmpty ( ) ) {
2018-06-25 19:55:27 +01:00
stateRequest = SecureRequest : : Serialize ( MTPMsgsStateReq (
MTP_msgs_state_req ( MTP_vector < MTPlong > ( stateReq ) ) ) ) ;
2019-02-19 10:57:53 +04:00
stateRequest - > msDate = crl : : now ( ) ; // > 0 - can send without container
2018-06-02 17:29:21 +03:00
stateRequest - > requestId = GetNextRequestId ( ) ; // add to haveSent / wereAcked maps, but don't add to requestMap
2014-11-05 20:43:32 +03:00
}
2018-04-24 23:09:20 +04:00
if ( _connection - > usingHttpWait ( ) ) {
2018-06-25 19:55:27 +01:00
httpWaitRequest = SecureRequest : : Serialize ( MTPHttpWait (
MTP_http_wait ( MTP_int ( 100 ) , MTP_int ( 30 ) , MTP_int ( 25000 ) ) ) ) ;
2019-02-19 10:57:53 +04:00
httpWaitRequest - > msDate = crl : : now ( ) ; // > 0 - can send without container
2015-03-12 13:28:10 +03:00
httpWaitRequest - > requestId = 0 ; // dont add to haveSent / wereAcked maps
}
2014-11-05 20:43:32 +03:00
}
2018-06-25 19:55:27 +01:00
MTPInitConnection < SecureRequest > initWrapper ;
2014-11-15 02:23:35 +03:00
int32 initSize = 0 , initSizeInInts = 0 ;
if ( needsLayer ) {
2018-04-24 12:46:27 +04:00
Assert ( _connectionOptions ! = nullptr ) ;
2018-05-11 17:03:53 +03:00
const auto systemLangCode = _connectionOptions - > systemLangCode ;
const auto cloudLangCode = _connectionOptions - > cloudLangCode ;
2018-08-20 14:31:40 +03:00
const auto langPackName = _connectionOptions - > langPackName ;
2018-05-11 17:03:53 +03:00
const auto deviceModel = ( _dcType = = DcType : : Cdn )
? " n/a "
2019-02-01 10:48:31 +03:00
: _instance - > deviceModel ( ) ;
2018-05-11 17:03:53 +03:00
const auto systemVersion = ( _dcType = = DcType : : Cdn )
? " n/a "
2019-02-01 10:48:31 +03:00
: _instance - > systemVersion ( ) ;
2019-06-03 13:54:25 +03:00
# if defined OS_MAC_STORE
2018-11-08 09:50:18 +04:00
const auto appVersion = QString : : fromLatin1 ( AppVersionStr )
2019-06-03 13:54:25 +03:00
+ " mac store " ;
# elif defined OS_WIN_STORE // OS_MAC_STORE
const auto appVersion = QString : : fromLatin1 ( AppVersionStr )
+ " win store " ;
2018-06-04 13:41:53 +03:00
# else // OS_MAC_STORE || OS_WIN_STORE
2018-11-08 09:50:18 +04:00
const auto appVersion = QString : : fromLatin1 ( AppVersionStr ) ;
2018-06-04 13:41:53 +03:00
# endif // OS_MAC_STORE || OS_WIN_STORE
2018-05-11 17:03:53 +03:00
const auto proxyType = _connectionOptions - > proxy . type ;
const auto mtprotoProxy = ( proxyType = = ProxyData : : Type : : Mtproto ) ;
const auto clientProxyFields = mtprotoProxy
? MTP_inputClientProxy (
MTP_string ( _connectionOptions - > proxy . host ) ,
MTP_int ( _connectionOptions - > proxy . port ) )
: MTPInputClientProxy ( ) ;
2018-06-25 19:55:27 +01:00
using Flag = MTPInitConnection < SecureRequest > : : Flag ;
initWrapper = MTPInitConnection < SecureRequest > (
2018-05-11 17:03:53 +03:00
MTP_flags ( mtprotoProxy ? Flag : : f_proxy : Flag ( 0 ) ) ,
MTP_int ( ApiId ) ,
MTP_string ( deviceModel ) ,
MTP_string ( systemVersion ) ,
2018-06-04 13:41:53 +03:00
MTP_string ( appVersion ) ,
2018-05-11 17:03:53 +03:00
MTP_string ( systemLangCode ) ,
2018-08-20 14:31:40 +03:00
MTP_string ( langPackName ) ,
2018-05-11 17:03:53 +03:00
MTP_string ( cloudLangCode ) ,
clientProxyFields ,
2018-06-25 19:55:27 +01:00
SecureRequest ( ) ) ;
2017-03-23 19:11:35 +03:00
initSizeInInts = ( initWrapper . innerLength ( ) > > 2 ) + 2 ;
2014-11-15 02:23:35 +03:00
initSize = initSizeInInts * sizeof ( mtpPrime ) ;
}
2014-05-30 12:53:19 +04:00
bool needAnyResponse = false ;
2018-06-25 19:55:27 +01:00
SecureRequest toSendRequest ;
2014-05-30 12:53:19 +04:00
{
QWriteLocker locker1 ( sessionData - > toSendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto toSendDummy = PreRequestMap ( ) ;
auto & toSend = prependOnly ? toSendDummy : sessionData - > toSendMap ( ) ;
2014-05-30 12:53:19 +04:00
if ( prependOnly ) locker1 . unlock ( ) ;
uint32 toSendCount = toSend . size ( ) ;
2014-11-05 20:43:32 +03:00
if ( pingRequest ) + + toSendCount ;
if ( ackRequest ) + + toSendCount ;
if ( resendRequest ) + + toSendCount ;
if ( stateRequest ) + + toSendCount ;
2015-03-12 13:28:10 +03:00
if ( httpWaitRequest ) + + toSendCount ;
2014-05-30 12:53:19 +04:00
if ( ! toSendCount ) return ; // nothing to send
2018-06-25 19:55:27 +01:00
auto first = pingRequest ? pingRequest : ( ackRequest ? ackRequest : ( resendRequest ? resendRequest : ( stateRequest ? stateRequest : ( httpWaitRequest ? httpWaitRequest : toSend . cbegin ( ) . value ( ) ) ) ) ) ;
2014-05-30 12:53:19 +04:00
if ( toSendCount = = 1 & & first - > msDate > 0 ) { // if can send without container
toSendRequest = first ;
if ( ! prependOnly ) {
toSend . clear ( ) ;
locker1 . unlock ( ) ;
}
2014-08-01 15:09:46 +04:00
mtpMsgId msgId = prepareToSend ( toSendRequest , msgid ( ) ) ;
2014-11-05 20:43:32 +03:00
if ( pingRequest ) {
2015-03-12 13:28:10 +03:00
_pingMsgId = msgId ;
2014-11-05 20:43:32 +03:00
needAnyResponse = true ;
} else if ( resendRequest | | stateRequest ) {
needAnyResponse = true ;
}
2014-05-30 12:53:19 +04:00
if ( toSendRequest - > requestId ) {
2018-06-25 19:55:27 +01:00
if ( toSendRequest . needAck ( ) ) {
2019-02-19 10:57:53 +04:00
toSendRequest - > msDate = toSendRequest . isStateRequest ( ) ? 0 : crl : : now ( ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-11-05 20:43:32 +03:00
haveSent . insert ( msgId , toSendRequest ) ;
2014-11-15 02:23:35 +03:00
if ( needsLayer & & ! toSendRequest - > needsLayer ) needsLayer = false ;
2014-11-05 20:43:32 +03:00
if ( toSendRequest - > after ) {
2018-06-25 19:55:27 +01:00
const auto toSendSize = toSendRequest . innerLength ( ) > > 2 ;
auto wrappedRequest = SecureRequest : : Prepare (
toSendSize ,
toSendSize + 3 ) ;
2014-11-05 20:43:32 +03:00
wrappedRequest - > resize ( 4 ) ;
memcpy ( wrappedRequest - > data ( ) , toSendRequest - > constData ( ) , 4 * sizeof ( mtpPrime ) ) ;
2016-03-24 11:57:11 +03:00
wrapInvokeAfter ( wrappedRequest , toSendRequest , haveSent ) ;
2018-06-25 19:55:27 +01:00
toSendRequest = std : : move ( wrappedRequest ) ;
2014-11-05 20:43:32 +03:00
}
2014-11-15 02:23:35 +03:00
if ( needsLayer ) {
2018-06-25 19:55:27 +01:00
const auto noWrapSize = ( toSendRequest . innerLength ( ) > > 2 ) ;
const auto toSendSize = noWrapSize + initSizeInInts ;
auto wrappedRequest = SecureRequest : : Prepare ( toSendSize ) ;
2014-11-15 02:23:35 +03:00
memcpy ( wrappedRequest - > data ( ) , toSendRequest - > constData ( ) , 7 * sizeof ( mtpPrime ) ) ; // all except length
wrappedRequest - > push_back ( mtpc_invokeWithLayer ) ;
2018-06-11 21:35:27 +03:00
wrappedRequest - > push_back ( internal : : CurrentLayer ) ;
2017-03-23 19:11:35 +03:00
initWrapper . write ( * wrappedRequest ) ;
2014-11-15 02:23:35 +03:00
wrappedRequest - > resize ( wrappedRequest - > size ( ) + noWrapSize ) ;
memcpy ( wrappedRequest - > data ( ) + wrappedRequest - > size ( ) - noWrapSize , toSendRequest - > constData ( ) + 8 , noWrapSize * sizeof ( mtpPrime ) ) ;
2018-06-25 19:55:27 +01:00
toSendRequest = std : : move ( wrappedRequest ) ;
2014-11-15 02:23:35 +03:00
}
2014-05-30 12:53:19 +04:00
needAnyResponse = true ;
} else {
QWriteLocker locker3 ( sessionData - > wereAckedMutex ( ) ) ;
sessionData - > wereAckedMap ( ) . insert ( msgId , toSendRequest - > requestId ) ;
}
}
} else { // send in container
2014-11-15 02:23:35 +03:00
bool willNeedInit = false ;
2014-05-30 12:53:19 +04:00
uint32 containerSize = 1 + 1 , idsWrapSize = ( toSendCount < < 1 ) ; // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector
2018-06-25 19:55:27 +01:00
if ( pingRequest ) containerSize + = pingRequest . messageSize ( ) ;
if ( ackRequest ) containerSize + = ackRequest . messageSize ( ) ;
if ( resendRequest ) containerSize + = resendRequest . messageSize ( ) ;
if ( stateRequest ) containerSize + = stateRequest . messageSize ( ) ;
if ( httpWaitRequest ) containerSize + = httpWaitRequest . messageSize ( ) ;
for ( auto i = toSend . begin ( ) , e = toSend . end ( ) ; i ! = e ; + + i ) {
containerSize + = i . value ( ) . messageSize ( ) ;
2014-11-15 02:23:35 +03:00
if ( needsLayer & & i . value ( ) - > needsLayer ) {
containerSize + = initSizeInInts ;
willNeedInit = true ;
}
}
mtpBuffer initSerialized ;
if ( willNeedInit ) {
initSerialized . reserve ( initSizeInInts ) ;
initSerialized . push_back ( mtpc_invokeWithLayer ) ;
2018-06-11 21:35:27 +03:00
initSerialized . push_back ( internal : : CurrentLayer ) ;
2017-03-23 19:11:35 +03:00
initWrapper . write ( initSerialized ) ;
2014-05-30 12:53:19 +04:00
}
2018-06-25 19:55:27 +01:00
// prepare container + each in invoke after
toSendRequest = SecureRequest : : Prepare (
containerSize ,
containerSize + 3 * toSend . size ( ) ) ;
2014-05-30 12:53:19 +04:00
toSendRequest - > push_back ( mtpc_msg_container ) ;
toSendRequest - > push_back ( toSendCount ) ;
2014-08-01 15:09:46 +04:00
mtpMsgId bigMsgId = msgid ( ) ; // check for a valid container
2018-06-25 19:55:27 +01:00
// the fact of this lock is used in replaceMsgId()
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ;
auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
// the fact of this lock is used in replaceMsgId()
QWriteLocker locker3 ( sessionData - > wereAckedMutex ( ) ) ;
auto & wereAcked = sessionData - > wereAckedMap ( ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
// prepare "request-like" wrap for msgId vector
auto haveSentIdsWrap = SecureRequest : : Prepare ( idsWrapSize ) ;
2014-05-30 12:53:19 +04:00
haveSentIdsWrap - > requestId = 0 ;
haveSentIdsWrap - > resize ( haveSentIdsWrap - > size ( ) + idsWrapSize ) ;
2018-06-25 19:55:27 +01:00
auto haveSentArr = ( mtpMsgId * ) ( haveSentIdsWrap - > data ( ) + 8 ) ;
2014-05-30 12:53:19 +04:00
2014-11-05 20:43:32 +03:00
if ( pingRequest ) {
2015-03-12 13:28:10 +03:00
_pingMsgId = placeToContainer ( toSendRequest , bigMsgId , haveSentArr , pingRequest ) ;
2014-11-05 20:43:32 +03:00
needAnyResponse = true ;
} else if ( resendRequest | | stateRequest ) {
2014-05-30 12:53:19 +04:00
needAnyResponse = true ;
}
2018-06-25 19:55:27 +01:00
for ( auto i = toSend . begin ( ) , e = toSend . end ( ) ; i ! = e ; + + i ) {
auto & req = i . value ( ) ;
auto msgId = prepareToSend ( req , bigMsgId ) ;
2014-08-01 15:09:46 +04:00
if ( msgId > bigMsgId ) msgId = replaceMsgId ( req , bigMsgId ) ;
if ( msgId > = bigMsgId ) bigMsgId = msgid ( ) ;
* ( haveSentArr + + ) = msgId ;
2014-11-05 20:43:32 +03:00
bool added = false ;
2014-05-30 12:53:19 +04:00
if ( req - > requestId ) {
2018-06-25 19:55:27 +01:00
if ( req . needAck ( ) ) {
2019-02-19 10:57:53 +04:00
req - > msDate = req . isStateRequest ( ) ? 0 : crl : : now ( ) ;
2014-11-15 02:23:35 +03:00
int32 reqNeedsLayer = ( needsLayer & & req - > needsLayer ) ? toSendRequest - > size ( ) : 0 ;
2014-11-05 20:43:32 +03:00
if ( req - > after ) {
2016-03-24 11:57:11 +03:00
wrapInvokeAfter ( toSendRequest , req , haveSent , reqNeedsLayer ? initSizeInInts : 0 ) ;
2014-11-15 02:23:35 +03:00
if ( reqNeedsLayer ) {
memcpy ( toSendRequest - > data ( ) + reqNeedsLayer + 4 , initSerialized . constData ( ) , initSize ) ;
* ( toSendRequest - > data ( ) + reqNeedsLayer + 3 ) + = initSize ;
}
added = true ;
} else if ( reqNeedsLayer ) {
2018-06-25 19:55:27 +01:00
toSendRequest - > resize ( reqNeedsLayer + initSizeInInts + req . messageSize ( ) ) ;
2014-11-15 02:23:35 +03:00
memcpy ( toSendRequest - > data ( ) + reqNeedsLayer , req - > constData ( ) + 4 , 4 * sizeof ( mtpPrime ) ) ;
memcpy ( toSendRequest - > data ( ) + reqNeedsLayer + 4 , initSerialized . constData ( ) , initSize ) ;
memcpy ( toSendRequest - > data ( ) + reqNeedsLayer + 4 + initSizeInInts , req - > constData ( ) + 8 , req . innerLength ( ) ) ;
* ( toSendRequest - > data ( ) + reqNeedsLayer + 3 ) + = initSize ;
2014-11-05 20:43:32 +03:00
added = true ;
}
2014-05-30 12:53:19 +04:00
haveSent . insert ( msgId , req ) ;
needAnyResponse = true ;
} else {
wereAcked . insert ( msgId , req - > requestId ) ;
}
}
2014-11-05 20:43:32 +03:00
if ( ! added ) {
2018-06-25 19:55:27 +01:00
uint32 from = toSendRequest - > size ( ) , len = req . messageSize ( ) ;
2014-11-05 20:43:32 +03:00
toSendRequest - > resize ( from + len ) ;
memcpy ( toSendRequest - > data ( ) + from , req - > constData ( ) + 4 , len * sizeof ( mtpPrime ) ) ;
}
}
if ( stateRequest ) {
mtpMsgId msgId = placeToContainer ( toSendRequest , bigMsgId , haveSentArr , stateRequest ) ;
stateRequest - > msDate = 0 ; // 0 for state request, do not request state of it
haveSent . insert ( msgId , stateRequest ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
if ( resendRequest ) placeToContainer ( toSendRequest , bigMsgId , haveSentArr , resendRequest ) ;
if ( ackRequest ) placeToContainer ( toSendRequest , bigMsgId , haveSentArr , ackRequest ) ;
2015-03-12 13:28:10 +03:00
if ( httpWaitRequest ) placeToContainer ( toSendRequest , bigMsgId , haveSentArr , httpWaitRequest ) ;
2014-05-30 12:53:19 +04:00
2014-08-01 15:09:46 +04:00
mtpMsgId contMsgId = prepareToSend ( toSendRequest , bigMsgId ) ;
2014-05-30 12:53:19 +04:00
* ( mtpMsgId * ) ( haveSentIdsWrap - > data ( ) + 4 ) = contMsgId ;
( * haveSentIdsWrap ) [ 6 ] = 0 ; // for container, msDate = 0, seqNo = 0
haveSent . insert ( contMsgId , haveSentIdsWrap ) ;
toSend . clear ( ) ;
}
}
2018-06-25 19:55:27 +01:00
sendSecureRequest (
std : : move ( toSendRequest ) ,
needAnyResponse ,
lockFinished ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : retryByTimer ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2018-04-24 23:09:20 +04:00
if ( _retryTimeout < 3 ) {
+ + _retryTimeout ;
} else if ( _retryTimeout = = 3 ) {
_retryTimeout = 1000 ;
} else if ( _retryTimeout < 64000 ) {
_retryTimeout * = 2 ;
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
if ( keyId = = kRecreateKeyId ) {
2014-05-30 12:53:19 +04:00
if ( sessionData - > getKey ( ) ) {
2015-05-14 19:50:04 +03:00
unlockKey ( ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker lock ( sessionData - > keyMutex ( ) ) ;
sessionData - > owner ( ) - > destroyKey ( ) ;
}
keyId = 0 ;
}
2017-03-23 19:11:35 +03:00
connectToServer ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : restartNow ( ) {
2018-04-24 23:09:20 +04:00
_retryTimeout = 1 ;
_retryTimer . cancel ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : connectToServer ( bool afterConfig ) {
2016-02-29 19:53:26 +03:00
if ( _finished ) {
2018-04-24 12:46:27 +04:00
DEBUG_LOG ( ( " MTP Error: "
" connectToServer() called for finished connection! " ) ) ;
2016-02-29 19:53:26 +03:00
return ;
}
2018-04-24 12:46:27 +04:00
auto hasKey = true ;
{
2016-02-25 20:23:42 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
2018-04-24 12:46:27 +04:00
if ( ! sessionData ) {
DEBUG_LOG ( ( " MTP Error: "
" connectToServer() called for stopped connection! " ) ) ;
return ;
2017-03-23 19:11:35 +03:00
}
2018-04-24 12:46:27 +04:00
_connectionOptions = std : : make_unique < ConnectionOptions > (
sessionData - > connectionOptions ( ) ) ;
hasKey = ( sessionData - > getKey ( ) ! = nullptr ) ;
}
2018-06-11 21:35:27 +03:00
auto bareDc = BareDcId ( _shiftedDcId ) ;
2018-04-24 12:46:27 +04:00
_dcType = _instance - > dcOptions ( ) - > dcType ( _shiftedDcId ) ;
// Use media_only addresses only if key for this dc is already created.
if ( _dcType = = DcType : : MediaDownload & & ! hasKey ) {
_dcType = DcType : : Regular ;
2017-03-23 19:11:35 +03:00
} else if ( _dcType = = DcType : : Cdn & & ! _instance - > isKeysDestroyer ( ) ) {
2017-06-26 20:38:16 +03:00
if ( ! _instance - > dcOptions ( ) - > hasCDNKeysForDc ( bareDc ) ) {
2017-03-23 19:11:35 +03:00
requestCDNConfig ( ) ;
return ;
2015-05-14 19:50:04 +03:00
}
}
2017-02-23 09:57:04 +03:00
2018-04-24 23:09:20 +04:00
if ( afterConfig & & ( ! _testConnections . empty ( ) | | _connection ) ) {
return ;
}
destroyAllConnections ( ) ;
2018-05-05 15:14:17 +03:00
if ( _connectionOptions - > proxy . type = = ProxyData : : Type : : Mtproto ) {
2018-05-17 22:58:00 +03:00
// host, port, secret for mtproto proxy are taken from proxy.
appendTestConnection ( DcOptions : : Variants : : Tcp , { } , 0 , { } ) ;
2018-04-24 23:09:20 +04:00
} else {
using Variants = DcOptions : : Variants ;
const auto special = ( _dcType = = DcType : : Temporary ) ;
const auto variants = _instance - > dcOptions ( ) - > lookup (
bareDc ,
_dcType ,
_connectionOptions - > proxy . type ! = ProxyData : : Type : : None ) ;
const auto useIPv4 = special ? true : _connectionOptions - > useIPv4 ;
const auto useIPv6 = special ? false : _connectionOptions - > useIPv6 ;
const auto useTcp = special ? true : _connectionOptions - > useTcp ;
const auto useHttp = special ? false : _connectionOptions - > useHttp ;
const auto skipAddress = ! useIPv4
? Variants : : IPv4
: ! useIPv6
? Variants : : IPv6
: Variants : : AddressTypeCount ;
const auto skipProtocol = ! useTcp
? Variants : : Tcp
: ! useHttp
? Variants : : Http
: Variants : : ProtocolCount ;
for ( auto address = 0 ; address ! = Variants : : AddressTypeCount ; + + address ) {
if ( address = = skipAddress ) {
continue ;
}
for ( auto protocol = 0 ; protocol ! = Variants : : ProtocolCount ; + + protocol ) {
if ( protocol = = skipProtocol ) {
continue ;
}
for ( const auto & endpoint : variants . data [ address ] [ protocol ] ) {
appendTestConnection (
static_cast < Variants : : Protocol > ( protocol ) ,
QString : : fromStdString ( endpoint . ip ) ,
endpoint . port ,
2018-05-02 22:07:34 +03:00
endpoint . secret ) ;
2018-04-24 23:09:20 +04:00
}
}
}
}
if ( _testConnections . empty ( ) ) {
2017-02-25 19:44:02 +03:00
if ( _instance - > isKeysDestroyer ( ) ) {
2018-04-24 23:09:20 +04:00
LOG ( ( " MTP Error: DC %1 options for not found for auth key destruction! " ) . arg ( _shiftedDcId ) ) ;
2017-02-25 19:44:02 +03:00
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
} else if ( afterConfig ) {
2018-04-24 23:09:20 +04:00
LOG ( ( " MTP Error: DC %1 options for not found right after config load! " ) . arg ( _shiftedDcId ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2018-04-24 23:09:20 +04:00
DEBUG_LOG ( ( " MTP Info: DC %1 options not found, waiting for config " ) . arg ( _shiftedDcId ) ) ;
2017-02-24 20:15:41 +03:00
connect ( _instance , SIGNAL ( configLoaded ( ) ) , this , SLOT ( onConfigLoaded ( ) ) , Qt : : UniqueConnection ) ;
2018-04-24 11:21:19 +04:00
InvokeQueued ( _instance , [ instance = _instance ] {
instance - > requestConfig ( ) ;
} ) ;
2015-05-14 19:50:04 +03:00
return ;
2014-05-30 12:53:19 +04:00
}
2018-05-28 11:36:12 +03:00
DEBUG_LOG ( ( " Connection Info: Connecting to %1 with %2 test connections. "
) . arg ( _shiftedDcId
) . arg ( _testConnections . size ( ) ) ) ;
2014-05-30 12:53:19 +04:00
2018-05-02 22:07:34 +03:00
if ( ! _startedConnectingAt ) {
2019-02-19 10:57:53 +04:00
_startedConnectingAt = crl : : now ( ) ;
} else if ( crl : : now ( ) - _startedConnectingAt > kRequestConfigTimeout ) {
2018-04-24 11:21:19 +04:00
InvokeQueued ( _instance , [ instance = _instance ] {
instance - > requestConfigIfOld ( ) ;
} ) ;
}
2015-06-10 15:48:26 +03:00
2018-04-24 23:09:20 +04:00
_retryTimer . cancel ( ) ;
_waitForConnectedTimer . cancel ( ) ;
2015-06-10 15:48:26 +03:00
2016-03-24 11:57:11 +03:00
setState ( ConnectingState ) ;
2015-06-10 15:48:26 +03:00
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0 ;
2018-04-24 23:09:20 +04:00
_pingSender . cancel ( ) ;
_waitForConnectedTimer . callOnce ( _waitForConnected ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
void ConnectionPrivate : : restart ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: restarting Connection " ) ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
_waitForReceivedTimer . cancel ( ) ;
_waitForConnectedTimer . cancel ( ) ;
2014-05-30 12:53:19 +04:00
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( key ) {
if ( ! sessionData - > isCheckedKey ( ) ) {
2017-02-25 19:44:02 +03:00
// No destroying in case of an error.
//
//if (mayBeBadKey) {
// clearMessages();
// keyId = kRecreateKeyId;
2015-12-08 23:41:04 +03:00
// retryTimeout = 1; // no ddos please
2017-02-25 19:44:02 +03:00
// LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now..."));
//}
2014-05-30 12:53:19 +04:00
} else {
sessionData - > setCheckedKey ( false ) ;
}
}
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
doDisconnect ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . relock ( ) ;
if ( sessionData & & _needSessionReset ) {
2014-08-01 15:09:46 +04:00
resetSession ( ) ;
}
2014-05-30 12:53:19 +04:00
restarted = true ;
2018-04-24 23:09:20 +04:00
if ( _retryTimer . isActive ( ) ) return ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
DEBUG_LOG ( ( " MTP Info: restart timeout: %1ms " ) . arg ( _retryTimeout ) ) ;
setState ( - _retryTimeout ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onSentSome ( uint64 size ) {
2015-06-10 15:48:26 +03:00
if ( ! _waitForReceivedTimer . isActive ( ) ) {
2017-03-23 19:11:35 +03:00
auto remain = static_cast < uint64 > ( _waitForReceived ) ;
2018-04-24 23:09:20 +04:00
if ( ! _oldConnection ) {
// 8kb / sec, so 512 kb give 64 sec
auto remainBySize = size * _waitForReceived / 8192 ;
remain = snap ( remainBySize , remain , uint64 ( kMaxReceiveTimeout ) ) ;
2015-06-10 15:48:26 +03:00
if ( remain ! = _waitForReceived ) {
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " Checking connect for request with size %1 bytes, delay will be %2 " ) . arg ( size ) . arg ( remain ) ) ;
}
}
2017-02-25 19:44:02 +03:00
if ( isUploadDcId ( _shiftedDcId ) ) {
2017-03-23 19:11:35 +03:00
remain * = kUploadSessionsCount ;
2017-02-25 19:44:02 +03:00
} else if ( isDownloadDcId ( _shiftedDcId ) ) {
2017-03-23 19:11:35 +03:00
remain * = kDownloadSessionsCount ;
2014-10-30 19:23:44 +03:00
}
2018-04-24 23:09:20 +04:00
_waitForReceivedTimer . callOnce ( remain ) ;
2014-05-30 12:53:19 +04:00
}
2019-02-19 10:57:53 +04:00
if ( ! firstSentAt ) firstSentAt = crl : : now ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onReceivedSome ( ) {
2018-04-24 23:09:20 +04:00
if ( _oldConnection ) {
_oldConnection = false ;
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " This connection marked as not old! " ) ) ;
}
2018-04-24 23:09:20 +04:00
_oldConnectionTimer . callOnce ( kMarkConnectionOldTimeout ) ;
_waitForReceivedTimer . cancel ( ) ;
2014-05-30 12:53:19 +04:00
if ( firstSentAt > 0 ) {
2019-02-19 10:57:53 +04:00
const auto ms = crl : : now ( ) - firstSentAt ;
2015-06-10 15:48:26 +03:00
DEBUG_LOG ( ( " MTP Info: response in %1ms, _waitForReceived: %2ms " ) . arg ( ms ) . arg ( _waitForReceived ) ) ;
2014-05-30 12:53:19 +04:00
2018-05-17 22:58:00 +03:00
if ( ms > 0 & & ms * 2 < _waitForReceived ) {
_waitForReceived = qMax ( ms * 2 , kMinReceiveTimeout ) ;
2018-04-24 23:09:20 +04:00
}
2014-05-30 12:53:19 +04:00
firstSentAt = - 1 ;
}
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : markConnectionOld ( ) {
_oldConnection = true ;
_waitForReceived = kMinReceiveTimeout ;
2015-06-10 15:48:26 +03:00
DEBUG_LOG ( ( " This connection marked as old! _waitForReceived now %1ms " ) . arg ( _waitForReceived ) ) ;
2014-05-30 12:53:19 +04:00
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : sendPingByTimer ( ) {
2015-03-12 13:28:10 +03:00
if ( _pingId ) {
2018-06-04 22:48:17 +03:00
// _pingSendAt: when to send next ping (lastPingAt + kPingSendAfter)
// could be equal to zero.
2019-02-19 10:57:53 +04:00
const auto now = crl : : now ( ) ;
2018-06-04 22:48:17 +03:00
const auto mustSendTill = _pingSendAt
+ kPingSendAfterForce
- kPingSendAfter ;
if ( mustSendTill < now + 1000 ) {
2018-04-24 23:09:20 +04:00
LOG ( ( " Could not send ping for some seconds, restarting... " ) ) ;
2015-03-12 13:28:10 +03:00
return restart ( ) ;
} else {
2018-06-04 22:48:17 +03:00
_pingSender . callOnce ( mustSendTill - now ) ;
2015-03-12 13:28:10 +03:00
}
} else {
emit needToSendAsync ( ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onPingSendForce ( ) {
2015-04-16 17:59:42 +03:00
if ( ! _pingId ) {
_pingSendAt = 0 ;
DEBUG_LOG ( ( " Will send ping! " ) ) ;
tryToSend ( ) ;
}
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : waitReceivedFailed ( ) {
2018-04-24 12:46:27 +04:00
Expects ( _connectionOptions ! = nullptr ) ;
if ( ! _connectionOptions - > useTcp ) {
2014-05-30 12:53:19 +04:00
return ;
}
2015-06-10 15:48:26 +03:00
DEBUG_LOG ( ( " MTP Info: bad connection, _waitForReceived: %1ms " ) . arg ( _waitForReceived ) ) ;
2018-04-24 23:09:20 +04:00
if ( _waitForReceived < kMaxReceiveTimeout ) {
2015-06-10 15:48:26 +03:00
_waitForReceived * = 2 ;
2014-05-30 12:53:19 +04:00
}
doDisconnect ( ) ;
restarted = true ;
2018-04-24 23:09:20 +04:00
if ( _retryTimer . isActive ( ) ) {
return ;
}
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " MTP Info: immediate restart! " ) ) ;
2018-05-17 22:58:00 +03:00
InvokeQueued ( this , [ = ] { connectToServer ( ) ; } ) ;
2014-05-30 12:53:19 +04:00
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : waitConnectedFailed ( ) {
2015-06-10 15:48:26 +03:00
DEBUG_LOG ( ( " MTP Info: can't connect in %1ms " ) . arg ( _waitForConnected ) ) ;
2018-05-17 22:58:00 +03:00
auto maxTimeout = kMaxConnectedTimeout ;
for ( const auto & connection : _testConnections ) {
accumulate_max ( maxTimeout , connection . data - > fullConnectTimeout ( ) ) ;
}
if ( _waitForConnected < maxTimeout ) {
_waitForConnected = std : : min ( maxTimeout , 2 * _waitForConnected ) ;
2018-04-24 23:09:20 +04:00
}
2015-06-02 14:22:00 +03:00
doDisconnect ( ) ;
restarted = true ;
DEBUG_LOG ( ( " MTP Info: immediate restart! " ) ) ;
2018-05-17 22:58:00 +03:00
InvokeQueued ( this , [ = ] { connectToServer ( ) ; } ) ;
2015-06-02 14:22:00 +03:00
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : waitBetterFailed ( ) {
confirmBestConnection ( ) ;
2015-06-10 15:48:26 +03:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : doDisconnect ( ) {
2018-04-23 14:24:03 +04:00
destroyAllConnections ( ) ;
2014-05-30 12:53:19 +04:00
2015-08-08 12:14:47 +03:00
{
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( sessionData ) {
unlockKey ( ) ;
}
}
2014-05-30 12:53:19 +04:00
clearAuthKeyData ( ) ;
2016-03-24 11:57:11 +03:00
setState ( DisconnectedState ) ;
2014-05-30 12:53:19 +04:00
restarted = false ;
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : finishAndDestroy ( ) {
2014-05-30 12:53:19 +04:00
doDisconnect ( ) ;
2016-02-29 19:53:26 +03:00
_finished = true ;
emit finished ( _owner ) ;
deleteLater ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : requestCDNConfig ( ) {
2018-05-17 22:58:00 +03:00
connect (
_instance ,
SIGNAL ( cdnConfigLoaded ( ) ) ,
this ,
SLOT ( onCDNConfigLoaded ( ) ) ,
Qt : : UniqueConnection ) ;
InvokeQueued ( _instance , [ instance = _instance ] {
instance - > requestCDNConfig ( ) ;
} ) ;
2017-03-23 19:11:35 +03:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : handleReceived ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2014-05-30 12:53:19 +04:00
onReceivedSome ( ) ;
2017-02-27 12:51:03 +03:00
auto restartOnError = [ this , & lockFinished ] {
lockFinished . unlock ( ) ;
restart ( ) ;
} ;
2014-05-30 12:53:19 +04:00
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key for dc %1 busy, cant lock " ) . arg ( _shiftedDcId ) ) ;
2014-05-30 12:53:19 +04:00
clearMessages ( ) ;
keyId = 0 ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( _shiftedDcId ) ) ;
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2018-04-24 23:09:20 +04:00
while ( ! _connection - > received ( ) . empty ( ) ) {
auto intsBuffer = std : : move ( _connection - > received ( ) . front ( ) ) ;
_connection - > received ( ) . pop_front ( ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
constexpr auto kExternalHeaderIntsCount = 6U ; // 2 auth_key_id, 4 msg_key
constexpr auto kEncryptedHeaderIntsCount = 8U ; // 2 salt, 2 session, 2 msg_id, 1 seq_no, 1 length
constexpr auto kMinimalEncryptedIntsCount = kEncryptedHeaderIntsCount + 4U ; // + 1 data + 3 padding
constexpr auto kMinimalIntsCount = kExternalHeaderIntsCount + kMinimalEncryptedIntsCount ;
auto intsCount = uint32 ( intsBuffer . size ( ) ) ;
auto ints = intsBuffer . constData ( ) ;
2016-12-31 12:58:56 +04:00
if ( ( intsCount < kMinimalIntsCount ) | | ( intsCount > kMaxMessageLength / kIntSize ) ) {
2017-02-27 12:51:03 +03:00
LOG ( ( " TCP Error: bad message received, len %1 " ) . arg ( intsCount * kIntSize ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( ints , intsCount * kIntSize ) . str ( ) ) ) ;
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
if ( keyId ! = * ( uint64 * ) ints ) {
LOG ( ( " TCP Error: bad auth_key_id %1 instead of %2 received " ) . arg ( keyId ) . arg ( * ( uint64 * ) ints ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( ints , intsCount * kIntSize ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
auto encryptedInts = ints + kExternalHeaderIntsCount ;
2018-06-25 22:18:27 +01:00
auto encryptedIntsCount = ( intsCount - kExternalHeaderIntsCount ) & ~ 0x03U ;
2017-02-27 12:51:03 +03:00
auto encryptedBytesCount = encryptedIntsCount * kIntSize ;
auto decryptedBuffer = QByteArray ( encryptedBytesCount , Qt : : Uninitialized ) ;
auto msgKey = * ( MTPint128 * ) ( ints + 2 ) ;
2016-01-11 23:43:29 +08:00
2016-12-31 12:58:56 +04:00
# ifdef TDESKTOP_MTPROTO_OLD
aesIgeDecrypt_oldmtp ( encryptedInts , decryptedBuffer . data ( ) , encryptedBytesCount , key , msgKey ) ;
# else // TDESKTOP_MTPROTO_OLD
2017-02-27 12:51:03 +03:00
aesIgeDecrypt ( encryptedInts , decryptedBuffer . data ( ) , encryptedBytesCount , key , msgKey ) ;
2016-12-31 12:58:56 +04:00
# endif // TDESKTOP_MTPROTO_OLD
2014-05-30 12:53:19 +04:00
2017-02-27 12:51:03 +03:00
auto decryptedInts = reinterpret_cast < const mtpPrime * > ( decryptedBuffer . constData ( ) ) ;
auto serverSalt = * ( uint64 * ) & decryptedInts [ 0 ] ;
auto session = * ( uint64 * ) & decryptedInts [ 2 ] ;
auto msgId = * ( uint64 * ) & decryptedInts [ 4 ] ;
auto seqNo = * ( uint32 * ) & decryptedInts [ 6 ] ;
auto needAck = ( ( seqNo & 0x01 ) ! = 0 ) ;
2014-05-30 12:53:19 +04:00
2017-02-27 12:51:03 +03:00
auto messageLength = * ( uint32 * ) & decryptedInts [ 7 ] ;
2016-12-31 12:58:56 +04:00
if ( messageLength > kMaxMessageLength ) {
LOG ( ( " TCP Error: bad messageLength %1 " ) . arg ( messageLength ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( ints , intsCount * kIntSize ) . str ( ) ) ) ;
return restartOnError ( ) ;
}
2017-02-27 12:51:03 +03:00
auto fullDataLength = kEncryptedHeaderIntsCount * kIntSize + messageLength ; // Without padding.
2015-08-08 12:14:47 +03:00
2016-12-31 12:58:56 +04:00
// Can underflow, but it is an unsigned type, so we just check the range later.
auto paddingSize = static_cast < uint32 > ( encryptedBytesCount ) - static_cast < uint32 > ( fullDataLength ) ;
# ifdef TDESKTOP_MTPROTO_OLD
constexpr auto kMinPaddingSize_oldmtp = 0U ;
constexpr auto kMaxPaddingSize_oldmtp = 15U ;
auto badMessageLength = ( /*paddingSize < kMinPaddingSize_oldmtp || */ paddingSize > kMaxPaddingSize_oldmtp ) ;
2017-02-27 12:51:03 +03:00
auto hashedDataLength = badMessageLength ? encryptedBytesCount : fullDataLength ;
auto sha1ForMsgKeyCheck = hashSha1 ( decryptedInts , hashedDataLength ) ;
2016-12-31 12:58:56 +04:00
constexpr auto kMsgKeyShift_oldmtp = 4U ;
if ( memcmp ( & msgKey , sha1ForMsgKeyCheck . data ( ) + kMsgKeyShift_oldmtp , sizeof ( msgKey ) ) ! = 0 ) {
2017-02-27 12:51:03 +03:00
LOG ( ( " TCP Error: bad SHA1 hash after aesDecrypt in message. " ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encryptedInts , encryptedBytesCount ) . str ( ) ) ) ;
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-31 12:58:56 +04:00
# else // TDESKTOP_MTPROTO_OLD
constexpr auto kMinPaddingSize = 12U ;
constexpr auto kMaxPaddingSize = 1024U ;
auto badMessageLength = ( paddingSize < kMinPaddingSize | | paddingSize > kMaxPaddingSize ) ;
std : : array < uchar , 32 > sha256Buffer = { { 0 } } ;
SHA256_CTX msgKeyLargeContext ;
SHA256_Init ( & msgKeyLargeContext ) ;
SHA256_Update ( & msgKeyLargeContext , key - > partForMsgKey ( false ) , 32 ) ;
SHA256_Update ( & msgKeyLargeContext , decryptedInts , encryptedBytesCount ) ;
SHA256_Final ( sha256Buffer . data ( ) , & msgKeyLargeContext ) ;
constexpr auto kMsgKeyShift = 8U ;
if ( memcmp ( & msgKey , sha256Buffer . data ( ) + kMsgKeyShift , sizeof ( msgKey ) ) ! = 0 ) {
LOG ( ( " TCP Error: bad SHA256 hash after aesDecrypt in message " ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encryptedInts , encryptedBytesCount ) . str ( ) ) ) ;
return restartOnError ( ) ;
}
# endif // TDESKTOP_MTPROTO_OLD
2017-02-27 12:51:03 +03:00
if ( badMessageLength | | ( messageLength & 0x03 ) ) {
LOG ( ( " TCP Error: bad msg_len received %1, data size: %2 " ) . arg ( messageLength ) . arg ( encryptedBytesCount ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encryptedInts , encryptedBytesCount ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
TCP_LOG ( ( " TCP Info: decrypted message %1,%2,%3 is %4 len " ) . arg ( msgId ) . arg ( seqNo ) . arg ( Logs : : b ( needAck ) ) . arg ( fullDataLength ) ) ;
2014-05-30 12:53:19 +04:00
uint64 serverSession = sessionData - > getSession ( ) ;
if ( session ! = serverSession ) {
LOG ( ( " MTP Error: bad server session received " ) ) ;
TCP_LOG ( ( " MTP Error: bad server session %1 instead of %2 in message received " ) . arg ( session ) . arg ( serverSession ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
int32 serverTime ( ( int32 ) ( msgId > > 32 ) ) , clientTime ( unixtime ( ) ) ;
bool isReply = ( ( msgId & 0x03 ) = = 1 ) ;
if ( ! isReply & & ( ( msgId & 0x03 ) ! = 3 ) ) {
LOG ( ( " MTP Error: bad msg_id %1 in message received " ) . arg ( msgId ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
bool badTime = false ;
uint64 mySalt = sessionData - > getSalt ( ) ;
if ( serverTime > clientTime + 60 | | serverTime + 300 < clientTime ) {
DEBUG_LOG ( ( " MTP Info: bad server time from msg_id: %1, my time: %2 " ) . arg ( serverTime ) . arg ( clientTime ) ) ;
badTime = true ;
}
2016-03-24 11:57:11 +03:00
bool wasConnected = ( getState ( ) = = ConnectedState ) ;
2014-05-30 12:53:19 +04:00
if ( serverSalt ! = mySalt ) {
if ( ! badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: other salt received... received: %1, my salt: %2, updating... " ) . arg ( serverSalt ) . arg ( mySalt ) ) ;
2014-05-30 12:53:19 +04:00
sessionData - > setSalt ( serverSalt ) ;
2016-03-24 11:57:11 +03:00
if ( setState ( ConnectedState , ConnectingState ) ) { // only connected
2014-05-30 12:53:19 +04:00
if ( restarted ) {
2014-11-25 15:15:29 +03:00
emit resendAllAsync ( ) ;
2014-05-30 12:53:19 +04:00
restarted = false ;
}
}
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: other salt received... received: %1, my salt: %2 " ) . arg ( serverSalt ) . arg ( mySalt ) ) ;
2014-05-30 12:53:19 +04:00
}
} else {
serverSalt = 0 ; // dont pass to handle method, so not to lock in setSalt()
}
2014-11-05 20:43:32 +03:00
if ( needAck ) ackRequestData . push_back ( MTP_long ( msgId ) ) ;
2014-05-30 12:53:19 +04:00
2016-12-07 16:32:25 +03:00
auto res = HandleResult : : Success ; // if no need to handle, then succeed
2017-02-27 12:51:03 +03:00
auto from = decryptedInts + kEncryptedHeaderIntsCount ;
auto end = from + ( messageLength / kIntSize ) ;
auto sfrom = decryptedInts + 4U ; // msg_id + seq_no + length + message
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Recv: " ) + mtpTextSerialize ( sfrom , end ) ) ;
2014-05-30 12:53:19 +04:00
bool needToHandle = false ;
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
needToHandle = sessionData - > receivedIdsSet ( ) . registerMsgId ( msgId , needAck ) ;
2014-05-30 12:53:19 +04:00
}
if ( needToHandle ) {
res = handleOneReceived ( from , end , msgId , serverTime , serverSalt , badTime ) ;
}
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
sessionData - > receivedIdsSet ( ) . shrink ( ) ;
2014-05-30 12:53:19 +04:00
}
// send acks
2014-11-05 20:43:32 +03:00
uint32 toAckSize = ackRequestData . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( toAckSize ) {
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " MTP Info: will send %1 acks, ids: %2 " ) . arg ( toAckSize ) . arg ( LogIdsVector ( ackRequestData ) ) ) ;
2019-01-21 17:42:21 +04:00
emit sendAnythingAsync ( kAckSendWaiting ) ;
2014-05-30 12:53:19 +04:00
}
bool emitSignal = false ;
{
QReadLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
2017-04-30 17:23:57 +03:00
emitSignal = ! sessionData - > haveReceivedResponses ( ) . isEmpty ( ) | | ! sessionData - > haveReceivedUpdates ( ) . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( emitSignal ) {
2017-04-30 17:23:57 +03:00
DEBUG_LOG ( ( " MTP Info: emitting needToReceive() - need to parse in another thread, %1 responses, %2 updates. " ) . arg ( sessionData - > haveReceivedResponses ( ) . size ( ) ) . arg ( sessionData - > haveReceivedUpdates ( ) . size ( ) ) ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
if ( emitSignal ) {
emit needToReceive ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( res ! = HandleResult : : Success & & res ! = HandleResult : : Ignored ) {
_needSessionReset = ( res = = HandleResult : : ResetSession ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2018-04-24 23:09:20 +04:00
_retryTimeout = 1 ; // reset restart() timer
2014-05-30 12:53:19 +04:00
if ( ! sessionData - > isCheckedKey ( ) ) {
DEBUG_LOG ( ( " MTP Info: marked auth key as checked " ) ) ;
sessionData - > setCheckedKey ( true ) ;
}
2019-02-19 10:57:53 +04:00
_startedConnectingAt = crl : : time ( 0 ) ;
2014-05-30 12:53:19 +04:00
if ( ! wasConnected ) {
2016-03-24 11:57:11 +03:00
if ( getState ( ) = = ConnectedState ) {
2014-11-22 12:45:04 +03:00
emit needToSendAsync ( ) ;
2014-05-30 12:53:19 +04:00
}
}
}
2018-04-24 23:09:20 +04:00
if ( _connection - > needHttpWait ( ) ) {
2014-11-25 15:15:29 +03:00
emit sendHttpWaitAsync ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-12-07 16:32:25 +03:00
ConnectionPrivate : : HandleResult ConnectionPrivate : : handleOneReceived ( const mtpPrime * from , const mtpPrime * end , uint64 msgId , int32 serverTime , uint64 serverSalt , bool badTime ) {
2014-05-30 12:53:19 +04:00
mtpTypeId cons = * from ;
try {
switch ( cons ) {
case mtpc_gzip_packed : {
DEBUG_LOG ( ( " Message Info: gzip container " ) ) ;
mtpBuffer response = ungzip ( + + from , end ) ;
2019-01-17 11:17:44 +04:00
if ( response . empty ( ) ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
return handleOneReceived ( response . data ( ) , response . data ( ) + response . size ( ) , msgId , serverTime , serverSalt , badTime ) ;
}
case mtpc_msg_container : {
if ( + + from > = end ) throw mtpErrorInsufficient ( ) ;
const mtpPrime * otherEnd ;
uint32 msgsCount = ( uint32 ) * ( from + + ) ;
DEBUG_LOG ( ( " Message Info: container received, count: %1 " ) . arg ( msgsCount ) ) ;
for ( uint32 i = 0 ; i < msgsCount ; + + i ) {
if ( from + 4 > = end ) throw mtpErrorInsufficient ( ) ;
otherEnd = from + 4 ;
2017-03-09 22:15:31 +03:00
MTPlong inMsgId ;
inMsgId . read ( from , otherEnd ) ;
2014-05-30 12:53:19 +04:00
bool isReply = ( ( inMsgId . v & 0x03 ) = = 1 ) ;
if ( ! isReply & & ( ( inMsgId . v & 0x03 ) ! = 3 ) ) {
LOG ( ( " Message Error: bad msg_id %1 in contained message received " ) . arg ( inMsgId . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPint inSeqNo ;
inSeqNo . read ( from , otherEnd ) ;
MTPint bytes ;
bytes . read ( from , otherEnd ) ;
2014-05-30 12:53:19 +04:00
if ( ( bytes . v & 0x03 ) | | bytes . v < 4 ) {
LOG ( ( " Message Error: bad length %1 of contained message received " ) . arg ( bytes . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
bool needAck = ( inSeqNo . v & 0x01 ) ;
2014-11-05 20:43:32 +03:00
if ( needAck ) ackRequestData . push_back ( inMsgId ) ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: message from container, msg_id: %1, needAck: %2 " ) . arg ( inMsgId . v ) . arg ( Logs : : b ( needAck ) ) ) ;
2014-05-30 12:53:19 +04:00
otherEnd = from + ( bytes . v > > 2 ) ;
if ( otherEnd > end ) throw mtpErrorInsufficient ( ) ;
bool needToHandle = false ;
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
needToHandle = sessionData - > receivedIdsSet ( ) . registerMsgId ( inMsgId . v , needAck ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
auto res = HandleResult : : Success ; // if no need to handle, then succeed
2014-05-30 12:53:19 +04:00
if ( needToHandle ) {
res = handleOneReceived ( from , otherEnd , inMsgId . v , serverTime , serverSalt , badTime ) ;
badTime = false ;
}
2016-12-07 16:32:25 +03:00
if ( res ! = HandleResult : : Success ) {
2014-05-30 12:53:19 +04:00
return res ;
}
from = otherEnd ;
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_ack : {
2017-03-09 22:15:31 +03:00
MTPMsgsAck msg ;
msg . read ( from , end ) ;
2019-07-05 15:38:38 +02:00
auto & ids = msg . c_msgs_ack ( ) . vmsg_ids ( ) . v ;
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " Message Info: acks received, ids: %1 " ) . arg ( LogIdsVector ( ids ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
requestsAcked ( ids ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_bad_msg_notification : {
2017-03-09 22:15:31 +03:00
MTPBadMsgNotification msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_msg_notification ( ) ) ;
2019-07-05 15:38:38 +02:00
LOG ( ( " Message Info: bad message notification received (error_code %3) for msg_id = %1, seq_no = %2 " ) . arg ( data . vbad_msg_id ( ) . v ) . arg ( data . vbad_msg_seqno ( ) . v ) . arg ( data . verror_code ( ) . v ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
mtpMsgId resendId = data . vbad_msg_id ( ) . v ;
2015-03-12 13:28:10 +03:00
if ( resendId = = _pingMsgId ) {
_pingId = 0 ;
}
2019-07-05 15:38:38 +02:00
int32 errorCode = data . verror_code ( ) . v ;
2018-01-02 16:44:12 +03:00
if ( false
| | errorCode = = 16
| | errorCode = = 17
| | errorCode = = 32
| | errorCode = = 33
| | errorCode = = 64 ) { // can handle
const auto needResend = false
| | ( errorCode = = 16 ) // bad msg_id
| | ( errorCode = = 17 ) // bad msg_id
| | ( errorCode = = 64 ) ; // bad container
2014-08-01 15:09:46 +04:00
if ( errorCode = = 64 ) { // bad container!
2018-06-05 16:32:26 +03:00
if ( Logs : : DebugEnabled ( ) ) {
2018-06-25 19:55:27 +01:00
SecureRequest request ;
2014-08-01 15:09:46 +04:00
{
QWriteLocker locker ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-08-01 15:09:46 +04:00
2018-06-25 19:55:27 +01:00
const auto i = haveSent . constFind ( resendId ) ;
2014-11-05 20:43:32 +03:00
if ( i = = haveSent . cend ( ) ) {
2014-08-01 15:09:46 +04:00
LOG ( ( " Message Error: Container not found! " ) ) ;
2014-11-05 20:43:32 +03:00
} else {
request = i . value ( ) ;
2014-08-01 15:09:46 +04:00
}
}
if ( request ) {
2018-06-25 19:55:27 +01:00
if ( request . isSentContainer ( ) ) {
2014-08-01 15:09:46 +04:00
QStringList lst ;
2018-06-25 19:55:27 +01:00
const auto ids = ( const mtpMsgId * ) ( request - > constData ( ) + 8 ) ;
2014-08-01 15:09:46 +04:00
for ( uint32 i = 0 , l = ( request - > size ( ) - 8 ) > > 1 ; i < l ; + + i ) {
lst . push_back ( QString : : number ( ids [ i ] ) ) ;
}
LOG ( ( " Message Info: bad container received! messages: %1 " ) . arg ( lst . join ( ' , ' ) ) ) ;
} else {
LOG ( ( " Message Error: bad container received, but request is not a container! " ) ) ;
}
}
}
}
2014-05-30 12:53:19 +04:00
2014-08-01 15:09:46 +04:00
if ( ! wasSent ( resendId ) ) {
2018-01-02 16:44:12 +03:00
DEBUG_LOG ( ( " Message Error: "
" such message was not sent recently %1 " ) . arg ( resendId ) ) ;
return badTime
? HandleResult : : Ignored
: HandleResult : : Success ;
2014-08-01 15:09:46 +04:00
}
2014-05-30 12:53:19 +04:00
2018-01-02 16:44:12 +03:00
if ( needResend ) { // bad msg_id or bad container
2014-05-30 12:53:19 +04:00
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ;
2014-08-01 15:09:46 +04:00
unixtimeSet ( serverTime , true ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: unixtime updated, now %1, resending in container... " ) . arg ( serverTime ) ) ;
2014-08-01 15:09:46 +04:00
resend ( resendId , 0 , true ) ;
} else { // must create new session, because msg_id and msg_seqno are inconsistent
if ( badTime ) {
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ;
2014-08-15 15:19:32 +04:00
unixtimeSet ( serverTime , true ) ;
2014-08-01 15:09:46 +04:00
badTime = false ;
}
2019-07-05 15:38:38 +02:00
LOG ( ( " Message Info: bad message notification received, msgId %1, error_code %2 " ) . arg ( data . vbad_msg_id ( ) . v ) . arg ( errorCode ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : ResetSession ;
2014-05-30 12:53:19 +04:00
}
2014-08-01 15:09:46 +04:00
} else { // fatal (except 48, but it must not get here)
2019-07-05 15:38:38 +02:00
const auto badMsgId = mtpMsgId ( data . vbad_msg_id ( ) . v ) ;
2018-01-02 16:44:12 +03:00
const auto requestId = wasSent ( resendId ) ;
2014-08-01 15:09:46 +04:00
if ( requestId ) {
2018-01-02 16:44:12 +03:00
LOG ( ( " Message Error: "
" bad message notification received, "
" msgId %1, error_code %2, fatal: clearing callbacks "
) . arg ( badMsgId
) . arg ( errorCode
) ) ;
_instance - > clearCallbacksDelayed ( { 1 , RPCCallbackClear (
requestId ,
- errorCode ) } ) ;
2014-08-01 15:09:46 +04:00
} else {
2018-01-02 16:44:12 +03:00
DEBUG_LOG ( ( " Message Error: "
" such message was not sent recently %1 " ) . arg ( badMsgId ) ) ;
2014-08-01 15:09:46 +04:00
}
2018-01-02 16:44:12 +03:00
return badTime
? HandleResult : : Ignored
: HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_bad_server_salt : {
2017-03-09 22:15:31 +03:00
MTPBadMsgNotification msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_server_salt ( ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: bad server salt received (error_code %4) for msg_id = %1, seq_no = %2, new salt: %3 " ) . arg ( data . vbad_msg_id ( ) . v ) . arg ( data . vbad_msg_seqno ( ) . v ) . arg ( data . vnew_server_salt ( ) . v ) . arg ( data . verror_code ( ) . v ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
mtpMsgId resendId = data . vbad_msg_id ( ) . v ;
2015-03-12 13:28:10 +03:00
if ( resendId = = _pingMsgId ) {
_pingId = 0 ;
} else if ( ! wasSent ( resendId ) ) {
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " Message Error: such message was not sent recently %1 " ) . arg ( resendId ) ) ;
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
}
2019-07-05 15:38:38 +02:00
uint64 serverSalt = data . vnew_server_salt ( ) . v ;
2014-05-30 12:53:19 +04:00
sessionData - > setSalt ( serverSalt ) ;
unixtimeSet ( serverTime ) ;
2016-03-24 11:57:11 +03:00
if ( setState ( ConnectedState , ConnectingState ) ) { // maybe only connected
2014-05-30 12:53:19 +04:00
if ( restarted ) {
2014-11-25 15:15:29 +03:00
emit resendAllAsync ( ) ;
2014-05-30 12:53:19 +04:00
restarted = false ;
}
}
badTime = false ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: unixtime updated, now %1, server_salt updated, now %2, resending... " ) . arg ( serverTime ) . arg ( serverSalt ) ) ;
2014-05-30 12:53:19 +04:00
resend ( resendId ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_state_req : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgsStateReq msg ;
msg . read ( from , end ) ;
2019-07-05 15:38:38 +02:00
auto & ids = msg . c_msgs_state_req ( ) . vmsg_ids ( ) . v ;
2017-03-10 22:46:28 +03:00
auto idsCount = ids . size ( ) ;
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " Message Info: msgs_state_req received, ids: %1 " ) . arg ( LogIdsVector ( ids ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
2014-11-25 15:15:29 +03:00
QByteArray info ( idsCount , Qt : : Uninitialized ) ;
2014-05-30 12:53:19 +04:00
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
auto & receivedIds = sessionData - > receivedIdsSet ( ) ;
auto minRecv = receivedIds . min ( ) ;
auto maxRecv = receivedIds . max ( ) ;
2014-05-30 12:53:19 +04:00
QReadLocker locker ( sessionData - > wereAckedMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & wereAcked = sessionData - > wereAckedMap ( ) ;
const auto wereAckedEnd = wereAcked . cend ( ) ;
2014-05-30 12:53:19 +04:00
for ( uint32 i = 0 , l = idsCount ; i < l ; + + i ) {
char state = 0 ;
uint64 reqMsgId = ids [ i ] . v ;
if ( reqMsgId < minRecv ) {
state | = 0x01 ;
} else if ( reqMsgId > maxRecv ) {
state | = 0x03 ;
} else {
2016-12-07 16:32:25 +03:00
auto msgIdState = receivedIds . lookup ( reqMsgId ) ;
if ( msgIdState = = ReceivedMsgIds : : State : : NotFound ) {
2014-05-30 12:53:19 +04:00
state | = 0x02 ;
} else {
state | = 0x04 ;
if ( wereAcked . constFind ( reqMsgId ) ! = wereAckedEnd ) {
state | = 0x80 ; // we know, that server knows, that we received request
}
2016-12-07 16:32:25 +03:00
if ( msgIdState = = ReceivedMsgIds : : State : : NeedsAck ) { // need ack, so we sent ack
2014-05-30 12:53:19 +04:00
state | = 0x08 ;
} else {
state | = 0x10 ;
}
}
}
info [ i ] = state ;
}
}
2014-11-25 15:15:29 +03:00
emit sendMsgsStateInfoAsync ( msgId , info ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_state_info : {
2017-03-09 22:15:31 +03:00
MTPMsgsStateInfo msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & data = msg . c_msgs_state_info ( ) ;
2016-01-11 23:43:29 +08:00
2019-07-05 15:38:38 +02:00
auto reqMsgId = data . vreq_msg_id ( ) . v ;
auto & states = data . vinfo ( ) . v ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: msg state received, msgId %1, reqMsgId: %2, HEX states %3 " ) . arg ( msgId ) . arg ( reqMsgId ) . arg ( Logs : : mb ( states . data ( ) , states . length ( ) ) . str ( ) ) ) ;
2018-06-25 19:55:27 +01:00
SecureRequest requestBuffer ;
2014-05-30 12:53:19 +04:00
{ // find this request in session-shared sent requests map
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & haveSent = sessionData - > haveSentMap ( ) ;
const auto replyTo = haveSent . constFind ( reqMsgId ) ;
2014-05-30 12:53:19 +04:00
if ( replyTo = = haveSent . cend ( ) ) { // do not look in toResend, because we do not resend msgs_state_req requests
DEBUG_LOG ( ( " Message Error: such message was not sent recently %1 " ) . arg ( reqMsgId ) ) ;
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
}
2014-10-30 19:23:44 +03:00
if ( badTime ) {
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ; // requestsFixTimeSalt with no lookup
unixtimeSet ( serverTime , true ) ;
2014-05-30 12:53:19 +04:00
2014-10-30 19:23:44 +03:00
DEBUG_LOG ( ( " Message Info: unixtime updated from mtpc_msgs_state_info, now %1 " ) . arg ( serverTime ) ) ;
2014-05-30 12:53:19 +04:00
2014-10-30 19:23:44 +03:00
badTime = false ;
}
2014-05-30 12:53:19 +04:00
requestBuffer = replyTo . value ( ) ;
}
2014-10-30 19:23:44 +03:00
QVector < MTPlong > toAckReq ( 1 , MTP_long ( reqMsgId ) ) , toAck ;
requestsAcked ( toAck , true ) ;
2014-05-30 12:53:19 +04:00
if ( requestBuffer - > size ( ) < 9 ) {
LOG ( ( " Message Error: bad request %1 found in requestMap, size: %2 " ) . arg ( reqMsgId ) . arg ( requestBuffer - > size ( ) ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
try {
const mtpPrime * rFrom = requestBuffer - > constData ( ) + 8 , * rEnd = requestBuffer - > constData ( ) + requestBuffer - > size ( ) ;
2014-08-11 13:06:16 +04:00
if ( mtpTypeId ( * rFrom ) = = mtpc_msgs_state_req ) {
2017-03-09 22:15:31 +03:00
MTPMsgsStateReq request ;
request . read ( rFrom , rEnd ) ;
2019-07-05 15:38:38 +02:00
handleMsgsStates ( request . c_msgs_state_req ( ) . vmsg_ids ( ) . v , states , toAck ) ;
2014-08-01 15:09:46 +04:00
} else {
2017-03-09 22:15:31 +03:00
MTPMsgResendReq request ;
request . read ( rFrom , rEnd ) ;
2019-07-05 15:38:38 +02:00
handleMsgsStates ( request . c_msg_resend_req ( ) . vmsg_ids ( ) . v , states , toAck ) ;
2014-08-01 15:09:46 +04:00
}
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " Message Error: could not parse sent msgs_state_req " ) ) ;
throw ;
}
requestsAcked ( toAck ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_all_info : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgsAllInfo msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & data = msg . c_msgs_all_info ( ) ;
2019-07-05 15:38:38 +02:00
auto & ids = data . vmsg_ids ( ) . v ;
auto & states = data . vinfo ( ) . v ;
2014-05-30 12:53:19 +04:00
QVector < MTPlong > toAck ;
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " Message Info: msgs all info received, msgId %1, reqMsgIds: %2, states %3 " ) . arg ( msgId ) . arg ( LogIdsVector ( ids ) ) . arg ( Logs : : mb ( states . data ( ) , states . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
handleMsgsStates ( ids , states , toAck ) ;
requestsAcked ( toAck ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msg_detailed_info : {
2017-03-09 22:15:31 +03:00
MTPMsgDetailedInfo msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msg_detailed_info ( ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: msg detailed info, sent msgId %1, answerId %2, status %3, bytes %4 " ) . arg ( data . vmsg_id ( ) . v ) . arg ( data . vanswer_msg_id ( ) . v ) . arg ( data . vstatus ( ) . v ) . arg ( data . vbytes ( ) . v ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
QVector < MTPlong > ids ( 1 , data . vmsg_id ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: error, such message was not sent recently %1 " ) . arg ( data . vmsg_id ( ) . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
requestsAcked ( ids ) ;
bool received = false ;
2019-07-05 15:38:38 +02:00
MTPlong resMsgId = data . vanswer_msg_id ( ) ;
2014-05-30 12:53:19 +04:00
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
received = ( sessionData - > receivedIdsSet ( ) . lookup ( resMsgId . v ) ! = ReceivedMsgIds : : State : : NotFound ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
if ( received ) {
ackRequestData . push_back ( resMsgId ) ;
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: answer message %1 was not received, requesting... " ) . arg ( resMsgId . v ) ) ;
2014-11-05 20:43:32 +03:00
resendRequestData . push_back ( resMsgId ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msg_new_detailed_info : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping msg_new_detailed_info with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgDetailedInfo msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msg_new_detailed_info ( ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: msg new detailed info, answerId %2, status %3, bytes %4 " ) . arg ( data . vanswer_msg_id ( ) . v ) . arg ( data . vstatus ( ) . v ) . arg ( data . vbytes ( ) . v ) ) ;
2014-05-30 12:53:19 +04:00
bool received = false ;
2019-07-05 15:38:38 +02:00
MTPlong resMsgId = data . vanswer_msg_id ( ) ;
2014-05-30 12:53:19 +04:00
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
received = ( sessionData - > receivedIdsSet ( ) . lookup ( resMsgId . v ) ! = ReceivedMsgIds : : State : : NotFound ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
if ( received ) {
ackRequestData . push_back ( resMsgId ) ;
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: answer message %1 was not received, requesting... " ) . arg ( resMsgId . v ) ) ;
2014-11-05 20:43:32 +03:00
resendRequestData . push_back ( resMsgId ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
case mtpc_msg_resend_req : {
2017-03-09 22:15:31 +03:00
MTPMsgResendReq msg ;
msg . read ( from , end ) ;
2019-07-05 15:38:38 +02:00
auto & ids = msg . c_msg_resend_req ( ) . vmsg_ids ( ) . v ;
2014-05-30 12:53:19 +04:00
2017-03-10 22:46:28 +03:00
auto idsCount = ids . size ( ) ;
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " Message Info: resend of msgs requested, ids: %1 " ) . arg ( LogIdsVector ( ids ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
2016-04-23 14:40:42 +03:00
QVector < quint64 > toResend ( ids . size ( ) ) ;
2014-11-25 15:15:29 +03:00
for ( int32 i = 0 , l = ids . size ( ) ; i < l ; + + i ) {
toResend [ i ] = ids . at ( i ) . v ;
2014-05-30 12:53:19 +04:00
}
2014-11-25 15:15:29 +03:00
resendMany ( toResend , 0 , false , true ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_rpc_result : {
if ( from + 3 > end ) throw mtpErrorInsufficient ( ) ;
2017-04-30 17:23:57 +03:00
auto response = SerializedMessage ( ) ;
2014-05-30 12:53:19 +04:00
2017-03-09 22:15:31 +03:00
MTPlong reqMsgId ;
reqMsgId . read ( + + from , end ) ;
2014-05-30 12:53:19 +04:00
mtpTypeId typeId = from [ 0 ] ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " RPC Info: response received for %1, queueing... " ) . arg ( reqMsgId . v ) ) ;
2014-05-30 12:53:19 +04:00
QVector < MTPlong > ids ( 1 , reqMsgId ) ;
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2014-08-15 15:19:32 +04:00
DEBUG_LOG ( ( " Message Info: error, such message was not sent recently %1 " ) . arg ( reqMsgId . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
2014-10-30 19:23:44 +03:00
requestsAcked ( ids , true ) ;
2014-05-30 12:53:19 +04:00
if ( typeId = = mtpc_gzip_packed ) {
DEBUG_LOG ( ( " RPC Info: gzip container " ) ) ;
response = ungzip ( + + from , end ) ;
if ( ! response . size ( ) ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
typeId = response [ 0 ] ;
} else {
response . resize ( end - from ) ;
memcpy ( response . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
}
2017-05-17 14:01:58 +03:00
if ( typeId ! = mtpc_rpc_error ) {
// An error could be some RPC_CALL_FAIL or other error inside
// the initConnection, so we're not sure yet that it was inited.
// Wait till a good response is received.
2018-05-17 22:58:00 +03:00
if ( ! _connectionOptions - > inited ) {
_connectionOptions - > inited = true ;
sessionData - > notifyConnectionInited ( * _connectionOptions ) ;
2017-05-17 14:01:58 +03:00
}
2014-11-15 02:23:35 +03:00
}
2014-05-30 12:53:19 +04:00
2017-04-30 17:23:57 +03:00
auto requestId = wasSent ( reqMsgId . v ) ;
2014-06-16 13:31:10 +04:00
if ( requestId & & requestId ! = mtpRequestId ( 0xFFFFFFFF ) ) {
2017-04-30 17:23:57 +03:00
// Save rpc_result for processing in the main thread.
2014-05-30 12:53:19 +04:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
2017-04-30 17:23:57 +03:00
sessionData - > haveReceivedResponses ( ) . insert ( requestId , response ) ;
2014-05-30 12:53:19 +04:00
} else {
DEBUG_LOG ( ( " RPC Info: requestId not found for msgId %1 " ) . arg ( reqMsgId . v ) ) ;
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_new_session_created : {
2015-04-23 18:50:11 +03:00
const mtpPrime * start = from ;
2017-03-09 22:15:31 +03:00
MTPNewSession msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_new_session_created ( ) ) ;
2015-10-01 17:19:27 +03:00
if ( badTime ) {
2019-07-05 15:38:38 +02:00
if ( requestsFixTimeSalt ( QVector < MTPlong > ( 1 , data . vfirst_msg_id ( ) ) , serverTime , serverSalt ) ) {
2015-10-01 17:19:27 +03:00
badTime = false ;
} else {
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: error, such message was not sent recently %1 " ) . arg ( data . vfirst_msg_id ( ) . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2015-10-01 17:19:27 +03:00
}
}
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: new server session created, unique_id %1, first_msg_id %2, server_salt %3 " ) . arg ( data . vunique_id ( ) . v ) . arg ( data . vfirst_msg_id ( ) . v ) . arg ( data . vserver_salt ( ) . v ) ) ;
sessionData - > setSalt ( data . vserver_salt ( ) . v ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
mtpMsgId firstMsgId = data . vfirst_msg_id ( ) . v ;
2014-11-25 15:15:29 +03:00
QVector < quint64 > toResend ;
2014-05-30 12:53:19 +04:00
{
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-05-30 12:53:19 +04:00
toResend . reserve ( haveSent . size ( ) ) ;
2018-06-25 19:55:27 +01:00
for ( auto i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) {
2014-05-30 12:53:19 +04:00
if ( i . key ( ) > = firstMsgId ) break ;
if ( i . value ( ) - > requestId ) toResend . push_back ( i . key ( ) ) ;
}
}
2014-11-25 15:15:29 +03:00
resendMany ( toResend , 10 , true ) ;
2014-05-30 12:53:19 +04:00
2015-04-23 18:50:11 +03:00
mtpBuffer update ( from - start ) ;
if ( from > start ) memcpy ( update . data ( ) , start , ( from - start ) * sizeof ( mtpPrime ) ) ;
2016-01-11 23:43:29 +08:00
2017-04-30 17:23:57 +03:00
// Notify main process about new session - need to get difference.
2014-05-30 12:53:19 +04:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
2017-04-30 17:23:57 +03:00
sessionData - > haveReceivedUpdates ( ) . push_back ( SerializedMessage ( update ) ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_pong : {
2017-03-09 22:15:31 +03:00
MTPPong msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_pong ( ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " Message Info: pong received, msg_id: %1, ping_id: %2 " ) . arg ( data . vmsg_id ( ) . v ) . arg ( data . vping_id ( ) . v ) ) ;
2016-01-11 23:43:29 +08:00
2019-07-05 15:38:38 +02:00
if ( ! wasSent ( data . vmsg_id ( ) . v ) ) {
DEBUG_LOG ( ( " Message Error: such msg_id %1 ping_id %2 was not sent recently " ) . arg ( data . vmsg_id ( ) . v ) . arg ( data . vping_id ( ) . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2019-07-05 15:38:38 +02:00
if ( data . vping_id ( ) . v = = _pingId ) {
2015-03-12 13:28:10 +03:00
_pingId = 0 ;
2014-05-30 12:53:19 +04:00
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: just pong... " ) ) ;
2014-05-30 12:53:19 +04:00
}
2019-07-05 15:38:38 +02:00
QVector < MTPlong > ids ( 1 , data . vmsg_id ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
2014-10-30 19:23:44 +03:00
requestsAcked ( ids , true ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
}
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
if ( badTime ) {
2015-01-23 00:59:07 +03:00
DEBUG_LOG ( ( " Message Error: bad time in updates cons, must create new session " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : ResetSession ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
if ( _dcType = = DcType : : Regular ) {
mtpBuffer update ( end - from ) ;
if ( end > from ) memcpy ( update . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
2016-01-11 23:43:29 +08:00
2017-04-30 17:23:57 +03:00
// Notify main process about the new updates.
2017-03-23 19:11:35 +03:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
2017-04-30 17:23:57 +03:00
sessionData - > haveReceivedUpdates ( ) . push_back ( SerializedMessage ( update ) ) ;
2014-05-30 12:53:19 +04:00
2018-03-04 23:04:13 +03:00
if ( cons ! = mtpc_updatesTooLong
& & cons ! = mtpc_updateShortMessage
& & cons ! = mtpc_updateShortChatMessage
& & cons ! = mtpc_updateShortSentMessage
& & cons ! = mtpc_updateShort
& & cons ! = mtpc_updatesCombined
& & cons ! = mtpc_updates ) {
// Maybe some new unknown update?
2019-04-15 13:20:07 +04:00
LOG ( ( " Message Error: unknown constructor 0x%1 " ) . arg ( cons , 0 , 16 ) ) ;
2017-03-23 19:11:35 +03:00
}
} else {
LOG ( ( " Message Error: unexpected updates in dcType: %1 " ) . arg ( static_cast < int > ( _dcType ) ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
mtpBuffer ConnectionPrivate : : ungzip ( const mtpPrime * from , const mtpPrime * end ) const {
2017-03-09 22:15:31 +03:00
MTPstring packed ;
packed . read ( from , end ) ; // read packed string as serialized mtp string type
2017-03-10 22:46:28 +03:00
uint32 packedLen = packed . v . size ( ) , unpackedChunk = packedLen , unpackedLen = 0 ;
2014-05-30 12:53:19 +04:00
mtpBuffer result ; // * 4 because of mtpPrime type
result . resize ( 0 ) ;
z_stream stream ;
stream . zalloc = 0 ;
stream . zfree = 0 ;
stream . opaque = 0 ;
stream . avail_in = 0 ;
stream . next_in = 0 ;
int res = inflateInit2 ( & stream , 16 + MAX_WBITS ) ;
if ( res ! = Z_OK ) {
LOG ( ( " RPC Error: could not init zlib stream, code: %1 " ) . arg ( res ) ) ;
return result ;
}
stream . avail_in = packedLen ;
2017-03-10 22:46:28 +03:00
stream . next_in = reinterpret_cast < Bytef * > ( packed . v . data ( ) ) ;
2014-05-30 12:53:19 +04:00
stream . avail_out = 0 ;
while ( ! stream . avail_out ) {
result . resize ( result . size ( ) + unpackedChunk ) ;
stream . avail_out = unpackedChunk * sizeof ( mtpPrime ) ;
stream . next_out = ( Bytef * ) & result [ result . size ( ) - unpackedChunk ] ;
int res = inflate ( & stream , Z_NO_FLUSH ) ;
if ( res ! = Z_OK & & res ! = Z_STREAM_END ) {
inflateEnd ( & stream ) ;
LOG ( ( " RPC Error: could not unpack gziped data, code: %1 " ) . arg ( res ) ) ;
2017-03-11 17:13:57 +03:00
DEBUG_LOG ( ( " RPC Error: bad gzip: %1 " ) . arg ( Logs : : mb ( packed . v . constData ( ) , packedLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return mtpBuffer ( ) ;
}
}
if ( stream . avail_out & 0x03 ) {
uint32 badSize = result . size ( ) * sizeof ( mtpPrime ) - stream . avail_out ;
LOG ( ( " RPC Error: bad length of unpacked data %1 " ) . arg ( badSize ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " RPC Error: bad unpacked data %1 " ) . arg ( Logs : : mb ( result . data ( ) , badSize ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return mtpBuffer ( ) ;
}
result . resize ( result . size ( ) - ( stream . avail_out > > 2 ) ) ;
inflateEnd ( & stream ) ;
if ( ! result . size ( ) ) {
LOG ( ( " RPC Error: bad length of unpacked data 0 " ) ) ;
}
return result ;
}
2016-03-24 11:57:11 +03:00
bool ConnectionPrivate : : requestsFixTimeSalt ( const QVector < MTPlong > & ids , int32 serverTime , uint64 serverSalt ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
for ( uint32 i = 0 ; i < idsCount ; + + i ) {
if ( wasSent ( ids [ i ] . v ) ) { // found such msg_id in recent acked requests or in recent sent requests
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ;
2014-08-15 15:19:32 +04:00
unixtimeSet ( serverTime , true ) ;
2014-05-30 12:53:19 +04:00
return true ;
}
}
return false ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : requestsAcked ( const QVector < MTPlong > & ids , bool byResponse ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
2017-12-11 18:45:29 +04:00
DEBUG_LOG ( ( " Message Info: requests acked, ids %1 " ) . arg ( LogIdsVector ( ids ) ) ) ;
2014-05-30 12:53:19 +04:00
2018-01-02 16:44:12 +03:00
auto clearedBecauseTooOld = std : : vector < RPCCallbackClear > ( ) ;
2014-05-30 12:53:19 +04:00
QVector < MTPlong > toAckMore ;
{
QWriteLocker locker1 ( sessionData - > wereAckedMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & wereAcked = sessionData - > wereAckedMap ( ) ;
2014-05-30 12:53:19 +04:00
{
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & haveSent = sessionData - > haveSentMap ( ) ;
2014-05-30 12:53:19 +04:00
for ( uint32 i = 0 ; i < idsCount ; + + i ) {
mtpMsgId msgId = ids [ i ] . v ;
2018-06-25 19:55:27 +01:00
const auto req = haveSent . find ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( req ! = haveSent . cend ( ) ) {
if ( ! req . value ( ) - > msDate ) {
DEBUG_LOG ( ( " Message Info: container ack received, msgId %1 " ) . arg ( ids [ i ] . v ) ) ;
uint32 inContCount = ( ( * req ) - > size ( ) - 8 ) / 2 ;
const mtpMsgId * inContId = ( const mtpMsgId * ) ( req . value ( ) - > constData ( ) + 8 ) ;
toAckMore . reserve ( toAckMore . size ( ) + inContCount ) ;
for ( uint32 j = 0 ; j < inContCount ; + + j ) {
toAckMore . push_back ( MTP_long ( * ( inContId + + ) ) ) ;
}
2014-10-30 19:23:44 +03:00
haveSent . erase ( req ) ;
2014-05-30 12:53:19 +04:00
} else {
2014-10-30 19:23:44 +03:00
mtpRequestId reqId = req . value ( ) - > requestId ;
bool moveToAcked = byResponse ;
if ( ! moveToAcked ) { // ignore ACK, if we need a response (if we have a handler)
2017-02-24 20:15:41 +03:00
moveToAcked = ! _instance - > hasCallbacks ( reqId ) ;
2014-10-30 19:23:44 +03:00
}
if ( moveToAcked ) {
wereAcked . insert ( msgId , reqId ) ;
haveSent . erase ( req ) ;
} else {
DEBUG_LOG ( ( " Message Info: ignoring ACK for msgId %1 because request %2 requires a response " ) . arg ( msgId ) . arg ( reqId ) ) ;
}
2014-05-30 12:53:19 +04:00
}
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: msgId %1 was not found in recent sent, while acking requests, searching in resend... " ) . arg ( msgId ) ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker locker3 ( sessionData - > toResendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & toResend = sessionData - > toResendMap ( ) ;
const auto reqIt = toResend . find ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( reqIt ! = toResend . cend ( ) ) {
2018-06-25 19:55:27 +01:00
const auto reqId = reqIt . value ( ) ;
2014-10-30 19:23:44 +03:00
bool moveToAcked = byResponse ;
if ( ! moveToAcked ) { // ignore ACK, if we need a response (if we have a handler)
2017-02-24 20:15:41 +03:00
moveToAcked = ! _instance - > hasCallbacks ( reqId ) ;
2014-10-30 19:23:44 +03:00
}
if ( moveToAcked ) {
QWriteLocker locker4 ( sessionData - > toSendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & toSend = sessionData - > toSendMap ( ) ;
const auto req = toSend . find ( reqId ) ;
2014-10-30 19:23:44 +03:00
if ( req ! = toSend . cend ( ) ) {
wereAcked . insert ( msgId , req . value ( ) - > requestId ) ;
if ( req . value ( ) - > requestId ! = reqId ) {
DEBUG_LOG ( ( " Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3 " ) . arg ( msgId ) . arg ( reqId ) . arg ( req . value ( ) - > requestId ) ) ;
} else {
DEBUG_LOG ( ( " Message Info: acked msgId %1 that was prepared to resend, requestId %2 " ) . arg ( msgId ) . arg ( reqId ) ) ;
}
toSend . erase ( req ) ;
2014-05-30 12:53:19 +04:00
} else {
2014-10-30 19:23:44 +03:00
DEBUG_LOG ( ( " Message Info: msgId %1 was found in recent resent, requestId %2 was not found in prepared to send " ) . arg ( msgId ) ) ;
2014-05-30 12:53:19 +04:00
}
2014-10-30 19:23:44 +03:00
toResend . erase ( reqIt ) ;
2014-05-30 12:53:19 +04:00
} else {
2014-10-30 19:23:44 +03:00
DEBUG_LOG ( ( " Message Info: ignoring ACK for msgId %1 because request %2 requires a response " ) . arg ( msgId ) . arg ( reqId ) ) ;
2014-05-30 12:53:19 +04:00
}
} else {
DEBUG_LOG ( ( " Message Info: msgId %1 was not found in recent resent either " ) . arg ( msgId ) ) ;
}
}
}
}
uint32 ackedCount = wereAcked . size ( ) ;
2019-01-21 17:42:21 +04:00
if ( ackedCount > kIdsBufferSize ) {
DEBUG_LOG ( ( " Message Info: removing some old acked sent msgIds %1 " ) . arg ( ackedCount - kIdsBufferSize ) ) ;
clearedBecauseTooOld . reserve ( ackedCount - kIdsBufferSize ) ;
while ( ackedCount - - > kIdsBufferSize ) {
2018-01-02 16:44:12 +03:00
auto i = wereAcked . begin ( ) ;
clearedBecauseTooOld . push_back ( RPCCallbackClear (
2018-07-18 22:21:09 +03:00
i . value ( ) ,
2017-12-18 16:40:15 +04:00
RPCError : : TimeoutError ) ) ;
2014-05-30 12:53:19 +04:00
wereAcked . erase ( i ) ;
}
}
}
2018-01-02 16:44:12 +03:00
if ( ! clearedBecauseTooOld . empty ( ) ) {
_instance - > clearCallbacksDelayed ( std : : move ( clearedBecauseTooOld ) ) ;
2014-05-30 12:53:19 +04:00
}
if ( toAckMore . size ( ) ) {
requestsAcked ( toAckMore ) ;
}
}
2017-03-10 22:46:28 +03:00
void ConnectionPrivate : : handleMsgsStates ( const QVector < MTPlong > & ids , const QByteArray & states , QVector < MTPlong > & acked ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
if ( ! idsCount ) {
DEBUG_LOG ( ( " Message Info: void ids vector in handleMsgsStates() " ) ) ;
return ;
}
2017-03-10 22:46:28 +03:00
if ( states . size ( ) < idsCount ) {
LOG ( ( " Message Error: got less states than required ids count. " ) ) ;
return ;
}
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
acked . reserve ( acked . size ( ) + idsCount ) ;
for ( uint32 i = 0 , count = idsCount ; i < count ; + + i ) {
char state = states [ i ] ;
uint64 requestMsgId = ids [ i ] . v ;
{
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & haveSent = sessionData - > haveSentMap ( ) ;
const auto haveSentEnd = haveSent . cend ( ) ;
2014-05-30 12:53:19 +04:00
if ( haveSent . find ( requestMsgId ) = = haveSentEnd ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: state was received for msgId %1, but request is not found, looking in resent requests... " ) . arg ( requestMsgId ) ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker locker2 ( sessionData - > toResendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
auto & toResend = sessionData - > toResendMap ( ) ;
const auto reqIt = toResend . find ( requestMsgId ) ;
2014-05-30 12:53:19 +04:00
if ( reqIt ! = toResend . cend ( ) ) {
if ( ( state & 0x07 ) ! = 0x04 ) { // was received
DEBUG_LOG ( ( " Message Info: state was received for msgId %1, state %2, already resending in container " ) . arg ( requestMsgId ) . arg ( ( int32 ) state ) ) ;
} else {
DEBUG_LOG ( ( " Message Info: state was received for msgId %1, state %2, ack, cancelling resend " ) . arg ( requestMsgId ) . arg ( ( int32 ) state ) ) ;
acked . push_back ( MTP_long ( requestMsgId ) ) ; // will remove from resend in requestsAcked
}
} else {
DEBUG_LOG ( ( " Message Info: msgId %1 was not found in recent resent either " ) . arg ( requestMsgId ) ) ;
}
continue ;
}
}
if ( ( state & 0x07 ) ! = 0x04 ) { // was received
DEBUG_LOG ( ( " Message Info: state was received for msgId %1, state %2, resending in container " ) . arg ( requestMsgId ) . arg ( ( int32 ) state ) ) ;
resend ( requestMsgId , 10 , true ) ;
} else {
DEBUG_LOG ( ( " Message Info: state was received for msgId %1, state %2, ack " ) . arg ( requestMsgId ) . arg ( ( int32 ) state ) ) ;
acked . push_back ( MTP_long ( requestMsgId ) ) ;
}
}
}
2016-12-01 22:20:33 +03:00
void ConnectionPrivate : : resend ( quint64 msgId , qint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) {
2015-03-12 13:28:10 +03:00
if ( msgId = = _pingMsgId ) return ;
2014-11-25 15:15:29 +03:00
emit resendAsync ( msgId , msCanWait , forceContainer , sendMsgStateInfo ) ;
}
2016-12-01 22:20:33 +03:00
void ConnectionPrivate : : resendMany ( QVector < quint64 > msgIds , qint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) {
2014-11-25 15:15:29 +03:00
for ( int32 i = 0 , l = msgIds . size ( ) ; i < l ; + + i ) {
2015-03-12 13:28:10 +03:00
if ( msgIds . at ( i ) = = _pingMsgId ) {
2014-11-25 15:15:29 +03:00
msgIds . remove ( i ) ;
- - l ;
}
}
emit resendManyAsync ( msgIds , msCanWait , forceContainer , sendMsgStateInfo ) ;
2014-05-30 12:53:19 +04:00
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : onConnected (
not_null < AbstractConnection * > connection ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2018-04-24 23:09:20 +04:00
disconnect ( connection , & AbstractConnection : : connected , nullptr , nullptr ) ;
if ( ! connection - > isConnected ( ) ) {
LOG ( ( " Connection Error: not connected in onConnected(), "
" state: %1 " ) . arg ( connection - > debugState ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2018-04-24 23:09:20 +04:00
_waitForConnected = kMinConnectedTimeout ;
_waitForConnectedTimer . cancel ( ) ;
const auto i = ranges : : find (
_testConnections ,
connection . get ( ) ,
[ ] ( const TestConnection & test ) { return test . data . get ( ) ; } ) ;
Assert ( i ! = end ( _testConnections ) ) ;
const auto my = i - > priority ;
const auto j = ranges : : find_if (
_testConnections ,
[ & ] ( const TestConnection & test ) { return test . priority > my ; } ) ;
if ( j ! = end ( _testConnections ) ) {
DEBUG_LOG ( ( " MTP Info: connection %1 succeed, "
" waiting for %2. " ) . arg ( i - > data - > tag ( ) ) . arg ( j - > data - > tag ( ) ) ) ;
_waitForBetterTimer . callOnce ( kWaitForBetterTimeout ) ;
} else {
DEBUG_LOG ( ( " MTP Info: connection through IPv4 succeed. " ) ) ;
_waitForBetterTimer . cancel ( ) ;
_connection = std : : move ( i - > data ) ;
_testConnections . clear ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2018-04-24 23:09:20 +04:00
updateAuthKey ( ) ;
2015-06-10 15:48:26 +03:00
}
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : onDisconnected (
not_null < AbstractConnection * > connection ) {
removeTestConnection ( connection ) ;
2015-06-10 15:48:26 +03:00
2018-04-24 23:09:20 +04:00
if ( _testConnections . empty ( ) ) {
2018-05-17 22:58:00 +03:00
destroyAllConnections ( ) ;
restart ( ) ;
2015-06-10 15:48:26 +03:00
} else {
2018-04-24 23:09:20 +04:00
confirmBestConnection ( ) ;
2015-06-10 15:48:26 +03:00
}
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : confirmBestConnection ( ) {
if ( _waitForBetterTimer . isActive ( ) ) {
return ;
2015-06-10 15:48:26 +03:00
}
2018-04-24 23:09:20 +04:00
const auto i = ranges : : max_element (
_testConnections ,
std : : less < > ( ) ,
[ ] ( const TestConnection & test ) {
return test . data - > isConnected ( ) ? test . priority : - 1 ;
} ) ;
Assert ( i ! = end ( _testConnections ) ) ;
if ( ! i - > data - > isConnected ( ) ) {
return ;
}
DEBUG_LOG ( ( " MTP Info: can't connect through better, using %1. "
) . arg ( i - > data - > tag ( ) ) ) ;
_connection = std : : move ( i - > data ) ;
_testConnections . clear ( ) ;
updateAuthKey ( ) ;
}
void ConnectionPrivate : : removeTestConnection (
not_null < AbstractConnection * > connection ) {
_testConnections . erase (
ranges : : remove (
_testConnections ,
connection . get ( ) ,
[ ] ( const TestConnection & test ) { return test . data . get ( ) ; } ) ,
end ( _testConnections ) ) ;
2015-06-10 15:48:26 +03:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : updateAuthKey ( ) {
2015-05-14 19:50:04 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
2018-04-24 23:09:20 +04:00
if ( ! sessionData | | ! _connection ) return ;
2015-05-14 19:50:04 +03:00
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection updating key from Session, dc %1 " ) . arg ( _shiftedDcId ) ) ;
2015-05-14 19:50:04 +03:00
uint64 newKeyId = 0 ;
{
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
DEBUG_LOG ( ( " MTP Info: could not lock auth_key for read, waiting signal emit " ) ) ;
clearMessages ( ) ;
keyId = newKeyId ;
return ; // some other connection is getting key
}
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2015-05-14 19:50:04 +03:00
newKeyId = key ? key - > keyId ( ) : 0 ;
}
if ( keyId ! = newKeyId ) {
clearMessages ( ) ;
keyId = newKeyId ;
}
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection update key from Session, dc %1 result: %2 " ) . arg ( _shiftedDcId ) . arg ( Logs : : mb ( & keyId , sizeof ( keyId ) ) . str ( ) ) ) ;
2015-05-14 19:50:04 +03:00
if ( keyId ) {
return authKeyCreated ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-05-14 19:50:04 +03:00
DEBUG_LOG ( ( " AuthKey Info: No key in updateAuthKey(), will be creating auth_key " ) ) ;
2014-05-30 12:53:19 +04:00
lockKey ( ) ;
2017-06-26 20:38:16 +03:00
auto & key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( key ) {
if ( keyId ! = key - > keyId ( ) ) clearMessages ( ) ;
keyId = key - > keyId ( ) ;
unlockKey ( ) ;
return authKeyCreated ( ) ;
2017-02-25 19:44:02 +03:00
} else if ( _instance - > isKeysDestroyer ( ) ) {
// We are here to destroy an old key, so we're done.
LOG ( ( " MTP Error: No key %1 in updateAuthKey() for destroying. " ) . arg ( _shiftedDcId ) ) ;
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
2014-05-30 12:53:19 +04:00
}
2017-02-21 16:45:56 +03:00
_authKeyData = std : : make_unique < ConnectionPrivate : : AuthKeyCreateData > ( ) ;
_authKeyStrings = std : : make_unique < ConnectionPrivate : : AuthKeyCreateStrings > ( ) ;
2019-07-05 15:38:38 +02:00
const auto nonce = _authKeyData - > nonce = rand_value < MTPint128 > ( ) ;
2014-05-30 12:53:19 +04:00
2018-04-24 23:09:20 +04:00
connect ( _connection , & AbstractConnection : : receivedData , [ = ] {
pqAnswered ( ) ;
} ) ;
2014-05-30 12:53:19 +04:00
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_pq... " ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2019-07-05 15:38:38 +02:00
sendNotSecureRequest ( MTPReq_pq_multi ( nonce ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : clearMessages ( ) {
2018-04-24 23:09:20 +04:00
if ( keyId & & keyId ! = kRecreateKeyId & & _connection ) {
_connection - > received ( ) . clear ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : pqAnswered ( ) {
2018-04-24 23:09:20 +04:00
disconnect ( _connection , & AbstractConnection : : receivedData , nullptr , nullptr ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: receiving Req_pq answer... " ) ) ;
2014-05-30 12:53:19 +04:00
MTPReq_pq : : ResponseType res_pq ;
2018-06-25 19:55:27 +01:00
if ( ! readNotSecureResponse ( res_pq ) ) {
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-09 21:13:55 +03:00
auto & res_pq_data = res_pq . c_resPQ ( ) ;
2019-07-05 15:38:38 +02:00
if ( res_pq_data . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in res_pq)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & res_pq_data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-23 19:11:35 +03:00
auto rsaKey = internal : : RSAPublicKey ( ) ;
2019-07-05 15:38:38 +02:00
if ( ! _instance - > dcOptions ( ) - > getDcRSAKey ( BareDcId ( _shiftedDcId ) , res_pq . c_resPQ ( ) . vserver_public_key_fingerprints ( ) . v , & rsaKey ) ) {
2017-03-23 19:11:35 +03:00
if ( _dcType = = DcType : : Cdn ) {
LOG ( ( " Warning: CDN public RSA key not found " ) ) ;
requestCDNConfig ( ) ;
return ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
LOG ( ( " AuthKey Error: could not choose public RSA key " ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-08-17 12:06:26 +03:00
Assert ( rsaKey . isValid ( ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
_authKeyData - > server_nonce = res_pq_data . vserver_nonce ( ) ;
2017-03-09 21:13:55 +03:00
_authKeyData - > new_nonce = rand_value < MTPint256 > ( ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
auto & pq = res_pq_data . vpq ( ) . v ;
2017-03-10 22:46:28 +03:00
auto p = QByteArray ( ) ;
auto q = QByteArray ( ) ;
2018-06-11 21:35:27 +03:00
if ( ! internal : : parsePQ ( pq , p , q ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: could not factor pq! " ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: problematic pq: %1 " ) . arg ( Logs : : mb ( pq . constData ( ) , pq . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2018-05-20 21:23:50 +03:00
auto p_q_inner = MTP_p_q_inner_data_dc (
2019-07-05 15:38:38 +02:00
res_pq_data . vpq ( ) ,
2018-05-17 22:58:00 +03:00
MTP_bytes ( std : : move ( p ) ) ,
MTP_bytes ( std : : move ( q ) ) ,
_authKeyData - > nonce ,
_authKeyData - > server_nonce ,
2018-05-20 21:23:50 +03:00
_authKeyData - > new_nonce ,
MTP_int ( getProtocolDcId ( ) ) ) ;
2017-03-09 21:13:55 +03:00
auto dhEncString = encryptPQInnerRSA ( p_q_inner , rsaKey ) ;
if ( dhEncString . empty ( ) ) {
return restart ( ) ;
}
2018-04-24 23:09:20 +04:00
connect ( _connection , & AbstractConnection : : receivedData , [ = ] {
dhParamsAnswered ( ) ;
} ) ;
2017-03-09 21:13:55 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_DH_params... " ) ) ;
2014-05-30 12:53:19 +04:00
2019-07-05 15:38:38 +02:00
sendNotSecureRequest ( MTPReq_DH_params (
_authKeyData - > nonce ,
_authKeyData - > server_nonce ,
p_q_inner . c_p_q_inner_data_dc ( ) . vp ( ) ,
p_q_inner . c_p_q_inner_data_dc ( ) . vq ( ) ,
MTP_long ( rsaKey . getFingerPrint ( ) ) ,
MTP_bytes ( dhEncString ) ) ) ;
2017-03-09 21:13:55 +03:00
}
2014-05-30 12:53:19 +04:00
2018-03-27 16:16:00 +04:00
bytes : : vector ConnectionPrivate : : encryptPQInnerRSA (
const MTPP_Q_inner_data & data ,
2018-06-11 21:35:27 +03:00
const internal : : RSAPublicKey & key ) {
2017-03-09 21:13:55 +03:00
auto p_q_inner_size = data . innerLength ( ) ;
auto encSize = ( p_q_inner_size > > 2 ) + 6 ;
2014-05-30 12:53:19 +04:00
if ( encSize > = 65 ) {
2017-03-09 21:13:55 +03:00
auto tmp = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
tmp . reserve ( encSize ) ;
2017-03-09 21:13:55 +03:00
data . write ( tmp ) ;
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: too large data for RSA encrypt, size %1 " ) . arg ( encSize * sizeof ( mtpPrime ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: bad data for RSA encrypt %1 " ) . arg ( Logs : : mb ( & tmp [ 0 ] , tmp . size ( ) * 4 ) . str ( ) ) ) ;
2018-03-27 16:16:00 +04:00
return { } ; // can't be 255-byte string
2014-05-30 12:53:19 +04:00
}
2017-03-09 21:13:55 +03:00
auto encBuffer = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
encBuffer . reserve ( 65 ) ; // 260 bytes
encBuffer . resize ( 6 ) ;
encBuffer [ 0 ] = 0 ;
2017-03-09 21:13:55 +03:00
data . write ( encBuffer ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( & encBuffer [ 6 ] , p_q_inner_size , & encBuffer [ 1 ] ) ;
if ( encSize < 65 ) {
encBuffer . resize ( 65 ) ;
memset_rand ( & encBuffer [ encSize ] , ( 65 - encSize ) * sizeof ( mtpPrime ) ) ;
}
2018-03-27 16:16:00 +04:00
auto bytes = bytes : : make_span ( encBuffer ) ;
2017-04-24 15:16:38 +03:00
auto bytesToEncrypt = bytes . subspan ( 3 , 256 ) ;
return key . encrypt ( bytesToEncrypt ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhParamsAnswered ( ) {
2018-04-24 23:09:20 +04:00
disconnect ( _connection , & AbstractConnection : : receivedData , nullptr , nullptr ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: receiving Req_DH_params answer... " ) ) ;
2014-05-30 12:53:19 +04:00
MTPReq_DH_params : : ResponseType res_DH_params ;
2018-06-25 19:55:27 +01:00
if ( ! readNotSecureResponse ( res_DH_params ) ) {
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
switch ( res_DH_params . type ( ) ) {
case mtpc_server_DH_params_ok : {
2016-04-08 14:44:35 +04:00
const auto & encDH ( res_DH_params . c_server_DH_params_ok ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( encDH . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_ok)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( encDH . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
auto & encDHStr = encDH . vencrypted_answer ( ) . v ;
2014-05-30 12:53:19 +04:00
uint32 encDHLen = encDHStr . length ( ) , encDHBufLen = encDHLen > > 2 ;
if ( ( encDHLen & 0x03 ) | | encDHBufLen < 6 ) {
LOG ( ( " AuthKey Error: bad encrypted data length %1 (in server_DH_params_ok)! " ) . arg ( encDHLen ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: received encrypted data %1 " ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
uint32 nlen = _authKeyData - > new_nonce . innerLength ( ) , slen = _authKeyData - > server_nonce . innerLength ( ) ;
2014-05-30 12:53:19 +04:00
uchar tmp_aes [ 1024 ] , sha1ns [ 20 ] , sha1sn [ 20 ] , sha1nn [ 20 ] ;
2016-12-07 16:32:25 +03:00
memcpy ( tmp_aes , & _authKeyData - > new_nonce , nlen ) ;
memcpy ( tmp_aes + nlen , & _authKeyData - > server_nonce , slen ) ;
memcpy ( tmp_aes + nlen + slen , & _authKeyData - > new_nonce , nlen ) ;
memcpy ( tmp_aes + nlen + slen + nlen , & _authKeyData - > new_nonce , nlen ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( tmp_aes , nlen + slen , sha1ns ) ;
hashSha1 ( tmp_aes + nlen , nlen + slen , sha1sn ) ;
hashSha1 ( tmp_aes + nlen + slen , nlen + nlen , sha1nn ) ;
mtpBuffer decBuffer ;
decBuffer . resize ( encDHBufLen ) ;
2016-12-07 16:32:25 +03:00
memcpy ( _authKeyData - > aesKey , sha1ns , 20 ) ;
memcpy ( _authKeyData - > aesKey + 20 , sha1sn , 12 ) ;
memcpy ( _authKeyData - > aesIV , sha1sn + 12 , 8 ) ;
memcpy ( _authKeyData - > aesIV + 8 , sha1nn , 20 ) ;
memcpy ( _authKeyData - > aesIV + 28 , & _authKeyData - > new_nonce , 4 ) ;
2014-05-30 12:53:19 +04:00
2016-12-31 12:58:56 +04:00
aesIgeDecryptRaw ( encDHStr . constData ( ) , & decBuffer [ 0 ] , encDHLen , _authKeyData - > aesKey , _authKeyData - > aesIV ) ;
2014-05-30 12:53:19 +04:00
const mtpPrime * from ( & decBuffer [ 5 ] ) , * to ( from ) , * end ( from + ( encDHBufLen - 5 ) ) ;
2017-03-09 22:15:31 +03:00
MTPServer_DH_inner_data dh_inner ;
dh_inner . read ( to , end ) ;
2016-04-08 14:44:35 +04:00
const auto & dh_inner_data ( dh_inner . c_server_DH_inner_data ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( dh_inner_data . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & dh_inner_data . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( dh_inner_data . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & dh_inner_data . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( & decBuffer [ 0 ] , hashSha1 ( & decBuffer [ 5 ] , ( to - from ) * sizeof ( mtpPrime ) , sha1Buffer ) , 20 ) ) {
LOG ( ( " AuthKey Error: sha1 hash of encrypted part did not match! " ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3 " ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > new_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
unixtimeSet ( dh_inner_data . vserver_time ( ) . v ) ;
2014-05-30 12:53:19 +04:00
2017-04-24 15:16:38 +03:00
// check that dhPrime and (dhPrime - 1) / 2 are really prime
2019-07-05 15:38:38 +02:00
if ( ! IsPrimeAndGood ( bytes : : make_span ( dh_inner_data . vdh_prime ( ) . v ) , dh_inner_data . vg ( ) . v ) ) {
2017-04-24 15:16:38 +03:00
LOG ( ( " AuthKey Error: bad dh_prime primality! " ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2018-03-27 16:16:00 +04:00
_authKeyStrings - > dh_prime = bytes : : make_vector (
2019-07-05 15:38:38 +02:00
dh_inner_data . vdh_prime ( ) . v ) ;
_authKeyData - > g = dh_inner_data . vg ( ) . v ;
_authKeyStrings - > g_a = bytes : : make_vector ( dh_inner_data . vg_a ( ) . v ) ;
2016-12-07 16:32:25 +03:00
_authKeyData - > retry_id = MTP_long ( 0 ) ;
_authKeyData - > retries = 0 ;
2014-05-30 12:53:19 +04:00
} return dhClientParamsSend ( ) ;
case mtpc_server_DH_params_fail : {
2016-04-08 14:44:35 +04:00
const auto & encDH ( res_DH_params . c_server_DH_params_fail ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( encDH . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_fail)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( encDH . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
uchar sha1Buffer [ 20 ] ;
2019-07-05 15:38:38 +02:00
if ( encDH . vnew_nonce_hash ( ) ! = * ( MTPint128 * ) ( hashSha1 ( & _authKeyData - > new_nonce , 32 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash did not match! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash: %1, new_nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vnew_nonce_hash ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > new_nonce , 32 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
LOG ( ( " AuthKey Error: server_DH_params_fail received! " ) ) ;
} return restart ( ) ;
}
LOG ( ( " AuthKey Error: unknown server_DH_params received, typeId = %1 " ) . arg ( res_DH_params . type ( ) ) ) ;
return restart ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhClientParamsSend ( ) {
2016-12-07 16:32:25 +03:00
if ( + + _authKeyData - > retries > 5 ) {
LOG ( ( " AuthKey Error: could not create auth_key for %1 retries " ) . arg ( _authKeyData - > retries - 1 ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
// gen rand 'b'
2018-03-27 16:16:00 +04:00
auto randomSeed = bytes : : vector ( ModExpFirst : : kRandomPowerSize ) ;
2018-04-24 12:46:27 +04:00
bytes : : set_random ( randomSeed ) ;
2017-04-24 15:16:38 +03:00
auto g_b_data = CreateModExp ( _authKeyData - > g , _authKeyStrings - > dh_prime , randomSeed ) ;
if ( g_b_data . modexp . empty ( ) ) {
LOG ( ( " AuthKey Error: could not generate good g_b. " ) ) ;
return restart ( ) ;
}
2014-05-30 12:53:19 +04:00
2017-04-24 15:16:38 +03:00
auto computedAuthKey = CreateAuthKey ( _authKeyStrings - > g_a , g_b_data . randomPower , _authKeyStrings - > dh_prime ) ;
if ( computedAuthKey . empty ( ) ) {
LOG ( ( " AuthKey Error: could not generate auth_key. " ) ) ;
return restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-04-24 15:16:38 +03:00
AuthKey : : FillData ( _authKeyStrings - > auth_key , computedAuthKey ) ;
2014-05-30 12:53:19 +04:00
// count auth_key hashes - parts of sha1(auth_key)
2017-02-22 18:18:26 +03:00
auto auth_key_sha = hashSha1 ( _authKeyStrings - > auth_key . data ( ) , _authKeyStrings - > auth_key . size ( ) ) ;
memcpy ( & _authKeyData - > auth_key_aux_hash , auth_key_sha . data ( ) , 8 ) ;
memcpy ( & _authKeyData - > auth_key_hash , auth_key_sha . data ( ) + 12 , 8 ) ;
2014-05-30 12:53:19 +04:00
2017-04-24 15:16:38 +03:00
auto client_dh_inner = MTP_client_DH_inner_data ( _authKeyData - > nonce , _authKeyData - > server_nonce , _authKeyData - > retry_id , MTP_bytes ( g_b_data . modexp ) ) ;
2017-03-09 21:13:55 +03:00
auto sdhEncString = encryptClientDHInner ( client_dh_inner ) ;
2018-04-24 23:09:20 +04:00
connect ( _connection , & AbstractConnection : : receivedData , [ = ] {
dhClientParamsAnswered ( ) ;
} ) ;
2017-03-09 21:13:55 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_client_DH_params... " ) ) ;
2019-07-05 15:38:38 +02:00
sendNotSecureRequest ( MTPSet_client_DH_params (
_authKeyData - > nonce ,
_authKeyData - > server_nonce ,
MTP_string ( std : : move ( sdhEncString ) ) ) ) ;
2017-03-09 21:13:55 +03:00
}
2014-05-30 12:53:19 +04:00
2017-03-09 21:13:55 +03:00
std : : string ConnectionPrivate : : encryptClientDHInner ( const MTPClient_DH_Inner_Data & data ) {
auto client_dh_inner_size = data . innerLength ( ) ;
auto encSize = ( client_dh_inner_size > > 2 ) + 5 ;
auto encFullSize = encSize ;
2014-05-30 12:53:19 +04:00
if ( encSize & 0x03 ) {
encFullSize + = 4 - ( encSize & 0x03 ) ;
}
2017-03-09 21:13:55 +03:00
auto encBuffer = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
encBuffer . reserve ( encFullSize ) ;
encBuffer . resize ( 5 ) ;
2017-03-09 21:13:55 +03:00
data . write ( encBuffer ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( & encBuffer [ 5 ] , client_dh_inner_size , & encBuffer [ 0 ] ) ;
if ( encSize < encFullSize ) {
encBuffer . resize ( encFullSize ) ;
memset_rand ( & encBuffer [ encSize ] , ( encFullSize - encSize ) * sizeof ( mtpPrime ) ) ;
}
2017-03-09 21:13:55 +03:00
auto sdhEncString = std : : string ( encFullSize * 4 , ' ' ) ;
2014-05-30 12:53:19 +04:00
2016-12-31 12:58:56 +04:00
aesIgeEncryptRaw ( & encBuffer [ 0 ] , & sdhEncString [ 0 ] , encFullSize * sizeof ( mtpPrime ) , _authKeyData - > aesKey , _authKeyData - > aesIV ) ;
2014-05-30 12:53:19 +04:00
2017-03-09 21:13:55 +03:00
return sdhEncString ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhClientParamsAnswered ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2018-04-24 23:09:20 +04:00
disconnect ( _connection , & AbstractConnection : : receivedData , nullptr , nullptr ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: receiving Req_client_DH_params answer... " ) ) ;
2014-05-30 12:53:19 +04:00
MTPSet_client_DH_params : : ResponseType res_client_DH_params ;
2018-06-25 19:55:27 +01:00
if ( ! readNotSecureResponse ( res_client_DH_params ) ) {
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
switch ( res_client_DH_params . type ( ) ) {
case mtpc_dh_gen_ok : {
2016-04-08 14:44:35 +04:00
const auto & resDH ( res_client_DH_params . c_dh_gen_ok ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( resDH . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 1 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnew_nonce_hash1 ( ) ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash1 did not match! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & resDH . vnew_nonce_hash1 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( _authKeyData - > new_nonce_buf , 41 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
uint64 salt1 = _authKeyData - > new_nonce . l . l , salt2 = _authKeyData - > server_nonce . l , serverSalt = salt1 ^ salt2 ;
2014-05-30 12:53:19 +04:00
sessionData - > setSalt ( serverSalt ) ;
2018-06-11 21:35:27 +03:00
auto authKey = std : : make_shared < AuthKey > ( AuthKey : : Type : : Generated , BareDcId ( _shiftedDcId ) , _authKeyStrings - > auth_key ) ;
2014-05-30 12:53:19 +04:00
2017-02-22 18:18:26 +03:00
DEBUG_LOG ( ( " AuthKey Info: auth key gen succeed, id: %1, server salt: %2 " ) . arg ( authKey - > keyId ( ) ) . arg ( serverSalt ) ) ;
2014-05-30 12:53:19 +04:00
2017-02-24 20:15:41 +03:00
sessionData - > owner ( ) - > notifyKeyCreated ( std : : move ( authKey ) ) ; // slot will call authKeyCreated()
sessionData - > clear ( _instance ) ;
2014-05-30 12:53:19 +04:00
unlockKey ( ) ;
} return ;
case mtpc_dh_gen_retry : {
2016-04-08 14:44:35 +04:00
const auto & resDH ( res_client_DH_params . c_dh_gen_retry ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( resDH . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 2 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnew_nonce_hash2 ( ) ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash2 did not match! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & resDH . vnew_nonce_hash2 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( _authKeyData - > new_nonce_buf , 41 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > retry_id = _authKeyData - > auth_key_aux_hash ;
2014-05-30 12:53:19 +04:00
} return dhClientParamsSend ( ) ;
case mtpc_dh_gen_fail : {
2016-04-08 14:44:35 +04:00
const auto & resDH ( res_client_DH_params . c_dh_gen_fail ( ) ) ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnonce ( ) ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vnonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2019-07-05 15:38:38 +02:00
if ( resDH . vserver_nonce ( ) ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 3 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2019-07-05 15:38:38 +02:00
if ( resDH . vnew_nonce_hash3 ( ) ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash3 did not match! " ) ) ;
2019-07-05 15:38:38 +02:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash3: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & resDH . vnew_nonce_hash3 ( ) , 16 ) . str ( ) ) . arg ( Logs : : mb ( _authKeyData - > new_nonce_buf , 41 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
LOG ( ( " AuthKey Error: dh_gen_fail received! " ) ) ;
2015-08-08 12:14:47 +03:00
}
lockFinished . unlock ( ) ;
return restart ( ) ;
2014-05-30 12:53:19 +04:00
}
LOG ( ( " AuthKey Error: unknown set_client_DH_params_answer received, typeId = %1 " ) . arg ( res_client_DH_params . type ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : authKeyCreated ( ) {
2014-05-30 12:53:19 +04:00
clearAuthKeyData ( ) ;
2018-04-24 23:09:20 +04:00
connect ( _connection , & AbstractConnection : : receivedData , [ = ] {
handleReceived ( ) ;
} ) ;
2014-05-30 12:53:19 +04:00
if ( sessionData - > getSalt ( ) ) { // else receive salt in bad_server_salt first, then try to send all the requests
2016-03-24 11:57:11 +03:00
setState ( ConnectedState ) ;
2014-05-30 12:53:19 +04:00
if ( restarted ) {
2014-11-25 15:15:29 +03:00
emit resendAllAsync ( ) ;
2014-05-30 12:53:19 +04:00
restarted = false ;
}
}
2016-03-24 13:12:18 +03:00
_pingIdToSend = rand_value < uint64 > ( ) ; // get server_salt
2014-05-30 12:53:19 +04:00
2014-11-22 12:45:04 +03:00
emit needToSendAsync ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : clearAuthKeyData ( ) {
2018-03-27 16:16:00 +04:00
auto zeroMemory = [ ] ( bytes : : span bytes ) {
2017-04-24 15:16:38 +03:00
# ifdef Q_OS_WIN2
SecureZeroMemory ( bytes . data ( ) , bytes . size ( ) ) ;
2017-02-22 18:18:26 +03:00
# else // Q_OS_WIN
2017-04-24 15:16:38 +03:00
auto end = reinterpret_cast < char * > ( bytes . data ( ) ) + bytes . size ( ) ;
for ( volatile auto p = reinterpret_cast < volatile char * > ( bytes . data ( ) ) ; p ! = end ; + + p ) {
2017-02-22 18:18:26 +03:00
* p = 0 ;
}
# endif // Q_OS_WIN
} ;
if ( _authKeyData ) {
2017-04-24 15:16:38 +03:00
zeroMemory ( gsl : : make_span ( reinterpret_cast < gsl : : byte * > ( _authKeyData . get ( ) ) , sizeof ( AuthKeyCreateData ) ) ) ;
2016-12-07 16:32:25 +03:00
_authKeyData . reset ( ) ;
2017-02-22 18:18:26 +03:00
}
if ( _authKeyStrings ) {
2017-04-24 15:16:38 +03:00
if ( ! _authKeyStrings - > dh_prime . empty ( ) ) {
zeroMemory ( _authKeyStrings - > dh_prime ) ;
2017-02-22 18:18:26 +03:00
}
2017-04-24 15:16:38 +03:00
if ( ! _authKeyStrings - > g_a . empty ( ) ) {
zeroMemory ( _authKeyStrings - > g_a ) ;
2017-02-22 18:18:26 +03:00
}
2017-04-24 15:16:38 +03:00
zeroMemory ( _authKeyStrings - > auth_key ) ;
2016-12-07 16:32:25 +03:00
_authKeyStrings . reset ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2018-04-24 23:09:20 +04:00
void ConnectionPrivate : : onError (
not_null < AbstractConnection * > connection ,
qint32 errorCode ) {
2017-02-25 19:44:02 +03:00
if ( errorCode = = - 429 ) {
LOG ( ( " Protocol Error: -429 flood code returned! " ) ) ;
2018-05-24 16:40:19 +03:00
} else if ( errorCode = = - 444 ) {
LOG ( ( " Protocol Error: -444 bad dc_id code returned! " ) ) ;
InvokeQueued ( _instance , [ instance = _instance ] {
instance - > badConfigurationError ( ) ;
} ) ;
2017-02-25 19:44:02 +03:00
}
2018-04-24 23:09:20 +04:00
removeTestConnection ( connection ) ;
if ( _testConnections . empty ( ) ) {
2018-05-17 22:58:00 +03:00
handleError ( errorCode ) ;
2017-03-23 19:11:35 +03:00
} else {
2018-04-24 23:09:20 +04:00
confirmBestConnection ( ) ;
2017-03-23 19:11:35 +03:00
}
}
void ConnectionPrivate : : handleError ( int errorCode ) {
2018-04-23 14:24:03 +04:00
destroyAllConnections ( ) ;
2018-04-24 23:09:20 +04:00
_waitForConnectedTimer . cancel ( ) ;
2015-06-10 15:48:26 +03:00
2017-03-23 19:11:35 +03:00
if ( errorCode = = - 404 ) {
if ( _instance - > isKeysDestroyer ( ) ) {
2017-02-25 19:44:02 +03:00
LOG ( ( " MTP Info: -404 error received on destroying key %1, assuming it is destroyed. " ) . arg ( _shiftedDcId ) ) ;
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
2017-03-23 19:11:35 +03:00
} else if ( _dcType = = DcType : : Cdn ) {
LOG ( ( " MTP Info: -404 error received in CDN dc %1, assuming it was destroyed, recreating. " ) . arg ( _shiftedDcId ) ) ;
clearMessages ( ) ;
keyId = kRecreateKeyId ;
2017-02-25 19:44:02 +03:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
}
2017-03-23 19:11:35 +03:00
MTP_LOG ( _shiftedDcId , ( " Restarting after error in connection, error code: %1... " ) . arg ( errorCode ) ) ;
return restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onReadyData ( ) {
2014-05-30 12:53:19 +04:00
}
2018-06-25 19:55:27 +01:00
template < typename Request >
void ConnectionPrivate : : sendNotSecureRequest ( const Request & request ) {
auto packet = _connection - > prepareNotSecurePacket ( request ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
DEBUG_LOG ( ( " AuthKey Info: sending request, size: %1, time: %3 "
) . arg ( packet . size ( ) - 8
) . arg ( packet [ 5 ] ) ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
const auto bytesSize = packet . size ( ) * sizeof ( mtpPrime ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
_connection - > sendData ( std : : move ( packet ) ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
onSentSome ( bytesSize ) ;
2014-05-30 12:53:19 +04:00
}
2018-06-25 19:55:27 +01:00
template < typename Response >
bool ConnectionPrivate : : readNotSecureResponse ( Response & response ) {
2014-05-30 12:53:19 +04:00
onReceivedSome ( ) ;
2018-06-25 22:18:27 +01:00
if ( _connection - > received ( ) . empty ( ) ) {
LOG ( ( " AuthKey Error: "
" trying to read response from empty received list " ) ) ;
return false ;
}
2017-02-27 12:51:03 +03:00
2018-06-25 22:18:27 +01:00
const auto buffer = std : : move ( _connection - > received ( ) . front ( ) ) ;
_connection - > received ( ) . pop_front ( ) ;
2014-05-30 12:53:19 +04:00
2018-06-25 22:18:27 +01:00
const auto answer = _connection - > parseNotSecureResponse ( buffer ) ;
if ( answer . empty ( ) ) {
return false ;
}
try {
auto from = answer . data ( ) ;
response . read ( from , from + answer . size ( ) ) ;
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
return false ;
}
return true ;
}
2018-06-25 19:55:27 +01:00
bool ConnectionPrivate : : sendSecureRequest (
SecureRequest & & request ,
bool needAnyResponse ,
QReadLocker & lockFinished ) {
request . addPadding ( _connection - > requiresExtendedPadding ( ) ) ;
2014-05-30 12:53:19 +04:00
uint32 fullSize = request - > size ( ) ;
2018-06-25 19:55:27 +01:00
if ( fullSize < 9 ) {
return false ;
}
2014-05-30 12:53:19 +04:00
2018-06-25 19:55:27 +01:00
auto messageSize = request . messageSize ( ) ;
if ( messageSize < 5 | | fullSize < messageSize + 4 ) {
return false ;
}
2016-01-11 23:43:29 +08:00
2017-06-26 20:38:16 +03:00
auto lock = ReadLockerAttempt ( sessionData - > keyMutex ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! lock ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting... " ) . arg ( _shiftedDcId ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
2016-12-31 12:58:56 +04:00
auto key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( _shiftedDcId ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
2017-06-26 20:38:16 +03:00
auto session = sessionData - > getSession ( ) ;
auto salt = sessionData - > getSalt ( ) ;
2014-05-30 12:53:19 +04:00
memcpy ( request - > data ( ) + 0 , & salt , 2 * sizeof ( mtpPrime ) ) ;
memcpy ( request - > data ( ) + 2 , & session , 2 * sizeof ( mtpPrime ) ) ;
2017-06-26 20:38:16 +03:00
auto from = request - > constData ( ) + 4 ;
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Send: " ) + mtpTextSerialize ( from , from + messageSize ) ) ;
2014-05-30 12:53:19 +04:00
2016-12-31 12:58:56 +04:00
# ifdef TDESKTOP_MTPROTO_OLD
uint32 padding = fullSize - 4 - messageSize ;
2014-05-30 12:53:19 +04:00
uchar encryptedSHA [ 20 ] ;
MTPint128 & msgKey ( * ( MTPint128 * ) ( encryptedSHA + 4 ) ) ;
2018-06-25 19:55:27 +01:00
hashSha1 (
request - > constData ( ) ,
( fullSize - padding ) * sizeof ( mtpPrime ) ,
encryptedSHA ) ;
auto packet = _connection - > prepareSecurePacket ( keyId , msgKey , fullSize ) ;
const auto prefix = packet . size ( ) ;
packet . resize ( prefix + fullSize ) ;
aesIgeEncrypt_oldmtp (
request - > constData ( ) ,
& packet [ prefix ] ,
fullSize * sizeof ( mtpPrime ) ,
key ,
msgKey ) ;
2016-12-31 12:58:56 +04:00
# else // TDESKTOP_MTPROTO_OLD
uchar encryptedSHA256 [ 32 ] ;
MTPint128 & msgKey ( * ( MTPint128 * ) ( encryptedSHA256 + 8 ) ) ;
SHA256_CTX msgKeyLargeContext ;
SHA256_Init ( & msgKeyLargeContext ) ;
SHA256_Update ( & msgKeyLargeContext , key - > partForMsgKey ( true ) , 32 ) ;
SHA256_Update ( & msgKeyLargeContext , request - > constData ( ) , fullSize * sizeof ( mtpPrime ) ) ;
SHA256_Final ( encryptedSHA256 , & msgKeyLargeContext ) ;
2018-06-25 19:55:27 +01:00
auto packet = _connection - > prepareSecurePacket ( keyId , msgKey , fullSize ) ;
const auto prefix = packet . size ( ) ;
packet . resize ( prefix + fullSize ) ;
2016-12-31 12:58:56 +04:00
2018-06-25 19:55:27 +01:00
aesIgeEncrypt (
request - > constData ( ) ,
& packet [ prefix ] ,
fullSize * sizeof ( mtpPrime ) ,
key ,
msgKey ) ;
2016-12-31 12:58:56 +04:00
# endif // TDESKTOP_MTPROTO_OLD
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
DEBUG_LOG ( ( " MTP Info: sending request, size: %1, num: %2, time: %3 " ) . arg ( fullSize + 6 ) . arg ( ( * request ) [ 4 ] ) . arg ( ( * request ) [ 5 ] ) ) ;
2018-04-24 23:09:20 +04:00
_connection - > setSentEncrypted ( ) ;
2018-06-25 19:55:27 +01:00
_connection - > sendData ( std : : move ( packet ) ) ;
2014-05-30 12:53:19 +04:00
if ( needAnyResponse ) {
2018-06-25 19:55:27 +01:00
onSentSome ( ( prefix + fullSize ) * sizeof ( mtpPrime ) ) ;
2014-05-30 12:53:19 +04:00
}
return true ;
}
2016-03-24 11:57:11 +03:00
mtpRequestId ConnectionPrivate : : wasSent ( mtpMsgId msgId ) const {
2015-03-12 13:28:10 +03:00
if ( msgId = = _pingMsgId ) return mtpRequestId ( 0xFFFFFFFF ) ;
2014-05-30 12:53:19 +04:00
{
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & haveSent = sessionData - > haveSentMap ( ) ;
const auto i = haveSent . constFind ( msgId ) ;
if ( i ! = haveSent . cend ( ) ) {
return i . value ( ) - > requestId
? i . value ( ) - > requestId
: mtpRequestId ( 0xFFFFFFFF ) ;
}
2014-05-30 12:53:19 +04:00
}
{
QReadLocker locker ( sessionData - > toResendMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & toResend = sessionData - > toResendMap ( ) ;
const auto i = toResend . constFind ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( i ! = toResend . cend ( ) ) return i . value ( ) ;
}
{
QReadLocker locker ( sessionData - > wereAckedMutex ( ) ) ;
2018-06-25 19:55:27 +01:00
const auto & wereAcked = sessionData - > wereAckedMap ( ) ;
const auto i = wereAcked . constFind ( msgId ) ;
2014-05-30 12:53:19 +04:00
if ( i ! = wereAcked . cend ( ) ) return i . value ( ) ;
}
return 0 ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : lockKey ( ) {
2014-05-30 12:53:19 +04:00
unlockKey ( ) ;
sessionData - > keyMutex ( ) - > lockForWrite ( ) ;
myKeyLock = true ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : unlockKey ( ) {
2014-05-30 12:53:19 +04:00
if ( myKeyLock ) {
myKeyLock = false ;
sessionData - > keyMutex ( ) - > unlock ( ) ;
}
}
2016-03-24 11:57:11 +03:00
ConnectionPrivate : : ~ ConnectionPrivate ( ) {
2017-02-22 18:18:26 +03:00
clearAuthKeyData ( ) ;
2018-04-24 23:09:20 +04:00
Assert ( _finished & & _connection = = nullptr & & _testConnections . empty ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : stop ( ) {
2014-11-13 14:27:10 +03:00
QWriteLocker lockFinished ( & sessionDataMutex ) ;
2015-05-14 19:50:04 +03:00
if ( sessionData ) {
if ( myKeyLock ) {
2016-03-24 15:57:10 +03:00
sessionData - > owner ( ) - > notifyKeyCreated ( AuthKeyPtr ( ) ) ; // release key lock, let someone else create it
2015-05-14 19:50:04 +03:00
sessionData - > keyMutex ( ) - > unlock ( ) ;
myKeyLock = false ;
}
2016-02-29 19:53:26 +03:00
sessionData = nullptr ;
2015-05-14 19:50:04 +03:00
}
2014-11-13 14:27:10 +03:00
}
2016-03-24 11:57:11 +03:00
} // namespace internal
2017-04-03 21:28:18 +03:00
2018-03-27 16:16:00 +04:00
bool IsPrimeAndGood ( bytes : : const_span primeBytes , int g ) {
2017-04-24 15:16:38 +03:00
return internal : : IsPrimeAndGood ( primeBytes , g ) ;
}
2018-08-10 22:19:46 +03:00
bool IsGoodModExpFirst ( const openssl : : BigNum & modexp , const openssl : : BigNum & prime ) {
return internal : : IsGoodModExpFirst ( modexp , prime ) ;
}
2018-03-27 16:16:00 +04:00
ModExpFirst CreateModExp ( int g , bytes : : const_span primeBytes , bytes : : const_span randomSeed ) {
2017-04-24 15:16:38 +03:00
return internal : : CreateModExp ( g , primeBytes , randomSeed ) ;
}
2018-03-27 16:16:00 +04:00
bytes : : vector CreateAuthKey ( bytes : : const_span firstBytes , bytes : : const_span randomBytes , bytes : : const_span primeBytes ) {
2017-04-24 15:16:38 +03:00
return internal : : CreateAuthKey ( firstBytes , randomBytes , primeBytes ) ;
2017-04-03 21:28:18 +03:00
}
2016-03-24 11:57:11 +03:00
} // namespace MTP