2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2014-12-01 10:47:38 +00:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 08:53:19 +00: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 13:16:42 +00: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 08:53:19 +00:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 18:31:31 +00:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2014-05-30 08:53:19 +00:00
*/
# pragma once
2016-03-23 18:43:12 +00:00
# include "mtproto/dcenter.h"
2016-10-05 16:56:27 +00:00
# include "core/single_timer.h"
2014-05-30 08:53:19 +00:00
2016-03-24 08:57:11 +00:00
namespace MTP {
2017-02-24 17:15:41 +00:00
class Instance ;
2016-03-24 08:57:11 +00:00
namespace internal {
2014-05-30 08:53:19 +00:00
2017-02-24 17:15:41 +00:00
class Connection ;
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 ( ) ) {
if ( _idsNeedAck . size ( ) < MTPIdsBufferSize | | msgId > min ( ) ) {
_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 ( ) ;
while ( size - - > MTPIdsBufferSize ) {
_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 ;
}
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 :
2016-12-07 13:32:25 +00:00
SessionData ( Session * creator ) : _owner ( creator ) {
2014-05-30 08:53:19 +00:00
}
void setSession ( uint64 session ) {
DEBUG_LOG ( ( " MTP Info: setting server_session: %1 " ) . arg ( session ) ) ;
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2014-05-30 08:53:19 +00:00
if ( _session ! = session ) {
_session = session ;
_messagesSent = 0 ;
}
}
uint64 getSession ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2014-05-30 08:53:19 +00:00
return _session ;
}
2014-11-14 23:23:35 +00:00
bool layerWasInited ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2014-11-14 23:23:35 +00:00
return _layerInited ;
}
void setLayerWasInited ( bool was ) {
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2014-11-14 23:23:35 +00:00
_layerInited = was ;
}
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 ;
}
uint64 getSalt ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2014-05-30 08:53:19 +00:00
return _salt ;
}
2016-03-24 12:57:10 +00:00
const AuthKeyPtr & getKey ( ) const {
2014-11-14 23:23:35 +00:00
return _authKey ;
2014-05-30 08:53:19 +00:00
}
2016-03-24 12:57:10 +00:00
void setKey ( const AuthKeyPtr & key ) {
2014-11-14 23:23:35 +00:00
if ( _authKey ! = key ) {
2016-03-24 10:12:18 +00:00
uint64 session = rand_value < uint64 > ( ) ;
2014-11-14 23:23:35 +00:00
_authKey = key ;
2014-05-30 08:53:19 +00:00
DEBUG_LOG ( ( " MTP Info: new auth key set in SessionData, id %1, setting random server_session %2 " ) . arg ( key ? key - > keyId ( ) : 0 ) . arg ( session ) ) ;
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2014-11-14 23:23:35 +00:00
if ( _session ! = session ) {
_session = session ;
_messagesSent = 0 ;
}
_layerInited = false ;
2014-05-30 08:53:19 +00:00
}
}
bool isCheckedKey ( ) const {
2017-04-30 14:23:57 +00:00
QReadLocker locker ( & _lock ) ;
2014-11-14 23:23:35 +00:00
return _keyChecked ;
2014-05-30 08:53:19 +00:00
}
void setCheckedKey ( bool checked ) {
2017-04-30 14:23:57 +00:00
QWriteLocker locker ( & _lock ) ;
2014-11-14 23:23:35 +00:00
_keyChecked = checked ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * keyMutex ( ) const ;
QReadWriteLock * toSendMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _toSendLock ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * haveSentMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _haveSentLock ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * toResendMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _toResendLock ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * wereAckedMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _wereAckedLock ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * receivedIdsMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _receivedIdsLock ;
2014-05-30 08:53:19 +00:00
}
QReadWriteLock * haveReceivedMutex ( ) const {
2017-04-30 14:23:57 +00:00
return & _haveReceivedLock ;
2014-05-30 08:53:19 +00:00
}
2014-11-05 17:43:32 +00:00
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
mtpPreRequestMap & toSendMap ( ) {
2017-04-30 14:23:57 +00:00
return _toSend ;
2014-05-30 08:53:19 +00:00
}
const mtpPreRequestMap & toSendMap ( ) const {
2017-04-30 14:23:57 +00:00
return _toSend ;
2014-05-30 08:53:19 +00:00
}
mtpRequestMap & haveSentMap ( ) {
2017-04-30 14:23:57 +00:00
return _haveSent ;
2014-05-30 08:53:19 +00:00
}
const mtpRequestMap & haveSentMap ( ) const {
2017-04-30 14:23:57 +00:00
return _haveSent ;
2014-05-30 08:53:19 +00:00
}
mtpRequestIdsMap & 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
}
const mtpRequestIdsMap & 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
}
mtpRequestIdsMap & wereAckedMap ( ) {
2017-04-30 14:23:57 +00:00
return _wereAcked ;
2014-05-30 08:53:19 +00:00
}
const mtpRequestIdsMap & 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
}
2014-11-05 17:43:32 +00:00
mtpMsgIdsSet & stateRequestMap ( ) {
2017-04-30 14:23:57 +00:00
return _stateRequest ;
2014-11-05 17:43:32 +00:00
}
const mtpMsgIdsSet & stateRequestMap ( ) const {
2017-04-30 14:23:57 +00:00
return _stateRequest ;
2014-05-30 08:53:19 +00:00
}
2016-03-24 08:57:11 +00:00
Session * owner ( ) {
2014-05-30 08:53:19 +00:00
return _owner ;
}
2016-03-24 08:57:11 +00:00
const Session * owner ( ) const {
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 ) ;
}
2017-02-24 17:15:41 +00:00
void clear ( Instance * instance ) ;
2014-05-30 08:53:19 +00:00
private :
2016-12-07 13:32:25 +00:00
uint64 _session = 0 ;
uint64 _salt = 0 ;
2014-05-30 08:53:19 +00:00
2016-12-07 13:32:25 +00:00
uint32 _messagesSent = 0 ;
2014-05-30 08:53:19 +00:00
2016-12-07 13:32:25 +00:00
Session * _owner = nullptr ;
2014-05-30 08:53:19 +00:00
2016-03-24 12:57:10 +00:00
AuthKeyPtr _authKey ;
2016-12-07 13:32:25 +00:00
bool _keyChecked = false ;
bool _layerInited = false ;
2014-05-30 08:53:19 +00:00
2017-04-30 14:23:57 +00:00
mtpPreRequestMap _toSend ; // map of request_id -> request, that is waiting to be sent
mtpRequestMap _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
mtpRequestIdsMap _toResend ; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent
ReceivedMsgIds _receivedIds ; // set of received msg_id's, for checking new msg_ids
mtpRequestIdsMap _wereAcked ; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack
mtpMsgIdsSet _stateRequest ; // set of msg_id's, whose state should be requested
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 :
2017-03-22 15:38:40 +00:00
Session ( gsl : : not_null < Instance * > instance , ShiftedDcId shiftedDcId ) ;
2014-05-30 08:53:19 +00:00
2017-02-25 16:44:02 +00:00
void start ( ) ;
2014-05-30 08:53:19 +00:00
void restart ( ) ;
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 ( ) ;
2017-02-24 17:15:41 +00:00
ShiftedDcId getDcWithShift ( ) const ;
2014-05-30 08:53:19 +00:00
QReadWriteLock * keyMutex ( ) const ;
2017-02-24 17:15:41 +00:00
void notifyKeyCreated ( AuthKeyPtr & & key ) ;
2014-05-30 08:53:19 +00:00
void destroyKey ( ) ;
2014-11-14 23:23:35 +00:00
void notifyLayerInited ( bool wasInited ) ;
2014-05-30 08:53:19 +00:00
template < typename TRequest >
2016-12-01 19:20:33 +00:00
mtpRequestId send ( const TRequest & request , RPCResponseHandler callbacks = RPCResponseHandler ( ) , TimeMs msCanWait = 0 , bool needsLayer = false , bool toMainDC = false , mtpRequestId after = 0 ) ; // send mtp request
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 ;
2016-12-01 19:20:33 +00:00
void sendPrepared ( const mtpRequest & request , TimeMs msCanWait = 0 , bool newRequest = true ) ; // nulls msgId and seqNo in request, if newRequest = true
2014-05-30 08:53:19 +00:00
2016-10-05 16:56:27 +00:00
~ Session ( ) ;
2014-05-30 08:53:19 +00:00
2016-10-05 16:56:27 +00:00
signals :
2014-05-30 08:53:19 +00:00
void authKeyCreated ( ) ;
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
public slots :
2014-12-05 13:44:27 +00:00
void needToResumeAndSend ( ) ;
2016-12-01 19:20:33 +00:00
mtpRequestId resend ( quint64 msgId , qint64 msCanWait = 0 , bool forceContainer = false , bool sendMsgStateInfo = false ) ;
void resendMany ( QVector < quint64 > msgIds , qint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) ;
2014-11-25 12:15:29 +00:00
void resendAll ( ) ; // after connection restart
2014-05-30 08:53:19 +00:00
void authKeyCreatedForDC ( ) ;
2014-11-14 23:23:35 +00:00
void layerWasInitedForDC ( bool wasInited ) ;
2014-05-30 08:53:19 +00:00
void tryToReceive ( ) ;
void checkRequestsByTimer ( ) ;
void onConnectionStateChange ( qint32 newState ) ;
2014-08-01 18:49:43 +00:00
void onResetDone ( ) ;
2014-05-30 08:53:19 +00:00
2016-12-01 19:20:33 +00:00
void sendAnything ( qint64 msCanWait = 0 ) ;
2014-11-25 12:15:29 +00:00
void sendPong ( quint64 msgId , quint64 pingId ) ;
void sendMsgsStateInfo ( quint64 msgId , QByteArray data ) ;
2014-11-24 13:21:27 +00:00
2014-05-30 08:53:19 +00:00
private :
2016-10-24 15:36:17 +00:00
void createDcData ( ) ;
2017-02-24 17:15:41 +00:00
void registerRequest ( mtpRequestId requestId , ShiftedDcId dcWithShift ) ;
mtpRequestId storeRequest ( mtpRequest & request , const RPCResponseHandler & parser ) ;
mtpRequest getRequest ( mtpRequestId requestId ) ;
bool rpcErrorOccured ( mtpRequestId requestId , const RPCFailHandlerPtr & onFail , const RPCError & err ) ;
2017-03-22 15:38:40 +00:00
gsl : : not_null < Instance * > _instance ;
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
2016-03-24 08:57:11 +00:00
SessionData data ;
2014-05-30 08:53:19 +00:00
2017-02-24 17:15:41 +00:00
ShiftedDcId dcWithShift = 0 ;
2016-03-24 12:57:10 +00:00
DcenterPtr dc ;
2014-05-30 08:53:19 +00:00
2017-02-24 17:15:41 +00:00
TimeMs msSendCall = 0 ;
TimeMs 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
2014-05-30 08:53:19 +00:00
QTimer timeouter ;
2014-11-12 20:30:26 +00:00
SingleTimer sender ;
2014-05-30 08:53:19 +00:00
} ;
2016-03-24 08:57:11 +00:00
inline QReadWriteLock * SessionData : : keyMutex ( ) const {
2014-05-30 08:53:19 +00:00
return _owner - > keyMutex ( ) ;
}
MTPrpcError rpcClientError ( const QString & type , const QString & description = QString ( ) ) ;
2016-03-24 08:57:11 +00:00
} // namespace internal
} // namespace MTP