2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2016-02-08 13:56:18 +03:00
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
2016-03-23 21:43:12 +03:00
# include "mtproto/connection.h"
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>
2016-03-24 15:57:10 +03:00
# include "zlib.h"
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
# include "mtproto/rsa_public_key.h"
using std : : string ;
namespace MTP {
namespace internal {
2016-03-24 11:57:11 +03:00
namespace {
2016-03-23 21:12:07 +03:00
bool parsePQ ( const string & pqStr , string & pStr , string & qStr ) {
if ( pqStr . length ( ) > 8 ) return false ; // more than 64 bit pq
uint64 pq = 0 , p , q ;
const uchar * pqChars = ( const uchar * ) & pqStr [ 0 ] ;
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 ) ;
uchar * pChars = ( uchar * ) & pStr [ 0 ] ;
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( pChars + 3 - i ) = ( uchar ) ( p & 0xFF ) ;
p > > = 8 ;
}
qStr . resize ( 4 ) ;
uchar * qChars = ( uchar * ) & qStr [ 0 ] ;
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( qChars + 3 - i ) = ( uchar ) ( q & 0xFF ) ;
q > > = 8 ;
}
return true ;
}
class BigNumCounter {
public :
bool count ( const void * power , const void * modul , uint32 g , void * gResult , const void * g_a , void * g_aResult ) {
DEBUG_LOG ( ( " BigNum Info: counting g_b = g ^ b % dh_prime and auth_key = g_a ^ b % dh_prime " ) ) ;
uint32 g_be = qToBigEndian ( g ) ;
if (
! BN_bin2bn ( ( const uchar * ) power , 64 * sizeof ( uint32 ) , & bnPower ) | |
! BN_bin2bn ( ( const uchar * ) modul , 64 * sizeof ( uint32 ) , & bnModul ) | |
! BN_bin2bn ( ( const uchar * ) & g_be , sizeof ( uint32 ) , & bn_g ) | |
! BN_bin2bn ( ( const uchar * ) g_a , 64 * sizeof ( uint32 ) , & bn_g_a )
) {
ERR_load_crypto_strings ( ) ;
LOG ( ( " BigNum Error: BN_bin2bn failed, error: %1 " ) . arg ( ERR_error_string ( ERR_get_error ( ) , 0 ) ) ) ;
DEBUG_LOG ( ( " BigNum Error: base %1, power %2, modul %3 " ) . arg ( Logs : : mb ( & g_be , sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( power , 64 * sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( modul , 64 * sizeof ( uint32 ) ) . str ( ) ) ) ;
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
if ( ! BN_mod_exp ( & bnResult , & bn_g , & bnPower , & bnModul , ctx ) ) {
ERR_load_crypto_strings ( ) ;
LOG ( ( " BigNum Error: BN_mod_exp failed, error: %1 " ) . arg ( ERR_error_string ( ERR_get_error ( ) , 0 ) ) ) ;
DEBUG_LOG ( ( " BigNum Error: base %1, power %2, modul %3 " ) . arg ( Logs : : mb ( & g_be , sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( power , 64 * sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( modul , 64 * sizeof ( uint32 ) ) . str ( ) ) ) ;
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
uint32 resultLen = BN_num_bytes ( & bnResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
DEBUG_LOG ( ( " BigNum Error: bad gResult len (%1) " ) . arg ( resultLen ) ) ;
return false ;
}
resultLen = BN_bn2bin ( & bnResult , ( uchar * ) gResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
DEBUG_LOG ( ( " BigNum Error: bad gResult export len (%1) " ) . arg ( resultLen ) ) ;
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
BN_add_word ( & bnResult , 1 ) ; // check g_b < dh_prime - 1
if ( BN_cmp ( & bnResult , & bnModul ) > = 0 ) {
DEBUG_LOG ( ( " BigNum Error: bad g_b >= dh_prime - 1 " ) ) ;
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
if ( ! BN_mod_exp ( & bnResult , & bn_g_a , & bnPower , & bnModul , ctx ) ) {
ERR_load_crypto_strings ( ) ;
LOG ( ( " BigNum Error: BN_mod_exp failed, error: %1 " ) . arg ( ERR_error_string ( ERR_get_error ( ) , 0 ) ) ) ;
DEBUG_LOG ( ( " BigNum Error: base %1, power %2, modul %3 " ) . arg ( Logs : : mb ( & g_be , sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( power , 64 * sizeof ( uint32 ) ) . str ( ) ) . arg ( Logs : : mb ( modul , 64 * sizeof ( uint32 ) ) . str ( ) ) ) ;
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
resultLen = BN_num_bytes ( & bnResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
DEBUG_LOG ( ( " BigNum Error: bad g_aResult len (%1) " ) . arg ( resultLen ) ) ;
return false ;
}
resultLen = BN_bn2bin ( & bnResult , ( uchar * ) g_aResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
DEBUG_LOG ( ( " BigNum Error: bad g_aResult export len (%1) " ) . arg ( resultLen ) ) ;
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
BN_add_word ( & bn_g_a , 1 ) ; // check g_a < dh_prime - 1
if ( BN_cmp ( & bn_g_a , & bnModul ) > = 0 ) {
DEBUG_LOG ( ( " BigNum Error: bad g_a >= dh_prime - 1 " ) ) ;
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
return true ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
BigNumCounter ( ) : ctx ( BN_CTX_new ( ) ) {
BN_init ( & bnPower ) ;
BN_init ( & bnModul ) ;
BN_init ( & bn_g ) ;
BN_init ( & bn_g_a ) ;
BN_init ( & bnResult ) ;
}
~ BigNumCounter ( ) {
BN_CTX_free ( ctx ) ;
BN_clear_free ( & bnPower ) ;
BN_clear_free ( & bnModul ) ;
BN_clear_free ( & bn_g ) ;
BN_clear_free ( & bn_g_a ) ;
BN_clear_free ( & bnResult ) ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
private :
BIGNUM bnPower , bnModul , bn_g , bn_g_a , bnResult ;
BN_CTX * ctx ;
} ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
// Miller-Rabin primality test
class BigNumPrimeTest {
public :
2016-01-11 23:43:29 +08:00
2016-03-23 21:12:07 +03:00
bool isPrimeAndGood ( const void * pData , uint32 iterCount , int32 g ) {
if ( ! memcmp ( pData , " \xC7 \x1C \xAE \xB9 \xC6 \xB1 \xC9 \x04 \x8E \x6C \x52 \x2F \x70 \xF1 \x3F \x73 \x98 \x0D \x40 \x23 \x8E \x3E \x21 \xC1 \x49 \x34 \xD0 \x37 \x56 \x3D \x93 \x0F \x48 \x19 \x8A \x0A \xA7 \xC1 \x40 \x58 \x22 \x94 \x93 \xD2 \x25 \x30 \xF4 \xDB \xFA \x33 \x6F \x6E \x0A \xC9 \x25 \x13 \x95 \x43 \xAE \xD4 \x4C \xCE \x7C \x37 \x20 \xFD \x51 \xF6 \x94 \x58 \x70 \x5A \xC6 \x8C \xD4 \xFE \x6B \x6B \x13 \xAB \xDC \x97 \x46 \x51 \x29 \x69 \x32 \x84 \x54 \xF1 \x8F \xAF \x8C \x59 \x5F \x64 \x24 \x77 \xFE \x96 \xBB \x2A \x94 \x1D \x5B \xCD \x1D \x4A \xC8 \xCC \x49 \x88 \x07 \x08 \xFA \x9B \x37 \x8E \x3C \x4F \x3A \x90 \x60 \xBE \xE6 \x7C \xF9 \xA4 \xA4 \xA6 \x95 \x81 \x10 \x51 \x90 \x7E \x16 \x27 \x53 \xB5 \x6B \x0F \x6B \x41 \x0D \xBA \x74 \xD8 \xA8 \x4B \x2A \x14 \xB3 \x14 \x4E \x0E \xF1 \x28 \x47 \x54 \xFD \x17 \xED \x95 \x0D \x59 \x65 \xB4 \xB9 \xDD \x46 \x58 \x2D \xB1 \x17 \x8D \x16 \x9C \x6B \xC4 \x65 \xB0 \xD6 \xFF \x9C \xA3 \x92 \x8F \xEF \x5B \x9A \xE4 \xE4 \x18 \xFC \x15 \xE8 \x3E \xBE \xA0 \xF8 \x7F \xA9 \xFF \x5E \xED \x70 \x05 \x0D \xED \x28 \x49 \xF4 \x7B \xF9 \x59 \xD9 \x56 \x85 \x0C \xE9 \x29 \x85 \x1F \x0D \x81 \x15 \xF6 \x35 \xB1 \x05 \xEE \x2E \x4E \x15 \xD0 \x4B \x24 \x54 \xBF \x6F \x4F \xAD \xF0 \x34 \xB1 \x04 \x03 \x11 \x9C \xD8 \xE3 \xB9 \x2F \xCC \x5B " , 256 ) ) {
if ( g = = 3 | | g = = 4 | | g = = 5 | | g = = 7 ) {
return true ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-23 21:12:07 +03:00
if (
! BN_bin2bn ( ( const uchar * ) pData , 64 * sizeof ( uint32 ) , & bnPrime )
) {
ERR_load_crypto_strings ( ) ;
LOG ( ( " BigNum PT Error: BN_bin2bn failed, error: %1 " ) . arg ( ERR_error_string ( ERR_get_error ( ) , 0 ) ) ) ;
DEBUG_LOG ( ( " BigNum PT Error: prime %1 " ) . arg ( Logs : : mb ( pData , 64 * sizeof ( uint32 ) ) . str ( ) ) ) ;
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
int32 numBits = BN_num_bits ( & bnPrime ) ;
if ( numBits ! = 2048 ) {
LOG ( ( " BigNum PT Error: BN_bin2bn failed, bad dh_prime num bits: %1 " ) . arg ( numBits ) ) ;
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
if ( BN_is_prime_ex ( & bnPrime , MTPMillerRabinIterCount , ctx , NULL ) = = 0 ) {
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
switch ( g ) {
case 2 : {
int32 mod8 = BN_mod_word ( & bnPrime , 8 ) ;
if ( mod8 ! = 7 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod8: %2 " ) . arg ( g ) . arg ( mod8 ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
2016-03-23 21:12:07 +03:00
} break ;
case 3 : {
int32 mod3 = BN_mod_word ( & bnPrime , 3 ) ;
if ( mod3 ! = 2 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod3: %2 " ) . arg ( g ) . arg ( mod3 ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
2016-03-23 21:12:07 +03:00
} break ;
case 4 : break ;
case 5 : {
int32 mod5 = BN_mod_word ( & bnPrime , 5 ) ;
if ( mod5 ! = 1 & & mod5 ! = 4 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod5: %2 " ) . arg ( g ) . arg ( mod5 ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
2016-03-23 21:12:07 +03:00
} break ;
case 6 : {
int32 mod24 = BN_mod_word ( & bnPrime , 24 ) ;
if ( mod24 ! = 19 & & mod24 ! = 23 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod24: %2 " ) . arg ( g ) . arg ( mod24 ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
2015-03-02 15:34:16 +03:00
}
2016-03-23 21:12:07 +03:00
} break ;
case 7 : {
int32 mod7 = BN_mod_word ( & bnPrime , 7 ) ;
if ( mod7 ! = 3 & & mod7 ! = 5 & & mod7 ! = 6 ) {
LOG ( ( " BigNum PT Error: bad g value: %1, mod7: %2 " ) . arg ( g ) . arg ( mod7 ) ) ;
2015-03-02 15:34:16 +03:00
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
} break ;
default :
LOG ( ( " BigNum PT Error: bad g value: %1 " ) . arg ( g ) ) ;
return false ;
break ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
BN_sub_word ( & bnPrime , 1 ) ; // (p - 1) / 2
BN_div_word ( & bnPrime , 2 ) ;
if ( BN_is_prime_ex ( & bnPrime , MTPMillerRabinIterCount , ctx , NULL ) = = 0 ) {
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
return true ;
}
BigNumPrimeTest ( ) : ctx ( BN_CTX_new ( ) ) {
BN_init ( & bnPrime ) ;
}
~ BigNumPrimeTest ( ) {
BN_CTX_free ( ctx ) ;
BN_clear_free ( & bnPrime ) ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
private :
BIGNUM bnPrime ;
BN_CTX * ctx ;
} ;
2014-05-30 12:53:19 +04:00
2016-03-24 11:57:11 +03:00
typedef QMap < uint64 , RSAPublicKey > RSAPublicKeys ;
2016-03-23 21:12:07 +03:00
RSAPublicKeys InitRSAPublicKeys ( ) {
DEBUG_LOG ( ( " MTP Info: RSA public keys list creation " ) ) ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
RSAPublicKeys result ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
int keysCount ;
const char * * keys = cPublicRSAKeys ( keysCount ) ;
for ( int i = 0 ; i < keysCount ; + + i ) {
RSAPublicKey key ( keys [ i ] ) ;
if ( key . isValid ( ) ) {
result . insert ( key . getFingerPrint ( ) , key ) ;
} else {
LOG ( ( " MTP Error: could not read this public RSA key: " ) ) ;
LOG ( ( keys [ i ] ) ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-23 21:12:07 +03:00
DEBUG_LOG ( ( " MTP Info: read %1 public RSA keys " ) . arg ( result . size ( ) ) ) ;
return result ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
} // namespace
2016-03-23 21:12:07 +03:00
2016-03-24 11:57:11 +03:00
uint32 ThreadIdIncrement = 0 ;
2016-02-29 19:53:26 +03:00
2016-03-24 11:57:11 +03:00
Thread : : Thread ( ) : QThread ( nullptr )
, _threadId ( + + ThreadIdIncrement ) {
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
uint32 Thread : : getThreadId ( ) const {
2016-02-29 19:53:26 +03:00
return _threadId ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
Thread : : ~ Thread ( ) {
2016-02-29 19:53:26 +03:00
}
2016-03-24 11:57:11 +03:00
Connection : : Connection ( ) : thread ( nullptr ) , data ( nullptr ) {
2014-05-30 12:53:19 +04:00
}
2016-10-24 18:36:17 +03:00
int32 Connection : : prepare ( SessionData * sessionData , int32 dc ) {
2016-02-29 19:53:26 +03:00
t_assert ( thread = = nullptr & & data = = nullptr ) ;
2014-05-30 12:53:19 +04:00
2016-03-24 11:57:11 +03:00
thread = new Thread ( ) ;
data = new ConnectionPrivate ( thread , this , sessionData , dc ) ;
2014-05-30 12:53:19 +04:00
dc = data - > getDC ( ) ;
if ( ! dc ) {
2014-11-24 16:21:27 +03:00
delete data ;
2016-02-29 19:53:26 +03:00
data = nullptr ;
2014-11-24 16:21:27 +03:00
delete thread ;
2016-02-29 19:53:26 +03:00
thread = nullptr ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
2016-10-24 18:36:17 +03:00
return dc ;
}
2016-02-29 19:53:26 +03:00
2016-10-24 18:36:17 +03:00
void Connection : : start ( ) {
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
2016-03-24 11:57:11 +03:00
void Connection : : kill ( ) {
2016-02-29 19:53:26 +03:00
t_assert ( data ! = nullptr & & thread ! = nullptr ) ;
data - > stop ( ) ;
data = nullptr ; // will be deleted in thread::finished signal
thread - > quit ( ) ;
2016-03-24 11:57:11 +03:00
queueQuittingConnection ( this ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void Connection : : waitTillFinish ( ) {
2016-02-29 19:53:26 +03:00
t_assert ( data = = nullptr & & thread ! = nullptr ) ;
2016-03-01 05:36:23 +03:00
DEBUG_LOG ( ( " Waiting for connectionThread to finish " ) ) ;
2016-02-29 19:53:26 +03:00
thread - > wait ( ) ;
delete thread ;
thread = nullptr ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
int32 Connection : : state ( ) const {
2016-02-29 19:53:26 +03:00
t_assert ( data ! = nullptr & & thread ! = nullptr ) ;
2014-05-30 12:53:19 +04:00
return data - > getState ( ) ;
}
2016-03-24 11:57:11 +03:00
QString Connection : : transport ( ) const {
2016-02-29 19:53:26 +03:00
t_assert ( data ! = nullptr & & thread ! = nullptr ) ;
2014-05-30 12:53:19 +04:00
return data - > transport ( ) ;
}
2016-03-24 11:57:11 +03:00
Connection : : ~ Connection ( ) {
2016-02-29 19:53:26 +03:00
t_assert ( data = = nullptr & & thread = = nullptr ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : createConn ( bool createIPv4 , bool createIPv6 ) {
2015-06-10 15:48:26 +03:00
destroyConn ( ) ;
if ( createIPv4 ) {
2015-06-25 21:04:40 +03:00
QWriteLocker lock ( & stateConnMutex ) ;
2016-03-24 13:55:42 +03:00
_conn4 = AbstractConnection : : create ( thread ( ) ) ;
2015-06-10 15:48:26 +03:00
connect ( _conn4 , SIGNAL ( error ( bool ) ) , this , SLOT ( onError4 ( bool ) ) ) ;
connect ( _conn4 , SIGNAL ( receivedSome ( ) ) , this , SLOT ( onReceivedSome ( ) ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-10 15:48:26 +03:00
if ( createIPv6 ) {
2015-06-25 21:04:40 +03:00
QWriteLocker lock ( & stateConnMutex ) ;
2016-03-24 13:55:42 +03:00
_conn6 = AbstractConnection : : create ( thread ( ) ) ;
2015-06-10 15:48:26 +03:00
connect ( _conn6 , SIGNAL ( error ( bool ) ) , this , SLOT ( onError6 ( bool ) ) ) ;
connect ( _conn6 , SIGNAL ( receivedSome ( ) ) , this , SLOT ( onReceivedSome ( ) ) ) ;
2014-05-30 12:53:19 +04:00
}
firstSentAt = 0 ;
if ( oldConnection ) {
oldConnection = false ;
DEBUG_LOG ( ( " This connection marked as not old! " ) ) ;
}
oldConnectionTimer . start ( MTPConnectionOldTimeout ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : destroyConn ( AbstractConnection * * conn ) {
2015-06-10 15:48:26 +03:00
if ( conn ) {
2016-03-24 11:57:11 +03:00
AbstractConnection * toDisconnect = nullptr ;
2015-06-29 15:25:28 +03:00
{
QWriteLocker lock ( & stateConnMutex ) ;
if ( * conn ) {
toDisconnect = * conn ;
2016-03-24 11:57:11 +03:00
disconnect ( * conn , SIGNAL ( connected ( ) ) , nullptr , nullptr ) ;
disconnect ( * conn , SIGNAL ( disconnected ( ) ) , nullptr , nullptr ) ;
disconnect ( * conn , SIGNAL ( error ( bool ) ) , nullptr , nullptr ) ;
disconnect ( * conn , SIGNAL ( receivedData ( ) ) , nullptr , nullptr ) ;
disconnect ( * conn , SIGNAL ( receivedSome ( ) ) , nullptr , nullptr ) ;
2016-03-14 12:48:53 +03:00
* conn = nullptr ;
2015-06-29 15:25:28 +03:00
}
}
if ( toDisconnect ) {
toDisconnect - > disconnectFromServer ( ) ;
toDisconnect - > deleteLater ( ) ;
2015-06-10 15:48:26 +03:00
}
} else {
destroyConn ( & _conn4 ) ;
destroyConn ( & _conn6 ) ;
2016-03-14 12:48:53 +03:00
_conn = nullptr ;
2015-06-10 15:48:26 +03:00
}
}
2016-03-24 11:57:11 +03:00
ConnectionPrivate : : ConnectionPrivate ( QThread * thread , Connection * owner , SessionData * data , uint32 _dc ) : QObject ( nullptr )
, _state ( DisconnectedState )
2016-02-29 19:53:26 +03:00
, _needSessionReset ( false )
, dc ( _dc )
, _owner ( owner )
2016-03-14 12:48:53 +03:00
, _conn ( nullptr )
, _conn4 ( nullptr )
, _conn6 ( nullptr )
2016-02-29 19:53:26 +03:00
, retryTimeout ( 1 )
, oldConnection ( true )
, _waitForReceived ( MTPMinReceiveDelay )
, _waitForConnected ( MTPMinConnectDelay )
, firstSentAt ( - 1 )
, _pingId ( 0 )
, _pingIdToSend ( 0 )
, _pingSendAt ( 0 )
, _pingMsgId ( 0 )
, restarted ( false )
, _finished ( false )
, keyId ( 0 )
2015-08-08 12:14:47 +03:00
// , sessionDataMutex(QReadWriteLock::Recursive)
2016-02-29 19:53:26 +03:00
, sessionData ( data )
, myKeyLock ( false )
, authKeyData ( 0 )
, authKeyStrings ( 0 ) {
2014-05-30 12:53:19 +04:00
oldConnectionTimer . moveToThread ( thread ) ;
2015-06-10 15:48:26 +03:00
_waitForConnectedTimer . moveToThread ( thread ) ;
_waitForReceivedTimer . moveToThread ( thread ) ;
_waitForIPv4Timer . moveToThread ( thread ) ;
2015-03-12 13:28:10 +03:00
_pingSender . moveToThread ( thread ) ;
2014-05-30 12:53:19 +04:00
retryTimer . moveToThread ( thread ) ;
moveToThread ( thread ) ;
if ( ! dc ) {
2016-03-24 15:57:10 +03:00
QReadLocker lock ( dcOptionsMutex ( ) ) ;
2016-04-08 14:44:35 +04:00
const auto & options ( Global : : DcOptions ( ) ) ;
2015-03-02 15:34:16 +03:00
if ( options . isEmpty ( ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " MTP Error: connect failed, no DCs " ) ) ;
dc = 0 ;
return ;
}
2015-03-02 15:34:16 +03:00
dc = options . cbegin ( ) . value ( ) . id ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: searching for any DC, %1 selected... " ) . arg ( dc ) ) ;
2014-05-30 12:53:19 +04:00
}
connect ( thread , SIGNAL ( started ( ) ) , this , SLOT ( socketStart ( ) ) ) ;
connect ( thread , SIGNAL ( finished ( ) ) , this , SLOT ( doFinish ( ) ) ) ;
2016-03-25 21:30:19 +03:00
connect ( this , SIGNAL ( finished ( Connection * ) ) , globalSlotCarrier ( ) , SLOT ( connectionFinished ( Connection * ) ) , Qt : : QueuedConnection ) ;
2014-05-30 12:53:19 +04:00
connect ( & retryTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( retryByTimer ( ) ) ) ;
2015-06-10 15:48:26 +03:00
connect ( & _waitForConnectedTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( onWaitConnectedFailed ( ) ) ) ;
connect ( & _waitForReceivedTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( onWaitReceivedFailed ( ) ) ) ;
connect ( & _waitForIPv4Timer , SIGNAL ( timeout ( ) ) , this , SLOT ( onWaitIPv4Failed ( ) ) ) ;
2014-05-30 12:53:19 +04:00
connect ( & oldConnectionTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( onOldConnection ( ) ) ) ;
2015-03-12 13:28:10 +03:00
connect ( & _pingSender , SIGNAL ( timeout ( ) ) , this , SLOT ( onPingSender ( ) ) ) ;
2014-11-24 16:21:27 +03:00
connect ( sessionData - > owner ( ) , SIGNAL ( authKeyCreated ( ) ) , this , SLOT ( updateAuthKey ( ) ) , Qt : : QueuedConnection ) ;
2014-05-30 12:53:19 +04:00
2014-11-24 16:21:27 +03:00
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 ;
2014-11-26 09:05:01 -08: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 ) ;
2014-11-24 16:21:27 +03:00
connect ( this , SIGNAL ( sendAnythingAsync ( quint64 ) ) , sessionData - > owner ( ) , SLOT ( sendAnything ( quint64 ) ) , 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 ) ;
connect ( this , SIGNAL ( resendAsync ( quint64 , quint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resend ( quint64 , quint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( resendManyAsync ( QVector < quint64 > , quint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resendMany ( QVector < quint64 > , quint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( resendAllAsync ( ) ) , sessionData - > owner ( ) , SLOT ( resendAll ( ) ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onConfigLoaded ( ) {
2014-05-30 12:53:19 +04:00
socketStart ( true ) ;
}
2016-03-24 11:57:11 +03:00
int32 ConnectionPrivate : : getDC ( ) const {
2014-05-30 12:53:19 +04:00
return dc ;
}
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 ) {
if ( retryTimer . isActive ( ) ) {
2014-11-12 23:30:26 +03:00
result = int32 ( getms ( true ) - 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 ) ;
if ( ( ! _conn4 & & ! _conn6 ) | | ( _conn4 & & _conn6 ) | | ( _state < 0 ) ) {
2014-05-30 12:53:19 +04:00
return QString ( ) ;
}
2015-06-25 21:04:40 +03:00
QString result = ( _conn4 ? _conn4 : _conn6 ) - > transport ( ) ;
2016-08-26 22:49:18 -06:00
if ( ! result . isEmpty ( ) & & Global : : TryIPv6 ( ) ) result + = ( _conn4 ? " /IPv4 " : " /IPv6 " ) ;
2015-06-25 21:04:40 +03:00
return result ;
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 ) {
retryTimeout = - state ;
retryTimer . start ( retryTimeout ) ;
2014-11-12 23:30:26 +03:00
retryWillFinish = getms ( true ) + 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 ( ) ) ;
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpPreRequestMap & toSend ( sessionData - > toSendMap ( ) ) ;
mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
mtpMsgId newId = msgid ( ) ;
mtpRequestMap setSeqNumbers ;
typedef QMap < mtpMsgId , mtpMsgId > Replaces ;
Replaces replaces ;
for ( mtpRequestMap : : const_iterator i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) {
if ( ! mtpRequestData : : isSentContainer ( i . value ( ) ) ) {
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 ;
}
MTP_LOG ( dc , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
replaces . insert ( id , newId ) ;
id = newId ;
* ( mtpMsgId * ) ( i . value ( ) - > data ( ) + 4 ) = id ;
}
setSeqNumbers . insert ( id , i . value ( ) ) ;
}
}
for ( mtpRequestIdsMap : : const_iterator i = toResend . cbegin ( ) , e = toResend . cend ( ) ; i ! = e ; + + i ) { // collect all non-container requests
mtpPreRequestMap : : const_iterator j = toSend . constFind ( i . value ( ) ) ;
if ( j = = toSend . cend ( ) ) continue ;
if ( ! mtpRequestData : : isSentContainer ( j . value ( ) ) ) {
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 ;
}
MTP_LOG ( dc , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
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 ) ;
for ( mtpRequestMap : : const_iterator i = setSeqNumbers . cbegin ( ) , e = setSeqNumbers . cend ( ) ; i ! = e ; + + i ) { // generate new seq_numbers
bool wasNeedAck = ( * ( i . value ( ) - > data ( ) + 6 ) & 1 ) ;
* ( i . value ( ) - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( wasNeedAck ) ;
}
if ( ! replaces . isEmpty ( ) ) {
for ( Replaces : : const_iterator i = replaces . cbegin ( ) , e = replaces . cend ( ) ; i ! = e ; + + i ) { // replace msgIds keys in all data structs
mtpRequestMap : : iterator j = haveSent . find ( i . key ( ) ) ;
if ( j ! = haveSent . cend ( ) ) {
mtpRequest req = j . value ( ) ;
haveSent . erase ( j ) ;
haveSent . insert ( i . value ( ) , req ) ;
}
mtpRequestIdsMap : : iterator k = toResend . find ( i . key ( ) ) ;
if ( k ! = toResend . cend ( ) ) {
mtpRequestId req = k . value ( ) ;
toResend . erase ( k ) ;
toResend . insert ( i . value ( ) , req ) ;
}
k = wereAcked . find ( i . key ( ) ) ;
if ( k ! = wereAcked . cend ( ) ) {
mtpRequestId req = k . value ( ) ;
wereAcked . erase ( k ) ;
wereAcked . insert ( i . value ( ) , req ) ;
}
}
for ( mtpRequestMap : : const_iterator i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) { // replace msgIds in saved containers
if ( mtpRequestData : : isSentContainer ( i . value ( ) ) ) {
mtpMsgId * ids = ( mtpMsgId * ) ( i . value ( ) - > data ( ) + 8 ) ;
for ( uint32 j = 0 , l = ( i . value ( ) - > size ( ) - 8 ) > > 1 ; j < l ; + + j ) {
Replaces : : const_iterator k = replaces . constFind ( ids [ j ] ) ;
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
}
2016-03-24 11:57:11 +03:00
mtpMsgId ConnectionPrivate : : prepareToSend ( mtpRequest & 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 ( ) ) ;
mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpRequestIdsMap : : iterator i = toResend . find ( msgId ) ;
if ( i ! = toResend . cend ( ) ) {
toResend . erase ( i ) ;
}
} else {
2014-08-01 15:09:46 +04:00
msgId = * ( mtpMsgId * ) ( request - > data ( ) + 4 ) = currentLastId ;
2014-05-30 12:53:19 +04:00
* ( request - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( mtpRequestData : : needAck ( request ) ) ;
}
return msgId ;
}
2016-03-24 11:57:11 +03:00
mtpMsgId ConnectionPrivate : : replaceMsgId ( mtpRequest & 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()
mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
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
2016-01-11 23:43:29 +08:00
2014-08-01 15:09:46 +04:00
newId = m ;
}
mtpRequestIdsMap : : iterator i = toResend . find ( oldMsgId ) ;
if ( i ! = toResend . cend ( ) ) {
mtpRequestId req = i . value ( ) ;
toResend . erase ( i ) ;
toResend . insert ( newId , req ) ;
}
mtpRequestIdsMap : : iterator j = wereAcked . find ( oldMsgId ) ;
if ( j ! = wereAcked . cend ( ) ) {
mtpRequestId req = j . value ( ) ;
wereAcked . erase ( j ) ;
wereAcked . insert ( newId , req ) ;
}
mtpRequestMap : : iterator k = haveSent . find ( oldMsgId ) ;
if ( k ! = haveSent . cend ( ) ) {
mtpRequest req = k . value ( ) ;
haveSent . erase ( k ) ;
haveSent . insert ( newId , req ) ;
}
for ( k = haveSent . begin ( ) ; k ! = haveSent . cend ( ) ; + + k ) {
mtpRequest req ( k . value ( ) ) ;
if ( mtpRequestData : : isSentContainer ( req ) ) {
mtpMsgId * ids = ( mtpMsgId * ) ( req - > data ( ) + 8 ) ;
for ( uint32 i = 0 , l = ( req - > size ( ) - 8 ) > > 1 ; i < l ; + + i ) {
if ( ids [ i ] = = oldMsgId ) {
ids [ i ] = newId ;
}
}
}
}
} else {
* ( request - > data ( ) + 6 ) = sessionData - > nextRequestSeqNumber ( mtpRequestData : : needAck ( request ) ) ;
}
* ( mtpMsgId * ) ( request - > data ( ) + 4 ) = newId ;
}
return newId ;
}
2016-03-24 11:57:11 +03:00
mtpMsgId ConnectionPrivate : : placeToContainer ( mtpRequest & toSendRequest , mtpMsgId & bigMsgId , mtpMsgId * & haveSentArr , mtpRequest & 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 ;
uint32 from = toSendRequest - > size ( ) , len = mtpRequestData : : messageSize ( req ) ;
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 ) ;
2015-06-10 15:48:26 +03:00
if ( ! sessionData | | ! _conn ) {
2014-11-13 14:27:10 +03:00
return ;
}
2014-05-30 12:53:19 +04:00
2014-11-15 02:23:35 +03:00
bool needsLayer = ! sessionData - > layerWasInited ( ) ;
2015-03-12 13:28:10 +03:00
int32 state = getState ( ) ;
2016-03-24 11:57:11 +03:00
bool prependOnly = ( state ! = ConnectedState ) ;
2014-11-05 20:43:32 +03:00
mtpRequest pingRequest ;
2016-03-24 11:57:11 +03:00
if ( dc = = bareDcId ( dc ) ) { // main session
2015-04-16 17:59:42 +03:00
if ( ! prependOnly & & ! _pingIdToSend & & ! _pingId & & _pingSendAt < = getms ( true ) ) {
2016-03-24 13:12:18 +03:00
_pingIdToSend = rand_value < mtpPingId > ( ) ;
2015-03-12 13:28:10 +03:00
}
}
if ( _pingIdToSend ) {
2016-03-24 11:57:11 +03:00
if ( prependOnly | | dc ! = bareDcId ( dc ) ) {
2015-03-12 13:28:10 +03:00
MTPPing ping ( MTPping ( MTP_long ( _pingIdToSend ) ) ) ;
2016-03-25 21:30:19 +03:00
uint32 pingSize = ping . innerLength ( ) > > 2 ; // copy from Session::send
2015-03-12 13:28:10 +03:00
pingRequest = mtpRequestData : : prepare ( pingSize ) ;
ping . write ( * pingRequest ) ;
DEBUG_LOG ( ( " MTP Info: sending ping, ping_id: %1 " ) . arg ( _pingIdToSend ) ) ;
} else {
MTPPing_delay_disconnect ping ( MTP_long ( _pingIdToSend ) , MTP_int ( MTPPingDelayDisconnect ) ) ;
2016-03-25 21:30:19 +03:00
uint32 pingSize = ping . innerLength ( ) > > 2 ; // copy from Session::send
2015-03-12 13:28:10 +03:00
pingRequest = mtpRequestData : : prepare ( pingSize ) ;
ping . write ( * pingRequest ) ;
DEBUG_LOG ( ( " MTP Info: sending ping_delay_disconnect, ping_id: %1 " ) . arg ( _pingIdToSend ) ) ;
}
2014-05-30 12:53:19 +04:00
2015-04-16 17:59:42 +03:00
pingRequest - > msDate = getms ( true ) ; // > 0 - can send without container
_pingSendAt = pingRequest - > msDate + ( MTPPingSendAfterAuto * 1000ULL ) ;
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
2016-03-24 11:57:11 +03:00
if ( dc = = bareDcId ( dc ) & & ! prependOnly ) { // main session
2015-03-13 16:01:25 +03:00
_pingSender . start ( MTPPingSendAfter * 1000 ) ;
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 ) {
DEBUG_LOG ( ( " MTP Info: dc %1 not sending, waiting for Connected state, state: %2 " ) . arg ( dc ) . 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 {
DEBUG_LOG ( ( " MTP Info: dc %1 trying to send after ping, state: %2 " ) . arg ( dc ) . arg ( state ) ) ;
2014-05-30 12:53:19 +04:00
}
}
2015-03-12 13:28:10 +03:00
mtpRequest ackRequest , resendRequest , stateRequest , httpWaitRequest ;
2014-11-05 20:43:32 +03:00
if ( ! prependOnly & & ! ackRequestData . isEmpty ( ) ) {
MTPMsgsAck ack ( MTP_msgs_ack ( MTP_vector < MTPlong > ( ackRequestData ) ) ) ;
2014-11-15 02:23:35 +03:00
ackRequest = mtpRequestData : : prepare ( ack . innerLength ( ) > > 2 ) ;
2014-11-05 20:43:32 +03:00
ack . write ( * ackRequest ) ;
2014-11-12 23:30:26 +03:00
ackRequest - > msDate = getms ( true ) ; // > 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 ( ) ) {
MTPMsgResendReq resend ( MTP_msg_resend_req ( MTP_vector < MTPlong > ( resendRequestData ) ) ) ;
2014-11-15 02:23:35 +03:00
resendRequest = mtpRequestData : : prepare ( resend . innerLength ( ) > > 2 ) ;
2014-11-05 20:43:32 +03:00
resend . write ( * resendRequest ) ;
2014-11-12 23:30:26 +03:00
resendRequest - > msDate = getms ( true ) ; // > 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 ( ) ) ;
mtpMsgIdsSet & ids ( sessionData - > stateRequestMap ( ) ) ;
if ( ! ids . isEmpty ( ) ) {
stateReq . reserve ( ids . size ( ) ) ;
for ( mtpMsgIdsSet : : const_iterator i = ids . cbegin ( ) , e = ids . cend ( ) ; i ! = e ; + + i ) {
stateReq . push_back ( MTP_long ( i . key ( ) ) ) ;
}
}
ids . clear ( ) ;
}
if ( ! stateReq . isEmpty ( ) ) {
MTPMsgsStateReq req ( MTP_msgs_state_req ( MTP_vector < MTPlong > ( stateReq ) ) ) ;
2014-11-15 02:23:35 +03:00
stateRequest = mtpRequestData : : prepare ( req . innerLength ( ) > > 2 ) ;
2014-11-05 20:43:32 +03:00
req . write ( * stateRequest ) ;
2014-11-12 23:30:26 +03:00
stateRequest - > msDate = getms ( true ) ; // > 0 - can send without container
2014-11-05 20:43:32 +03:00
stateRequest - > requestId = reqid ( ) ; // add to haveSent / wereAcked maps, but don't add to requestMap
}
2015-06-10 15:48:26 +03:00
if ( _conn - > usingHttpWait ( ) ) {
2015-03-12 13:28:10 +03:00
MTPHttpWait req ( MTP_http_wait ( MTP_int ( 100 ) , MTP_int ( 30 ) , MTP_int ( 25000 ) ) ) ;
httpWaitRequest = mtpRequestData : : prepare ( req . innerLength ( ) > > 2 ) ;
req . write ( * httpWaitRequest ) ;
httpWaitRequest - > msDate = getms ( true ) ; // > 0 - can send without container
httpWaitRequest - > requestId = 0 ; // dont add to haveSent / wereAcked maps
}
2014-11-05 20:43:32 +03:00
}
2014-11-15 02:23:35 +03:00
MTPInitConnection < mtpRequest > initWrapperImpl , * initWrapper = & initWrapperImpl ;
int32 initSize = 0 , initSizeInInts = 0 ;
if ( needsLayer ) {
2016-05-20 19:01:06 +03:00
initWrapperImpl = MTPInitConnection < mtpRequest > ( MTP_int ( ApiId ) , MTP_string ( cApiDeviceModel ( ) ) , MTP_string ( cApiSystemVersion ( ) ) , MTP_string ( cApiAppVersion ( ) ) , MTP_string ( Sandbox : : LangSystemISO ( ) ) , mtpRequest ( ) ) ;
2014-11-15 02:23:35 +03:00
initSizeInInts = ( initWrapper - > innerLength ( ) > > 2 ) + 2 ;
initSize = initSizeInInts * sizeof ( mtpPrime ) ;
}
2014-05-30 12:53:19 +04:00
bool needAnyResponse = false ;
mtpRequest toSendRequest ;
{
QWriteLocker locker1 ( sessionData - > toSendMutex ( ) ) ;
mtpPreRequestMap toSendDummy , & toSend ( prependOnly ? toSendDummy : sessionData - > toSendMap ( ) ) ;
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
2015-03-12 13:28:10 +03:00
mtpRequest 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 ) {
if ( mtpRequestData : : needAck ( toSendRequest ) ) {
2014-11-12 23:30:26 +03:00
toSendRequest - > msDate = mtpRequestData : : isStateRequest ( toSendRequest ) ? 0 : getms ( true ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ;
2014-11-05 20:43:32 +03:00
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
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 ) {
2014-11-15 02:23:35 +03:00
int32 toSendSize = toSendRequest . innerLength ( ) > > 2 ;
2014-11-05 20:43:32 +03:00
mtpRequest wrappedRequest ( mtpRequestData : : prepare ( toSendSize , toSendSize + 3 ) ) ; // cons + msg_id
wrappedRequest - > resize ( 4 ) ;
memcpy ( wrappedRequest - > data ( ) , toSendRequest - > constData ( ) , 4 * sizeof ( mtpPrime ) ) ;
2016-03-24 11:57:11 +03:00
wrapInvokeAfter ( wrappedRequest , toSendRequest , haveSent ) ;
2014-11-05 20:43:32 +03:00
toSendRequest = wrappedRequest ;
}
2014-11-15 02:23:35 +03:00
if ( needsLayer ) {
int32 noWrapSize = ( toSendRequest . innerLength ( ) > > 2 ) , toSendSize = noWrapSize + initSizeInInts ;
mtpRequest wrappedRequest ( mtpRequestData : : prepare ( toSendSize ) ) ;
memcpy ( wrappedRequest - > data ( ) , toSendRequest - > constData ( ) , 7 * sizeof ( mtpPrime ) ) ; // all except length
wrappedRequest - > push_back ( mtpc_invokeWithLayer ) ;
2016-04-01 20:37:23 +04:00
wrappedRequest - > push_back ( MTP : : internal : : CurrentLayer ) ;
2014-11-15 02:23:35 +03:00
initWrapper - > write ( * wrappedRequest ) ;
wrappedRequest - > resize ( wrappedRequest - > size ( ) + noWrapSize ) ;
memcpy ( wrappedRequest - > data ( ) + wrappedRequest - > size ( ) - noWrapSize , toSendRequest - > constData ( ) + 8 , noWrapSize * sizeof ( mtpPrime ) ) ;
toSendRequest = wrappedRequest ;
}
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
2014-11-05 20:43:32 +03:00
if ( pingRequest ) containerSize + = mtpRequestData : : messageSize ( pingRequest ) ;
if ( ackRequest ) containerSize + = mtpRequestData : : messageSize ( ackRequest ) ;
if ( resendRequest ) containerSize + = mtpRequestData : : messageSize ( resendRequest ) ;
if ( stateRequest ) containerSize + = mtpRequestData : : messageSize ( stateRequest ) ;
2015-03-12 13:28:10 +03:00
if ( httpWaitRequest ) containerSize + = mtpRequestData : : messageSize ( httpWaitRequest ) ;
2014-05-30 12:53:19 +04:00
for ( mtpPreRequestMap : : iterator i = toSend . begin ( ) , e = toSend . end ( ) ; i ! = e ; + + i ) {
containerSize + = mtpRequestData : : messageSize ( i . value ( ) ) ;
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 ) ;
2016-04-01 20:37:23 +04:00
initSerialized . push_back ( MTP : : internal : : CurrentLayer ) ;
2014-11-15 02:23:35 +03:00
initWrapper - > write ( initSerialized ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
toSendRequest = mtpRequestData : : prepare ( containerSize , containerSize + 3 * toSend . size ( ) ) ; // prepare container + each in invoke after
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
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ; // the fact of this lock is used in replaceMsgId()
2014-05-30 12:53:19 +04:00
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
2014-08-01 15:09:46 +04:00
QWriteLocker locker3 ( sessionData - > wereAckedMutex ( ) ) ; // the fact of this lock is used in replaceMsgId()
2014-05-30 12:53:19 +04:00
mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
mtpRequest haveSentIdsWrap ( mtpRequestData : : prepare ( idsWrapSize ) ) ; // prepare "request-like" wrap for msgId vector
haveSentIdsWrap - > requestId = 0 ;
haveSentIdsWrap - > resize ( haveSentIdsWrap - > size ( ) + idsWrapSize ) ;
mtpMsgId * haveSentArr = ( mtpMsgId * ) ( haveSentIdsWrap - > data ( ) + 8 ) ;
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 ;
}
for ( mtpPreRequestMap : : iterator i = toSend . begin ( ) , e = toSend . end ( ) ; i ! = e ; + + i ) {
mtpRequest & req ( i . value ( ) ) ;
2014-08-01 15:09:46 +04:00
mtpMsgId msgId = prepareToSend ( req , bigMsgId ) ;
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 ) {
if ( mtpRequestData : : needAck ( req ) ) {
2014-11-12 23:30:26 +03:00
req - > msDate = mtpRequestData : : isStateRequest ( req ) ? 0 : getms ( true ) ;
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 ) {
toSendRequest - > resize ( reqNeedsLayer + initSizeInInts + mtpRequestData : : messageSize ( req ) ) ;
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 ) {
uint32 from = toSendRequest - > size ( ) , len = mtpRequestData : : messageSize ( req ) ;
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 ( ) ;
}
}
mtpRequestData : : padding ( toSendRequest ) ;
2015-08-08 12:14:47 +03:00
sendRequest ( 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 ;
2014-05-30 12:53:19 +04:00
if ( retryTimeout < 3 ) {
+ + retryTimeout ;
} else if ( retryTimeout = = 3 ) {
retryTimeout = 1000 ;
} else if ( retryTimeout < 64000 ) {
retryTimeout * = 2 ;
}
2016-03-24 15:57:10 +03:00
if ( keyId = = AuthKey : : RecreateKeyId ) {
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 ;
}
socketStart ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : restartNow ( ) {
2014-05-30 12:53:19 +04:00
retryTimeout = 1 ;
retryTimer . stop ( ) ;
restart ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : socketStart ( bool afterConfig ) {
2016-02-29 19:53:26 +03:00
if ( _finished ) {
DEBUG_LOG ( ( " MTP Error: socketStart() called for finished connection! " ) ) ;
return ;
}
2016-03-24 11:57:11 +03:00
bool isDldDc = isDldDcId ( dc ) ;
2016-02-25 20:23:42 +03:00
if ( isDldDc ) { // using media_only addresses only if key for this dc is already created
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( sessionData ) {
if ( ! sessionData - > getKey ( ) ) {
isDldDc = false ;
}
}
}
2016-03-24 11:57:11 +03:00
int32 bareDc = bareDcId ( dc ) ;
2016-02-23 12:52:18 +03:00
static const int IPv4address = 0 , IPv6address = 1 ;
static const int TcpProtocol = 0 , HttpProtocol = 1 ;
2016-03-19 19:55:15 +03:00
MTPDdcOption : : Flags flags [ 2 ] [ 2 ] = { { 0 } } ;
2016-02-23 12:52:18 +03:00
string ip [ 2 ] [ 2 ] ;
uint32 port [ 2 ] [ 2 ] = { { 0 } } ;
2015-05-14 19:50:04 +03:00
{
2016-03-24 15:57:10 +03:00
QReadLocker lock ( dcOptionsMutex ( ) ) ;
2016-04-08 14:44:35 +04:00
const auto & options ( Global : : DcOptions ( ) ) ;
2016-02-23 12:52:18 +03:00
int32 shifts [ 2 ] [ 2 ] [ 4 ] = {
{ // IPv4
{ // TCP IPv4
2016-03-19 19:55:15 +03:00
isDldDc ? ( MTPDdcOption : : Flag : : f_media_only | MTPDdcOption : : Flag : : f_tcpo_only ) : - 1 ,
qFlags ( MTPDdcOption : : Flag : : f_tcpo_only ) ,
isDldDc ? qFlags ( MTPDdcOption : : Flag : : f_media_only ) : - 1 ,
2016-02-23 12:52:18 +03:00
0
} , { // HTTP IPv4
- 1 ,
- 1 ,
2016-03-19 19:55:15 +03:00
isDldDc ? qFlags ( MTPDdcOption : : Flag : : f_media_only ) : - 1 ,
2016-02-23 12:52:18 +03:00
0
} ,
} , { // IPv6
{ // TCP IPv6
2016-03-19 19:55:15 +03:00
isDldDc ? ( MTPDdcOption : : Flag : : f_media_only | MTPDdcOption : : Flag : : f_tcpo_only | MTPDdcOption : : Flag : : f_ipv6 ) : - 1 ,
MTPDdcOption : : Flag : : f_tcpo_only | MTPDdcOption : : Flag : : f_ipv6 ,
isDldDc ? ( MTPDdcOption : : Flag : : f_media_only | MTPDdcOption : : Flag : : f_ipv6 ) : - 1 ,
qFlags ( MTPDdcOption : : Flag : : f_ipv6 )
2016-02-23 12:52:18 +03:00
} , { // HTTP IPv6
- 1 ,
- 1 ,
2016-03-19 19:55:15 +03:00
isDldDc ? ( MTPDdcOption : : Flag : : f_media_only | MTPDdcOption : : Flag : : f_ipv6 ) : - 1 ,
qFlags ( MTPDdcOption : : Flag : : f_ipv6 )
2016-02-23 12:52:18 +03:00
} ,
} ,
} ;
for ( int32 address = 0 , acount = sizeof ( shifts ) / sizeof ( shifts [ 0 ] ) ; address < acount ; + + address ) {
for ( int32 protocol = 0 , pcount = sizeof ( shifts [ 0 ] ) / sizeof ( shifts [ 0 ] [ 0 ] ) ; protocol < pcount ; + + protocol ) {
for ( int32 shift = 0 , scount = sizeof ( shifts [ 0 ] [ 0 ] ) / sizeof ( shifts [ 0 ] [ 0 ] [ 0 ] ) ; shift < scount ; + + shift ) {
int32 mask = shifts [ address ] [ protocol ] [ shift ] ;
if ( mask < 0 ) continue ;
2016-03-24 11:57:11 +03:00
auto index = options . constFind ( shiftDcId ( bareDc , mask ) ) ;
2016-02-23 12:52:18 +03:00
if ( index ! = options . cend ( ) ) {
ip [ address ] [ protocol ] = index - > ip ;
flags [ address ] [ protocol ] = index - > flags ;
port [ address ] [ protocol ] = index - > port ;
break ;
}
}
}
2015-05-14 19:50:04 +03:00
}
}
2016-08-26 22:49:18 -06:00
bool noIPv4 = ! port [ IPv4address ] [ HttpProtocol ] , noIPv6 = ( ! Global : : TryIPv6 ( ) | | ! port [ IPv6address ] [ HttpProtocol ] ) ;
2015-06-10 15:48:26 +03:00
if ( noIPv4 & & noIPv6 ) {
2014-05-30 12:53:19 +04:00
if ( afterConfig ) {
2016-02-23 12:52:18 +03:00
if ( noIPv4 ) LOG ( ( " MTP Error: DC %1 options for IPv4 over HTTP not found right after config load! " ) . arg ( dc ) ) ;
2016-08-26 22:49:18 -06:00
if ( Global : : TryIPv6 ( ) & & noIPv6 ) LOG ( ( " MTP Error: DC %1 options for IPv6 over HTTP not found right after config load! " ) . arg ( dc ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-02-23 12:52:18 +03:00
if ( noIPv4 ) DEBUG_LOG ( ( " MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config " ) . arg ( dc ) ) ;
2016-08-26 22:49:18 -06:00
if ( Global : : TryIPv6 ( ) & & noIPv6 ) DEBUG_LOG ( ( " MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config " ) . arg ( dc ) ) ;
2016-03-24 15:57:10 +03:00
connect ( configLoader ( ) , SIGNAL ( loaded ( ) ) , this , SLOT ( onConfigLoaded ( ) ) ) ;
configLoader ( ) - > load ( ) ;
2015-05-14 19:50:04 +03:00
return ;
2014-05-30 12:53:19 +04:00
}
2015-06-10 15:48:26 +03:00
if ( afterConfig & & ( _conn4 | | _conn6 ) ) return ;
2015-06-25 21:04:40 +03:00
createConn ( ! noIPv4 , ! noIPv6 ) ;
2015-06-10 15:48:26 +03:00
retryTimer . stop ( ) ;
_waitForConnectedTimer . stop ( ) ;
2016-03-24 11:57:11 +03:00
setState ( ConnectingState ) ;
2015-06-10 15:48:26 +03:00
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0 ;
_pingSender . stop ( ) ;
2016-03-24 18:07:13 +03:00
if ( ! noIPv4 ) DEBUG_LOG ( ( " MTP Info: creating IPv4 connection to %1:%2 (tcp) and %3:%4 (http)... " ) . arg ( ip [ IPv4address ] [ TcpProtocol ] . c_str ( ) ) . arg ( port [ IPv4address ] [ TcpProtocol ] ) . arg ( ip [ IPv4address ] [ HttpProtocol ] . c_str ( ) ) . arg ( port [ IPv4address ] [ HttpProtocol ] ) ) ;
if ( ! noIPv6 ) DEBUG_LOG ( ( " MTP Info: creating IPv6 connection to [%1]:%2 (tcp) and [%3]:%4 (http)... " ) . arg ( ip [ IPv6address ] [ TcpProtocol ] . c_str ( ) ) . arg ( port [ IPv6address ] [ TcpProtocol ] ) . arg ( ip [ IPv4address ] [ HttpProtocol ] . c_str ( ) ) . arg ( port [ IPv4address ] [ HttpProtocol ] ) ) ;
2014-05-30 12:53:19 +04:00
2015-06-10 15:48:26 +03:00
_waitForConnectedTimer . start ( _waitForConnected ) ;
2016-03-14 12:48:53 +03:00
if ( auto conn = _conn4 ) {
connect ( conn , SIGNAL ( connected ( ) ) , this , SLOT ( onConnected4 ( ) ) ) ;
connect ( conn , SIGNAL ( disconnected ( ) ) , this , SLOT ( onDisconnected4 ( ) ) ) ;
conn - > connectTcp ( ip [ IPv4address ] [ TcpProtocol ] . c_str ( ) , port [ IPv4address ] [ TcpProtocol ] , flags [ IPv4address ] [ TcpProtocol ] ) ;
conn - > connectHttp ( ip [ IPv4address ] [ HttpProtocol ] . c_str ( ) , port [ IPv4address ] [ HttpProtocol ] , flags [ IPv4address ] [ HttpProtocol ] ) ;
}
if ( auto conn = _conn6 ) {
connect ( conn , SIGNAL ( connected ( ) ) , this , SLOT ( onConnected6 ( ) ) ) ;
connect ( conn , SIGNAL ( disconnected ( ) ) , this , SLOT ( onDisconnected6 ( ) ) ) ;
conn - > connectTcp ( ip [ IPv6address ] [ TcpProtocol ] . c_str ( ) , port [ IPv6address ] [ TcpProtocol ] , flags [ IPv6address ] [ TcpProtocol ] ) ;
conn - > connectHttp ( ip [ IPv6address ] [ HttpProtocol ] . c_str ( ) , port [ IPv6address ] [ HttpProtocol ] , flags [ IPv6address ] [ HttpProtocol ] ) ;
2015-06-10 15:48:26 +03:00
}
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : restart ( bool mayBeBadKey ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2016-03-25 21:30:19 +03:00
DEBUG_LOG ( ( " MTP Info: restarting Connection, maybe bad key = %1 " ) . arg ( Logs : : b ( mayBeBadKey ) ) ) ;
2014-05-30 12:53:19 +04:00
2015-06-10 15:48:26 +03:00
_waitForReceivedTimer . stop ( ) ;
_waitForConnectedTimer . stop ( ) ;
2014-05-30 12:53:19 +04:00
2016-03-24 15:57:10 +03:00
AuthKeyPtr key ( sessionData - > getKey ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( key ) {
if ( ! sessionData - > isCheckedKey ( ) ) {
2015-12-08 23:41:04 +03:00
if ( mayBeBadKey ) {
clearMessages ( ) ;
2016-03-24 15:57:10 +03:00
keyId = AuthKey : : RecreateKeyId ;
2015-12-08 23:41:04 +03:00
// retryTimeout = 1; // no ddos please
2016-03-24 18:07:13 +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... " ) ) ;
2015-12-08 23:41:04 +03:00
}
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 ;
if ( retryTimer . isActive ( ) ) return ;
DEBUG_LOG ( ( " MTP Info: restart timeout: %1ms " ) . arg ( retryTimeout ) ) ;
setState ( - retryTimeout ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onSentSome ( uint64 size ) {
2015-06-10 15:48:26 +03:00
if ( ! _waitForReceivedTimer . isActive ( ) ) {
uint64 remain = _waitForReceived ;
2014-05-30 12:53:19 +04:00
if ( ! oldConnection ) {
2015-06-10 15:48:26 +03:00
uint64 remainBySize = size * _waitForReceived / 8192 ; // 8kb / sec, so 512 kb give 64 sec
2014-05-30 12:53:19 +04:00
remain = snap ( remainBySize , remain , uint64 ( MTPMaxReceiveDelay ) ) ;
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 ) ) ;
}
}
2016-03-24 11:57:11 +03:00
if ( isUplDcId ( dc ) ) {
2014-10-30 19:23:44 +03:00
remain * = MTPUploadSessionsCount ;
2016-03-24 11:57:11 +03:00
} else if ( isDldDcId ( dc ) ) {
2014-10-30 19:23:44 +03:00
remain * = MTPDownloadSessionsCount ;
}
2015-06-10 15:48:26 +03:00
_waitForReceivedTimer . start ( remain ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-12 23:30:26 +03:00
if ( ! firstSentAt ) firstSentAt = getms ( true ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onReceivedSome ( ) {
2014-05-30 12:53:19 +04:00
if ( oldConnection ) {
oldConnection = false ;
DEBUG_LOG ( ( " This connection marked as not old! " ) ) ;
}
oldConnectionTimer . start ( MTPConnectionOldTimeout ) ;
2015-06-10 15:48:26 +03:00
_waitForReceivedTimer . stop ( ) ;
2014-05-30 12:53:19 +04:00
if ( firstSentAt > 0 ) {
2014-11-12 23:30:26 +03:00
int32 ms = getms ( true ) - 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
2015-06-10 15:48:26 +03:00
if ( ms > 0 & & ms * 2 < int32 ( _waitForReceived ) ) _waitForReceived = qMax ( ms * 2 , int32 ( MTPMinReceiveDelay ) ) ;
2014-05-30 12:53:19 +04:00
firstSentAt = - 1 ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onOldConnection ( ) {
2014-05-30 12:53:19 +04:00
oldConnection = true ;
2015-06-10 15:48:26 +03:00
_waitForReceived = MTPMinReceiveDelay ;
DEBUG_LOG ( ( " This connection marked as old! _waitForReceived now %1ms " ) . arg ( _waitForReceived ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onPingSender ( ) {
2015-03-12 13:28:10 +03:00
if ( _pingId ) {
2015-04-16 17:59:42 +03:00
if ( _pingSendAt + ( MTPPingSendAfter - MTPPingSendAfterAuto - 1 ) * 1000ULL < getms ( true ) ) {
2016-03-24 18:07:13 +03:00
LOG ( ( " Could not send ping for MTPPingSendAfter seconds, restarting... " ) ) ;
2015-03-12 13:28:10 +03:00
return restart ( ) ;
} else {
2015-04-16 17:59:42 +03:00
_pingSender . start ( _pingSendAt + ( MTPPingSendAfter - MTPPingSendAfterAuto ) * 1000ULL - getms ( true ) ) ;
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 ( ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onWaitReceivedFailed ( ) {
2016-08-26 22:49:18 -06:00
if ( Global : : ConnectionType ( ) ! = dbictAuto & & Global : : ConnectionType ( ) ! = dbictTcpProxy ) {
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 ) ) ;
if ( _waitForReceived < MTPMaxReceiveDelay ) {
_waitForReceived * = 2 ;
2014-05-30 12:53:19 +04:00
}
doDisconnect ( ) ;
restarted = true ;
if ( retryTimer . isActive ( ) ) return ;
DEBUG_LOG ( ( " MTP Info: immediate restart! " ) ) ;
QTimer : : singleShot ( 0 , this , SLOT ( socketStart ( ) ) ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onWaitConnectedFailed ( ) {
2015-06-10 15:48:26 +03:00
DEBUG_LOG ( ( " MTP Info: can't connect in %1ms " ) . arg ( _waitForConnected ) ) ;
if ( _waitForConnected < MTPMaxConnectDelay ) _waitForConnected * = 2 ;
2015-06-02 14:22:00 +03:00
doDisconnect ( ) ;
restarted = true ;
DEBUG_LOG ( ( " MTP Info: immediate restart! " ) ) ;
QTimer : : singleShot ( 0 , this , SLOT ( socketStart ( ) ) ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onWaitIPv4Failed ( ) {
2015-06-10 15:48:26 +03:00
_conn = _conn6 ;
destroyConn ( & _conn4 ) ;
2016-01-11 23:43:29 +08:00
2015-06-10 15:48:26 +03:00
if ( _conn ) {
DEBUG_LOG ( ( " MTP Info: can't connect through IPv4, using IPv6 connection. " ) ) ;
2014-05-30 12:53:19 +04:00
2015-06-10 15:48:26 +03:00
updateAuthKey ( ) ;
} else {
restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-10 15:48:26 +03:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : doDisconnect ( ) {
2015-06-10 15:48:26 +03:00
destroyConn ( ) ;
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 ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : doFinish ( ) {
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
}
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 ( ) ;
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
DEBUG_LOG ( ( " MTP Error: auth_key for dc %1 busy, cant lock " ) . arg ( dc ) ) ;
clearMessages ( ) ;
keyId = 0 ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-03-24 15:57:10 +03:00
AuthKeyPtr key ( sessionData - > getKey ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( dc ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
while ( _conn - > received ( ) . size ( ) ) {
const mtpBuffer & encryptedBuf ( _conn - > received ( ) . front ( ) ) ;
2014-05-30 12:53:19 +04:00
uint32 len = encryptedBuf . size ( ) ;
const mtpPrime * encrypted ( encryptedBuf . data ( ) ) ;
if ( len < 18 ) { // 2 auth_key_id, 4 msg_key, 2 salt, 2 session, 2 msg_id, 1 seq_no, 1 length, (1 data + 3 padding) min
LOG ( ( " TCP Error: bad message received, len %1 " ) . arg ( len * sizeof ( mtpPrime ) ) ) ;
2016-01-11 23:43:29 +08:00
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encrypted , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
if ( keyId ! = * ( uint64 * ) encrypted ) {
LOG ( ( " TCP Error: bad auth_key_id %1 instead of %2 received " ) . arg ( keyId ) . arg ( * ( uint64 * ) encrypted ) ) ;
2016-01-11 23:43:29 +08:00
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encrypted , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
QByteArray dataBuffer ( ( len - 6 ) * sizeof ( mtpPrime ) , Qt : : Uninitialized ) ;
mtpPrime * data ( ( mtpPrime * ) dataBuffer . data ( ) ) , * msg = data + 8 ;
const mtpPrime * from ( msg ) , * end ;
MTPint128 msgKey ( * ( MTPint128 * ) ( encrypted + 2 ) ) ;
2016-01-11 23:43:29 +08:00
2016-03-24 15:57:10 +03:00
aesIgeDecrypt ( encrypted + 6 , data , dataBuffer . size ( ) , key , msgKey ) ;
2014-05-30 12:53:19 +04:00
uint64 serverSalt = * ( uint64 * ) & data [ 0 ] , session = * ( uint64 * ) & data [ 2 ] , msgId = * ( uint64 * ) & data [ 4 ] ;
uint32 seqNo = * ( uint32 * ) & data [ 6 ] , msgLen = * ( uint32 * ) & data [ 7 ] ;
bool needAck = ( seqNo & 0x01 ) ;
2014-06-16 13:31:10 +04:00
if ( uint32 ( dataBuffer . size ( ) ) < msgLen + 8 * sizeof ( mtpPrime ) | | ( msgLen & 0x03 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " TCP Error: bad msg_len received %1, data size: %2 " ) . arg ( msgLen ) . arg ( dataBuffer . size ( ) ) ) ;
2016-01-11 23:43:29 +08:00
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encrypted , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2015-06-10 15:48:26 +03:00
_conn - > received ( ) . pop_front ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( & msgKey , hashSha1 ( data , msgLen + 8 * sizeof ( mtpPrime ) , sha1Buffer ) + 1 , sizeof ( msgKey ) ) ) {
LOG ( ( " TCP Error: bad SHA1 hash after aesDecrypt in message " ) ) ;
2016-01-11 23:43:29 +08:00
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encrypted , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2015-06-10 15:48:26 +03:00
_conn - > received ( ) . pop_front ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-01-11 23:43:29 +08:00
TCP_LOG ( ( " TCP Info: decrypted message %1,%2,%3 is %4 len " ) . arg ( msgId ) . arg ( seqNo ) . arg ( Logs : : b ( needAck ) ) . arg ( msgLen + 8 * sizeof ( mtpPrime ) ) ) ;
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-06-10 15:48:26 +03:00
_conn - > received ( ) . pop_front ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
_conn - > received ( ) . pop_front ( ) ;
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
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
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
int32 res = 1 ; // if no need to handle, then succeed
end = data + 8 + ( msgLen > > 2 ) ;
const mtpPrime * sfrom ( data + 4 ) ;
2014-10-21 02:49:37 +04:00
MTP_LOG ( dc , ( " Recv: " ) + mtpTextSerialize ( sfrom , end ) ) ;
2014-05-30 12:53:19 +04:00
bool needToHandle = false ;
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2014-11-05 20:43:32 +03:00
mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
2014-05-30 12:53:19 +04:00
needToHandle = receivedIds . insert ( msgId , needAck ) ;
}
if ( needToHandle ) {
res = handleOneReceived ( from , end , msgId , serverTime , serverSalt , badTime ) ;
}
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2014-11-05 20:43:32 +03:00
mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
2014-05-30 12:53:19 +04:00
uint32 receivedIdsSize = receivedIds . size ( ) ;
while ( receivedIdsSize - - > MTPIdsBufferSize ) {
receivedIds . erase ( receivedIds . begin ( ) ) ;
}
}
// send acks
2014-11-05 20:43:32 +03:00
uint32 toAckSize = ackRequestData . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( toAckSize ) {
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " MTP Info: will send %1 acks, ids: %2 " ) . arg ( toAckSize ) . arg ( Logs : : vector ( ackRequestData ) ) ) ;
2014-11-22 12:45:04 +03:00
emit sendAnythingAsync ( MTPAckSendWaiting ) ;
2014-05-30 12:53:19 +04:00
}
bool emitSignal = false ;
{
QReadLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
emitSignal = ! sessionData - > haveReceivedMap ( ) . isEmpty ( ) ;
if ( emitSignal ) {
DEBUG_LOG ( ( " MTP Info: emitting needToReceive() - need to parse in another thread, haveReceivedMap.size() = %1 " ) . arg ( sessionData - > haveReceivedMap ( ) . size ( ) ) ) ;
}
}
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
if ( emitSignal ) {
emit needToReceive ( ) ;
}
if ( res < 0 ) {
2014-08-01 15:09:46 +04:00
_needSessionReset = ( res < - 1 ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03: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 ) ;
}
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
}
}
}
2015-06-10 15:48:26 +03:00
if ( _conn - > needHttpWait ( ) ) {
2014-11-25 15:15:29 +03:00
emit sendHttpWaitAsync ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-24 11:57:11 +03:00
int32 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 ) ;
if ( ! response . size ( ) ) {
return - 1 ;
}
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 ;
MTPlong inMsgId ( from , otherEnd ) ;
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 ) ) ;
return - 1 ;
}
MTPint inSeqNo ( from , otherEnd ) ;
MTPint bytes ( from , otherEnd ) ;
if ( ( bytes . v & 0x03 ) | | bytes . v < 4 ) {
LOG ( ( " Message Error: bad length %1 of contained message received " ) . arg ( bytes . v ) ) ;
return - 1 ;
}
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 ( ) ) ;
2014-11-05 20:43:32 +03:00
mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
2014-05-30 12:53:19 +04:00
needToHandle = receivedIds . insert ( inMsgId . v , needAck ) ;
}
int32 res = 1 ; // if no need to handle, then succeed
if ( needToHandle ) {
res = handleOneReceived ( from , otherEnd , inMsgId . v , serverTime , serverSalt , badTime ) ;
badTime = false ;
}
if ( res < = 0 ) {
return res ;
}
from = otherEnd ;
}
} return 1 ;
case mtpc_msgs_ack : {
MTPMsgsAck msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & ids ( msg . c_msgs_ack ( ) . vmsg_ids . c_vector ( ) . v ) ;
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: acks received, ids: %1 " ) . arg ( Logs : : vector ( ids ) ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! idsCount ) return ( badTime ? 0 : 1 ) ;
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
return 0 ;
}
}
requestsAcked ( ids ) ;
} return 1 ;
case mtpc_bad_msg_notification : {
MTPBadMsgNotification msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_msg_notification ( ) ) ;
2014-05-30 12:53:19 +04: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-11-05 20:43:32 +03:00
mtpMsgId resendId = data . vbad_msg_id . v ;
2015-03-12 13:28:10 +03:00
if ( resendId = = _pingMsgId ) {
_pingId = 0 ;
}
2014-08-01 15:09:46 +04:00
int32 errorCode = data . verror_code . v ;
if ( errorCode = = 16 | | errorCode = = 17 | | errorCode = = 32 | | errorCode = = 33 | | errorCode = = 64 ) { // can handle
bool needResend = ( errorCode = = 16 | | errorCode = = 17 ) ; // bad msg_id
if ( errorCode = = 64 ) { // bad container!
needResend = true ;
if ( cDebug ( ) ) {
mtpRequest request ;
{
QWriteLocker locker ( sessionData - > haveSentMutex ( ) ) ;
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
2014-11-05 20:43:32 +03:00
mtpRequestMap : : const_iterator i = haveSent . constFind ( resendId ) ;
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 ) {
if ( mtpRequestData : : isSentContainer ( request ) ) {
QStringList lst ;
const mtpMsgId * ids = ( const mtpMsgId * ) ( request - > constData ( ) + 8 ) ;
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 ) ) {
DEBUG_LOG ( ( " Message Error: such message was not sent recently %1 " ) . arg ( resendId ) ) ;
return ( badTime ? 0 : 1 ) ;
}
2014-05-30 12:53:19 +04:00
2014-08-01 15:09:46 +04:00
if ( needResend ) { // bad msg_id
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 ;
}
LOG ( ( " Message Info: bad message notification received, msgId %1, error_code %2 " ) . arg ( data . vbad_msg_id . v ) . arg ( errorCode ) ) ;
return - 2 ;
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)
mtpMsgId resendId = data . vbad_msg_id . v ;
mtpRequestId requestId = wasSent ( resendId ) ;
if ( requestId ) {
LOG ( ( " Message Error: bad message notification received, msgId %1, error_code %2, fatal: clearing callbacks " ) . arg ( data . vbad_msg_id . v ) . arg ( errorCode ) ) ;
2016-03-24 11:57:11 +03:00
clearCallbacksDelayed ( RPCCallbackClears ( 1 , RPCCallbackClear ( requestId , - errorCode ) ) ) ;
2014-08-01 15:09:46 +04:00
} else {
DEBUG_LOG ( ( " Message Error: such message was not sent recently %1 " ) . arg ( resendId ) ) ;
}
return ( badTime ? 0 : 1 ) ;
2014-05-30 12:53:19 +04:00
}
} return 1 ;
case mtpc_bad_server_salt : {
MTPBadMsgNotification msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_server_salt ( ) ) ;
2014-05-30 12:53:19 +04: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 ) ) ;
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 ) ) ;
return ( badTime ? 0 : 1 ) ;
}
uint64 serverSalt = data . vnew_server_salt . v ;
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 ) ;
} return 1 ;
case mtpc_msgs_state_req : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
MTPMsgsStateReq msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & ids ( msg . c_msgs_state_req ( ) . vmsg_ids . c_vector ( ) . v ) ;
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: msgs_state_req received, ids: %1 " ) . arg ( Logs : : vector ( ids ) ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! idsCount ) return 1 ;
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 ( ) ) ;
2014-11-05 20:43:32 +03:00
const mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
mtpMsgIdsMap : : const_iterator receivedIdsEnd ( receivedIds . cend ( ) ) ;
2014-05-30 12:53:19 +04:00
uint64 minRecv = receivedIds . min ( ) , maxRecv = receivedIds . max ( ) ;
QReadLocker locker ( sessionData - > wereAckedMutex ( ) ) ;
const mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
mtpRequestIdsMap : : const_iterator wereAckedEnd ( wereAcked . cend ( ) ) ;
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 {
2014-11-05 20:43:32 +03:00
mtpMsgIdsMap : : const_iterator recv = receivedIds . constFind ( reqMsgId ) ;
2014-05-30 12:53:19 +04:00
if ( recv = = receivedIdsEnd ) {
state | = 0x02 ;
} else {
state | = 0x04 ;
if ( wereAcked . constFind ( reqMsgId ) ! = wereAckedEnd ) {
state | = 0x80 ; // we know, that server knows, that we received request
}
if ( recv . value ( ) ) { // need ack, so we sent ack
state | = 0x08 ;
} else {
state | = 0x10 ;
}
}
}
info [ i ] = state ;
}
}
2014-11-25 15:15:29 +03:00
emit sendMsgsStateInfoAsync ( msgId , info ) ;
2014-05-30 12:53:19 +04:00
} return 1 ;
case mtpc_msgs_state_info : {
MTPMsgsStateInfo msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msgs_state_info ( ) ) ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
uint64 reqMsgId = data . vreq_msg_id . v ;
2016-04-08 14:44:35 +04:00
const auto & states ( data . vinfo . c_string ( ) . 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 ( ) ) ) ;
2014-05-30 12:53:19 +04:00
mtpRequest requestBuffer ;
{ // find this request in session-shared sent requests map
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
const mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
mtpRequestMap : : const_iterator replyTo = haveSent . constFind ( reqMsgId ) ;
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 ) ) ;
return ( badTime ? 0 : 1 ) ;
}
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 ( ) ) ) ;
return - 1 ;
}
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 ) {
2014-08-01 15:09:46 +04:00
MTPMsgsStateReq request ( rFrom , rEnd ) ;
handleMsgsStates ( request . c_msgs_state_req ( ) . vmsg_ids . c_vector ( ) . v , states , toAck ) ;
} else {
MTPMsgResendReq request ( rFrom , rEnd ) ;
handleMsgsStates ( request . c_msg_resend_req ( ) . vmsg_ids . c_vector ( ) . v , states , toAck ) ;
}
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 ) ;
} return 1 ;
case mtpc_msgs_all_info : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
MTPMsgsAllInfo msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msgs_all_info ( ) ) ;
const auto & ids ( data . vmsg_ids . c_vector ( ) . v ) ;
const auto & states ( data . vinfo . c_string ( ) . v ) ;
2014-05-30 12:53:19 +04:00
QVector < MTPlong > toAck ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: msgs all info received, msgId %1, reqMsgIds: %2, states %3 " ) . arg ( msgId ) . arg ( Logs : : vector ( ids ) ) . arg ( Logs : : mb ( states . data ( ) , states . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
handleMsgsStates ( ids , states , toAck ) ;
requestsAcked ( toAck ) ;
} return 1 ;
case mtpc_msg_detailed_info : {
MTPMsgDetailedInfo msg ( 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
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 ) ) ;
QVector < MTPlong > ids ( 1 , data . vmsg_id ) ;
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 ( data . vmsg_id . v ) ) ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
}
requestsAcked ( ids ) ;
bool received = false ;
MTPlong resMsgId = data . vanswer_msg_id ;
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2014-11-05 20:43:32 +03:00
const mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
2014-05-30 12:53:19 +04:00
received = ( receivedIds . find ( resMsgId . v ) ! = receivedIds . cend ( ) ) & & ( receivedIds . min ( ) < resMsgId . v ) ;
}
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
}
} return 1 ;
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... " ) ) ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
MTPMsgDetailedInfo msg ( 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
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 ) ) ;
bool received = false ;
MTPlong resMsgId = data . vanswer_msg_id ;
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2014-11-05 20:43:32 +03:00
const mtpMsgIdsMap & receivedIds ( sessionData - > receivedIdsSet ( ) ) ;
2014-05-30 12:53:19 +04:00
received = ( receivedIds . find ( resMsgId . v ) ! = receivedIds . cend ( ) ) & & ( receivedIds . min ( ) < resMsgId . v ) ;
}
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
}
} return 1 ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
case mtpc_msg_resend_req : {
MTPMsgResendReq msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & ids ( msg . c_msg_resend_req ( ) . vmsg_ids . c_vector ( ) . v ) ;
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: resend of msgs requested, ids: %1 " ) . arg ( Logs : : vector ( ids ) ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! idsCount ) return ( badTime ? 0 : 1 ) ;
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 ) ;
2014-05-30 12:53:19 +04:00
} return 1 ;
case mtpc_rpc_result : {
if ( from + 3 > end ) throw mtpErrorInsufficient ( ) ;
mtpResponse response ;
MTPlong reqMsgId ( + + from , end ) ;
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 ) ) ;
2014-05-30 12:53:19 +04:00
return 0 ;
}
}
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 ( ) ) {
return - 1 ;
}
typeId = response [ 0 ] ;
} else {
response . resize ( end - from ) ;
memcpy ( response . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
}
2014-11-15 02:23:35 +03:00
if ( ! sessionData - > layerWasInited ( ) ) {
sessionData - > setLayerWasInited ( true ) ;
sessionData - > owner ( ) - > notifyLayerInited ( true ) ;
}
2014-05-30 12:53:19 +04:00
mtpRequestId requestId = wasSent ( reqMsgId . v ) ;
2014-06-16 13:31:10 +04:00
if ( requestId & & requestId ! = mtpRequestId ( 0xFFFFFFFF ) ) {
2014-05-30 12:53:19 +04:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
sessionData - > haveReceivedMap ( ) . insert ( requestId , response ) ; // save rpc_result for processing in main mtp thread
} else {
DEBUG_LOG ( ( " RPC Info: requestId not found for msgId %1 " ) . arg ( reqMsgId . v ) ) ;
}
} return 1 ;
case mtpc_new_session_created : {
2015-04-23 18:50:11 +03:00
const mtpPrime * start = from ;
2014-05-30 12:53:19 +04:00
MTPNewSession msg ( 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 ) {
if ( requestsFixTimeSalt ( QVector < MTPlong > ( 1 , data . vfirst_msg_id ) , serverTime , serverSalt ) ) {
badTime = false ;
} else {
DEBUG_LOG ( ( " Message Info: error, such message was not sent recently %1 " ) . arg ( data . vfirst_msg_id . v ) ) ;
return 0 ;
}
}
2014-05-30 12:53:19 +04: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 ) ;
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 ( ) ) ;
const mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
toResend . reserve ( haveSent . size ( ) ) ;
for ( mtpRequestMap : : const_iterator i = haveSent . cbegin ( ) , e = haveSent . cend ( ) ; i ! = e ; + + i ) {
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
2014-05-30 12:53:19 +04:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
mtpResponseMap & haveReceived ( sessionData - > haveReceivedMap ( ) ) ;
mtpRequestId fakeRequestId = sessionData - > nextFakeRequestId ( ) ;
haveReceived . insert ( fakeRequestId , mtpResponse ( update ) ) ; // notify main process about new session - need to get difference
} return 1 ;
case mtpc_ping : {
if ( badTime ) return 0 ;
MTPPing msg ( from , end ) ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: ping received, ping_id: %1, sending pong... " ) . arg ( msg . vping_id . v ) ) ;
2014-05-30 12:53:19 +04:00
2014-11-25 15:15:29 +03:00
emit sendPongAsync ( msgId , msg . vping_id . v ) ;
2014-05-30 12:53:19 +04:00
} return 1 ;
case mtpc_pong : {
MTPPong msg ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_pong ( ) ) ;
2014-05-30 12:53:19 +04: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
2014-05-30 12:53:19 +04: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 ) ) ;
return 0 ;
}
2015-03-12 13:28:10 +03:00
if ( data . vping_id . v = = _pingId ) {
_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
}
QVector < MTPlong > ids ( 1 , data . vmsg_id ) ;
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
return 0 ;
}
}
2014-10-30 19:23:44 +03:00
requestsAcked ( ids , true ) ;
2014-05-30 12:53:19 +04:00
} return 1 ;
}
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
return - 1 ;
}
if ( badTime ) {
2015-01-23 00:59:07 +03:00
DEBUG_LOG ( ( " Message Error: bad time in updates cons, must create new session " ) ) ;
return - 2 ;
2014-05-30 12:53:19 +04:00
}
mtpBuffer update ( end - from ) ;
if ( end > from ) memcpy ( update . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
mtpResponseMap & haveReceived ( sessionData - > haveReceivedMap ( ) ) ;
mtpRequestId fakeRequestId = sessionData - > nextFakeRequestId ( ) ;
haveReceived . insert ( fakeRequestId , mtpResponse ( update ) ) ; // notify main process about new updates
2015-08-30 17:57:21 +03:00
if ( cons ! = mtpc_updatesTooLong & & cons ! = mtpc_updateShortMessage & & cons ! = mtpc_updateShortChatMessage & & cons ! = mtpc_updateShortSentMessage & & cons ! = mtpc_updateShort & & cons ! = mtpc_updatesCombined & & cons ! = mtpc_updates ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " Message Error: unknown constructor %1 " ) . arg ( cons ) ) ; // maybe new api?..
}
return 1 ;
}
2016-03-24 11:57:11 +03:00
mtpBuffer ConnectionPrivate : : ungzip ( const mtpPrime * from , const mtpPrime * end ) const {
2014-05-30 12:53:19 +04:00
MTPstring packed ( from , end ) ; // read packed string as serialized mtp string type
uint32 packedLen = packed . c_string ( ) . v . size ( ) , unpackedChunk = packedLen , unpackedLen = 0 ;
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 ;
stream . next_in = ( Bytef * ) & packed . _string ( ) . v [ 0 ] ;
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 ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " RPC Error: bad gzip: %1 " ) . arg ( Logs : : mb ( & packed . c_string ( ) . v [ 0 ] , 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 ( ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: requests acked, ids %1 " ) . arg ( Logs : : vector ( ids ) ) ) ;
2014-05-30 12:53:19 +04:00
RPCCallbackClears clearedAcked ;
QVector < MTPlong > toAckMore ;
{
QWriteLocker locker1 ( sessionData - > wereAckedMutex ( ) ) ;
mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
{
QWriteLocker locker2 ( sessionData - > haveSentMutex ( ) ) ;
mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
for ( uint32 i = 0 ; i < idsCount ; + + i ) {
mtpMsgId msgId = ids [ i ] . v ;
mtpRequestMap : : iterator req = haveSent . find ( msgId ) ;
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)
2016-03-24 11:57:11 +03:00
moveToAcked = ! 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 ( ) ) ;
mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpRequestIdsMap : : iterator reqIt = toResend . find ( msgId ) ;
if ( reqIt ! = toResend . cend ( ) ) {
mtpRequestId 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)
2016-03-24 11:57:11 +03:00
moveToAcked = ! hasCallbacks ( reqId ) ;
2014-10-30 19:23:44 +03:00
}
if ( moveToAcked ) {
QWriteLocker locker4 ( sessionData - > toSendMutex ( ) ) ;
mtpPreRequestMap & toSend ( sessionData - > toSendMap ( ) ) ;
mtpPreRequestMap : : iterator req = toSend . find ( reqId ) ;
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 ( ) ;
if ( ackedCount > MTPIdsBufferSize ) {
DEBUG_LOG ( ( " Message Info: removing some old acked sent msgIds %1 " ) . arg ( ackedCount - MTPIdsBufferSize ) ) ;
clearedAcked . reserve ( ackedCount - MTPIdsBufferSize ) ;
while ( ackedCount - - > MTPIdsBufferSize ) {
mtpRequestIdsMap : : iterator i ( wereAcked . begin ( ) ) ;
clearedAcked . push_back ( RPCCallbackClear ( i . key ( ) , RPCError : : TimeoutError ) ) ;
wereAcked . erase ( i ) ;
}
}
}
if ( clearedAcked . size ( ) ) {
2016-03-24 11:57:11 +03:00
clearCallbacksDelayed ( clearedAcked ) ;
2014-05-30 12:53:19 +04:00
}
if ( toAckMore . size ( ) ) {
requestsAcked ( toAckMore ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : handleMsgsStates ( const QVector < MTPlong > & ids , const string & 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 ;
}
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 ( ) ) ;
const mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
mtpRequestMap : : const_iterator haveSentEnd = haveSent . cend ( ) ;
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 ( ) ) ;
mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpRequestIdsMap : : iterator reqIt = toResend . find ( requestMsgId ) ;
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-03-24 11:57:11 +03:00
void ConnectionPrivate : : resend ( quint64 msgId , quint64 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-03-24 11:57:11 +03:00
void ConnectionPrivate : : resendMany ( QVector < quint64 > msgIds , quint64 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
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onConnected4 ( ) {
2015-06-10 15:48:26 +03:00
_waitForConnected = MTPMinConnectDelay ;
_waitForConnectedTimer . stop ( ) ;
_waitForIPv4Timer . stop ( ) ;
2015-06-02 14:22:00 +03:00
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2015-06-10 15:48:26 +03:00
disconnect ( _conn4 , SIGNAL ( connected ( ) ) , this , SLOT ( onConnected4 ( ) ) ) ;
if ( ! _conn4 - > isConnected ( ) ) {
LOG ( ( " Connection Error: not connected in onConnected4(), state: %1 " ) . arg ( _conn4 - > debugState ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
_conn = _conn4 ;
destroyConn ( & _conn6 ) ;
DEBUG_LOG ( ( " MTP Info: connection through IPv4 succeed. " ) ) ;
2014-05-30 12:53:19 +04:00
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2015-05-14 19:50:04 +03:00
updateAuthKey ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onConnected6 ( ) {
2015-06-10 15:48:26 +03:00
_waitForConnected = MTPMinConnectDelay ;
_waitForConnectedTimer . stop ( ) ;
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2015-06-30 01:22:14 +03:00
disconnect ( _conn6 , SIGNAL ( connected ( ) ) , this , SLOT ( onConnected6 ( ) ) ) ;
2015-06-10 15:48:26 +03:00
if ( ! _conn6 - > isConnected ( ) ) {
LOG ( ( " Connection Error: not connected in onConnected(), state: %1 " ) . arg ( _conn6 - > debugState ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2015-06-10 15:48:26 +03:00
return restart ( ) ;
}
DEBUG_LOG ( ( " MTP Info: connection through IPv6 succeed, waiting IPv4 for %1ms. " ) . arg ( MTPIPv4ConnectionWaitTimeout ) ) ;
_waitForIPv4Timer . start ( MTPIPv4ConnectionWaitTimeout ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onDisconnected4 ( ) {
2015-06-10 15:48:26 +03:00
if ( _conn & & _conn = = _conn6 ) return ; // disconnected the unused
if ( _conn | | ! _conn6 ) {
destroyConn ( ) ;
restart ( ) ;
} else {
destroyConn ( & _conn4 ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onDisconnected6 ( ) {
2015-06-10 15:48:26 +03:00
if ( _conn & & _conn = = _conn4 ) return ; // disconnected the unused
if ( _conn | | ! _conn4 ) {
destroyConn ( ) ;
restart ( ) ;
} else {
destroyConn ( & _conn6 ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : updateAuthKey ( ) {
2015-05-14 19:50:04 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
2015-06-10 15:48:26 +03:00
if ( ! sessionData | | ! _conn ) return ;
2015-05-14 19:50:04 +03:00
2016-03-25 21:30:19 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection updating key from Session, dc %1 " ) . arg ( dc ) ) ;
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
}
2016-03-24 15:57:10 +03:00
const AuthKeyPtr & key ( sessionData - > getKey ( ) ) ;
2015-05-14 19:50:04 +03:00
newKeyId = key ? key - > keyId ( ) : 0 ;
}
if ( keyId ! = newKeyId ) {
clearMessages ( ) ;
keyId = newKeyId ;
}
2016-03-25 21:30:19 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection update key from Session, dc %1 result: %2 " ) . arg ( dc ) . 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 ( ) ;
2016-03-24 15:57:10 +03:00
const AuthKeyPtr & key ( sessionData - > getKey ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( key ) {
if ( keyId ! = key - > keyId ( ) ) clearMessages ( ) ;
keyId = key - > keyId ( ) ;
unlockKey ( ) ;
return authKeyCreated ( ) ;
}
2016-03-24 11:57:11 +03:00
authKeyData = new ConnectionPrivate : : AuthKeyCreateData ( ) ;
authKeyStrings = new ConnectionPrivate : : AuthKeyCreateStrings ( ) ;
2014-05-30 12:53:19 +04:00
authKeyData - > req_num = 0 ;
2016-03-24 13:12:18 +03:00
authKeyData - > nonce = rand_value < MTPint128 > ( ) ;
2014-05-30 12:53:19 +04:00
MTPReq_pq req_pq ;
req_pq . vnonce = authKeyData - > nonce ;
2015-06-10 15:48:26 +03:00
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( 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 ( ) ;
2014-05-30 12:53:19 +04:00
sendRequestNotSecure ( req_pq ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : clearMessages ( ) {
2016-03-24 15:57:10 +03:00
if ( keyId & & keyId ! = AuthKey : : RecreateKeyId & & _conn ) {
2015-06-10 15:48:26 +03:00
_conn - > received ( ) . clear ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : pqAnswered ( ) {
2015-06-10 15:48:26 +03:00
disconnect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( pqAnswered ( ) ) ) ;
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 ;
if ( ! readResponseNotSecure ( res_pq ) ) {
return restart ( ) ;
}
2016-04-08 14:44:35 +04:00
const auto & res_pq_data ( res_pq . c_resPQ ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( res_pq_data . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in res_pq)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
2016-03-23 21:12:07 +03:00
static MTP : : internal : : RSAPublicKeys RSAKeys = MTP : : internal : : InitRSAPublicKeys ( ) ;
const MTP : : internal : : RSAPublicKey * rsaKey = nullptr ;
2016-04-08 14:44:35 +04:00
const auto & fingerPrints ( res_pq . c_resPQ ( ) . vserver_public_key_fingerprints . c_vector ( ) . v ) ;
for ( const auto & fingerPrint : fingerPrints ) {
auto it = RSAKeys . constFind ( static_cast < uint64 > ( fingerPrint . v ) ) ;
2016-03-23 21:12:07 +03:00
if ( it ! = RSAKeys . cend ( ) ) {
rsaKey = & it . value ( ) ;
2014-05-30 12:53:19 +04:00
break ;
}
}
if ( ! rsaKey ) {
QStringList suggested , my ;
2016-04-08 14:44:35 +04:00
for ( const auto & fingerPrint : fingerPrints ) {
2016-03-23 21:12:07 +03:00
suggested . push_back ( QString ( " %1 " ) . arg ( fingerPrint . v ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
for ( auto i = RSAKeys . cbegin ( ) , e = RSAKeys . cend ( ) ; i ! = e ; + + i ) {
2014-05-30 12:53:19 +04:00
my . push_back ( QString ( " %1 " ) . arg ( i . key ( ) ) ) ;
}
LOG ( ( " AuthKey Error: could not choose public RSA key, suggested fingerprints: %1, my fingerprints: %2 " ) . arg ( suggested . join ( " , " ) ) . arg ( my . join ( " , " ) ) ) ;
return restart ( ) ;
}
authKeyData - > server_nonce = res_pq_data . vserver_nonce ;
MTPP_Q_inner_data p_q_inner ;
MTPDp_q_inner_data & p_q_inner_data ( p_q_inner . _p_q_inner_data ( ) ) ;
p_q_inner_data . vnonce = authKeyData - > nonce ;
p_q_inner_data . vserver_nonce = authKeyData - > server_nonce ;
p_q_inner_data . vpq = res_pq_data . vpq ;
const string & pq ( res_pq_data . vpq . c_string ( ) . v ) ;
string & p ( p_q_inner_data . vp . _string ( ) . v ) , & q ( p_q_inner_data . vq . _string ( ) . v ) ;
2016-03-23 21:12:07 +03:00
if ( ! MTP : : internal : : parsePQ ( pq , p , q ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: could not factor pq! " ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: problematic pq: %1 " ) . arg ( Logs : : mb ( & pq [ 0 ] , pq . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-03-24 13:12:18 +03:00
authKeyData - > new_nonce = rand_value < MTPint256 > ( ) ;
2014-05-30 12:53:19 +04:00
p_q_inner_data . vnew_nonce = authKeyData - > new_nonce ;
MTPReq_DH_params req_DH_params ;
req_DH_params . vnonce = authKeyData - > nonce ;
req_DH_params . vserver_nonce = authKeyData - > server_nonce ;
2016-03-23 21:12:07 +03:00
req_DH_params . vpublic_key_fingerprint = MTP_long ( rsaKey - > getFingerPrint ( ) ) ;
2014-05-30 12:53:19 +04:00
req_DH_params . vp = p_q_inner_data . vp ;
req_DH_params . vq = p_q_inner_data . vq ;
string & dhEncString ( req_DH_params . vencrypted_data . _string ( ) . v ) ;
2014-11-15 02:23:35 +03:00
uint32 p_q_inner_size = p_q_inner . innerLength ( ) , encSize = ( p_q_inner_size > > 2 ) + 6 ;
2014-05-30 12:53:19 +04:00
if ( encSize > = 65 ) {
mtpBuffer tmp ;
tmp . reserve ( encSize ) ;
p_q_inner . write ( tmp ) ;
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 ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ; // can't be 255-byte string
}
mtpBuffer encBuffer ;
encBuffer . reserve ( 65 ) ; // 260 bytes
encBuffer . resize ( 6 ) ;
encBuffer [ 0 ] = 0 ;
p_q_inner . write ( encBuffer ) ;
hashSha1 ( & encBuffer [ 6 ] , p_q_inner_size , & encBuffer [ 1 ] ) ;
if ( encSize < 65 ) {
encBuffer . resize ( 65 ) ;
memset_rand ( & encBuffer [ encSize ] , ( 65 - encSize ) * sizeof ( mtpPrime ) ) ;
}
2016-03-23 21:12:07 +03:00
if ( ! rsaKey - > encrypt ( reinterpret_cast < const char * > ( & encBuffer [ 0 ] ) + 3 , dhEncString ) ) {
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhParamsAnswered ( ) ) ) ;
2014-05-30 12:53:19 +04:00
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_DH_params... " ) ) ;
2014-05-30 12:53:19 +04:00
sendRequestNotSecure ( req_DH_params ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhParamsAnswered ( ) {
2015-06-10 15:48:26 +03:00
disconnect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhParamsAnswered ( ) ) ) ;
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 ;
if ( ! readResponseNotSecure ( res_DH_params ) ) {
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 ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( encDH . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_ok)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( encDH . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
const string & encDHStr ( encDH . vencrypted_answer . c_string ( ) . v ) ;
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 ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: received encrypted data %1 " ) . arg ( Logs : : mb ( & encDHStr [ 0 ] , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2014-11-15 02:23:35 +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 ] ;
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 ) ;
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 ) ;
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 ) ;
2016-03-24 15:57:10 +03:00
aesIgeDecrypt ( & encDHStr [ 0 ] , & 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 ) ) ;
MTPServer_DH_inner_data dh_inner ( to , end ) ;
2016-04-08 14:44:35 +04:00
const auto & dh_inner_data ( dh_inner . c_server_DH_inner_data ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( dh_inner_data . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( dh_inner_data . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)! " ) ) ;
2016-01-11 23:43:29 +08: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! " ) ) ;
2016-01-11 23:43:29 +08: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 [ 0 ] , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
unixtimeSet ( dh_inner_data . vserver_time . v ) ;
const string & dhPrime ( dh_inner_data . vdh_prime . c_string ( ) . v ) , & g_a ( dh_inner_data . vg_a . c_string ( ) . v ) ;
if ( dhPrime . length ( ) ! = 256 | | g_a . length ( ) ! = 256 ) {
LOG ( ( " AuthKey Error: bad dh_prime len (%1) or g_a len (%2) " ) . arg ( dhPrime . length ( ) ) . arg ( g_a . length ( ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: dh_prime %1, g_a %2 " ) . arg ( Logs : : mb ( & dhPrime [ 0 ] , dhPrime . length ( ) ) . str ( ) ) . arg ( Logs : : mb ( & g_a [ 0 ] , g_a . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
// check that dhPrime and (dhPrime - 1) / 2 are really prime using openssl BIGNUM methods
2016-03-23 21:12:07 +03:00
MTP : : internal : : BigNumPrimeTest bnPrimeTest ;
2014-05-30 12:53:19 +04:00
if ( ! bnPrimeTest . isPrimeAndGood ( & dhPrime [ 0 ] , MTPMillerRabinIterCount , dh_inner_data . vg . v ) ) {
LOG ( ( " AuthKey Error: bad dh_prime primality! " ) . arg ( dhPrime . length ( ) ) . arg ( g_a . length ( ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: dh_prime %1 " ) . arg ( Logs : : mb ( & dhPrime [ 0 ] , dhPrime . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2014-11-05 20:43:32 +03:00
authKeyStrings - > dh_prime = QByteArray ( dhPrime . data ( ) , dhPrime . size ( ) ) ;
2014-05-30 12:53:19 +04:00
authKeyData - > g = dh_inner_data . vg . v ;
2014-11-05 20:43:32 +03:00
authKeyStrings - > g_a = QByteArray ( g_a . data ( ) , g_a . size ( ) ) ;
2014-05-30 12:53:19 +04:00
authKeyData - > retry_id = MTP_long ( 0 ) ;
authKeyData - > retries = 0 ;
} 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 ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( encDH . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_fail)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( encDH . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)! " ) ) ;
2016-01-11 23:43:29 +08: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 ] ;
if ( encDH . vnew_nonce_hash ! = * ( MTPint128 * ) ( hashSha1 ( & authKeyData - > new_nonce , 32 , sha1Buffer ) + 1 ) ) {
LOG ( ( " AuthKey Error: received new_nonce_hash did not match! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) {
2014-05-30 12:53:19 +04:00
if ( + + authKeyData - > retries > 5 ) {
LOG ( ( " AuthKey Error: could not create auth_key for %1 retries " ) . arg ( authKeyData - > retries - 1 ) ) ;
return restart ( ) ;
}
MTPClient_DH_Inner_Data client_dh_inner ;
MTPDclient_DH_inner_data & client_dh_inner_data ( client_dh_inner . _client_DH_inner_data ( ) ) ;
client_dh_inner_data . vnonce = authKeyData - > nonce ;
client_dh_inner_data . vserver_nonce = authKeyData - > server_nonce ;
client_dh_inner_data . vretry_id = authKeyData - > retry_id ;
client_dh_inner_data . vg_b . _string ( ) . v . resize ( 256 ) ;
// gen rand 'b'
2016-03-20 11:16:35 +03:00
uint32 b [ 64 ] , * g_b ( ( uint32 * ) & client_dh_inner_data . vg_b . _string ( ) . v [ 0 ] ) ;
2014-05-30 12:53:19 +04:00
memset_rand ( b , sizeof ( b ) ) ;
// count g_b and auth_key using openssl BIGNUM methods
2016-03-23 21:12:07 +03:00
MTP : : internal : : BigNumCounter bnCounter ;
2014-11-05 20:43:32 +03:00
if ( ! bnCounter . count ( b , authKeyStrings - > dh_prime . constData ( ) , authKeyData - > g , g_b , authKeyStrings - > g_a . constData ( ) , authKeyData - > auth_key ) ) {
2014-05-30 12:53:19 +04:00
return dhClientParamsSend ( ) ;
}
// count auth_key hashes - parts of sha1(auth_key)
uchar sha1Buffer [ 20 ] ;
int32 * auth_key_sha = hashSha1 ( authKeyData - > auth_key , 256 , sha1Buffer ) ;
memcpy ( & authKeyData - > auth_key_aux_hash , auth_key_sha , 8 ) ;
memcpy ( & authKeyData - > auth_key_hash , auth_key_sha + 3 , 8 ) ;
MTPSet_client_DH_params req_client_DH_params ;
req_client_DH_params . vnonce = authKeyData - > nonce ;
req_client_DH_params . vserver_nonce = authKeyData - > server_nonce ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
string & sdhEncString ( req_client_DH_params . vencrypted_data . _string ( ) . v ) ;
2014-11-15 02:23:35 +03:00
uint32 client_dh_inner_size = client_dh_inner . innerLength ( ) , encSize = ( client_dh_inner_size > > 2 ) + 5 , encFullSize = encSize ;
2014-05-30 12:53:19 +04:00
if ( encSize & 0x03 ) {
encFullSize + = 4 - ( encSize & 0x03 ) ;
}
mtpBuffer encBuffer ;
encBuffer . reserve ( encFullSize ) ;
encBuffer . resize ( 5 ) ;
client_dh_inner . write ( encBuffer ) ;
hashSha1 ( & encBuffer [ 5 ] , client_dh_inner_size , & encBuffer [ 0 ] ) ;
if ( encSize < encFullSize ) {
encBuffer . resize ( encFullSize ) ;
memset_rand ( & encBuffer [ encSize ] , ( encFullSize - encSize ) * sizeof ( mtpPrime ) ) ;
}
sdhEncString . resize ( encFullSize * 4 ) ;
2016-03-24 15:57:10 +03:00
aesIgeEncrypt ( & encBuffer [ 0 ] , & sdhEncString [ 0 ] , encFullSize * sizeof ( mtpPrime ) , authKeyData - > aesKey , authKeyData - > aesIV ) ;
2014-05-30 12:53:19 +04:00
2015-06-10 15:48:26 +03:00
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhClientParamsAnswered ( ) ) ) ;
2014-05-30 12:53:19 +04:00
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_client_DH_params... " ) ) ;
2014-05-30 12:53:19 +04:00
sendRequestNotSecure ( req_client_DH_params ) ;
}
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 ;
2015-06-10 15:48:26 +03:00
disconnect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhClientParamsAnswered ( ) ) ) ;
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 ;
if ( ! readResponseNotSecure ( 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 ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( resDH . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( resDH . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
authKeyData - > new_nonce_buf [ 32 ] = 1 ;
uchar sha1Buffer [ 20 ] ;
if ( resDH . vnew_nonce_hash1 ! = * ( MTPint128 * ) ( hashSha1 ( authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
LOG ( ( " AuthKey Error: received new_nonce_hash1 did not match! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
uint64 salt1 = authKeyData - > new_nonce . l . l , salt2 = authKeyData - > server_nonce . l , serverSalt = salt1 ^ salt2 ;
sessionData - > setSalt ( serverSalt ) ;
2016-03-24 15:57:10 +03:00
AuthKeyPtr authKey ( new AuthKey ( ) ) ;
2014-05-30 12:53:19 +04:00
authKey - > setKey ( authKeyData - > auth_key ) ;
2016-03-24 11:57:11 +03:00
authKey - > setDC ( bareDcId ( dc ) ) ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3 " ) . arg ( authKey - > keyId ( ) ) . arg ( serverSalt ) . arg ( Logs : : mb ( authKeyData - > auth_key , 256 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
2014-11-15 02:23:35 +03:00
sessionData - > owner ( ) - > notifyKeyCreated ( authKey ) ; // slot will call authKeyCreated()
2014-05-30 12:53:19 +04:00
sessionData - > clear ( ) ;
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 ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( resDH . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( resDH . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
authKeyData - > new_nonce_buf [ 32 ] = 2 ;
uchar sha1Buffer [ 20 ] ;
if ( resDH . vnew_nonce_hash2 ! = * ( MTPint128 * ) ( hashSha1 ( authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
LOG ( ( " AuthKey Error: received new_nonce_hash2 did not match! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
authKeyData - > retry_id = authKeyData - > auth_key_aux_hash ;
} 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 ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( resDH . vnonce ! = authKeyData - > nonce ) {
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
if ( resDH . vserver_nonce ! = authKeyData - > server_nonce ) {
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
}
authKeyData - > new_nonce_buf [ 32 ] = 3 ;
uchar sha1Buffer [ 20 ] ;
if ( resDH . vnew_nonce_hash3 ! = * ( MTPint128 * ) ( hashSha1 ( authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
LOG ( ( " AuthKey Error: received new_nonce_hash3 did not match! " ) ) ;
2016-01-11 23:43:29 +08: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 ( ) ;
2015-06-10 15:48:26 +03:00
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( 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 ( ) {
2014-05-30 12:53:19 +04:00
if ( authKeyData ) {
2015-03-12 13:28:10 +03:00
# ifdef Q_OS_WIN
2014-11-05 20:43:32 +03:00
SecureZeroMemory ( authKeyData , sizeof ( AuthKeyCreateData ) ) ;
if ( ! authKeyStrings - > dh_prime . isEmpty ( ) ) SecureZeroMemory ( authKeyStrings - > dh_prime . data ( ) , authKeyStrings - > dh_prime . size ( ) ) ;
if ( ! authKeyStrings - > g_a . isEmpty ( ) ) SecureZeroMemory ( authKeyStrings - > g_a . data ( ) , authKeyStrings - > g_a . size ( ) ) ;
2014-05-30 12:53:19 +04:00
# else
2014-11-05 20:43:32 +03:00
memset ( authKeyData , 0 , sizeof ( AuthKeyCreateData ) ) ;
if ( ! authKeyStrings - > dh_prime . isEmpty ( ) ) memset ( authKeyStrings - > dh_prime . data ( ) , 0 , authKeyStrings - > dh_prime . size ( ) ) ;
if ( ! authKeyStrings - > g_a . isEmpty ( ) ) memset ( authKeyStrings - > g_a . data ( ) , 0 , authKeyStrings - > g_a . size ( ) ) ;
2014-05-30 12:53:19 +04:00
# endif
2014-07-08 14:24:21 +04:00
delete authKeyData ;
2014-05-30 12:53:19 +04:00
authKeyData = 0 ;
2014-11-05 20:43:32 +03:00
delete authKeyStrings ;
authKeyStrings = 0 ;
2014-05-30 12:53:19 +04:00
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onError4 ( bool mayBeBadKey ) {
2015-06-10 15:48:26 +03:00
if ( _conn & & _conn = = _conn6 ) return ; // error in the unused
2015-06-02 14:22:00 +03:00
2015-06-10 15:48:26 +03:00
if ( _conn | | ! _conn6 ) {
destroyConn ( ) ;
_waitForConnectedTimer . stop ( ) ;
2016-03-24 18:07:13 +03:00
MTP_LOG ( dc , ( " Restarting after error in IPv4 connection, maybe bad key: %1... " ) . arg ( Logs : : b ( mayBeBadKey ) ) ) ;
2015-06-10 15:48:26 +03:00
return restart ( mayBeBadKey ) ;
} else {
destroyConn ( & _conn4 ) ;
}
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onError6 ( bool mayBeBadKey ) {
2015-06-10 15:48:26 +03:00
if ( _conn & & _conn = = _conn4 ) return ; // error in the unused
if ( _conn | | ! _conn4 ) {
destroyConn ( ) ;
_waitForConnectedTimer . stop ( ) ;
2016-03-24 18:07:13 +03:00
MTP_LOG ( dc , ( " Restarting after error in IPv6 connection, maybe bad key: %1... " ) . arg ( Logs : : b ( mayBeBadKey ) ) ) ;
2015-06-10 15:48:26 +03:00
return restart ( mayBeBadKey ) ;
} else {
destroyConn ( & _conn6 ) ;
}
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
}
template < typename TRequest >
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : sendRequestNotSecure ( const TRequest & request ) {
2014-05-30 12:53:19 +04:00
try {
mtpBuffer buffer ;
2014-11-15 02:23:35 +03:00
uint32 requestSize = request . innerLength ( ) > > 2 ;
2014-05-30 12:53:19 +04:00
buffer . resize ( 0 ) ;
buffer . reserve ( 8 + requestSize ) ;
buffer . push_back ( 0 ) ; // tcp packet len
buffer . push_back ( 0 ) ; // tcp packet num
buffer . push_back ( 0 ) ;
buffer . push_back ( 0 ) ;
buffer . push_back ( authKeyData - > req_num ) ;
buffer . push_back ( unixtime ( ) ) ;
buffer . push_back ( requestSize * 4 ) ;
request . write ( buffer ) ;
buffer . push_back ( 0 ) ; // tcp crc32 hash
+ + authKeyData - > msgs_sent ;
DEBUG_LOG ( ( " AuthKey Info: sending request, size: %1, num: %2, time: %3 " ) . arg ( requestSize ) . arg ( authKeyData - > req_num ) . arg ( buffer [ 5 ] ) ) ;
2015-06-10 15:48:26 +03:00
_conn - > sendData ( buffer ) ;
2014-05-30 12:53:19 +04:00
onSentSome ( buffer . size ( ) * sizeof ( mtpPrime ) ) ;
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
}
template < typename TResponse >
2016-03-24 11:57:11 +03:00
bool ConnectionPrivate : : readResponseNotSecure ( TResponse & response ) {
2014-05-30 12:53:19 +04:00
onReceivedSome ( ) ;
try {
2015-06-10 15:48:26 +03:00
if ( _conn - > received ( ) . isEmpty ( ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: trying to read response from empty received list " ) ) ;
return false ;
}
2015-06-10 15:48:26 +03:00
mtpBuffer buffer ( _conn - > received ( ) . front ( ) ) ;
_conn - > received ( ) . pop_front ( ) ;
2014-05-30 12:53:19 +04:00
const mtpPrime * answer ( buffer . constData ( ) ) ;
uint32 len = buffer . size ( ) ;
if ( len < 5 ) {
LOG ( ( " AuthKey Error: bad request answer, len = %1 " ) . arg ( len * sizeof ( mtpPrime ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: answer bytes %1 " ) . arg ( Logs : : mb ( answer , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
if ( answer [ 0 ] ! = 0 | | answer [ 1 ] ! = 0 | | ( ( ( uint32 ) answer [ 2 ] ) & 0x03 ) ! = 1 /* || (unixtime() - answer[3] > 300) || (answer[3] - unixtime() > 60)*/ ) { // didnt sync time yet
LOG ( ( " AuthKey Error: bad request answer start (%1 %2 %3) " ) . arg ( answer [ 0 ] ) . arg ( answer [ 1 ] ) . arg ( answer [ 2 ] ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: answer bytes %1 " ) . arg ( Logs : : mb ( answer , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
uint32 answerLen = ( uint32 ) answer [ 4 ] ;
if ( answerLen ! = ( len - 5 ) * sizeof ( mtpPrime ) ) {
LOG ( ( " AuthKey Error: bad request answer %1 <> %2 " ) . arg ( answerLen ) . arg ( ( len - 5 ) * sizeof ( mtpPrime ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: answer bytes %1 " ) . arg ( Logs : : mb ( answer , len * sizeof ( mtpPrime ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return false ;
}
const mtpPrime * from ( answer + 5 ) , * end ( from + len - 5 ) ;
response . read ( from , end ) ;
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
return false ;
}
return true ;
}
2016-03-24 11:57:11 +03:00
bool ConnectionPrivate : : sendRequest ( mtpRequest & request , bool needAnyResponse , QReadLocker & lockFinished ) {
2014-05-30 12:53:19 +04:00
uint32 fullSize = request - > size ( ) ;
if ( fullSize < 9 ) return false ;
uint32 messageSize = mtpRequestData : : messageSize ( request ) ;
if ( messageSize < 5 | | fullSize < messageSize + 4 ) return false ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting... " ) . arg ( dc ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
2016-03-24 15:57:10 +03:00
AuthKeyPtr key ( sessionData - > getKey ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( dc ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
uint32 padding = fullSize - 4 - messageSize ;
uint64 session ( sessionData - > getSession ( ) ) , salt ( sessionData - > getSalt ( ) ) ;
memcpy ( request - > data ( ) + 0 , & salt , 2 * sizeof ( mtpPrime ) ) ;
memcpy ( request - > data ( ) + 2 , & session , 2 * sizeof ( mtpPrime ) ) ;
const mtpPrime * from = request - > constData ( ) + 4 ;
2014-10-21 02:49:37 +04:00
MTP_LOG ( dc , ( " Send: " ) + mtpTextSerialize ( from , from + messageSize ) ) ;
2014-05-30 12:53:19 +04:00
uchar encryptedSHA [ 20 ] ;
MTPint128 & msgKey ( * ( MTPint128 * ) ( encryptedSHA + 4 ) ) ;
hashSha1 ( request - > constData ( ) , ( fullSize - padding ) * sizeof ( mtpPrime ) , encryptedSHA ) ;
mtpBuffer result ;
result . resize ( 9 + fullSize ) ;
* ( ( uint64 * ) & result [ 2 ] ) = keyId ;
* ( ( MTPint128 * ) & result [ 4 ] ) = msgKey ;
2016-03-24 15:57:10 +03:00
aesIgeEncrypt ( request - > constData ( ) , & result [ 8 ] , fullSize * sizeof ( mtpPrime ) , key , msgKey ) ;
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 ] ) ) ;
2015-06-10 15:48:26 +03:00
_conn - > setSentEncrypted ( ) ;
_conn - > sendData ( result ) ;
2014-05-30 12:53:19 +04:00
if ( needAnyResponse ) {
onSentSome ( result . size ( ) * sizeof ( mtpPrime ) ) ;
}
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 ( ) ) ;
const mtpRequestMap & haveSent ( sessionData - > haveSentMap ( ) ) ;
mtpRequestMap : : const_iterator i = haveSent . constFind ( msgId ) ;
2014-06-16 13:31:10 +04:00
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 ( ) ) ;
const mtpRequestIdsMap & toResend ( sessionData - > toResendMap ( ) ) ;
mtpRequestIdsMap : : const_iterator i = toResend . constFind ( msgId ) ;
if ( i ! = toResend . cend ( ) ) return i . value ( ) ;
}
{
QReadLocker locker ( sessionData - > wereAckedMutex ( ) ) ;
const mtpRequestIdsMap & wereAcked ( sessionData - > wereAckedMap ( ) ) ;
mtpRequestIdsMap : : const_iterator i = wereAcked . constFind ( msgId ) ;
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 ( ) {
2016-02-29 19:53:26 +03:00
t_assert ( _finished & & _conn = = nullptr & & _conn4 = = nullptr & & _conn6 = = nullptr ) ;
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
} // namespace MTP