2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2014-11-25 20:15:18 +00:00
an official desktop 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 .
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright ( c ) 2014 John Preston , https : //tdesktop.com
*/
# pragma once
# include "mtpConnection.h"
# include "mtpDC.h"
# include "mtpRPC.h"
class MTProtoSession ;
class MTPSessionData {
public :
MTPSessionData ( MTProtoSession * creator )
2014-06-16 09:31:10 +00:00
: _session ( 0 ) , _salt ( 0 )
2014-11-14 23:23:35 +00:00
, _messagesSent ( 0 ) , _fakeRequestId ( - 2000000000 )
, _owner ( creator ) , _keyChecked ( false ) , _layerInited ( false ) {
2014-05-30 08:53:19 +00:00
}
void setSession ( uint64 session ) {
DEBUG_LOG ( ( " MTP Info: setting server_session: %1 " ) . arg ( session ) ) ;
QWriteLocker locker ( & lock ) ;
if ( _session ! = session ) {
_session = session ;
_messagesSent = 0 ;
}
}
uint64 getSession ( ) const {
QReadLocker locker ( & lock ) ;
return _session ;
}
2014-11-14 23:23:35 +00:00
bool layerWasInited ( ) const {
QReadLocker locker ( & lock ) ;
return _layerInited ;
}
void setLayerWasInited ( bool was ) {
QWriteLocker locker ( & lock ) ;
_layerInited = was ;
}
2014-05-30 08:53:19 +00:00
void setSalt ( uint64 salt ) {
QWriteLocker locker ( & lock ) ;
_salt = salt ;
}
uint64 getSalt ( ) const {
QReadLocker locker ( & lock ) ;
return _salt ;
}
const mtpAuthKeyPtr & getKey ( ) const {
2014-11-14 23:23:35 +00:00
return _authKey ;
2014-05-30 08:53:19 +00:00
}
void setKey ( const mtpAuthKeyPtr & key ) {
2014-11-14 23:23:35 +00:00
if ( _authKey ! = key ) {
2014-05-30 08:53:19 +00:00
uint64 session ;
2014-08-01 11:09:46 +00:00
memsetrnd ( session ) ;
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 ) ) ;
2014-11-14 23:23:35 +00:00
QWriteLocker locker ( & lock ) ;
if ( _session ! = session ) {
_session = session ;
_messagesSent = 0 ;
}
_layerInited = false ;
2014-05-30 08:53:19 +00:00
}
}
bool isCheckedKey ( ) const {
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 ) {
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 {
return & toSendLock ;
}
QReadWriteLock * haveSentMutex ( ) const {
return & haveSentLock ;
}
QReadWriteLock * toResendMutex ( ) const {
return & toResendLock ;
}
QReadWriteLock * wereAckedMutex ( ) const {
return & wereAckedLock ;
}
QReadWriteLock * receivedIdsMutex ( ) const {
return & receivedIdsLock ;
}
QReadWriteLock * haveReceivedMutex ( ) const {
return & haveReceivedLock ;
}
2014-11-05 17:43:32 +00:00
QReadWriteLock * stateRequestMutex ( ) const {
return & stateRequestLock ;
}
2014-05-30 08:53:19 +00:00
mtpPreRequestMap & toSendMap ( ) {
return toSend ;
}
const mtpPreRequestMap & toSendMap ( ) const {
return toSend ;
}
mtpRequestMap & haveSentMap ( ) {
return haveSent ;
}
const mtpRequestMap & haveSentMap ( ) const {
return haveSent ;
}
mtpRequestIdsMap & toResendMap ( ) { // msgId -> requestId, on which toSend: requestId -> request for resended requests
return toResend ;
}
const mtpRequestIdsMap & toResendMap ( ) const {
return toResend ;
}
2014-11-05 17:43:32 +00:00
mtpMsgIdsMap & receivedIdsSet ( ) {
2014-05-30 08:53:19 +00:00
return receivedIds ;
}
2014-11-05 17:43:32 +00:00
const mtpMsgIdsMap & receivedIdsSet ( ) const {
2014-05-30 08:53:19 +00:00
return receivedIds ;
}
mtpRequestIdsMap & wereAckedMap ( ) {
return wereAcked ;
}
const mtpRequestIdsMap & wereAckedMap ( ) const {
return wereAcked ;
}
mtpResponseMap & haveReceivedMap ( ) {
return haveReceived ;
}
const mtpResponseMap & haveReceivedMap ( ) const {
return haveReceived ;
}
2014-11-05 17:43:32 +00:00
mtpMsgIdsSet & stateRequestMap ( ) {
return stateRequest ;
}
const mtpMsgIdsSet & stateRequestMap ( ) const {
return stateRequest ;
}
2014-05-30 08:53:19 +00:00
mtpRequestId nextFakeRequestId ( ) { // must be locked by haveReceivedMutex()
if ( haveReceived . isEmpty ( ) | | haveReceived . cbegin ( ) . key ( ) > 0 ) {
2014-11-14 23:23:35 +00:00
_fakeRequestId = - 2000000000 ;
2014-05-30 08:53:19 +00:00
} else {
2014-11-14 23:23:35 +00:00
+ + _fakeRequestId ;
2014-05-30 08:53:19 +00:00
}
2014-11-14 23:23:35 +00:00
return _fakeRequestId ;
2014-05-30 08:53:19 +00:00
}
MTProtoSession * owner ( ) {
return _owner ;
}
const MTProtoSession * owner ( ) const {
return _owner ;
}
uint32 nextRequestSeqNumber ( bool needAck = true ) {
QWriteLocker locker ( & lock ) ;
uint32 result ( _messagesSent ) ;
_messagesSent + = ( needAck ? 1 : 0 ) ;
return result * 2 + ( needAck ? 1 : 0 ) ;
}
void clear ( ) ;
private :
uint64 _session , _salt ;
uint32 _messagesSent ;
2014-11-14 23:23:35 +00:00
mtpRequestId _fakeRequestId ;
2014-05-30 08:53:19 +00:00
MTProtoSession * _owner ;
2014-11-14 23:23:35 +00:00
mtpAuthKeyPtr _authKey ;
bool _keyChecked , _layerInited ;
2014-05-30 08:53:19 +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
2014-11-05 17:43:32 +00:00
mtpMsgIdsMap receivedIds ; // set of received msg_id's, for checking new msg_ids
2014-05-30 08:53:19 +00:00
mtpRequestIdsMap wereAcked ; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack
mtpResponseMap haveReceived ; // map of request_id -> response, that should be processed in other thread
2014-11-05 17:43:32 +00:00
mtpMsgIdsSet stateRequest ; // set of msg_id's, whose state should be requested
2014-05-30 08:53:19 +00:00
// mutexes
mutable QReadWriteLock lock ;
mutable QReadWriteLock toSendLock ;
mutable QReadWriteLock haveSentLock ;
mutable QReadWriteLock toResendLock ;
mutable QReadWriteLock receivedIdsLock ;
mutable QReadWriteLock wereAckedLock ;
mutable QReadWriteLock haveReceivedLock ;
2014-11-05 17:43:32 +00:00
mutable QReadWriteLock stateRequestLock ;
2014-05-30 08:53:19 +00:00
} ;
class MTProtoSession : public QObject {
Q_OBJECT
public :
MTProtoSession ( ) ;
void start ( int32 dcenter = 0 , uint32 connects = 0 ) ;
void restart ( ) ;
void stop ( ) ;
int32 getDC ( ) const ;
~ MTProtoSession ( ) ;
QReadWriteLock * keyMutex ( ) const ;
2014-11-14 23:23:35 +00:00
void notifyKeyCreated ( const mtpAuthKeyPtr & 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 >
2014-11-14 23:23:35 +00:00
mtpRequestId send ( const TRequest & request , RPCResponseHandler callbacks = RPCResponseHandler ( ) , uint64 msCanWait = 0 , bool needsLayer = false , bool toMainDC = false , mtpRequestId after = 0 ) ; // send mtp request
2014-05-30 08:53:19 +00:00
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 ;
void sendPrepared ( const mtpRequest & request , uint64 msCanWait = 0 , bool newRequest = true ) ; // nulls msgId and seqNo in request, if newRequest = true
void sendPreparedWithInit ( const mtpRequest & request , uint64 msCanWait = 0 ) ;
signals :
void authKeyCreated ( ) ;
void needToSend ( ) ;
2014-11-24 13:21:27 +00:00
void needToRestart ( ) ;
2014-05-30 08:53:19 +00:00
public slots :
2014-11-25 12:15:29 +00:00
mtpRequestId resend ( quint64 msgId , quint64 msCanWait = 0 , bool forceContainer = false , bool sendMsgStateInfo = false ) ;
void resendMany ( QVector < quint64 > msgIds , quint64 msCanWait , bool forceContainer , bool sendMsgStateInfo ) ;
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
2014-11-22 09:45:04 +00:00
void sendAnything ( quint64 msCanWait ) ;
2014-11-24 13:21:27 +00:00
void sendHttpWait ( ) ;
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 :
typedef QList < MTProtoConnection * > MTProtoConnections ;
MTProtoConnections connections ;
MTPSessionData data ;
int32 dcId ;
MTProtoDCPtr dc ;
uint64 msSendCall , msWait ;
QTimer timeouter ;
2014-11-12 20:30:26 +00:00
SingleTimer sender ;
2014-05-30 08:53:19 +00:00
} ;
inline QReadWriteLock * MTPSessionData : : keyMutex ( ) const {
return _owner - > keyMutex ( ) ;
}
MTPrpcError rpcClientError ( const QString & type , const QString & description = QString ( ) ) ;
// here
typedef QSharedPointer < MTProtoSession > MTProtoSessionPtr ;