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
2017-01-11 22:31:31 +04:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
2016-03-23 21:43:12 +03:00
# include "mtproto/connection.h"
2016-03-23 21:12:07 +03:00
# 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"
2017-01-13 14:58:41 +03:00
# include "lang.h"
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
# include "mtproto/rsa_public_key.h"
2017-02-23 13:59:19 +03:00
# include "messenger.h"
2017-02-23 09:57:04 +03:00
# include "mtproto/dc_options.h"
# include "mtproto/connection_abstract.h"
2016-03-23 21:12:07 +03:00
namespace MTP {
namespace internal {
2016-03-24 11:57:11 +03:00
namespace {
2017-02-25 19:44:02 +03:00
constexpr auto kRecreateKeyId = AuthKey : : KeyId ( 0xFFFFFFFFFFFFFFFFULL ) ;
2017-02-27 12:51:03 +03:00
constexpr auto kIntSize = static_cast < int > ( sizeof ( mtpPrime ) ) ;
2017-02-25 19:44:02 +03:00
2017-02-24 20:15:41 +03:00
void wrapInvokeAfter ( mtpRequest & to , const mtpRequest & from , const mtpRequestMap & haveSent , int32 skipBeforeRequest = 0 ) {
mtpMsgId afterId ( * ( mtpMsgId * ) ( from - > after - > data ( ) + 4 ) ) ;
mtpRequestMap : : const_iterator i = afterId ? haveSent . constFind ( afterId ) : haveSent . cend ( ) ;
int32 size = to - > size ( ) , lenInInts = ( from . innerLength ( ) > > 2 ) , headlen = 4 , fulllen = headlen + lenInInts ;
if ( i = = haveSent . constEnd ( ) ) { // no invoke after or such msg was not sent or was completed recently
to - > resize ( size + fulllen + skipBeforeRequest ) ;
if ( skipBeforeRequest ) {
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , headlen * sizeof ( mtpPrime ) ) ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest , from - > constData ( ) + 4 + headlen , lenInInts * sizeof ( mtpPrime ) ) ;
} else {
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , fulllen * sizeof ( mtpPrime ) ) ;
}
} else {
to - > resize ( size + fulllen + skipBeforeRequest + 3 ) ;
memcpy ( to - > data ( ) + size , from - > constData ( ) + 4 , headlen * sizeof ( mtpPrime ) ) ;
( * to ) [ size + 3 ] + = 3 * sizeof ( mtpPrime ) ;
* ( ( mtpTypeId * ) & ( ( * to ) [ size + headlen + skipBeforeRequest ] ) ) = mtpc_invokeAfterMsg ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest + 1 , & afterId , 2 * sizeof ( mtpPrime ) ) ;
memcpy ( to - > data ( ) + size + headlen + skipBeforeRequest + 3 , from - > constData ( ) + 4 + headlen , lenInInts * sizeof ( mtpPrime ) ) ;
if ( size + 3 ! = 7 ) ( * to ) [ 7 ] + = 3 * sizeof ( mtpPrime ) ;
}
}
2017-03-10 22:46:28 +03:00
bool parsePQ ( const QByteArray & pqStr , QByteArray & pStr , QByteArray & qStr ) {
2016-03-23 21:12:07 +03:00
if ( pqStr . length ( ) > 8 ) return false ; // more than 64 bit pq
uint64 pq = 0 , p , q ;
2017-03-10 22:46:28 +03:00
const uchar * pqChars = ( const uchar * ) pqStr . constData ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 , l = pqStr . length ( ) ; i < l ; + + i ) {
pq < < = 8 ;
pq | = ( uint64 ) pqChars [ i ] ;
}
uint64 pqSqrt = ( uint64 ) sqrtl ( ( long double ) pq ) , ySqr , y ;
while ( pqSqrt * pqSqrt > pq ) - - pqSqrt ;
while ( pqSqrt * pqSqrt < pq ) + + pqSqrt ;
for ( ySqr = pqSqrt * pqSqrt - pq ; ; + + pqSqrt , ySqr = pqSqrt * pqSqrt - pq ) {
y = ( uint64 ) sqrtl ( ( long double ) ySqr ) ;
while ( y * y > ySqr ) - - y ;
while ( y * y < ySqr ) + + y ;
if ( ! ySqr | | y + pqSqrt > = pq ) return false ;
if ( y * y = = ySqr ) {
p = pqSqrt + y ;
q = ( pqSqrt > y ) ? ( pqSqrt - y ) : ( y - pqSqrt ) ;
break ;
}
}
2016-03-28 20:15:17 +03:00
if ( p > q ) std : : swap ( p , q ) ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
pStr . resize ( 4 ) ;
2017-03-10 22:46:28 +03:00
uchar * pChars = ( uchar * ) pStr . data ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( pChars + 3 - i ) = ( uchar ) ( p & 0xFF ) ;
p > > = 8 ;
}
qStr . resize ( 4 ) ;
2017-03-10 22:46:28 +03:00
uchar * qChars = ( uchar * ) qStr . data ( ) ;
2016-03-23 21:12:07 +03:00
for ( uint32 i = 0 ; i < 4 ; + + i ) {
* ( qChars + 3 - i ) = ( uchar ) ( q & 0xFF ) ;
q > > = 8 ;
}
return true ;
}
class BigNumCounter {
public :
2017-04-03 21:28:18 +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 ) ;
BN_init ( & bnTemp ) ;
}
~ 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 ) ;
BN_clear_free ( & bnTemp ) ;
}
2016-03-23 21:12:07 +03:00
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-12-07 16:32:25 +03:00
// check g_b > 2^{2048 - 8} and get the value of g_b
if ( BN_is_negative ( & bnResult ) ) {
LOG ( ( " BigNum Error: bad g_b - negative " ) ) ;
return false ;
}
2016-03-23 21:12:07 +03:00
uint32 resultLen = BN_num_bytes ( & bnResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
2016-12-07 16:32:25 +03:00
LOG ( ( " BigNum Error: bad g_b len (%1) " ) . arg ( resultLen ) ) ;
2016-03-23 21:12:07 +03:00
return false ;
}
resultLen = BN_bn2bin ( & bnResult , ( uchar * ) gResult ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
2016-12-07 16:32:25 +03:00
LOG ( ( " BigNum Error: bad g_b export len (%1) " ) . arg ( resultLen ) ) ;
2016-03-23 21:12:07 +03:00
return false ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
// check g_b < dh_prime - 2^{2048 - 8}
BN_sub ( & bnTemp , & bnModul , & bnResult ) ;
if ( BN_is_negative ( & bnTemp ) ) {
DEBUG_LOG ( ( " BigNum Error: bad g_b > dh_prime " ) ) ;
return false ;
}
if ( BN_num_bytes ( & bnTemp ) ! = 64 * sizeof ( uint32 ) ) {
DEBUG_LOG ( ( " BigNum Error: bad g_b > dh_prime - 2^{2048 - 8} " ) ) ;
2016-03-23 21:12:07 +03:00
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-12-07 16:32:25 +03:00
// check g_a > 2^{2048 - 8}
if ( BN_is_negative ( & bn_g_a ) ) {
LOG ( ( " BigNum Error: bad g_a - negative " ) ) ;
return false ;
}
resultLen = BN_num_bytes ( & bn_g_a ) ;
if ( resultLen ! = 64 * sizeof ( uint32 ) ) {
LOG ( ( " BigNum Error: bad g_a len (%1) " ) . arg ( resultLen ) ) ;
return false ;
}
// check g_a < dh_prime - 2^{2048 - 8}
BN_sub ( & bnTemp , & bnModul , & bn_g_a ) ;
if ( BN_is_negative ( & bnTemp ) ) {
LOG ( ( " BigNum Error: bad g_b > dh_prime " ) ) ;
return false ;
}
if ( BN_num_bytes ( & bnTemp ) ! = 64 * sizeof ( uint32 ) ) {
LOG ( ( " BigNum Error: bad g_b > dh_prime - 2^{2048 - 8} " ) ) ;
2016-03-23 21:12:07 +03:00
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
private :
2016-12-07 16:32:25 +03:00
BIGNUM bnPower , bnModul , bn_g , bn_g_a , bnResult , bnTemp ;
2016-03-23 21:12:07 +03:00
BN_CTX * ctx ;
2016-12-07 16:32:25 +03:00
2016-03-23 21:12:07 +03:00
} ;
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
// Miller-Rabin primality test
class BigNumPrimeTest {
public :
2017-04-03 21:28:18 +03:00
BigNumPrimeTest ( ) : _context ( BN_CTX_new ( ) ) {
BN_init ( & _prime ) ;
}
~ BigNumPrimeTest ( ) {
BN_clear_free ( & _prime ) ;
BN_CTX_free ( _context ) ;
}
bool isPrimeAndGood ( const QByteArray & data , int g ) {
constexpr auto kMillerRabinIterationCount = 30 ;
constexpr auto kGoodPrimeSize = 256 ;
2016-01-11 23:43:29 +08:00
2017-04-03 21:28:18 +03:00
if ( data . size ( ) ! = kGoodPrimeSize ) {
LOG ( ( " BigNum PT Error: data size %1 " ) . arg ( data . size ( ) ) ) ;
return false ;
}
if ( ! memcmp ( data . constData ( ) , " \
\ 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 " , kGoodPrimeSize)) {
2016-03-23 21:12:07 +03:00
if ( g = = 3 | | g = = 4 | | g = = 5 | | g = = 7 ) {
return true ;
2014-05-30 12:53:19 +04:00
}
}
2017-04-03 21:28:18 +03:00
if ( ! BN_bin2bn ( ( const uchar * ) data . constData ( ) , kGoodPrimeSize , & _prime ) ) {
2016-03-23 21:12:07 +03:00
ERR_load_crypto_strings ( ) ;
LOG ( ( " BigNum PT Error: BN_bin2bn failed, error: %1 " ) . arg ( ERR_error_string ( ERR_get_error ( ) , 0 ) ) ) ;
2017-04-03 21:28:18 +03:00
DEBUG_LOG ( ( " BigNum PT Error: prime %1 " ) . arg ( Logs : : mb ( data . constData ( ) , kGoodPrimeSize ) . str ( ) ) ) ;
2016-03-23 21:12:07 +03:00
return false ;
2014-05-30 12:53:19 +04:00
}
2017-04-03 21:28:18 +03:00
auto numBits = BN_num_bits ( & _prime ) ;
2016-03-23 21:12:07 +03:00
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
2017-04-03 21:28:18 +03:00
if ( BN_is_prime_ex ( & _prime , kMillerRabinIterationCount , _context , NULL ) = = 0 ) {
2016-03-23 21:12:07 +03:00
return false ;
}
2014-05-30 12:53:19 +04:00
2016-03-23 21:12:07 +03:00
switch ( g ) {
case 2 : {
2017-04-03 21:28:18 +03:00
auto mod8 = BN_mod_word ( & _prime , 8 ) ;
2016-03-23 21:12:07 +03:00
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 : {
2017-04-03 21:28:18 +03:00
auto mod3 = BN_mod_word ( & _prime , 3 ) ;
2016-03-23 21:12:07 +03:00
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 : {
2017-04-03 21:28:18 +03:00
auto mod5 = BN_mod_word ( & _prime , 5 ) ;
2016-03-23 21:12:07 +03:00
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 : {
2017-04-03 21:28:18 +03:00
auto mod24 = BN_mod_word ( & _prime , 24 ) ;
2016-03-23 21:12:07 +03:00
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 : {
2017-04-03 21:28:18 +03:00
auto mod7 = BN_mod_word ( & _prime , 7 ) ;
2016-03-23 21:12:07 +03:00
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 ;
2017-04-03 21:28:18 +03:00
default : {
LOG ( ( " BigNum PT Error: bad g value: %1 " ) . arg ( g ) ) ;
return false ;
} break ;
2014-05-30 12:53:19 +04:00
}
2017-04-03 21:28:18 +03:00
BN_sub_word ( & _prime , 1 ) ; // (p - 1) / 2
BN_div_word ( & _prime , 2 ) ;
2016-03-23 21:12:07 +03:00
2017-04-03 21:28:18 +03:00
if ( BN_is_prime_ex ( & _prime , kMillerRabinIterationCount , _context , NULL ) = = 0 ) {
2016-03-23 21:12:07 +03:00
return false ;
2014-05-30 12:53:19 +04:00
}
2016-03-23 21:12:07 +03:00
return true ;
}
private :
2017-04-03 21:28:18 +03:00
BIGNUM _prime ;
BN_CTX * _context ;
2016-03-23 21:12:07 +03:00
} ;
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
2017-02-24 20:15:41 +03:00
Connection : : Connection ( Instance * instance ) : _instance ( instance ) {
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
void Connection : : start ( SessionData * sessionData , ShiftedDcId shiftedDcId ) {
2017-03-23 19:11:35 +03:00
Expects ( thread = = nullptr & & data = = nullptr ) ;
2014-05-30 12:53:19 +04:00
2017-02-24 20:15:41 +03:00
thread = std : : make_unique < Thread > ( ) ;
2017-02-25 19:44:02 +03:00
auto newData = std : : make_unique < ConnectionPrivate > ( _instance , thread . get ( ) , this , sessionData , shiftedDcId ) ;
2016-02-29 19:53:26 +03:00
2017-02-25 19:44:02 +03:00
// will be deleted in the thread::finished signal
data = newData . release ( ) ;
2014-05-30 12:53:19 +04:00
thread - > start ( ) ;
}
2016-03-24 11:57:11 +03:00
void Connection : : kill ( ) {
2017-03-23 19:11:35 +03:00
Expects ( data ! = nullptr & & thread ! = nullptr ) ;
2016-02-29 19:53:26 +03:00
data - > stop ( ) ;
2017-02-24 20:15:41 +03:00
data = nullptr ;
2016-02-29 19:53:26 +03:00
thread - > quit ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void Connection : : waitTillFinish ( ) {
2017-03-23 19:11:35 +03:00
Expects ( data = = nullptr & & thread ! = nullptr ) ;
2016-02-29 19:53:26 +03:00
2016-03-01 05:36:23 +03:00
DEBUG_LOG ( ( " Waiting for connectionThread to finish " ) ) ;
2016-02-29 19:53:26 +03:00
thread - > wait ( ) ;
2017-02-24 20:15:41 +03:00
thread . reset ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
int32 Connection : : state ( ) const {
2017-03-23 19:11:35 +03:00
Expects ( 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 {
2017-03-23 19:11:35 +03:00
Expects ( 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 ( ) {
2017-03-23 19:11:35 +03:00
Expects ( data = = nullptr ) ;
2017-02-24 20:15:41 +03:00
if ( thread ) {
waitTillFinish ( ) ;
}
2016-02-29 19:53:26 +03:00
}
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 ( ) ) ;
2017-02-25 19:44:02 +03:00
connect ( _conn4 , SIGNAL ( error ( qint32 ) ) , this , SLOT ( onError4 ( qint32 ) ) ) ;
2015-06-10 15:48:26 +03:00
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 ( ) ) ;
2017-02-25 19:44:02 +03:00
connect ( _conn6 , SIGNAL ( error ( qint32 ) ) , this , SLOT ( onError6 ( qint32 ) ) ) ;
2015-06-10 15:48:26 +03:00
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 ) ;
2017-02-25 19:44:02 +03:00
disconnect ( * conn , SIGNAL ( error ( qint32 ) ) , nullptr , nullptr ) ;
2016-03-24 11:57:11 +03:00
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
}
}
2017-02-25 19:44:02 +03:00
ConnectionPrivate : : ConnectionPrivate ( Instance * instance , QThread * thread , Connection * owner , SessionData * data , ShiftedDcId shiftedDcId ) : QObject ( )
2017-02-24 20:15:41 +03:00
, _instance ( instance )
2016-03-24 11:57:11 +03:00
, _state ( DisconnectedState )
2017-02-25 19:44:02 +03:00
, _shiftedDcId ( shiftedDcId )
2016-02-29 19:53:26 +03:00
, _owner ( owner )
, _waitForReceived ( MTPMinReceiveDelay )
, _waitForConnected ( MTPMinConnectDelay )
2017-02-22 18:18:26 +03:00
//, sessionDataMutex(QReadWriteLock::Recursive)
2016-12-07 16:32:25 +03:00
, sessionData ( data ) {
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 ) ;
2017-03-23 19:11:35 +03:00
Expects ( _shiftedDcId ! = 0 ) ;
2014-05-30 12:53:19 +04:00
2017-03-23 19:11:35 +03:00
connect ( thread , & QThread : : started , this , [ this ] { connectToServer ( ) ; } ) ;
connect ( thread , & QThread : : finished , this , [ this ] { finishAndDestroy ( ) ; } ) ;
2017-02-24 20:15:41 +03:00
connect ( this , SIGNAL ( finished ( internal : : Connection * ) ) , _instance , SLOT ( connectionFinished ( internal : : Connection * ) ) , Qt : : QueuedConnection ) ;
2014-05-30 12:53:19 +04:00
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 ;
2016-12-07 16:32:25 +03:00
qRegisterMetaType < QVector < quint64 > > ( " QVector<quint64> " ) ;
2014-11-25 15:15:29 +03:00
}
2014-12-05 16:44:27 +03:00
connect ( this , SIGNAL ( needToSendAsync ( ) ) , sessionData - > owner ( ) , SLOT ( needToResumeAndSend ( ) ) , Qt : : QueuedConnection ) ;
2016-12-01 22:20:33 +03:00
connect ( this , SIGNAL ( sendAnythingAsync ( qint64 ) ) , sessionData - > owner ( ) , SLOT ( sendAnything ( qint64 ) ) , Qt : : QueuedConnection ) ;
2015-03-12 13:28:10 +03:00
connect ( this , SIGNAL ( sendHttpWaitAsync ( ) ) , sessionData - > owner ( ) , SLOT ( sendAnything ( ) ) , Qt : : QueuedConnection ) ;
2014-11-25 15:15:29 +03:00
connect ( this , SIGNAL ( sendPongAsync ( quint64 , quint64 ) ) , sessionData - > owner ( ) , SLOT ( sendPong ( quint64 , quint64 ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( sendMsgsStateInfoAsync ( quint64 , QByteArray ) ) , sessionData - > owner ( ) , SLOT ( sendMsgsStateInfo ( quint64 , QByteArray ) ) , Qt : : QueuedConnection ) ;
2016-12-01 22:20:33 +03:00
connect ( this , SIGNAL ( resendAsync ( quint64 , qint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resend ( quint64 , qint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
connect ( this , SIGNAL ( resendManyAsync ( QVector < quint64 > , qint64 , bool , bool ) ) , sessionData - > owner ( ) , SLOT ( resendMany ( QVector < quint64 > , qint64 , bool , bool ) ) , Qt : : QueuedConnection ) ;
2014-11-25 15:15:29 +03:00
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 ( ) {
2017-03-23 19:11:35 +03:00
connectToServer ( true ) ;
}
void ConnectionPrivate : : onCDNConfigLoaded ( ) {
restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
int32 ConnectionPrivate : : getShiftedDcId ( ) const {
return _shiftedDcId ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
int32 ConnectionPrivate : : getState ( ) const {
2015-06-25 21:04:40 +03:00
QReadLocker lock ( & stateConnMutex ) ;
2014-05-30 12:53:19 +04:00
int32 result = _state ;
if ( _state < 0 ) {
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 ;
}
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
2014-08-01 15:09:46 +04:00
replaces . insert ( id , newId ) ;
id = newId ;
* ( mtpMsgId * ) ( i . value ( ) - > data ( ) + 4 ) = id ;
}
setSeqNumbers . insert ( id , i . value ( ) ) ;
}
}
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 ;
}
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Replacing msgId %1 to %2! " ) . arg ( id ) . arg ( newId ) ) ;
2014-08-01 15:09:46 +04:00
replaces . insert ( id , newId ) ;
id = newId ;
* ( mtpMsgId * ) ( j . value ( ) - > data ( ) + 4 ) = id ;
}
setSeqNumbers . insert ( id , j . value ( ) ) ;
}
}
2016-03-24 13:12:18 +03:00
uint64 session = rand_value < uint64 > ( ) ;
2014-08-01 15:09:46 +04:00
DEBUG_LOG ( ( " MTP Info: creating new session after bad_msg_notification, setting random server_session %1 " ) . arg ( session ) ) ;
sessionData - > setSession ( session ) ;
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 ;
2017-02-25 19:44:02 +03:00
if ( _shiftedDcId = = bareDcId ( _shiftedDcId ) ) { // 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 ) {
2017-02-25 19:44:02 +03:00
if ( prependOnly | | _shiftedDcId ! = bareDcId ( _shiftedDcId ) ) {
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
2016-12-01 22:20:33 +03:00
_pingSendAt = pingRequest - > msDate + ( MTPPingSendAfterAuto * 1000LL ) ;
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
2017-02-25 19:44:02 +03:00
if ( _shiftedDcId = = bareDcId ( _shiftedDcId ) & & ! 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 ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: dc %1 not sending, waiting for Connected state, state: %2 " ) . arg ( _shiftedDcId ) . arg ( state ) ) ;
2014-05-30 12:53:19 +04:00
return ; // just do nothing, if is not connected yet
2015-03-12 13:28:10 +03:00
} else {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: dc %1 trying to send after ping, state: %2 " ) . arg ( _shiftedDcId ) . arg ( state ) ) ;
2014-05-30 12:53:19 +04:00
}
}
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
}
2017-03-23 19:11:35 +03:00
MTPInitConnection < mtpRequest > initWrapper ;
2014-11-15 02:23:35 +03:00
int32 initSize = 0 , initSizeInInts = 0 ;
if ( needsLayer ) {
2017-01-13 14:58:41 +03:00
auto langCode = ( cLang ( ) = = languageTest | | cLang ( ) = = languageDefault ) ? Sandbox : : LangSystemISO ( ) : str_const_toString ( LanguageCodes [ cLang ( ) ] ) ;
2017-03-23 19:11:35 +03:00
auto deviceModel = ( _dcType = = DcType : : Cdn ) ? " n/a " : cApiDeviceModel ( ) ;
auto systemVersion = ( _dcType = = DcType : : Cdn ) ? " n/a " : cApiSystemVersion ( ) ;
initWrapper = MTPInitConnection < mtpRequest > ( MTP_int ( ApiId ) , MTP_string ( deviceModel ) , MTP_string ( systemVersion ) , MTP_string ( cApiAppVersion ( ) ) , MTP_string ( langCode ) , mtpRequest ( ) ) ;
initSizeInInts = ( initWrapper . innerLength ( ) > > 2 ) + 2 ;
2014-11-15 02:23:35 +03:00
initSize = initSizeInInts * sizeof ( mtpPrime ) ;
}
2014-05-30 12:53:19 +04:00
bool needAnyResponse = false ;
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 ) ;
2017-03-23 19:11:35 +03:00
initWrapper . write ( * wrappedRequest ) ;
2014-11-15 02:23:35 +03:00
wrappedRequest - > resize ( wrappedRequest - > size ( ) + noWrapSize ) ;
memcpy ( wrappedRequest - > data ( ) + wrappedRequest - > size ( ) - noWrapSize , toSendRequest - > constData ( ) + 8 , noWrapSize * sizeof ( mtpPrime ) ) ;
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 ) ;
2017-03-23 19:11: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 ;
}
2017-02-25 19:44:02 +03:00
if ( keyId = = kRecreateKeyId ) {
2014-05-30 12:53:19 +04:00
if ( sessionData - > getKey ( ) ) {
2015-05-14 19:50:04 +03:00
unlockKey ( ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker lock ( sessionData - > keyMutex ( ) ) ;
sessionData - > owner ( ) - > destroyKey ( ) ;
}
keyId = 0 ;
}
2017-03-23 19:11:35 +03:00
connectToServer ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : restartNow ( ) {
2014-05-30 12:53:19 +04:00
retryTimeout = 1 ;
retryTimer . stop ( ) ;
restart ( ) ;
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : connectToServer ( bool afterConfig ) {
2016-02-29 19:53:26 +03:00
if ( _finished ) {
2017-03-23 19:11:35 +03:00
DEBUG_LOG ( ( " MTP Error: connectToServer() called for finished connection! " ) ) ;
2016-02-29 19:53:26 +03:00
return ;
}
2017-03-23 19:11:35 +03:00
auto bareDc = bareDcId ( _shiftedDcId ) ;
_dcType = Messenger : : Instance ( ) . dcOptions ( ) - > dcType ( _shiftedDcId ) ;
if ( _dcType = = DcType : : MediaDownload ) { // using media_only addresses only if key for this dc is already created
2016-02-25 20:23:42 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
2017-03-23 19:11:35 +03:00
if ( ! sessionData | | ! sessionData - > getKey ( ) ) {
_dcType = DcType : : Regular ;
}
} else if ( _dcType = = DcType : : Cdn & & ! _instance - > isKeysDestroyer ( ) ) {
if ( ! Messenger : : Instance ( ) . dcOptions ( ) - > hasCDNKeysForDc ( bareDc ) ) {
requestCDNConfig ( ) ;
return ;
2015-05-14 19:50:04 +03:00
}
}
2017-02-23 09:57:04 +03:00
using Variants = DcOptions : : Variants ;
auto kIPv4 = Variants : : IPv4 ;
auto kIPv6 = Variants : : IPv6 ;
auto kTcp = Variants : : Tcp ;
auto kHttp = Variants : : Http ;
2017-03-23 19:11:35 +03:00
auto variants = Messenger : : Instance ( ) . dcOptions ( ) - > lookup ( bareDc , _dcType ) ;
2017-02-23 09:57:04 +03:00
auto noIPv4 = ( variants . data [ kIPv4 ] [ kHttp ] . port = = 0 ) ;
auto noIPv6 = ( ! Global : : TryIPv6 ( ) | | ( variants . data [ kIPv6 ] [ kHttp ] . port = = 0 ) ) ;
2015-06-10 15:48:26 +03:00
if ( noIPv4 & & noIPv6 ) {
2017-02-25 19:44:02 +03:00
if ( _instance - > isKeysDestroyer ( ) ) {
LOG ( ( " MTP Error: DC %1 options for IPv4 over HTTP not found for auth key destruction! " ) . arg ( _shiftedDcId ) ) ;
if ( Global : : TryIPv6 ( ) & & noIPv6 ) LOG ( ( " MTP Error: DC %1 options for IPv6 over HTTP not found for auth key destruction! " ) . arg ( _shiftedDcId ) ) ;
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
} else if ( afterConfig ) {
LOG ( ( " MTP Error: DC %1 options for IPv4 over HTTP not found right after config load! " ) . arg ( _shiftedDcId ) ) ;
if ( Global : : TryIPv6 ( ) & & noIPv6 ) LOG ( ( " MTP Error: DC %1 options for IPv6 over HTTP not found right after config load! " ) . arg ( _shiftedDcId ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config " ) . arg ( _shiftedDcId ) ) ;
if ( Global : : TryIPv6 ( ) & & noIPv6 ) DEBUG_LOG ( ( " MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config " ) . arg ( _shiftedDcId ) ) ;
2017-02-24 20:15:41 +03:00
connect ( _instance , SIGNAL ( configLoaded ( ) ) , this , SLOT ( onConfigLoaded ( ) ) , Qt : : UniqueConnection ) ;
2017-03-23 19:11:35 +03:00
InvokeQueued ( _instance , [ instance = _instance ] { instance - > configLoadRequest ( ) ; } ) ;
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 ( ) ;
2017-02-23 09:57:04 +03:00
if ( ! noIPv4 ) DEBUG_LOG ( ( " MTP Info: creating IPv4 connection to %1:%2 (tcp) and %3:%4 (http)... " ) . arg ( variants . data [ kIPv4 ] [ kTcp ] . ip . c_str ( ) ) . arg ( variants . data [ kIPv4 ] [ kTcp ] . port ) . arg ( variants . data [ kIPv4 ] [ kHttp ] . ip . c_str ( ) ) . arg ( variants . data [ kIPv4 ] [ kHttp ] . port ) ) ;
if ( ! noIPv6 ) DEBUG_LOG ( ( " MTP Info: creating IPv6 connection to [%1]:%2 (tcp) and [%3]:%4 (http)... " ) . arg ( variants . data [ kIPv6 ] [ kTcp ] . ip . c_str ( ) ) . arg ( variants . data [ kIPv6 ] [ kTcp ] . port ) . arg ( variants . data [ kIPv4 ] [ kHttp ] . ip . c_str ( ) ) . arg ( variants . data [ kIPv4 ] [ kHttp ] . port ) ) ;
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 ( ) ) ) ;
2017-02-23 09:57:04 +03:00
conn - > connectTcp ( variants . data [ kIPv4 ] [ kTcp ] ) ;
conn - > connectHttp ( variants . data [ kIPv4 ] [ kHttp ] ) ;
2016-03-14 12:48:53 +03:00
}
if ( auto conn = _conn6 ) {
connect ( conn , SIGNAL ( connected ( ) ) , this , SLOT ( onConnected6 ( ) ) ) ;
connect ( conn , SIGNAL ( disconnected ( ) ) , this , SLOT ( onDisconnected6 ( ) ) ) ;
2017-02-23 09:57:04 +03:00
conn - > connectTcp ( variants . data [ kIPv6 ] [ kTcp ] ) ;
conn - > connectHttp ( variants . data [ kIPv6 ] [ kHttp ] ) ;
2015-06-10 15:48:26 +03:00
}
2014-05-30 12:53:19 +04:00
}
2017-02-25 19:44:02 +03:00
void ConnectionPrivate : : restart ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: restarting Connection " ) ) ;
2014-05-30 12:53:19 +04:00
2015-06-10 15:48:26 +03:00
_waitForReceivedTimer . stop ( ) ;
_waitForConnectedTimer . stop ( ) ;
2014-05-30 12:53:19 +04:00
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( key ) {
if ( ! sessionData - > isCheckedKey ( ) ) {
2017-02-25 19:44:02 +03:00
// No destroying in case of an error.
//
//if (mayBeBadKey) {
// clearMessages();
// keyId = kRecreateKeyId;
2015-12-08 23:41:04 +03:00
// retryTimeout = 1; // no ddos please
2017-02-25 19:44:02 +03:00
// LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now..."));
//}
2014-05-30 12:53:19 +04:00
} else {
sessionData - > setCheckedKey ( false ) ;
}
}
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
doDisconnect ( ) ;
2015-08-08 12:14:47 +03:00
lockFinished . relock ( ) ;
if ( sessionData & & _needSessionReset ) {
2014-08-01 15:09:46 +04:00
resetSession ( ) ;
}
2014-05-30 12:53:19 +04:00
restarted = true ;
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 ( ) ) {
2017-03-23 19:11:35 +03:00
auto remain = static_cast < uint64 > ( _waitForReceived ) ;
2014-05-30 12:53:19 +04:00
if ( ! oldConnection ) {
2017-03-23 19:11:35 +03:00
auto 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 ) ) ;
}
}
2017-02-25 19:44:02 +03:00
if ( isUploadDcId ( _shiftedDcId ) ) {
2017-03-23 19:11:35 +03:00
remain * = kUploadSessionsCount ;
2017-02-25 19:44:02 +03:00
} else if ( isDownloadDcId ( _shiftedDcId ) ) {
2017-03-23 19:11:35 +03:00
remain * = kDownloadSessionsCount ;
2014-10-30 19:23:44 +03:00
}
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 ) {
2017-01-13 14:58:41 +03:00
if ( _pingSendAt + ( MTPPingSendAfter - MTPPingSendAfterAuto - 1 ) * 1000LL < 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 {
2016-12-01 22:20:33 +03:00
_pingSender . start ( _pingSendAt + ( MTPPingSendAfter - MTPPingSendAfterAuto ) * 1000LL - 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! " ) ) ;
2017-03-23 19:11:35 +03:00
InvokeQueued ( this , [ this ] { connectToServer ( ) ; } ) ;
2014-05-30 12:53:19 +04:00
}
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! " ) ) ;
2017-03-23 19:11:35 +03:00
InvokeQueued ( this , [ this ] { connectToServer ( ) ; } ) ;
2015-06-02 14:22:00 +03:00
}
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 ;
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : finishAndDestroy ( ) {
2014-05-30 12:53:19 +04:00
doDisconnect ( ) ;
2016-02-29 19:53:26 +03:00
_finished = true ;
emit finished ( _owner ) ;
deleteLater ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
void ConnectionPrivate : : requestCDNConfig ( ) {
connect ( _instance , SIGNAL ( cdnConfigLoaded ( ) ) , this , SLOT ( onCDNConfigLoaded ( ) ) , Qt : : UniqueConnection ) ;
InvokeQueued ( _instance , [ instance = _instance ] { instance - > cdnConfigLoadRequest ( ) ; } ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : handleReceived ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
2014-05-30 12:53:19 +04:00
onReceivedSome ( ) ;
2017-02-27 12:51:03 +03:00
auto restartOnError = [ this , & lockFinished ] {
lockFinished . unlock ( ) ;
restart ( ) ;
} ;
2014-05-30 12:53:19 +04:00
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key for dc %1 busy, cant lock " ) . arg ( _shiftedDcId ) ) ;
2014-05-30 12:53:19 +04:00
clearMessages ( ) ;
keyId = 0 ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( _shiftedDcId ) ) ;
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
while ( ! _conn - > received ( ) . empty ( ) ) {
auto intsBuffer = std : : move ( _conn - > received ( ) . front ( ) ) ;
_conn - > received ( ) . pop_front ( ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
constexpr auto kExternalHeaderIntsCount = 6U ; // 2 auth_key_id, 4 msg_key
constexpr auto kEncryptedHeaderIntsCount = 8U ; // 2 salt, 2 session, 2 msg_id, 1 seq_no, 1 length
constexpr auto kMinimalEncryptedIntsCount = kEncryptedHeaderIntsCount + 4U ; // + 1 data + 3 padding
constexpr auto kMinimalIntsCount = kExternalHeaderIntsCount + kMinimalEncryptedIntsCount ;
auto intsCount = uint32 ( intsBuffer . size ( ) ) ;
auto ints = intsBuffer . constData ( ) ;
if ( intsCount < kMinimalIntsCount ) {
LOG ( ( " TCP Error: bad message received, len %1 " ) . arg ( intsCount * kIntSize ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( ints , intsCount * kIntSize ) . str ( ) ) ) ;
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
if ( keyId ! = * ( uint64 * ) ints ) {
LOG ( ( " TCP Error: bad auth_key_id %1 instead of %2 received " ) . arg ( keyId ) . arg ( * ( uint64 * ) ints ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( ints , intsCount * kIntSize ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
auto encryptedInts = ints + kExternalHeaderIntsCount ;
auto encryptedIntsCount = ( intsCount - kExternalHeaderIntsCount ) ;
auto encryptedBytesCount = encryptedIntsCount * kIntSize ;
auto decryptedBuffer = QByteArray ( encryptedBytesCount , Qt : : Uninitialized ) ;
auto msgKey = * ( MTPint128 * ) ( ints + 2 ) ;
2016-01-11 23:43:29 +08:00
2017-02-27 12:51:03 +03:00
aesIgeDecrypt ( encryptedInts , decryptedBuffer . data ( ) , encryptedBytesCount , key , msgKey ) ;
2014-05-30 12:53:19 +04:00
2017-02-27 12:51:03 +03:00
auto decryptedInts = reinterpret_cast < const mtpPrime * > ( decryptedBuffer . constData ( ) ) ;
auto serverSalt = * ( uint64 * ) & decryptedInts [ 0 ] ;
auto session = * ( uint64 * ) & decryptedInts [ 2 ] ;
auto msgId = * ( uint64 * ) & decryptedInts [ 4 ] ;
auto seqNo = * ( uint32 * ) & decryptedInts [ 6 ] ;
auto needAck = ( ( seqNo & 0x01 ) ! = 0 ) ;
2014-05-30 12:53:19 +04:00
2017-02-27 12:51:03 +03:00
auto messageLength = * ( uint32 * ) & decryptedInts [ 7 ] ;
auto fullDataLength = kEncryptedHeaderIntsCount * kIntSize + messageLength ; // Without padding.
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
constexpr auto kMaxPaddingSize = 15U ;
auto paddingSize = encryptedBytesCount - fullDataLength ; // Can underflow.
auto badMessageLength = ( /*paddingSize < 0 || */ paddingSize > kMaxPaddingSize ) ;
auto hashedDataLength = badMessageLength ? encryptedBytesCount : fullDataLength ;
auto sha1ForMsgKeyCheck = hashSha1 ( decryptedInts , hashedDataLength ) ;
if ( memcmp ( & msgKey , sha1ForMsgKeyCheck . data ( ) + sha1ForMsgKeyCheck . size ( ) - sizeof ( msgKey ) , sizeof ( msgKey ) ) ! = 0 ) {
LOG ( ( " TCP Error: bad SHA1 hash after aesDecrypt in message. " ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encryptedInts , encryptedBytesCount ) . str ( ) ) ) ;
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
if ( badMessageLength | | ( messageLength & 0x03 ) ) {
LOG ( ( " TCP Error: bad msg_len received %1, data size: %2 " ) . arg ( messageLength ) . arg ( encryptedBytesCount ) ) ;
TCP_LOG ( ( " TCP Error: bad message %1 " ) . arg ( Logs : : mb ( encryptedInts , encryptedBytesCount ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-02-27 12:51:03 +03:00
TCP_LOG ( ( " TCP Info: decrypted message %1,%2,%3 is %4 len " ) . arg ( msgId ) . arg ( seqNo ) . arg ( Logs : : b ( needAck ) ) . arg ( fullDataLength ) ) ;
2014-05-30 12:53:19 +04:00
uint64 serverSession = sessionData - > getSession ( ) ;
if ( session ! = serverSession ) {
LOG ( ( " MTP Error: bad server session received " ) ) ;
TCP_LOG ( ( " MTP Error: bad server session %1 instead of %2 in message received " ) . arg ( session ) . arg ( serverSession ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
int32 serverTime ( ( int32 ) ( msgId > > 32 ) ) , clientTime ( unixtime ( ) ) ;
bool isReply = ( ( msgId & 0x03 ) = = 1 ) ;
if ( ! isReply & & ( ( msgId & 0x03 ) ! = 3 ) ) {
LOG ( ( " MTP Error: bad msg_id %1 in message received " ) . arg ( msgId ) ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
bool badTime = false ;
uint64 mySalt = sessionData - > getSalt ( ) ;
if ( serverTime > clientTime + 60 | | serverTime + 300 < clientTime ) {
DEBUG_LOG ( ( " MTP Info: bad server time from msg_id: %1, my time: %2 " ) . arg ( serverTime ) . arg ( clientTime ) ) ;
badTime = true ;
}
2016-03-24 11:57:11 +03:00
bool wasConnected = ( getState ( ) = = ConnectedState ) ;
2014-05-30 12:53:19 +04:00
if ( serverSalt ! = mySalt ) {
if ( ! badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: other salt received... received: %1, my salt: %2, updating... " ) . arg ( serverSalt ) . arg ( mySalt ) ) ;
2014-05-30 12:53:19 +04:00
sessionData - > setSalt ( serverSalt ) ;
2016-03-24 11:57:11 +03:00
if ( setState ( ConnectedState , ConnectingState ) ) { // only connected
2014-05-30 12:53:19 +04:00
if ( restarted ) {
2014-11-25 15:15:29 +03:00
emit resendAllAsync ( ) ;
2014-05-30 12:53:19 +04:00
restarted = false ;
}
}
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " MTP Info: other salt received... received: %1, my salt: %2 " ) . arg ( serverSalt ) . arg ( mySalt ) ) ;
2014-05-30 12:53:19 +04:00
}
} else {
serverSalt = 0 ; // dont pass to handle method, so not to lock in setSalt()
}
2014-11-05 20:43:32 +03:00
if ( needAck ) ackRequestData . push_back ( MTP_long ( msgId ) ) ;
2014-05-30 12:53:19 +04:00
2016-12-07 16:32:25 +03:00
auto res = HandleResult : : Success ; // if no need to handle, then succeed
2017-02-27 12:51:03 +03:00
auto from = decryptedInts + kEncryptedHeaderIntsCount ;
auto end = from + ( messageLength / kIntSize ) ;
auto sfrom = decryptedInts + 4U ; // msg_id + seq_no + length + message
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " Recv: " ) + mtpTextSerialize ( sfrom , end ) ) ;
2014-05-30 12:53:19 +04:00
bool needToHandle = false ;
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
needToHandle = sessionData - > receivedIdsSet ( ) . registerMsgId ( msgId , needAck ) ;
2014-05-30 12:53:19 +04:00
}
if ( needToHandle ) {
res = handleOneReceived ( from , end , msgId , serverTime , serverSalt , badTime ) ;
}
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
sessionData - > receivedIdsSet ( ) . shrink ( ) ;
2014-05-30 12:53:19 +04:00
}
// send acks
2014-11-05 20:43:32 +03:00
uint32 toAckSize = ackRequestData . size ( ) ;
2014-05-30 12:53:19 +04:00
if ( toAckSize ) {
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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( res ! = HandleResult : : Success & & res ! = HandleResult : : Ignored ) {
_needSessionReset = ( res = = HandleResult : : ResetSession ) ;
2015-08-08 12:14:47 +03:00
2017-02-27 12:51:03 +03:00
return restartOnError ( ) ;
2014-05-30 12:53:19 +04:00
}
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-12-07 16:32:25 +03:00
ConnectionPrivate : : HandleResult ConnectionPrivate : : handleOneReceived ( const mtpPrime * from , const mtpPrime * end , uint64 msgId , int32 serverTime , uint64 serverSalt , bool badTime ) {
2014-05-30 12:53:19 +04:00
mtpTypeId cons = * from ;
try {
switch ( cons ) {
case mtpc_gzip_packed : {
DEBUG_LOG ( ( " Message Info: gzip container " ) ) ;
mtpBuffer response = ungzip ( + + from , end ) ;
if ( ! response . size ( ) ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
return handleOneReceived ( response . data ( ) , response . data ( ) + response . size ( ) , msgId , serverTime , serverSalt , badTime ) ;
}
case mtpc_msg_container : {
if ( + + from > = end ) throw mtpErrorInsufficient ( ) ;
const mtpPrime * otherEnd ;
uint32 msgsCount = ( uint32 ) * ( from + + ) ;
DEBUG_LOG ( ( " Message Info: container received, count: %1 " ) . arg ( msgsCount ) ) ;
for ( uint32 i = 0 ; i < msgsCount ; + + i ) {
if ( from + 4 > = end ) throw mtpErrorInsufficient ( ) ;
otherEnd = from + 4 ;
2017-03-09 22:15:31 +03:00
MTPlong inMsgId ;
inMsgId . read ( from , otherEnd ) ;
2014-05-30 12:53:19 +04:00
bool isReply = ( ( inMsgId . v & 0x03 ) = = 1 ) ;
if ( ! isReply & & ( ( inMsgId . v & 0x03 ) ! = 3 ) ) {
LOG ( ( " Message Error: bad msg_id %1 in contained message received " ) . arg ( inMsgId . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPint inSeqNo ;
inSeqNo . read ( from , otherEnd ) ;
MTPint bytes ;
bytes . read ( from , otherEnd ) ;
2014-05-30 12:53:19 +04:00
if ( ( bytes . v & 0x03 ) | | bytes . v < 4 ) {
LOG ( ( " Message Error: bad length %1 of contained message received " ) . arg ( bytes . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
bool needAck = ( inSeqNo . v & 0x01 ) ;
2014-11-05 20:43:32 +03:00
if ( needAck ) ackRequestData . push_back ( inMsgId ) ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: message from container, msg_id: %1, needAck: %2 " ) . arg ( inMsgId . v ) . arg ( Logs : : b ( needAck ) ) ) ;
2014-05-30 12:53:19 +04:00
otherEnd = from + ( bytes . v > > 2 ) ;
if ( otherEnd > end ) throw mtpErrorInsufficient ( ) ;
bool needToHandle = false ;
{
QWriteLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
needToHandle = sessionData - > receivedIdsSet ( ) . registerMsgId ( inMsgId . v , needAck ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
auto res = HandleResult : : Success ; // if no need to handle, then succeed
2014-05-30 12:53:19 +04:00
if ( needToHandle ) {
res = handleOneReceived ( from , otherEnd , inMsgId . v , serverTime , serverSalt , badTime ) ;
badTime = false ;
}
2016-12-07 16:32:25 +03:00
if ( res ! = HandleResult : : Success ) {
2014-05-30 12:53:19 +04:00
return res ;
}
from = otherEnd ;
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_ack : {
2017-03-09 22:15:31 +03:00
MTPMsgsAck msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & ids = msg . c_msgs_ack ( ) . vmsg_ids . 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 ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
requestsAcked ( ids ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_bad_msg_notification : {
2017-03-09 22:15:31 +03:00
MTPBadMsgNotification msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_msg_notification ( ) ) ;
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 ) ) ;
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-08-01 15:09:46 +04:00
}
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 ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : ResetSession ;
2014-05-30 12:53:19 +04:00
}
2014-08-01 15:09:46 +04:00
} else { // fatal (except 48, but it must not get here)
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 ) ) ;
2017-02-24 20:15:41 +03:00
_instance - > 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 ) ) ;
}
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_bad_server_salt : {
2017-03-09 22:15:31 +03:00
MTPBadMsgNotification msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_bad_server_salt ( ) ) ;
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 ) ) ;
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
}
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 ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_state_req : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgsStateReq msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & ids = msg . c_msgs_state_req ( ) . vmsg_ids . v ;
auto 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 ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
2014-11-25 15:15:29 +03:00
QByteArray info ( idsCount , Qt : : Uninitialized ) ;
2014-05-30 12:53:19 +04:00
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
auto & receivedIds = sessionData - > receivedIdsSet ( ) ;
auto minRecv = receivedIds . min ( ) ;
auto maxRecv = receivedIds . max ( ) ;
2014-05-30 12:53:19 +04:00
QReadLocker locker ( sessionData - > wereAckedMutex ( ) ) ;
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 {
2016-12-07 16:32:25 +03:00
auto msgIdState = receivedIds . lookup ( reqMsgId ) ;
if ( msgIdState = = ReceivedMsgIds : : State : : NotFound ) {
2014-05-30 12:53:19 +04:00
state | = 0x02 ;
} else {
state | = 0x04 ;
if ( wereAcked . constFind ( reqMsgId ) ! = wereAckedEnd ) {
state | = 0x80 ; // we know, that server knows, that we received request
}
2016-12-07 16:32:25 +03:00
if ( msgIdState = = ReceivedMsgIds : : State : : NeedsAck ) { // need ack, so we sent ack
2014-05-30 12:53:19 +04:00
state | = 0x08 ;
} else {
state | = 0x10 ;
}
}
}
info [ i ] = state ;
}
}
2014-11-25 15:15:29 +03:00
emit sendMsgsStateInfoAsync ( msgId , info ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_state_info : {
2017-03-09 22:15:31 +03:00
MTPMsgsStateInfo msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & data = msg . c_msgs_state_info ( ) ;
2016-01-11 23:43:29 +08:00
2017-03-10 22:46:28 +03:00
auto reqMsgId = data . vreq_msg_id . v ;
auto & states = data . vinfo . v ;
2014-05-30 12:53:19 +04:00
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: msg state received, msgId %1, reqMsgId: %2, HEX states %3 " ) . arg ( msgId ) . arg ( reqMsgId ) . arg ( Logs : : mb ( states . data ( ) , states . length ( ) ) . str ( ) ) ) ;
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 ) ) ;
2016-12-07 16:32:25 +03:00
return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
}
2014-10-30 19:23:44 +03:00
if ( badTime ) {
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ; // requestsFixTimeSalt with no lookup
unixtimeSet ( serverTime , true ) ;
2014-05-30 12:53:19 +04:00
2014-10-30 19:23:44 +03:00
DEBUG_LOG ( ( " Message Info: unixtime updated from mtpc_msgs_state_info, now %1 " ) . arg ( serverTime ) ) ;
2014-05-30 12:53:19 +04:00
2014-10-30 19:23:44 +03:00
badTime = false ;
}
2014-05-30 12:53:19 +04:00
requestBuffer = replyTo . value ( ) ;
}
2014-10-30 19:23:44 +03:00
QVector < MTPlong > toAckReq ( 1 , MTP_long ( reqMsgId ) ) , toAck ;
requestsAcked ( toAck , true ) ;
2014-05-30 12:53:19 +04:00
if ( requestBuffer - > size ( ) < 9 ) {
LOG ( ( " Message Error: bad request %1 found in requestMap, size: %2 " ) . arg ( reqMsgId ) . arg ( requestBuffer - > size ( ) ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
try {
const mtpPrime * rFrom = requestBuffer - > constData ( ) + 8 , * rEnd = requestBuffer - > constData ( ) + requestBuffer - > size ( ) ;
2014-08-11 13:06:16 +04:00
if ( mtpTypeId ( * rFrom ) = = mtpc_msgs_state_req ) {
2017-03-09 22:15:31 +03:00
MTPMsgsStateReq request ;
request . read ( rFrom , rEnd ) ;
2017-03-10 22:46:28 +03:00
handleMsgsStates ( request . c_msgs_state_req ( ) . vmsg_ids . v , states , toAck ) ;
2014-08-01 15:09:46 +04:00
} else {
2017-03-09 22:15:31 +03:00
MTPMsgResendReq request ;
request . read ( rFrom , rEnd ) ;
2017-03-10 22:46:28 +03:00
handleMsgsStates ( request . c_msg_resend_req ( ) . vmsg_ids . v , states , toAck ) ;
2014-08-01 15:09:46 +04:00
}
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " Message Error: could not parse sent msgs_state_req " ) ) ;
throw ;
}
requestsAcked ( toAck ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msgs_all_info : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgsAllInfo msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & data = msg . c_msgs_all_info ( ) ;
auto & ids = data . vmsg_ids . v ;
auto & states = data . vinfo . 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 ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msg_detailed_info : {
2017-03-09 22:15:31 +03:00
MTPMsgDetailedInfo msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msg_detailed_info ( ) ) ;
2014-05-30 12:53:19 +04:00
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 ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
requestsAcked ( ids ) ;
bool received = false ;
MTPlong resMsgId = data . vanswer_msg_id ;
{
QReadLocker lock ( sessionData - > receivedIdsMutex ( ) ) ;
2016-12-07 16:32:25 +03:00
received = ( sessionData - > receivedIdsSet ( ) . lookup ( resMsgId . v ) ! = ReceivedMsgIds : : State : : NotFound ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
if ( received ) {
ackRequestData . push_back ( resMsgId ) ;
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: answer message %1 was not received, requesting... " ) . arg ( resMsgId . v ) ) ;
2014-11-05 20:43:32 +03:00
resendRequestData . push_back ( resMsgId ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_msg_new_detailed_info : {
if ( badTime ) {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: skipping msg_new_detailed_info with bad time... " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 22:15:31 +03:00
MTPMsgDetailedInfo msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_msg_new_detailed_info ( ) ) ;
2014-05-30 12:53:19 +04:00
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 ( ) ) ;
2016-12-07 16:32:25 +03:00
received = ( sessionData - > receivedIdsSet ( ) . lookup ( resMsgId . v ) ! = ReceivedMsgIds : : State : : NotFound ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-05 20:43:32 +03:00
if ( received ) {
ackRequestData . push_back ( resMsgId ) ;
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: answer message %1 was not received, requesting... " ) . arg ( resMsgId . v ) ) ;
2014-11-05 20:43:32 +03:00
resendRequestData . push_back ( resMsgId ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
case mtpc_msg_resend_req : {
2017-03-09 22:15:31 +03:00
MTPMsgResendReq msg ;
msg . read ( from , end ) ;
2017-03-10 22:46:28 +03:00
auto & ids = msg . c_msg_resend_req ( ) . vmsg_ids . v ;
2014-05-30 12:53:19 +04:00
2017-03-10 22:46:28 +03:00
auto idsCount = ids . size ( ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " Message Info: resend of msgs requested, ids: %1 " ) . arg ( Logs : : vector ( ids ) ) ) ;
2016-12-07 16:32:25 +03:00
if ( ! idsCount ) return ( badTime ? HandleResult : : Ignored : HandleResult : : Success ) ;
2014-05-30 12:53:19 +04:00
2016-04-23 14:40:42 +03:00
QVector < quint64 > toResend ( ids . size ( ) ) ;
2014-11-25 15:15:29 +03:00
for ( int32 i = 0 , l = ids . size ( ) ; i < l ; + + i ) {
toResend [ i ] = ids . at ( i ) . v ;
2014-05-30 12:53:19 +04:00
}
2014-11-25 15:15:29 +03:00
resendMany ( toResend , 0 , false , true ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_rpc_result : {
if ( from + 3 > end ) throw mtpErrorInsufficient ( ) ;
mtpResponse response ;
2017-03-09 22:15:31 +03:00
MTPlong reqMsgId ;
reqMsgId . read ( + + from , end ) ;
2014-05-30 12:53:19 +04:00
mtpTypeId typeId = from [ 0 ] ;
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " RPC Info: response received for %1, queueing... " ) . arg ( reqMsgId . v ) ) ;
2014-05-30 12:53:19 +04:00
QVector < MTPlong > ids ( 1 , reqMsgId ) ;
if ( badTime ) {
if ( requestsFixTimeSalt ( ids , serverTime , serverSalt ) ) {
badTime = false ;
} else {
2014-08-15 15:19:32 +04:00
DEBUG_LOG ( ( " Message Info: error, such message was not sent recently %1 " ) . arg ( reqMsgId . v ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
2014-10-30 19:23:44 +03:00
requestsAcked ( ids , true ) ;
2014-05-30 12:53:19 +04:00
if ( typeId = = mtpc_gzip_packed ) {
DEBUG_LOG ( ( " RPC Info: gzip container " ) ) ;
response = ungzip ( + + from , end ) ;
if ( ! response . size ( ) ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
typeId = response [ 0 ] ;
} else {
response . resize ( end - from ) ;
memcpy ( response . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
}
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 ) ) ;
}
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_new_session_created : {
2015-04-23 18:50:11 +03:00
const mtpPrime * start = from ;
2017-03-09 22:15:31 +03:00
MTPNewSession msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_new_session_created ( ) ) ;
2015-10-01 17:19:27 +03:00
if ( badTime ) {
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 ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2015-10-01 17:19:27 +03:00
}
}
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
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_ping : {
2016-12-07 16:32:25 +03:00
if ( badTime ) return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
2017-03-09 22:15:31 +03:00
MTPPing msg ;
msg . read ( 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 ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
case mtpc_pong : {
2017-03-09 22:15:31 +03:00
MTPPong msg ;
msg . read ( from , end ) ;
2016-04-08 14:44:35 +04:00
const auto & data ( msg . c_pong ( ) ) ;
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 ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
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 {
2016-12-07 16:32:25 +03:00
return HandleResult : : Ignored ;
2014-05-30 12:53:19 +04:00
}
}
2014-10-30 19:23:44 +03:00
requestsAcked ( ids , true ) ;
2016-12-07 16:32:25 +03:00
} return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
}
2016-03-20 11:16:35 +03:00
} catch ( Exception & ) {
2016-12-07 16:32:25 +03:00
return HandleResult : : RestartConnection ;
2014-05-30 12:53:19 +04:00
}
if ( badTime ) {
2015-01-23 00:59:07 +03:00
DEBUG_LOG ( ( " Message Error: bad time in updates cons, must create new session " ) ) ;
2016-12-07 16:32:25 +03:00
return HandleResult : : ResetSession ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
if ( _dcType = = DcType : : Regular ) {
mtpBuffer update ( end - from ) ;
if ( end > from ) memcpy ( update . data ( ) , from , ( end - from ) * sizeof ( mtpPrime ) ) ;
2016-01-11 23:43:29 +08:00
2017-03-23 19:11:35 +03:00
QWriteLocker locker ( sessionData - > haveReceivedMutex ( ) ) ;
mtpResponseMap & haveReceived ( sessionData - > haveReceivedMap ( ) ) ;
mtpRequestId fakeRequestId = sessionData - > nextFakeRequestId ( ) ;
haveReceived . insert ( fakeRequestId , mtpResponse ( update ) ) ; // notify main process about new updates
2014-05-30 12:53:19 +04:00
2017-03-23 19:11:35 +03:00
if ( cons ! = mtpc_updatesTooLong & & cons ! = mtpc_updateShortMessage & & cons ! = mtpc_updateShortChatMessage & & cons ! = mtpc_updateShortSentMessage & & cons ! = mtpc_updateShort & & cons ! = mtpc_updatesCombined & & cons ! = mtpc_updates ) {
LOG ( ( " Message Error: unknown constructor %1 " ) . arg ( cons ) ) ; // maybe new api?..
}
} else {
LOG ( ( " Message Error: unexpected updates in dcType: %1 " ) . arg ( static_cast < int > ( _dcType ) ) ) ;
2014-05-30 12:53:19 +04:00
}
2016-12-07 16:32:25 +03:00
return HandleResult : : Success ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
mtpBuffer ConnectionPrivate : : ungzip ( const mtpPrime * from , const mtpPrime * end ) const {
2017-03-09 22:15:31 +03:00
MTPstring packed ;
packed . read ( from , end ) ; // read packed string as serialized mtp string type
2017-03-10 22:46:28 +03:00
uint32 packedLen = packed . v . size ( ) , unpackedChunk = packedLen , unpackedLen = 0 ;
2014-05-30 12:53:19 +04:00
mtpBuffer result ; // * 4 because of mtpPrime type
result . resize ( 0 ) ;
z_stream stream ;
stream . zalloc = 0 ;
stream . zfree = 0 ;
stream . opaque = 0 ;
stream . avail_in = 0 ;
stream . next_in = 0 ;
int res = inflateInit2 ( & stream , 16 + MAX_WBITS ) ;
if ( res ! = Z_OK ) {
LOG ( ( " RPC Error: could not init zlib stream, code: %1 " ) . arg ( res ) ) ;
return result ;
}
stream . avail_in = packedLen ;
2017-03-10 22:46:28 +03:00
stream . next_in = reinterpret_cast < Bytef * > ( packed . v . data ( ) ) ;
2014-05-30 12:53:19 +04:00
stream . avail_out = 0 ;
while ( ! stream . avail_out ) {
result . resize ( result . size ( ) + unpackedChunk ) ;
stream . avail_out = unpackedChunk * sizeof ( mtpPrime ) ;
stream . next_out = ( Bytef * ) & result [ result . size ( ) - unpackedChunk ] ;
int res = inflate ( & stream , Z_NO_FLUSH ) ;
if ( res ! = Z_OK & & res ! = Z_STREAM_END ) {
inflateEnd ( & stream ) ;
LOG ( ( " RPC Error: could not unpack gziped data, code: %1 " ) . arg ( res ) ) ;
2017-03-11 17:13:57 +03:00
DEBUG_LOG ( ( " RPC Error: bad gzip: %1 " ) . arg ( Logs : : mb ( packed . v . constData ( ) , packedLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return mtpBuffer ( ) ;
}
}
if ( stream . avail_out & 0x03 ) {
uint32 badSize = result . size ( ) * sizeof ( mtpPrime ) - stream . avail_out ;
LOG ( ( " RPC Error: bad length of unpacked data %1 " ) . arg ( badSize ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " RPC Error: bad unpacked data %1 " ) . arg ( Logs : : mb ( result . data ( ) , badSize ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return mtpBuffer ( ) ;
}
result . resize ( result . size ( ) - ( stream . avail_out > > 2 ) ) ;
inflateEnd ( & stream ) ;
if ( ! result . size ( ) ) {
LOG ( ( " RPC Error: bad length of unpacked data 0 " ) ) ;
}
return result ;
}
2016-03-24 11:57:11 +03:00
bool ConnectionPrivate : : requestsFixTimeSalt ( const QVector < MTPlong > & ids , int32 serverTime , uint64 serverSalt ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
for ( uint32 i = 0 ; i < idsCount ; + + i ) {
if ( wasSent ( ids [ i ] . v ) ) { // found such msg_id in recent acked requests or in recent sent requests
if ( serverSalt ) sessionData - > setSalt ( serverSalt ) ;
2014-08-15 15:19:32 +04:00
unixtimeSet ( serverTime , true ) ;
2014-05-30 12:53:19 +04:00
return true ;
}
}
return false ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : requestsAcked ( const QVector < MTPlong > & ids , bool byResponse ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
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)
2017-02-24 20:15:41 +03:00
moveToAcked = ! _instance - > hasCallbacks ( reqId ) ;
2014-10-30 19:23:44 +03:00
}
if ( moveToAcked ) {
wereAcked . insert ( msgId , reqId ) ;
haveSent . erase ( req ) ;
} else {
DEBUG_LOG ( ( " Message Info: ignoring ACK for msgId %1 because request %2 requires a response " ) . arg ( msgId ) . arg ( reqId ) ) ;
}
2014-05-30 12:53:19 +04:00
}
} else {
2016-03-24 18:07:13 +03:00
DEBUG_LOG ( ( " Message Info: msgId %1 was not found in recent sent, while acking requests, searching in resend... " ) . arg ( msgId ) ) ;
2014-05-30 12:53:19 +04:00
QWriteLocker locker3 ( sessionData - > toResendMutex ( ) ) ;
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)
2017-02-24 20:15:41 +03:00
moveToAcked = ! _instance - > hasCallbacks ( reqId ) ;
2014-10-30 19:23:44 +03:00
}
if ( moveToAcked ) {
QWriteLocker locker4 ( sessionData - > toSendMutex ( ) ) ;
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 ( ) ) {
2017-02-24 20:15:41 +03:00
_instance - > clearCallbacksDelayed ( clearedAcked ) ;
2014-05-30 12:53:19 +04:00
}
if ( toAckMore . size ( ) ) {
requestsAcked ( toAckMore ) ;
}
}
2017-03-10 22:46:28 +03:00
void ConnectionPrivate : : handleMsgsStates ( const QVector < MTPlong > & ids , const QByteArray & states , QVector < MTPlong > & acked ) {
2014-05-30 12:53:19 +04:00
uint32 idsCount = ids . size ( ) ;
if ( ! idsCount ) {
DEBUG_LOG ( ( " Message Info: void ids vector in handleMsgsStates() " ) ) ;
return ;
}
2017-03-10 22:46:28 +03:00
if ( states . size ( ) < idsCount ) {
LOG ( ( " Message Error: got less states than required ids count. " ) ) ;
return ;
}
2016-01-11 23:43:29 +08:00
2014-05-30 12:53:19 +04:00
acked . reserve ( acked . size ( ) + idsCount ) ;
for ( uint32 i = 0 , count = idsCount ; i < count ; + + i ) {
char state = states [ i ] ;
uint64 requestMsgId = ids [ i ] . v ;
{
QReadLocker locker ( sessionData - > haveSentMutex ( ) ) ;
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-12-01 22:20:33 +03:00
void ConnectionPrivate : : resend ( quint64 msgId , qint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) {
2015-03-12 13:28:10 +03:00
if ( msgId = = _pingMsgId ) return ;
2014-11-25 15:15:29 +03:00
emit resendAsync ( msgId , msCanWait , forceContainer , sendMsgStateInfo ) ;
}
2016-12-01 22:20:33 +03:00
void ConnectionPrivate : : resendMany ( QVector < quint64 > msgIds , qint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) {
2014-11-25 15:15:29 +03:00
for ( int32 i = 0 , l = msgIds . size ( ) ; i < l ; + + i ) {
2015-03-12 13:28:10 +03:00
if ( msgIds . at ( i ) = = _pingMsgId ) {
2014-11-25 15:15:29 +03:00
msgIds . remove ( i ) ;
- - l ;
}
}
emit resendManyAsync ( msgIds , msCanWait , forceContainer , sendMsgStateInfo ) ;
2014-05-30 12:53:19 +04:00
}
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
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection updating key from Session, dc %1 " ) . arg ( _shiftedDcId ) ) ;
2015-05-14 19:50:04 +03:00
uint64 newKeyId = 0 ;
{
ReadLockerAttempt lock ( sessionData - > keyMutex ( ) ) ;
if ( ! lock ) {
DEBUG_LOG ( ( " MTP Info: could not lock auth_key for read, waiting signal emit " ) ) ;
clearMessages ( ) ;
keyId = newKeyId ;
return ; // some other connection is getting key
}
2017-02-22 18:18:26 +03:00
auto key = sessionData - > getKey ( ) ;
2015-05-14 19:50:04 +03:00
newKeyId = key ? key - > keyId ( ) : 0 ;
}
if ( keyId ! = newKeyId ) {
clearMessages ( ) ;
keyId = newKeyId ;
}
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " AuthKey Info: Connection update key from Session, dc %1 result: %2 " ) . arg ( _shiftedDcId ) . arg ( Logs : : mb ( & keyId , sizeof ( keyId ) ) . str ( ) ) ) ;
2015-05-14 19:50:04 +03:00
if ( keyId ) {
return authKeyCreated ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-05-14 19:50:04 +03:00
DEBUG_LOG ( ( " AuthKey Info: No key in updateAuthKey(), will be creating auth_key " ) ) ;
2014-05-30 12:53:19 +04:00
lockKey ( ) ;
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 ( ) ;
2017-02-25 19:44:02 +03:00
} else if ( _instance - > isKeysDestroyer ( ) ) {
// We are here to destroy an old key, so we're done.
LOG ( ( " MTP Error: No key %1 in updateAuthKey() for destroying. " ) . arg ( _shiftedDcId ) ) ;
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
2014-05-30 12:53:19 +04:00
}
2017-02-21 16:45:56 +03:00
_authKeyData = std : : make_unique < ConnectionPrivate : : AuthKeyCreateData > ( ) ;
_authKeyStrings = std : : make_unique < ConnectionPrivate : : AuthKeyCreateStrings > ( ) ;
2016-12-07 16:32:25 +03:00
_authKeyData - > req_num = 0 ;
_authKeyData - > nonce = rand_value < MTPint128 > ( ) ;
2014-05-30 12:53:19 +04:00
MTPReq_pq req_pq ;
2016-12-07 16:32:25 +03:00
req_pq . vnonce = _authKeyData - > nonce ;
2014-05-30 12:53:19 +04:00
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 ( ) {
2017-02-25 19:44:02 +03:00
if ( keyId & & keyId ! = kRecreateKeyId & & _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 ( ) ;
}
2017-03-09 21:13:55 +03:00
auto & res_pq_data = res_pq . c_resPQ ( ) ;
2016-12-07 16:32:25 +03:00
if ( res_pq_data . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in res_pq)! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received nonce: %1, sent nonce: %2 " ) . arg ( Logs : : mb ( & res_pq_data . vnonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-23 19:11:35 +03:00
auto rsaKey = internal : : RSAPublicKey ( ) ;
if ( ! Messenger : : Instance ( ) . dcOptions ( ) - > getDcRSAKey ( bareDcId ( _shiftedDcId ) , res_pq . c_resPQ ( ) . vserver_public_key_fingerprints . v , & rsaKey ) ) {
if ( _dcType = = DcType : : Cdn ) {
LOG ( ( " Warning: CDN public RSA key not found " ) ) ;
requestCDNConfig ( ) ;
return ;
2014-05-30 12:53:19 +04:00
}
2017-03-23 19:11:35 +03:00
LOG ( ( " AuthKey Error: could not choose public RSA key " ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-23 19:11:35 +03:00
t_assert ( rsaKey . isValid ( ) ) ;
2014-05-30 12:53:19 +04:00
2016-12-07 16:32:25 +03:00
_authKeyData - > server_nonce = res_pq_data . vserver_nonce ;
2017-03-09 21:13:55 +03:00
_authKeyData - > new_nonce = rand_value < MTPint256 > ( ) ;
2014-05-30 12:53:19 +04:00
2017-03-10 22:46:28 +03:00
auto & pq = res_pq_data . vpq . v ;
auto p = QByteArray ( ) ;
auto q = QByteArray ( ) ;
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! " ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: problematic pq: %1 " ) . arg ( Logs : : mb ( pq . constData ( ) , pq . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-10 22:46:28 +03:00
auto p_q_inner = MTP_p_q_inner_data ( res_pq_data . vpq , MTP_bytes ( std : : move ( p ) ) , MTP_bytes ( std : : move ( q ) ) , _authKeyData - > nonce , _authKeyData - > server_nonce , _authKeyData - > new_nonce ) ;
2017-03-09 21:13:55 +03:00
auto dhEncString = encryptPQInnerRSA ( p_q_inner , rsaKey ) ;
if ( dhEncString . empty ( ) ) {
return restart ( ) ;
}
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhParamsAnswered ( ) ) ) ;
DEBUG_LOG ( ( " AuthKey Info: sending Req_DH_params... " ) ) ;
2014-05-30 12:53:19 +04:00
MTPReq_DH_params req_DH_params ;
2016-12-07 16:32:25 +03:00
req_DH_params . vnonce = _authKeyData - > nonce ;
req_DH_params . vserver_nonce = _authKeyData - > server_nonce ;
2017-03-23 19:11:35 +03:00
req_DH_params . vpublic_key_fingerprint = MTP_long ( rsaKey . getFingerPrint ( ) ) ;
2017-03-09 21:13:55 +03:00
req_DH_params . vp = p_q_inner . c_p_q_inner_data ( ) . vp ;
req_DH_params . vq = p_q_inner . c_p_q_inner_data ( ) . vq ;
req_DH_params . vencrypted_data = MTP_string ( std : : move ( dhEncString ) ) ;
sendRequestNotSecure ( req_DH_params ) ;
}
2014-05-30 12:53:19 +04:00
2017-03-23 19:11:35 +03:00
std : : string ConnectionPrivate : : encryptPQInnerRSA ( const MTPP_Q_inner_data & data , const MTP : : internal : : RSAPublicKey & key ) {
2017-03-09 21:13:55 +03:00
auto p_q_inner_size = data . innerLength ( ) ;
auto encSize = ( p_q_inner_size > > 2 ) + 6 ;
2014-05-30 12:53:19 +04:00
if ( encSize > = 65 ) {
2017-03-09 21:13:55 +03:00
auto tmp = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
tmp . reserve ( encSize ) ;
2017-03-09 21:13:55 +03:00
data . write ( tmp ) ;
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: too large data for RSA encrypt, size %1 " ) . arg ( encSize * sizeof ( mtpPrime ) ) ) ;
2016-01-11 23:43:29 +08:00
DEBUG_LOG ( ( " AuthKey Error: bad data for RSA encrypt %1 " ) . arg ( Logs : : mb ( & tmp [ 0 ] , tmp . size ( ) * 4 ) . str ( ) ) ) ;
2017-03-09 21:13:55 +03:00
return std : : string ( ) ; // can't be 255-byte string
2014-05-30 12:53:19 +04:00
}
2017-03-09 21:13:55 +03:00
auto encBuffer = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
encBuffer . reserve ( 65 ) ; // 260 bytes
encBuffer . resize ( 6 ) ;
encBuffer [ 0 ] = 0 ;
2017-03-09 21:13:55 +03:00
data . write ( encBuffer ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( & encBuffer [ 6 ] , p_q_inner_size , & encBuffer [ 1 ] ) ;
if ( encSize < 65 ) {
encBuffer . resize ( 65 ) ;
memset_rand ( & encBuffer [ encSize ] , ( 65 - encSize ) * sizeof ( mtpPrime ) ) ;
}
2017-03-09 21:13:55 +03:00
auto dhEncString = std : : string ( ) ;
2017-03-23 19:11:35 +03:00
if ( ! key . encrypt ( reinterpret_cast < const char * > ( & encBuffer [ 0 ] ) + 3 , dhEncString ) ) {
2017-03-09 21:13:55 +03:00
return std : : string ( ) ;
2014-05-30 12:53:19 +04:00
}
2017-03-09 21:13:55 +03:00
return dhEncString ;
2014-05-30 12:53:19 +04:00
}
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 ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( encDH . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_ok)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( encDH . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2017-03-10 22:46:28 +03:00
auto & encDHStr = encDH . vencrypted_answer . v ;
2014-05-30 12:53:19 +04:00
uint32 encDHLen = encDHStr . length ( ) , encDHBufLen = encDHLen > > 2 ;
if ( ( encDHLen & 0x03 ) | | encDHBufLen < 6 ) {
LOG ( ( " AuthKey Error: bad encrypted data length %1 (in server_DH_params_ok)! " ) . arg ( encDHLen ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: received encrypted data %1 " ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
uint32 nlen = _authKeyData - > new_nonce . innerLength ( ) , slen = _authKeyData - > server_nonce . innerLength ( ) ;
2014-05-30 12:53:19 +04:00
uchar tmp_aes [ 1024 ] , sha1ns [ 20 ] , sha1sn [ 20 ] , sha1nn [ 20 ] ;
2016-12-07 16:32:25 +03:00
memcpy ( tmp_aes , & _authKeyData - > new_nonce , nlen ) ;
memcpy ( tmp_aes + nlen , & _authKeyData - > server_nonce , slen ) ;
memcpy ( tmp_aes + nlen + slen , & _authKeyData - > new_nonce , nlen ) ;
memcpy ( tmp_aes + nlen + slen + nlen , & _authKeyData - > new_nonce , nlen ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( tmp_aes , nlen + slen , sha1ns ) ;
hashSha1 ( tmp_aes + nlen , nlen + slen , sha1sn ) ;
hashSha1 ( tmp_aes + nlen + slen , nlen + nlen , sha1nn ) ;
mtpBuffer decBuffer ;
decBuffer . resize ( encDHBufLen ) ;
2016-12-07 16:32:25 +03:00
memcpy ( _authKeyData - > aesKey , sha1ns , 20 ) ;
memcpy ( _authKeyData - > aesKey + 20 , sha1sn , 12 ) ;
memcpy ( _authKeyData - > aesIV , sha1sn + 12 , 8 ) ;
memcpy ( _authKeyData - > aesIV + 8 , sha1nn , 20 ) ;
memcpy ( _authKeyData - > aesIV + 28 , & _authKeyData - > new_nonce , 4 ) ;
2014-05-30 12:53:19 +04:00
2017-03-10 22:46:28 +03:00
aesIgeDecrypt ( encDHStr . constData ( ) , & decBuffer [ 0 ] , encDHLen , _authKeyData - > aesKey , _authKeyData - > aesIV ) ;
2014-05-30 12:53:19 +04:00
const mtpPrime * from ( & decBuffer [ 5 ] ) , * to ( from ) , * end ( from + ( encDHBufLen - 5 ) ) ;
2017-03-09 22:15:31 +03:00
MTPServer_DH_inner_data dh_inner ;
dh_inner . read ( to , end ) ;
2016-04-08 14:44:35 +04:00
const auto & dh_inner_data ( dh_inner . c_server_DH_inner_data ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( dh_inner_data . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( dh_inner_data . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & dh_inner_data . vserver_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
uchar sha1Buffer [ 20 ] ;
if ( memcmp ( & decBuffer [ 0 ] , hashSha1 ( & decBuffer [ 5 ] , ( to - from ) * sizeof ( mtpPrime ) , sha1Buffer ) , 20 ) ) {
LOG ( ( " AuthKey Error: sha1 hash of encrypted part did not match! " ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3 " ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > new_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( encDHStr . constData ( ) , encDHLen ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
unixtimeSet ( dh_inner_data . vserver_time . v ) ;
2017-03-10 22:46:28 +03:00
auto & dhPrime = dh_inner_data . vdh_prime . v ;
auto & g_a = dh_inner_data . vg_a . v ;
2014-05-30 12:53:19 +04:00
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 ( ) ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: dh_prime %1, g_a %2 " ) . arg ( Logs : : mb ( dhPrime . constData ( ) , dhPrime . length ( ) ) . str ( ) ) . arg ( Logs : : mb ( g_a . constData ( ) , 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
2017-04-03 21:28:18 +03:00
if ( ! IsPrimeAndGood ( dhPrime , dh_inner_data . vg . v ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: bad dh_prime primality! " ) . arg ( dhPrime . length ( ) ) . arg ( g_a . length ( ) ) ) ;
2017-03-10 22:46:28 +03:00
DEBUG_LOG ( ( " AuthKey Error: dh_prime %1 " ) . arg ( Logs : : mb ( dhPrime . constData ( ) , dhPrime . length ( ) ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyStrings - > dh_prime = QByteArray ( dhPrime . data ( ) , dhPrime . size ( ) ) ;
_authKeyData - > g = dh_inner_data . vg . v ;
_authKeyStrings - > g_a = QByteArray ( g_a . data ( ) , g_a . size ( ) ) ;
_authKeyData - > retry_id = MTP_long ( 0 ) ;
_authKeyData - > retries = 0 ;
2014-05-30 12:53:19 +04:00
} return dhClientParamsSend ( ) ;
case mtpc_server_DH_params_fail : {
2016-04-08 14:44:35 +04:00
const auto & encDH ( res_DH_params . c_server_DH_params_fail ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( encDH . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in server_DH_params_fail)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( encDH . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)! " ) ) ;
2016-12-07 16:32:25 +03: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 ] ;
2016-12-07 16:32:25 +03:00
if ( encDH . vnew_nonce_hash ! = * ( MTPint128 * ) ( hashSha1 ( & _authKeyData - > new_nonce , 32 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash did not match! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash: %1, new_nonce: %2 " ) . arg ( Logs : : mb ( & encDH . vnew_nonce_hash , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > new_nonce , 32 ) . str ( ) ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
LOG ( ( " AuthKey Error: server_DH_params_fail received! " ) ) ;
} return restart ( ) ;
}
LOG ( ( " AuthKey Error: unknown server_DH_params received, typeId = %1 " ) . arg ( res_DH_params . type ( ) ) ) ;
return restart ( ) ;
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhClientParamsSend ( ) {
2016-12-07 16:32:25 +03:00
if ( + + _authKeyData - > retries > 5 ) {
LOG ( ( " AuthKey Error: could not create auth_key for %1 retries " ) . arg ( _authKeyData - > retries - 1 ) ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2017-03-09 21:13:55 +03:00
auto g_b_string = std : : string ( 256 , ' ' ) ;
2014-05-30 12:53:19 +04:00
// gen rand 'b'
2017-03-09 21:13:55 +03:00
uint32 b [ 64 ] ;
auto g_b = reinterpret_cast < uint32 * > ( & g_b_string [ 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 ;
2017-02-22 18:18:26 +03:00
if ( ! bnCounter . count ( b , _authKeyStrings - > dh_prime . constData ( ) , _authKeyData - > g , g_b , _authKeyStrings - > g_a . constData ( ) , _authKeyStrings - > auth_key . data ( ) ) ) {
2014-05-30 12:53:19 +04:00
return dhClientParamsSend ( ) ;
}
// count auth_key hashes - parts of sha1(auth_key)
2017-02-22 18:18:26 +03:00
auto auth_key_sha = hashSha1 ( _authKeyStrings - > auth_key . data ( ) , _authKeyStrings - > auth_key . size ( ) ) ;
memcpy ( & _authKeyData - > auth_key_aux_hash , auth_key_sha . data ( ) , 8 ) ;
memcpy ( & _authKeyData - > auth_key_hash , auth_key_sha . data ( ) + 12 , 8 ) ;
2014-05-30 12:53:19 +04:00
2017-03-09 21:13:55 +03:00
auto client_dh_inner = MTP_client_DH_inner_data ( _authKeyData - > nonce , _authKeyData - > server_nonce , _authKeyData - > retry_id , MTP_string ( std : : move ( g_b_string ) ) ) ;
auto sdhEncString = encryptClientDHInner ( client_dh_inner ) ;
connect ( _conn , SIGNAL ( receivedData ( ) ) , this , SLOT ( dhClientParamsAnswered ( ) ) ) ;
2014-05-30 12:53:19 +04:00
MTPSet_client_DH_params req_client_DH_params ;
2016-12-07 16:32:25 +03:00
req_client_DH_params . vnonce = _authKeyData - > nonce ;
req_client_DH_params . vserver_nonce = _authKeyData - > server_nonce ;
2017-03-09 21:13:55 +03:00
req_client_DH_params . vencrypted_data = MTP_string ( std : : move ( sdhEncString ) ) ;
2016-01-11 23:43:29 +08:00
2017-03-09 21:13:55 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending Req_client_DH_params... " ) ) ;
sendRequestNotSecure ( req_client_DH_params ) ;
}
2014-05-30 12:53:19 +04:00
2017-03-09 21:13:55 +03:00
std : : string ConnectionPrivate : : encryptClientDHInner ( const MTPClient_DH_Inner_Data & data ) {
auto client_dh_inner_size = data . innerLength ( ) ;
auto encSize = ( client_dh_inner_size > > 2 ) + 5 ;
auto encFullSize = encSize ;
2014-05-30 12:53:19 +04:00
if ( encSize & 0x03 ) {
encFullSize + = 4 - ( encSize & 0x03 ) ;
}
2017-03-09 21:13:55 +03:00
auto encBuffer = mtpBuffer ( ) ;
2014-05-30 12:53:19 +04:00
encBuffer . reserve ( encFullSize ) ;
encBuffer . resize ( 5 ) ;
2017-03-09 21:13:55 +03:00
data . write ( encBuffer ) ;
2014-05-30 12:53:19 +04:00
hashSha1 ( & encBuffer [ 5 ] , client_dh_inner_size , & encBuffer [ 0 ] ) ;
if ( encSize < encFullSize ) {
encBuffer . resize ( encFullSize ) ;
memset_rand ( & encBuffer [ encSize ] , ( encFullSize - encSize ) * sizeof ( mtpPrime ) ) ;
}
2017-03-09 21:13:55 +03:00
auto sdhEncString = std : : string ( encFullSize * 4 , ' ' ) ;
2014-05-30 12:53:19 +04:00
2016-12-07 16:32:25 +03:00
aesIgeEncrypt ( & encBuffer [ 0 ] , & sdhEncString [ 0 ] , encFullSize * sizeof ( mtpPrime ) , _authKeyData - > aesKey , _authKeyData - > aesIV ) ;
2014-05-30 12:53:19 +04:00
2017-03-09 21:13:55 +03:00
return sdhEncString ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : dhClientParamsAnswered ( ) {
2014-11-13 14:27:10 +03:00
QReadLocker lockFinished ( & sessionDataMutex ) ;
if ( ! sessionData ) return ;
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 ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( resDH . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 1 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnew_nonce_hash1 ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash1 did not match! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & resDH . vnew_nonce_hash1 , 16 ) . str ( ) ) . arg ( Logs : : mb ( _authKeyData - > new_nonce_buf , 41 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
uint64 salt1 = _authKeyData - > new_nonce . l . l , salt2 = _authKeyData - > server_nonce . l , serverSalt = salt1 ^ salt2 ;
2014-05-30 12:53:19 +04:00
sessionData - > setSalt ( serverSalt ) ;
2017-02-25 19:44:02 +03:00
auto authKey = std : : make_shared < AuthKey > ( AuthKey : : Type : : Generated , bareDcId ( _shiftedDcId ) , _authKeyStrings - > auth_key ) ;
2014-05-30 12:53:19 +04:00
2017-02-22 18:18:26 +03:00
DEBUG_LOG ( ( " AuthKey Info: auth key gen succeed, id: %1, server salt: %2 " ) . arg ( authKey - > keyId ( ) ) . arg ( serverSalt ) ) ;
2014-05-30 12:53:19 +04:00
2017-02-24 20:15:41 +03:00
sessionData - > owner ( ) - > notifyKeyCreated ( std : : move ( authKey ) ) ; // slot will call authKeyCreated()
sessionData - > clear ( _instance ) ;
2014-05-30 12:53:19 +04:00
unlockKey ( ) ;
} return ;
case mtpc_dh_gen_retry : {
2016-04-08 14:44:35 +04:00
const auto & resDH ( res_client_DH_params . c_dh_gen_retry ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( resDH . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 2 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnew_nonce_hash2 ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash2 did not match! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2 " ) . arg ( Logs : : mb ( & resDH . vnew_nonce_hash2 , 16 ) . str ( ) ) . arg ( Logs : : mb ( _authKeyData - > new_nonce_buf , 41 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > retry_id = _authKeyData - > auth_key_aux_hash ;
2014-05-30 12:53:19 +04:00
} return dhClientParamsSend ( ) ;
case mtpc_dh_gen_fail : {
2016-04-08 14:44:35 +04:00
const auto & resDH ( res_client_DH_params . c_dh_gen_fail ( ) ) ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnonce ! = _authKeyData - > nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) ;
}
2016-12-07 16:32:25 +03:00
if ( resDH . vserver_nonce ! = _authKeyData - > server_nonce ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)! " ) ) ;
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Error: received server_nonce: %1, sent server_nonce: %2 " ) . arg ( Logs : : mb ( & resDH . vserver_nonce , 16 ) . str ( ) ) . arg ( Logs : : mb ( & _authKeyData - > server_nonce , 16 ) . str ( ) ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
return restart ( ) ;
}
2016-12-07 16:32:25 +03:00
_authKeyData - > new_nonce_buf [ 32 ] = 3 ;
2014-05-30 12:53:19 +04:00
uchar sha1Buffer [ 20 ] ;
2016-12-07 16:32:25 +03:00
if ( resDH . vnew_nonce_hash3 ! = * ( MTPint128 * ) ( hashSha1 ( _authKeyData - > new_nonce_buf , 41 , sha1Buffer ) + 1 ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: received new_nonce_hash3 did not match! " ) ) ;
2016-12-07 16:32:25 +03: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 ( ) {
2017-02-22 18:18:26 +03:00
auto zeroMemory = [ ] ( void * data , int size ) {
2015-03-12 13:28:10 +03:00
# ifdef Q_OS_WIN
2017-02-22 18:18:26 +03:00
SecureZeroMemory ( data , size ) ;
# else // Q_OS_WIN
auto end = static_cast < char * > ( data ) + size ;
for ( volatile auto p = static_cast < volatile char * > ( data ) ; p ! = end ; + + p ) {
* p = 0 ;
}
# endif // Q_OS_WIN
} ;
if ( _authKeyData ) {
zeroMemory ( _authKeyData . get ( ) , sizeof ( AuthKeyCreateData ) ) ;
2016-12-07 16:32:25 +03:00
_authKeyData . reset ( ) ;
2017-02-22 18:18:26 +03:00
}
if ( _authKeyStrings ) {
if ( ! _authKeyStrings - > dh_prime . isEmpty ( ) ) {
zeroMemory ( _authKeyStrings - > dh_prime . data ( ) , _authKeyStrings - > dh_prime . size ( ) ) ;
}
if ( ! _authKeyStrings - > g_a . isEmpty ( ) ) {
zeroMemory ( _authKeyStrings - > g_a . data ( ) , _authKeyStrings - > g_a . size ( ) ) ;
}
zeroMemory ( _authKeyStrings - > auth_key . data ( ) , _authKeyStrings - > auth_key . size ( ) ) ;
2016-12-07 16:32:25 +03:00
_authKeyStrings . reset ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2017-02-25 19:44:02 +03:00
void ConnectionPrivate : : onError4 ( qint32 errorCode ) {
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
2017-02-25 19:44:02 +03:00
if ( errorCode = = - 429 ) {
LOG ( ( " Protocol Error: -429 flood code returned! " ) ) ;
}
2015-06-10 15:48:26 +03:00
if ( _conn | | ! _conn6 ) {
2017-03-23 19:11:35 +03:00
handleError ( errorCode ) ;
2015-06-10 15:48:26 +03:00
} else {
destroyConn ( & _conn4 ) ;
}
}
2017-02-25 19:44:02 +03:00
void ConnectionPrivate : : onError6 ( qint32 errorCode ) {
2015-06-10 15:48:26 +03:00
if ( _conn & & _conn = = _conn4 ) return ; // error in the unused
2017-02-25 19:44:02 +03:00
if ( errorCode = = - 429 ) {
LOG ( ( " Protocol Error: -429 flood code returned! " ) ) ;
}
2015-06-10 15:48:26 +03:00
if ( _conn | | ! _conn4 ) {
2017-03-23 19:11:35 +03:00
handleError ( errorCode ) ;
} else {
destroyConn ( & _conn6 ) ;
}
}
void ConnectionPrivate : : handleError ( int errorCode ) {
destroyConn ( ) ;
_waitForConnectedTimer . stop ( ) ;
2015-06-10 15:48:26 +03:00
2017-03-23 19:11:35 +03:00
if ( errorCode = = - 404 ) {
if ( _instance - > isKeysDestroyer ( ) ) {
2017-02-25 19:44:02 +03:00
LOG ( ( " MTP Info: -404 error received on destroying key %1, assuming it is destroyed. " ) . arg ( _shiftedDcId ) ) ;
emit _instance - > keyDestroyed ( _shiftedDcId ) ;
return ;
2017-03-23 19:11:35 +03:00
} else if ( _dcType = = DcType : : Cdn ) {
LOG ( ( " MTP Info: -404 error received in CDN dc %1, assuming it was destroyed, recreating. " ) . arg ( _shiftedDcId ) ) ;
clearMessages ( ) ;
keyId = kRecreateKeyId ;
2017-02-25 19:44:02 +03:00
return restart ( ) ;
}
2015-06-10 15:48:26 +03:00
}
2017-03-23 19:11:35 +03:00
MTP_LOG ( _shiftedDcId , ( " Restarting after error in connection, error code: %1... " ) . arg ( errorCode ) ) ;
return restart ( ) ;
2014-05-30 12:53:19 +04:00
}
2016-03-24 11:57:11 +03:00
void ConnectionPrivate : : onReadyData ( ) {
2014-05-30 12:53:19 +04:00
}
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 ) ;
2016-12-07 16:32:25 +03:00
buffer . push_back ( _authKeyData - > req_num ) ;
2014-05-30 12:53:19 +04:00
buffer . push_back ( unixtime ( ) ) ;
buffer . push_back ( requestSize * 4 ) ;
request . write ( buffer ) ;
buffer . push_back ( 0 ) ; // tcp crc32 hash
2016-12-07 16:32:25 +03:00
+ + _authKeyData - > msgs_sent ;
2014-05-30 12:53:19 +04:00
2016-12-07 16:32:25 +03:00
DEBUG_LOG ( ( " AuthKey Info: sending request, size: %1, num: %2, time: %3 " ) . arg ( requestSize ) . arg ( _authKeyData - > req_num ) . arg ( buffer [ 5 ] ) ) ;
2014-05-30 12:53:19 +04:00
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 {
2017-02-27 12:51:03 +03:00
if ( _conn - > received ( ) . empty ( ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " AuthKey Error: trying to read response from empty received list " ) ) ;
return false ;
}
2017-02-27 12:51:03 +03:00
auto buffer = std : : move ( _conn - > received ( ) . front ( ) ) ;
2015-06-10 15:48:26 +03:00
_conn - > received ( ) . pop_front ( ) ;
2014-05-30 12:53:19 +04:00
2017-02-27 12:51:03 +03:00
auto answer = buffer . constData ( ) ;
auto len = buffer . size ( ) ;
2014-05-30 12:53:19 +04:00
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 ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting... " ) . arg ( _shiftedDcId ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
2016-03-24 15:57:10 +03:00
AuthKeyPtr key ( sessionData - > getKey ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! key | | key - > keyId ( ) ! = keyId ) {
2017-02-25 19:44:02 +03:00
DEBUG_LOG ( ( " MTP Error: auth_key id for dc %1 changed " ) . arg ( _shiftedDcId ) ) ;
2015-08-08 12:14:47 +03:00
lockFinished . unlock ( ) ;
2014-05-30 12:53:19 +04:00
restart ( ) ;
return false ;
}
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 ;
2017-02-25 19:44:02 +03:00
MTP_LOG ( _shiftedDcId , ( " 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 ( ) {
2017-02-22 18:18:26 +03:00
clearAuthKeyData ( ) ;
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
2017-04-03 21:28:18 +03:00
bool IsPrimeAndGood ( const QByteArray & data , int g ) {
return MTP : : internal : : BigNumPrimeTest ( ) . isPrimeAndGood ( data , g ) ;
}
2016-03-24 11:57:11 +03:00
} // namespace MTP