2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2014-05-30 08:53:19 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2014-05-30 08:53:19 +00:00
*/
# pragma once
2019-01-18 11:26:43 +00:00
# include "base/timer.h"
2019-11-18 09:28:14 +00:00
# include "mtproto/mtproto_rpc_sender.h"
2019-11-13 14:12:04 +00:00
# include "mtproto/mtproto_proxy_data.h"
2014-05-30 08:53:19 +00:00
2019-09-13 06:06:02 +00:00
# include <QtCore/QTimer>
2016-03-24 08:57:11 +00:00
namespace MTP {
2017-02-24 17:15:41 +00:00
class Instance ;
2017-06-26 17:38:16 +00:00
class AuthKey ;
using AuthKeyPtr = std : : shared_ptr < AuthKey > ;
2017-02-24 17:15:41 +00:00
2016-03-24 08:57:11 +00:00
namespace internal {
2014-05-30 08:53:19 +00:00
2019-01-21 13:42:21 +00:00
// Received msgIds and wereAcked msgIds count stored.
constexpr auto kIdsBufferSize = 400 ;
2017-06-26 17:38:16 +00:00
class Dcenter ;
2017-02-24 17:15:41 +00:00
class Connection ;
2018-06-25 18:55:27 +00:00
using PreRequestMap = QMap < mtpRequestId , SecureRequest > ;
using RequestMap = QMap < mtpMsgId , SecureRequest > ;
class RequestIdsMap : public QMap < mtpMsgId , mtpRequestId > {
public :
using ParentType = QMap < mtpMsgId , mtpRequestId > ;
mtpMsgId min ( ) const {
return size ( ) ? cbegin ( ) . key ( ) : 0 ;
}
mtpMsgId max ( ) const {
ParentType : : const_iterator e ( cend ( ) ) ;
return size ( ) ? ( - - e ) . key ( ) : 0 ;
}
} ;
2016-12-07 13:32:25 +00:00
class ReceivedMsgIds {
public :
bool registerMsgId ( mtpMsgId msgId , bool needAck ) {
auto i = _idsNeedAck . constFind ( msgId ) ;
if ( i = = _idsNeedAck . cend ( ) ) {
2019-01-21 13:42:21 +00:00
if ( _idsNeedAck . size ( ) < kIdsBufferSize | | msgId > min ( ) ) {
2016-12-07 13:32:25 +00:00
_idsNeedAck . insert ( msgId , needAck ) ;
return true ;
}
MTP_LOG ( - 1 , ( " No need to handle - %1 < min = %2 " ) . arg ( msgId ) . arg ( min ( ) ) ) ;
} else {
MTP_LOG ( - 1 , ( " No need to handle - %1 already is in map " ) . arg ( msgId ) ) ;
}
return false ;
}
2016-03-24 08:57:11 +00:00
2016-12-07 13:32:25 +00:00
mtpMsgId min ( ) const {
return _idsNeedAck . isEmpty ( ) ? 0 : _idsNeedAck . cbegin ( ) . key ( ) ;
}
mtpMsgId max ( ) const {
auto end = _idsNeedAck . cend ( ) ;
return _idsNeedAck . isEmpty ( ) ? 0 : ( - - end ) . key ( ) ;
}
void shrink ( ) {
auto size = _idsNeedAck . size ( ) ;
2019-01-21 13:42:21 +00:00
while ( size - - > kIdsBufferSize ) {
2016-12-07 13:32:25 +00:00
_idsNeedAck . erase ( _idsNeedAck . begin ( ) ) ;
}
}
enum class State {
NotFound ,
NeedsAck ,
NoAckNeeded ,
} ;
State lookup ( mtpMsgId msgId ) const {
auto i = _idsNeedAck . constFind ( msgId ) ;
if ( i = = _idsNeedAck . cend ( ) ) {
return State : : NotFound ;
}
return i . value ( ) ? State : : NeedsAck : State : : NoAckNeeded ;
}
void clear ( ) {
_idsNeedAck . clear ( ) ;
}
private :
QMap < mtpMsgId , bool > _idsNeedAck ;
} ;
2017-04-30 14:23:57 +00:00
using SerializedMessage = mtpBuffer ;
inline bool ResponseNeedsAck ( const SerializedMessage & response ) {
if ( response . size ( ) < 8 ) {
return false ;
}
auto seqNo = * ( uint32 * ) ( response . constData ( ) + 6 ) ;
return ( seqNo & 0x01 ) ? true : false ;
}
2018-04-24 08:46:27 +00:00
struct ConnectionOptions {
ConnectionOptions ( ) = default ;
ConnectionOptions (
const QString & systemLangCode ,
const QString & cloudLangCode ,
2018-08-20 11:31:40 +00:00
const QString & langPackName ,
2018-04-24 08:46:27 +00:00
const ProxyData & proxy ,
bool useIPv4 ,
bool useIPv6 ,
bool useHttp ,
bool useTcp ) ;
ConnectionOptions ( const ConnectionOptions & other ) = default ;
ConnectionOptions & operator = ( const ConnectionOptions & other ) = default ;
QString systemLangCode ;
QString cloudLangCode ;
2018-08-20 11:31:40 +00:00
QString langPackName ;
2018-04-24 08:46:27 +00:00
ProxyData proxy ;
bool useIPv4 = true ;
bool useIPv6 = true ;
bool useHttp = true ;
bool useTcp = true ;
} ;
2016-12-07 13:32:25 +00:00
class Session ;
2016-03-24 08:57:11 +00:00
class SessionData {
2014-05-30 08:53:19 +00:00
public :
2017-08-17 08:31:24 +00:00
SessionData ( not_null < Session * > creator ) : _owner ( creator ) {
2014-05-30 08:53:19 +00:00
}
2019-11-15 13:04:32 +00:00
void setCurrentKeyId ( uint64 keyId ) ;
2019-11-14 07:13:17 +00:00
void setSessionId ( uint64 sessionId ) {
DEBUG_LOG ( ( " MTP Info: setting server_session: %1 " ) . arg ( sessionId ) ) ;
2014-05-30 08:53:19 +00:00
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2019-11-14 07:13:17 +00:00
if ( _sessionId ! = sessionId ) {
_sessionId = sessionId ;
2014-05-30 08:53:19 +00:00
_messagesSent = 0 ;
}
}
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] uint64 getSessionId ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2019-11-14 07:13:17 +00:00
return _sessionId ;
2014-05-30 08:53:19 +00:00
}
2018-05-17 19:58:00 +00:00
void notifyConnectionInited ( const ConnectionOptions & options ) ;
2019-11-15 13:04:32 +00:00
void setConnectionOptions ( ConnectionOptions options ) {
2017-04-13 17:59:05 +00:00
QWriteLocker locker ( & _lock ) ;
2018-04-24 08:46:27 +00:00
_options = options ;
2017-05-30 09:31:32 +00:00
}
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] ConnectionOptions connectionOptions ( ) const {
2017-05-30 09:31:32 +00:00
QReadLocker locker ( & _lock ) ;
2018-04-24 08:46:27 +00:00
return _options ;
2017-04-13 17:59:05 +00:00
}
2014-05-30 08:53:19 +00:00
void setSalt ( uint64 salt ) {
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2014-05-30 08:53:19 +00:00
_salt = salt ;
}
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] uint64 getSalt ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2014-05-30 08:53:19 +00:00
return _salt ;
}
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] const AuthKeyPtr & getKeyForCheck ( ) const {
2019-11-14 13:34:58 +00:00
return _dcKeyForCheck ;
}
void setKeyForCheck ( const AuthKeyPtr & key ) ;
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > toSendMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _toSendLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > haveSentMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _haveSentLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > toResendMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _toResendLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > wereAckedMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _wereAckedLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > receivedIdsMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _receivedIdsLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > haveReceivedMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _haveReceivedLock ;
2014-05-30 08:53:19 +00:00
}
2017-08-17 08:31:24 +00:00
not_null < QReadWriteLock * > stateRequestMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _stateRequestLock ;
2014-11-05 17:43:32 +00:00
}
2014-05-30 08:53:19 +00:00
2018-06-25 18:55:27 +00:00
PreRequestMap & toSendMap ( ) {
2017-04-30 14:23:57 +00:00
return _toSend ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
const PreRequestMap & toSendMap ( ) const {
2017-04-30 14:23:57 +00:00
return _toSend ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
RequestMap & haveSentMap ( ) {
2017-04-30 14:23:57 +00:00
return _haveSent ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
const RequestMap & haveSentMap ( ) const {
2017-04-30 14:23:57 +00:00
return _haveSent ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
RequestIdsMap & toResendMap ( ) { // msgId -> requestId, on which toSend: requestId -> request for resended requests
2017-04-30 14:23:57 +00:00
return _toResend ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
const RequestIdsMap & toResendMap ( ) const {
2017-04-30 14:23:57 +00:00
return _toResend ;
2014-05-30 08:53:19 +00:00
}
2016-12-07 13:32:25 +00:00
ReceivedMsgIds & receivedIdsSet ( ) {
2017-04-30 14:23:57 +00:00
return _receivedIds ;
2014-05-30 08:53:19 +00:00
}
2016-12-07 13:32:25 +00:00
const ReceivedMsgIds & receivedIdsSet ( ) const {
2017-04-30 14:23:57 +00:00
return _receivedIds ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
RequestIdsMap & wereAckedMap ( ) {
2017-04-30 14:23:57 +00:00
return _wereAcked ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
const RequestIdsMap & wereAckedMap ( ) const {
2017-04-30 14:23:57 +00:00
return _wereAcked ;
}
QMap < mtpRequestId , SerializedMessage > & haveReceivedResponses ( ) {
return _receivedResponses ;
}
const QMap < mtpRequestId , SerializedMessage > & haveReceivedResponses ( ) const {
return _receivedResponses ;
2014-05-30 08:53:19 +00:00
}
2017-04-30 14:23:57 +00:00
QList < SerializedMessage > & haveReceivedUpdates ( ) {
return _receivedUpdates ;
2014-05-30 08:53:19 +00:00
}
2017-04-30 14:23:57 +00:00
const QList < SerializedMessage > & haveReceivedUpdates ( ) const {
return _receivedUpdates ;
2014-05-30 08:53:19 +00:00
}
2018-06-25 18:55:27 +00:00
QMap < mtpMsgId , bool > & stateRequestMap ( ) {
2017-04-30 14:23:57 +00:00
return _stateRequest ;
2014-11-05 17:43:32 +00:00
}
2018-06-25 18:55:27 +00:00
const QMap < mtpMsgId , bool > & stateRequestMap ( ) const {
2017-04-30 14:23:57 +00:00
return _stateRequest ;
2014-05-30 08:53:19 +00:00
}
2019-11-18 12:53:37 +00:00
// Warning! Valid only in constructor, _owner is guaranteed != null.
[ [ nodiscard ] ] not_null < Session * > owner ( ) {
2014-05-30 08:53:19 +00:00
return _owner ;
}
uint32 nextRequestSeqNumber ( bool needAck = true ) {
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
auto result = _messagesSent ;
2014-05-30 08:53:19 +00:00
_messagesSent + = ( needAck ? 1 : 0 ) ;
return result * 2 + ( needAck ? 1 : 0 ) ;
}
2019-11-15 13:04:32 +00:00
void clearForNewKey ( not_null < Instance * > instance ) ;
2014-05-30 08:53:19 +00:00
2019-11-18 12:53:37 +00:00
// Connection -> Session interface.
void queueTryToReceive ( ) ;
void queueNeedToResumeAndSend ( ) ;
void queueConnectionStateChange ( int newState ) ;
void queueResendAll ( ) ;
void queueResetDone ( ) ;
void queueSendAnything ( crl : : time msCanWait = 0 ) ;
void queueSendMsgsStateInfo ( quint64 msgId , QByteArray data ) ;
void queueResend (
mtpMsgId msgId ,
crl : : time msCanWait ,
bool forceContainer ,
bool sendMsgStateInfo ) ;
void queueResendMany (
QVector < mtpMsgId > msgIds ,
crl : : time msCanWait ,
bool forceContainer ,
bool sendMsgStateInfo ) ;
[ [ nodiscard ] ] bool connectionInited ( ) const ;
2019-11-19 10:10:51 +00:00
[ [ nodiscard ] ] AuthKeyPtr getPersistentKey ( ) const ;
[ [ nodiscard ] ] AuthKeyPtr getTemporaryKey ( ) const ;
2019-11-18 12:53:37 +00:00
[ [ nodiscard ] ] bool acquireKeyCreation ( ) ;
2019-11-19 10:10:51 +00:00
void releaseKeyCreationOnDone (
const AuthKeyPtr & temporaryKey ,
const AuthKeyPtr & persistentKey ) ;
2019-11-18 12:53:37 +00:00
void releaseKeyCreationOnFail ( ) ;
2019-11-19 10:10:51 +00:00
void destroyTemporaryKey ( uint64 keyId ) ;
2019-11-18 12:53:37 +00:00
void detach ( ) ;
2014-05-30 08:53:19 +00:00
private :
2019-11-18 12:53:37 +00:00
template < typename Callback >
void withSession ( Callback & & callback ) ;
2019-11-15 13:04:32 +00:00
uint64 _keyId = 0 ;
2019-11-14 07:13:17 +00:00
uint64 _sessionId = 0 ;
2016-12-07 13:32:25 +00:00
uint64 _salt = 0 ;
uint32 _messagesSent = 0 ;
2014-05-30 08:53:19 +00:00
2019-11-18 12:53:37 +00:00
Session * _owner = nullptr ;
mutable QMutex _ownerMutex ;
2014-05-30 08:53:19 +00:00
2019-11-14 13:34:58 +00:00
AuthKeyPtr _dcKeyForCheck ;
2018-04-24 08:46:27 +00:00
ConnectionOptions _options ;
2014-05-30 08:53:19 +00:00
2018-06-25 18:55:27 +00:00
PreRequestMap _toSend ; // map of request_id -> request, that is waiting to be sent
RequestMap _haveSent ; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers
RequestIdsMap _toResend ; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent
2017-04-30 14:23:57 +00:00
ReceivedMsgIds _receivedIds ; // set of received msg_id's, for checking new msg_ids
2018-06-25 18:55:27 +00:00
RequestIdsMap _wereAcked ; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack
QMap < mtpMsgId , bool > _stateRequest ; // set of msg_id's, whose state should be requested
2017-04-30 14:23:57 +00:00
QMap < mtpRequestId , SerializedMessage > _receivedResponses ; // map of request_id -> response that should be processed in the main thread
QList < SerializedMessage > _receivedUpdates ; // list of updates that should be processed in the main thread
2014-05-30 08:53:19 +00:00
// mutexes
2017-04-30 14:23:57 +00:00
mutable QReadWriteLock _lock ;
mutable QReadWriteLock _toSendLock ;
mutable QReadWriteLock _haveSentLock ;
mutable QReadWriteLock _toResendLock ;
mutable QReadWriteLock _receivedIdsLock ;
mutable QReadWriteLock _wereAckedLock ;
mutable QReadWriteLock _haveReceivedLock ;
mutable QReadWriteLock _stateRequestLock ;
2014-05-30 08:53:19 +00:00
} ;
2016-03-24 08:57:11 +00:00
class Session : public QObject {
2014-05-30 08:53:19 +00:00
Q_OBJECT
public :
2019-11-15 13:04:32 +00:00
// Main thread.
2019-11-15 07:28:33 +00:00
Session (
not_null < Instance * > instance ,
ShiftedDcId shiftedDcId ,
Dcenter * dc ) ;
2019-11-15 13:04:32 +00:00
~ Session ( ) ;
2014-05-30 08:53:19 +00:00
2017-02-25 16:44:02 +00:00
void start ( ) ;
2019-11-15 13:04:32 +00:00
void reInitConnection ( ) ;
2014-05-30 08:53:19 +00:00
void restart ( ) ;
2018-05-17 19:58:00 +00:00
void refreshOptions ( ) ;
2014-05-30 08:53:19 +00:00
void stop ( ) ;
2015-05-14 16:50:04 +00:00
void kill ( ) ;
2014-05-30 08:53:19 +00:00
2015-10-15 10:18:24 +00:00
void unpaused ( ) ;
2019-11-15 13:04:32 +00:00
// Thread-safe.
[ [ nodiscard ] ] ShiftedDcId getDcWithShift ( ) const ;
2019-11-19 10:10:51 +00:00
[ [ nodiscard ] ] AuthKeyPtr getPersistentKey ( ) const ;
[ [ nodiscard ] ] AuthKeyPtr getTemporaryKey ( ) const ;
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] bool connectionInited ( ) const ;
// Connection thread.
[ [ nodiscard ] ] bool acquireKeyCreation ( ) ;
2019-11-19 10:10:51 +00:00
void releaseKeyCreationOnDone (
const AuthKeyPtr & temporaryKey ,
const AuthKeyPtr & persistentKey ) ;
2019-11-15 13:04:32 +00:00
void releaseKeyCreationOnFail ( ) ;
2019-11-19 10:10:51 +00:00
void destroyTemporaryKey ( uint64 keyId ) ;
2014-05-30 08:53:19 +00:00
2018-05-17 19:58:00 +00:00
void notifyDcConnectionInited ( ) ;
2014-05-30 08:53:19 +00:00
2015-04-16 14:59:42 +00:00
void ping ( ) ;
2014-11-05 17:43:32 +00:00
void cancel ( mtpRequestId requestId , mtpMsgId msgId ) ;
2014-05-30 08:53:19 +00:00
int32 requestState ( mtpRequestId requestId ) const ;
int32 getState ( ) const ;
QString transport ( ) const ;
2019-11-14 13:34:58 +00:00
void sendDcKeyCheck ( const AuthKeyPtr & key ) ;
2017-12-18 12:40:15 +00:00
// Nulls msgId and seqNo in request, if newRequest = true.
void sendPrepared (
2018-06-25 18:55:27 +00:00
const SecureRequest & request ,
2019-02-19 06:57:53 +00:00
crl : : time msCanWait = 0 ,
2017-12-18 12:40:15 +00:00
bool newRequest = true ) ;
2014-05-30 08:53:19 +00:00
2019-11-18 12:53:37 +00:00
void tryToReceive ( ) ;
void needToResumeAndSend ( ) ;
void connectionStateChange ( int newState ) ;
void resendAll ( ) ; // After connection restart.
void resetDone ( ) ;
void sendAnything ( crl : : time msCanWait = 0 ) ;
void sendMsgsStateInfo ( quint64 msgId , QByteArray data ) ;
mtpRequestId resend (
mtpMsgId msgId ,
crl : : time msCanWait = 0 ,
bool forceContainer = false ,
bool sendMsgStateInfo = false ) ;
2016-10-05 16:56:27 +00:00
signals :
2019-11-15 13:04:32 +00:00
void authKeyChanged ( ) ;
2014-05-30 08:53:19 +00:00
void needToSend ( ) ;
2015-04-16 14:59:42 +00:00
void needToPing ( ) ;
2014-11-24 13:21:27 +00:00
void needToRestart ( ) ;
2014-05-30 08:53:19 +00:00
private :
2019-11-15 13:04:32 +00:00
[ [ nodiscard ] ] bool sharedDc ( ) const ;
2019-11-14 17:39:15 +00:00
void checkRequestsByTimer ( ) ;
2019-11-18 12:53:37 +00:00
void watchDcKeyChanges ( ) ;
2016-10-24 15:36:17 +00:00
2017-02-24 17:15:41 +00:00
bool rpcErrorOccured ( mtpRequestId requestId , const RPCFailHandlerPtr & onFail , const RPCError & err ) ;
2019-11-14 17:39:15 +00:00
const not_null < Instance * > _instance ;
const ShiftedDcId _shiftedDcId = 0 ;
2019-11-15 13:04:32 +00:00
const std : : unique_ptr < Dcenter > _ownedDc ;
const not_null < Dcenter * > _dc ;
2019-11-18 12:53:37 +00:00
const std : : shared_ptr < SessionData > _data ;
2019-11-14 17:39:15 +00:00
2017-02-24 17:15:41 +00:00
std : : unique_ptr < Connection > _connection ;
2015-05-14 16:50:04 +00:00
2017-02-24 17:15:41 +00:00
bool _killed = false ;
bool _needToReceive = false ;
2016-02-29 16:53:26 +00:00
2019-11-14 13:34:58 +00:00
AuthKeyPtr _dcKeyForCheck ;
2019-11-18 12:53:37 +00:00
bool _myKeyCreation = false ;
2014-05-30 08:53:19 +00:00
2019-11-14 07:13:17 +00:00
crl : : time _msSendCall = 0 ;
crl : : time _msWait = 0 ;
2014-05-30 08:53:19 +00:00
2017-02-24 17:15:41 +00:00
bool _ping = false ;
2015-04-16 14:59:42 +00:00
2019-11-14 17:39:15 +00:00
base : : Timer _timeouter ;
2019-11-14 07:13:17 +00:00
base : : Timer _sender ;
2014-05-30 08:53:19 +00:00
2019-11-18 12:53:37 +00:00
rpl : : lifetime _lifetime ;
2014-05-30 08:53:19 +00:00
} ;
2016-03-24 08:57:11 +00:00
} // namespace internal
} // namespace MTP