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
|
|
|
*/
|
2016-03-23 18:43:12 +00:00
|
|
|
#include "mtproto/session.h"
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-02-24 17:15:41 +00:00
|
|
|
#include "mtproto/connection.h"
|
2017-06-26 17:38:16 +00:00
|
|
|
#include "mtproto/dcenter.h"
|
2019-11-18 09:28:14 +00:00
|
|
|
#include "mtproto/mtproto_auth_key.h"
|
2019-07-10 17:28:33 +00:00
|
|
|
#include "base/unixtime.h"
|
2019-11-15 13:04:32 +00:00
|
|
|
#include "base/openssl_help.h"
|
2017-12-11 14:45:29 +00:00
|
|
|
#include "core/crash_reports.h"
|
2019-09-13 06:06:02 +00:00
|
|
|
#include "facades.h"
|
2017-02-24 17:15:41 +00:00
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
namespace MTP {
|
|
|
|
namespace internal {
|
|
|
|
|
2018-04-24 08:46:27 +00:00
|
|
|
ConnectionOptions::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)
|
|
|
|
: systemLangCode(systemLangCode)
|
|
|
|
, cloudLangCode(cloudLangCode)
|
2018-08-20 11:31:40 +00:00
|
|
|
, langPackName(langPackName)
|
2018-04-24 08:46:27 +00:00
|
|
|
, proxy(proxy)
|
|
|
|
, useIPv4(useIPv4)
|
|
|
|
, useIPv6(useIPv6)
|
|
|
|
, useHttp(useHttp)
|
|
|
|
, useTcp(useTcp) {
|
|
|
|
}
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
template <typename Callback>
|
|
|
|
void SessionData::withSession(Callback &&callback) {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (const auto session = _owner) {
|
|
|
|
InvokeQueued(session, [
|
|
|
|
session,
|
|
|
|
callback = std::forward<Callback>(callback)
|
|
|
|
] {
|
|
|
|
callback(session);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 13:34:58 +00:00
|
|
|
void SessionData::setKeyForCheck(const AuthKeyPtr &key) {
|
|
|
|
_dcKeyForCheck = key;
|
|
|
|
}
|
|
|
|
|
2018-05-17 19:58:00 +00:00
|
|
|
void SessionData::notifyConnectionInited(const ConnectionOptions &options) {
|
2019-11-15 13:04:32 +00:00
|
|
|
// #TODO race
|
|
|
|
const auto current = connectionOptions();
|
|
|
|
if (current.cloudLangCode == _options.cloudLangCode
|
|
|
|
&& current.systemLangCode == _options.systemLangCode
|
|
|
|
&& current.langPackName == _options.langPackName
|
|
|
|
&& current.proxy == _options.proxy) {
|
2018-05-17 19:58:00 +00:00
|
|
|
owner()->notifyDcConnectionInited();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 13:04:32 +00:00
|
|
|
void SessionData::clearForNewKey(not_null<Instance*> instance) {
|
2018-01-02 13:44:12 +00:00
|
|
|
auto clearCallbacks = std::vector<RPCCallbackClear>();
|
2014-05-30 08:53:19 +00:00
|
|
|
{
|
2019-11-15 13:04:32 +00:00
|
|
|
QReadLocker locker1(haveSentMutex());
|
|
|
|
QReadLocker locker2(toResendMutex());
|
|
|
|
QReadLocker locker3(haveReceivedMutex());
|
|
|
|
QReadLocker locker4(wereAckedMutex());
|
|
|
|
clearCallbacks.reserve(_haveSent.size() + _toResend.size() + _wereAcked.size());
|
2017-04-30 14:23:57 +00:00
|
|
|
for (auto i = _haveSent.cbegin(), e = _haveSent.cend(); i != e; ++i) {
|
|
|
|
auto requestId = i.value()->requestId;
|
|
|
|
if (!_receivedResponses.contains(requestId)) {
|
2014-05-30 08:53:19 +00:00
|
|
|
clearCallbacks.push_back(requestId);
|
|
|
|
}
|
|
|
|
}
|
2017-04-30 14:23:57 +00:00
|
|
|
for (auto i = _toResend.cbegin(), e = _toResend.cend(); i != e; ++i) {
|
|
|
|
auto requestId = i.value();
|
|
|
|
if (!_receivedResponses.contains(requestId)) {
|
2014-05-30 08:53:19 +00:00
|
|
|
clearCallbacks.push_back(requestId);
|
|
|
|
}
|
|
|
|
}
|
2017-04-30 14:23:57 +00:00
|
|
|
for (auto i = _wereAcked.cbegin(), e = _wereAcked.cend(); i != e; ++i) {
|
|
|
|
auto requestId = i.value();
|
|
|
|
if (!_receivedResponses.contains(requestId)) {
|
2014-05-30 08:53:19 +00:00
|
|
|
clearCallbacks.push_back(requestId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QWriteLocker locker(haveSentMutex());
|
2017-04-30 14:23:57 +00:00
|
|
|
_haveSent.clear();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
QWriteLocker locker(toResendMutex());
|
2017-04-30 14:23:57 +00:00
|
|
|
_toResend.clear();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
QWriteLocker locker(wereAckedMutex());
|
2017-04-30 14:23:57 +00:00
|
|
|
_wereAcked.clear();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
2018-01-02 13:44:12 +00:00
|
|
|
instance->clearCallbacksDelayed(std::move(clearCallbacks));
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
void SessionData::queueTryToReceive() {
|
|
|
|
withSession([](not_null<Session*> session) {
|
|
|
|
session->tryToReceive();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::queueNeedToResumeAndSend() {
|
|
|
|
withSession([](not_null<Session*> session) {
|
|
|
|
session->needToResumeAndSend();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::queueConnectionStateChange(int newState) {
|
|
|
|
withSession([=](not_null<Session*> session) {
|
|
|
|
session->connectionStateChange(newState);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::queueResetDone() {
|
|
|
|
withSession([](not_null<Session*> session) {
|
|
|
|
session->resetDone();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::queueSendAnything(crl::time msCanWait) {
|
|
|
|
withSession([=](not_null<Session*> session) {
|
|
|
|
session->sendAnything(msCanWait);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::queueSendMsgsStateInfo(quint64 msgId, QByteArray data) {
|
|
|
|
withSession([=](not_null<Session*> session) {
|
|
|
|
session->sendMsgsStateInfo(msgId, data);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-19 16:14:50 +00:00
|
|
|
void SessionData::resend(
|
2019-11-18 12:53:37 +00:00
|
|
|
mtpMsgId msgId,
|
|
|
|
crl::time msCanWait,
|
2019-11-19 11:55:39 +00:00
|
|
|
bool forceContainer) {
|
2019-11-19 16:14:50 +00:00
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (_owner) {
|
|
|
|
_owner->resend(msgId, msCanWait, forceContainer);
|
|
|
|
}
|
2019-11-18 12:53:37 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 16:14:50 +00:00
|
|
|
void SessionData::resendAll() {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (_owner) {
|
|
|
|
_owner->resendAll();
|
|
|
|
}
|
2019-11-18 12:53:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SessionData::connectionInited() const {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
return _owner ? _owner->connectionInited() : false;
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
AuthKeyPtr SessionData::getTemporaryKey() const {
|
2019-11-18 12:53:37 +00:00
|
|
|
QMutexLocker lock(&_ownerMutex);
|
2019-11-19 10:10:51 +00:00
|
|
|
return _owner ? _owner->getTemporaryKey() : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
AuthKeyPtr SessionData::getPersistentKey() const {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
return _owner ? _owner->getPersistentKey() : nullptr;
|
2019-11-18 12:53:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SessionData::acquireKeyCreation() {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
return _owner ? _owner->acquireKeyCreation() : false;
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
void SessionData::releaseKeyCreationOnDone(
|
|
|
|
const AuthKeyPtr &temporaryKey,
|
|
|
|
const AuthKeyPtr &persistentKey) {
|
2019-11-18 12:53:37 +00:00
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (_owner) {
|
2019-11-19 10:10:51 +00:00
|
|
|
_owner->releaseKeyCreationOnDone(temporaryKey, persistentKey);
|
2019-11-18 12:53:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::releaseKeyCreationOnFail() {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (_owner) {
|
|
|
|
_owner->releaseKeyCreationOnFail();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
void SessionData::destroyTemporaryKey(uint64 keyId) {
|
2019-11-18 12:53:37 +00:00
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
if (_owner) {
|
2019-11-19 10:10:51 +00:00
|
|
|
_owner->destroyTemporaryKey(keyId);
|
2019-11-18 12:53:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SessionData::detach() {
|
|
|
|
QMutexLocker lock(&_ownerMutex);
|
|
|
|
_owner = nullptr;
|
|
|
|
}
|
|
|
|
|
2019-11-15 07:28:33 +00:00
|
|
|
Session::Session(
|
|
|
|
not_null<Instance*> instance,
|
|
|
|
ShiftedDcId shiftedDcId,
|
|
|
|
Dcenter *dc)
|
2019-11-14 07:13:17 +00:00
|
|
|
: QObject()
|
2017-02-24 17:15:41 +00:00
|
|
|
, _instance(instance)
|
2019-11-14 07:13:17 +00:00
|
|
|
, _shiftedDcId(shiftedDcId)
|
2019-11-15 13:04:32 +00:00
|
|
|
, _ownedDc(dc ? nullptr : std::make_unique<Dcenter>(shiftedDcId, nullptr))
|
|
|
|
, _dc(dc ? dc : _ownedDc.get())
|
2019-11-18 12:53:37 +00:00
|
|
|
, _data(std::make_shared<SessionData>(this))
|
2019-11-14 07:13:17 +00:00
|
|
|
, _sender([=] { needToResumeAndSend(); }) {
|
2019-11-14 17:39:15 +00:00
|
|
|
_timeouter.callEach(1000);
|
2018-05-17 19:58:00 +00:00
|
|
|
refreshOptions();
|
2019-11-15 13:04:32 +00:00
|
|
|
if (sharedDc()) {
|
2019-11-18 12:53:37 +00:00
|
|
|
watchDcKeyChanges();
|
2019-11-15 07:28:33 +00:00
|
|
|
}
|
2017-02-25 16:44:02 +00:00
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
void Session::watchDcKeyChanges() {
|
2019-11-19 10:10:51 +00:00
|
|
|
_instance->dcTemporaryKeyChanged(
|
2019-11-18 12:53:37 +00:00
|
|
|
) | rpl::filter([=](DcId dcId) {
|
|
|
|
return (dcId == _shiftedDcId) || (dcId == BareDcId(_shiftedDcId));
|
|
|
|
}) | rpl::start_with_next([=] {
|
|
|
|
DEBUG_LOG(("AuthKey Info: Session::authKeyCreatedForDC slot, "
|
|
|
|
"emitting authKeyChanged(), dcWithShift %1").arg(_shiftedDcId));
|
|
|
|
emit authKeyChanged();
|
|
|
|
}, _lifetime);
|
|
|
|
}
|
|
|
|
|
2017-02-25 16:44:02 +00:00
|
|
|
void Session::start() {
|
2017-02-24 17:15:41 +00:00
|
|
|
_connection = std::make_unique<Connection>(_instance);
|
2019-11-18 12:53:37 +00:00
|
|
|
_connection->start(_data, _shiftedDcId);
|
2017-02-25 16:44:02 +00:00
|
|
|
if (_instance->isKeysDestroyer()) {
|
2019-11-14 07:13:17 +00:00
|
|
|
_instance->scheduleKeyDestroy(_shiftedDcId);
|
2016-02-29 16:53:26 +00:00
|
|
|
}
|
2016-10-24 15:36:17 +00:00
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2019-01-13 13:28:05 +00:00
|
|
|
bool Session::rpcErrorOccured(
|
|
|
|
mtpRequestId requestId,
|
|
|
|
const RPCFailHandlerPtr &onFail,
|
|
|
|
const RPCError &error) { // return true if need to clean request data
|
|
|
|
return _instance->rpcErrorOccured(requestId, onFail, error);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::restart() {
|
2015-05-14 16:50:04 +00:00
|
|
|
if (_killed) {
|
|
|
|
DEBUG_LOG(("Session Error: can't restart a killed session"));
|
|
|
|
return;
|
|
|
|
}
|
2018-05-17 19:58:00 +00:00
|
|
|
refreshOptions();
|
2014-11-24 13:21:27 +00:00
|
|
|
emit needToRestart();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 19:58:00 +00:00
|
|
|
void Session::refreshOptions() {
|
2018-04-27 17:26:45 +00:00
|
|
|
const auto &proxy = Global::SelectedProxy();
|
2018-11-05 13:58:24 +00:00
|
|
|
const auto proxyType =
|
|
|
|
(Global::ProxySettings() == ProxyData::Settings::Enabled
|
|
|
|
? proxy.type
|
|
|
|
: ProxyData::Type::None);
|
2018-04-27 17:26:45 +00:00
|
|
|
const auto useTcp = (proxyType != ProxyData::Type::Http);
|
|
|
|
const auto useHttp = (proxyType != ProxyData::Type::Mtproto);
|
2018-04-24 08:46:27 +00:00
|
|
|
const auto useIPv4 = true;
|
2018-04-24 19:09:20 +00:00
|
|
|
const auto useIPv6 = Global::TryIPv6();
|
2019-11-18 12:53:37 +00:00
|
|
|
_data->setConnectionOptions(ConnectionOptions(
|
2018-04-24 08:46:27 +00:00
|
|
|
_instance->systemLangCode(),
|
|
|
|
_instance->cloudLangCode(),
|
2018-08-20 11:31:40 +00:00
|
|
|
_instance->langPackName(),
|
2018-11-05 13:58:24 +00:00
|
|
|
(Global::ProxySettings() == ProxyData::Settings::Enabled
|
|
|
|
? proxy
|
|
|
|
: ProxyData()),
|
2018-04-24 08:46:27 +00:00
|
|
|
useIPv4,
|
|
|
|
useIPv6,
|
|
|
|
useHttp,
|
|
|
|
useTcp));
|
|
|
|
}
|
|
|
|
|
2018-05-17 19:58:00 +00:00
|
|
|
void Session::reInitConnection() {
|
2019-11-15 13:04:32 +00:00
|
|
|
_dc->setConnectionInited(false);
|
2018-05-17 19:58:00 +00:00
|
|
|
restart();
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::stop() {
|
2016-02-29 16:53:26 +00:00
|
|
|
if (_killed) {
|
|
|
|
DEBUG_LOG(("Session Error: can't kill a killed session"));
|
|
|
|
return;
|
|
|
|
}
|
2019-11-14 07:13:17 +00:00
|
|
|
DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(_shiftedDcId));
|
2016-02-29 16:53:26 +00:00
|
|
|
if (_connection) {
|
|
|
|
_connection->kill();
|
2017-02-24 17:15:41 +00:00
|
|
|
_instance->queueQuittingConnection(std::move(_connection));
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::kill() {
|
2015-05-14 16:50:04 +00:00
|
|
|
stop();
|
|
|
|
_killed = true;
|
2019-11-18 12:53:37 +00:00
|
|
|
_data->detach();
|
2019-11-14 07:13:17 +00:00
|
|
|
DEBUG_LOG(("Session Info: marked session dcWithShift %1 as killed").arg(_shiftedDcId));
|
2015-05-14 16:50:04 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::unpaused() {
|
2015-10-15 10:18:24 +00:00
|
|
|
if (_needToReceive) {
|
|
|
|
_needToReceive = false;
|
2019-11-18 12:53:37 +00:00
|
|
|
InvokeQueued(this, [=] {
|
|
|
|
tryToReceive();
|
|
|
|
});
|
2015-10-15 10:18:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 13:34:58 +00:00
|
|
|
void Session::sendDcKeyCheck(const AuthKeyPtr &key) {
|
2019-11-18 12:53:37 +00:00
|
|
|
_data->setKeyForCheck(key);
|
2019-11-14 13:34:58 +00:00
|
|
|
needToResumeAndSend();
|
|
|
|
}
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
void Session::sendAnything(crl::time msCanWait) {
|
2015-05-14 16:50:04 +00:00
|
|
|
if (_killed) {
|
|
|
|
DEBUG_LOG(("Session Error: can't send anything in a killed session"));
|
|
|
|
return;
|
|
|
|
}
|
2019-11-14 07:13:17 +00:00
|
|
|
const auto ms = crl::now();
|
|
|
|
if (_msSendCall) {
|
|
|
|
if (ms > _msSendCall + _msWait) {
|
|
|
|
_msWait = 0;
|
2014-11-05 17:43:32 +00:00
|
|
|
} else {
|
2019-11-14 07:13:17 +00:00
|
|
|
_msWait = (_msSendCall + _msWait) - ms;
|
|
|
|
if (_msWait > msCanWait) {
|
|
|
|
_msWait = msCanWait;
|
2014-11-05 17:43:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2019-11-14 07:13:17 +00:00
|
|
|
_msWait = msCanWait;
|
2014-11-05 17:43:32 +00:00
|
|
|
}
|
2019-11-14 07:13:17 +00:00
|
|
|
if (_msWait) {
|
|
|
|
DEBUG_LOG(("MTP Info: dcWithShift %1 can wait for %2ms from current %3").arg(_shiftedDcId).arg(_msWait).arg(_msSendCall));
|
|
|
|
_msSendCall = ms;
|
|
|
|
_sender.callOnce(_msWait);
|
2014-11-05 17:43:32 +00:00
|
|
|
} else {
|
2019-11-14 07:13:17 +00:00
|
|
|
DEBUG_LOG(("MTP Info: dcWithShift %1 stopped send timer, can wait for %2ms from current %3").arg(_shiftedDcId).arg(_msWait).arg(_msSendCall));
|
|
|
|
_sender.cancel();
|
|
|
|
_msSendCall = 0;
|
2014-12-05 13:44:27 +00:00
|
|
|
needToResumeAndSend();
|
2014-11-05 17:43:32 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::needToResumeAndSend() {
|
2015-05-14 16:50:04 +00:00
|
|
|
if (_killed) {
|
|
|
|
DEBUG_LOG(("Session Info: can't resume a killed session"));
|
|
|
|
return;
|
|
|
|
}
|
2016-02-29 16:53:26 +00:00
|
|
|
if (!_connection) {
|
2019-11-14 07:13:17 +00:00
|
|
|
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(_shiftedDcId));
|
2019-11-14 17:39:15 +00:00
|
|
|
start();
|
2014-12-05 13:44:27 +00:00
|
|
|
}
|
2015-04-16 14:59:42 +00:00
|
|
|
if (_ping) {
|
|
|
|
_ping = false;
|
|
|
|
emit needToPing();
|
|
|
|
} else {
|
|
|
|
emit needToSend();
|
|
|
|
}
|
2014-12-05 13:44:27 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::sendMsgsStateInfo(quint64 msgId, QByteArray data) {
|
2018-03-27 12:16:00 +00:00
|
|
|
auto info = bytes::vector();
|
2014-11-25 12:15:29 +00:00
|
|
|
if (!data.isEmpty()) {
|
2017-03-09 18:13:55 +00:00
|
|
|
info.resize(data.size());
|
2018-03-27 12:16:00 +00:00
|
|
|
bytes::copy(info, bytes::make_span(data));
|
2014-11-25 12:15:29 +00:00
|
|
|
}
|
2018-06-02 14:29:21 +00:00
|
|
|
_instance->sendProtocolMessage(
|
2019-11-14 07:13:17 +00:00
|
|
|
_shiftedDcId,
|
2018-06-02 14:29:21 +00:00
|
|
|
MTPMsgsStateInfo(
|
|
|
|
MTP_msgs_state_info(MTP_long(msgId), MTP_bytes(data))));
|
2014-11-25 12:15:29 +00:00
|
|
|
}
|
|
|
|
|
2019-11-15 13:04:32 +00:00
|
|
|
bool Session::sharedDc() const {
|
|
|
|
return (_ownedDc == nullptr);
|
|
|
|
}
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
void Session::connectionStateChange(int newState) {
|
2019-11-14 07:13:17 +00:00
|
|
|
_instance->onStateChange(_shiftedDcId, newState);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
void Session::resetDone() {
|
2019-11-14 07:13:17 +00:00
|
|
|
_instance->onSessionReset(_shiftedDcId);
|
2014-08-01 18:49:43 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::cancel(mtpRequestId requestId, mtpMsgId msgId) {
|
2014-11-05 17:43:32 +00:00
|
|
|
if (requestId) {
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->toSendMutex());
|
|
|
|
_data->toSendMap().remove(requestId);
|
2014-11-05 17:43:32 +00:00
|
|
|
}
|
|
|
|
if (msgId) {
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->haveSentMutex());
|
|
|
|
_data->haveSentMap().remove(msgId);
|
2014-11-05 17:43:32 +00:00
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::ping() {
|
2015-04-16 14:59:42 +00:00
|
|
|
_ping = true;
|
2019-11-18 12:53:37 +00:00
|
|
|
sendAnything();
|
2015-04-16 14:59:42 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
int32 Session::requestState(mtpRequestId requestId) const {
|
2014-05-30 08:53:19 +00:00
|
|
|
int32 result = MTP::RequestSent;
|
2016-02-29 16:53:26 +00:00
|
|
|
|
|
|
|
bool connected = false;
|
|
|
|
if (_connection) {
|
|
|
|
int32 s = _connection->state();
|
2016-03-24 08:57:11 +00:00
|
|
|
if (s == ConnectedState) {
|
2016-02-29 16:53:26 +00:00
|
|
|
connected = true;
|
2016-03-24 08:57:11 +00:00
|
|
|
} else if (s == ConnectingState || s == DisconnectedState) {
|
2014-05-30 08:53:19 +00:00
|
|
|
if (result < 0 || result == MTP::RequestSent) {
|
|
|
|
result = MTP::RequestConnecting;
|
|
|
|
}
|
|
|
|
} else if (s < 0) {
|
2014-06-16 09:31:10 +00:00
|
|
|
if ((result < 0 && s > result) || result == MTP::RequestSent) {
|
2014-05-30 08:53:19 +00:00
|
|
|
result = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-29 16:53:26 +00:00
|
|
|
if (!connected) {
|
2014-05-30 08:53:19 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if (!requestId) return MTP::RequestSent;
|
|
|
|
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->toSendMutex());
|
|
|
|
const auto &toSend = _data->toSendMap();
|
2018-06-25 18:55:27 +00:00
|
|
|
const auto i = toSend.constFind(requestId);
|
2014-05-30 08:53:19 +00:00
|
|
|
if (i != toSend.cend()) {
|
|
|
|
return MTP::RequestSending;
|
|
|
|
} else {
|
|
|
|
return MTP::RequestSent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
int32 Session::getState() const {
|
2014-05-30 08:53:19 +00:00
|
|
|
int32 result = -86400000;
|
2016-02-29 16:53:26 +00:00
|
|
|
|
|
|
|
if (_connection) {
|
|
|
|
int32 s = _connection->state();
|
2016-03-24 08:57:11 +00:00
|
|
|
if (s == ConnectedState) {
|
2014-05-30 08:53:19 +00:00
|
|
|
return s;
|
2016-03-24 08:57:11 +00:00
|
|
|
} else if (s == ConnectingState || s == DisconnectedState) {
|
2014-05-30 08:53:19 +00:00
|
|
|
if (result < 0) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
} else if (s < 0) {
|
|
|
|
if (result < 0 && s > result) {
|
|
|
|
result = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (result == -86400000) {
|
2016-03-24 08:57:11 +00:00
|
|
|
result = DisconnectedState;
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
QString Session::transport() const {
|
2016-02-29 16:53:26 +00:00
|
|
|
return _connection ? _connection->transport() : QString();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 16:14:50 +00:00
|
|
|
void Session::resend(
|
2019-11-18 12:53:37 +00:00
|
|
|
mtpMsgId msgId,
|
|
|
|
crl::time msCanWait,
|
2019-11-19 11:55:39 +00:00
|
|
|
bool forceContainer) {
|
2019-11-19 16:14:50 +00:00
|
|
|
auto lock = QWriteLocker(_data->haveSentMutex());
|
|
|
|
auto &haveSent = _data->haveSentMap();
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2019-11-19 16:14:50 +00:00
|
|
|
auto i = haveSent.find(msgId);
|
|
|
|
if (i == haveSent.end()) {
|
|
|
|
return;
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
2019-11-19 16:14:50 +00:00
|
|
|
auto request = i.value();
|
|
|
|
haveSent.erase(i);
|
|
|
|
lock.unlock();
|
|
|
|
|
|
|
|
// For container just resend all messages we can.
|
|
|
|
if (request.isSentContainer()) {
|
2014-05-30 08:53:19 +00:00
|
|
|
DEBUG_LOG(("Message Info: resending container from haveSent, msgId %1").arg(msgId));
|
|
|
|
const mtpMsgId *ids = (const mtpMsgId *)(request->constData() + 8);
|
|
|
|
for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) {
|
|
|
|
resend(ids[i], 10, true);
|
|
|
|
}
|
2018-06-25 18:55:27 +00:00
|
|
|
} else if (!request.isStateRequest()) {
|
2019-02-19 06:57:53 +00:00
|
|
|
request->msDate = forceContainer ? 0 : crl::now();
|
2014-05-30 08:53:19 +00:00
|
|
|
{
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->toResendMutex());
|
|
|
|
_data->toResendMap().insert(msgId, request->requestId);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
2019-11-19 16:14:50 +00:00
|
|
|
sendPrepared(request, msCanWait, false);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::resendAll() {
|
2014-05-30 08:53:19 +00:00
|
|
|
QVector<mtpMsgId> toResend;
|
|
|
|
{
|
2019-11-18 12:53:37 +00:00
|
|
|
QReadLocker locker(_data->haveSentMutex());
|
|
|
|
const auto &haveSent = _data->haveSentMap();
|
2014-05-30 08:53:19 +00:00
|
|
|
toResend.reserve(haveSent.size());
|
2018-06-25 18:55:27 +00:00
|
|
|
for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) {
|
|
|
|
if (i.value()->requestId) {
|
|
|
|
toResend.push_back(i.key());
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (uint32 i = 0, l = toResend.size(); i < l; ++i) {
|
2019-11-19 16:14:50 +00:00
|
|
|
resend(toResend[i], -1, true);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
2019-11-19 16:14:50 +00:00
|
|
|
InvokeQueued(this, [=] {
|
|
|
|
sendAnything();
|
|
|
|
});
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2018-06-02 14:29:21 +00:00
|
|
|
void Session::sendPrepared(
|
2018-06-25 18:55:27 +00:00
|
|
|
const SecureRequest &request,
|
2019-02-19 06:57:53 +00:00
|
|
|
crl::time msCanWait,
|
2018-06-02 14:29:21 +00:00
|
|
|
bool newRequest) {
|
|
|
|
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1"
|
|
|
|
).arg(msCanWait));
|
2014-05-30 08:53:19 +00:00
|
|
|
{
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->toSendMutex());
|
|
|
|
_data->toSendMap().insert(request->requestId, request);
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
if (newRequest) {
|
|
|
|
*(mtpMsgId*)(request->data() + 4) = 0;
|
|
|
|
*(request->data() + 6) = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_LOG(("MTP Info: added, requestId %1").arg(request->requestId));
|
2019-11-19 16:14:50 +00:00
|
|
|
if (msCanWait >= 0) {
|
|
|
|
InvokeQueued(this, [=] {
|
|
|
|
sendAnything(msCanWait);
|
|
|
|
});
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-15 13:04:32 +00:00
|
|
|
bool Session::acquireKeyCreation() {
|
2019-11-18 12:53:37 +00:00
|
|
|
Expects(!_myKeyCreation);
|
|
|
|
|
|
|
|
if (!_dc->acquireKeyCreation()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_myKeyCreation = true;
|
|
|
|
return true;
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
void Session::releaseKeyCreationOnDone(
|
|
|
|
const AuthKeyPtr &temporaryKey,
|
|
|
|
const AuthKeyPtr &persistentKey) {
|
2019-11-18 12:53:37 +00:00
|
|
|
Expects(_myKeyCreation);
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
DEBUG_LOG(("AuthKey Info: Session key bound, setting, dcWithShift %1"
|
|
|
|
).arg(_shiftedDcId));
|
|
|
|
_dc->releaseKeyCreationOnDone(temporaryKey, persistentKey);
|
2019-11-18 12:53:37 +00:00
|
|
|
_myKeyCreation = false;
|
|
|
|
|
2019-11-15 13:04:32 +00:00
|
|
|
if (sharedDc()) {
|
|
|
|
const auto dcId = _dc->id();
|
|
|
|
const auto instance = _instance;
|
|
|
|
InvokeQueued(instance, [=] {
|
2019-11-19 10:10:51 +00:00
|
|
|
if (persistentKey) {
|
|
|
|
instance->dcPersistentKeyChanged(dcId, persistentKey);
|
|
|
|
} else {
|
|
|
|
instance->dcTemporaryKeyChanged(dcId);
|
|
|
|
}
|
2019-11-15 13:04:32 +00:00
|
|
|
});
|
|
|
|
}
|
2014-11-14 23:23:35 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
void Session::releaseKeyCreationOnFail() {
|
|
|
|
Expects(_myKeyCreation);
|
|
|
|
|
|
|
|
_dc->releaseKeyCreationOnFail();
|
|
|
|
_myKeyCreation = false;
|
|
|
|
}
|
|
|
|
|
2018-05-17 19:58:00 +00:00
|
|
|
void Session::notifyDcConnectionInited() {
|
2019-11-14 07:13:17 +00:00
|
|
|
DEBUG_LOG(("MTP Info: emitting MTProtoDC::connectionWasInited(), dcWithShift %1").arg(_shiftedDcId));
|
2019-11-15 13:04:32 +00:00
|
|
|
_dc->setConnectionInited();
|
2014-11-14 23:23:35 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
void Session::destroyTemporaryKey(uint64 keyId) {
|
|
|
|
if (!_dc->destroyTemporaryKey(keyId)) {
|
2019-11-18 12:53:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-11-15 13:04:32 +00:00
|
|
|
if (sharedDc()) {
|
|
|
|
const auto dcId = _dc->id();
|
|
|
|
const auto instance = _instance;
|
|
|
|
InvokeQueued(instance, [=] {
|
2019-11-19 10:10:51 +00:00
|
|
|
instance->dcTemporaryKeyChanged(dcId);
|
2019-11-15 13:04:32 +00:00
|
|
|
});
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
int32 Session::getDcWithShift() const {
|
2019-11-14 07:13:17 +00:00
|
|
|
return _shiftedDcId;
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:10:51 +00:00
|
|
|
AuthKeyPtr Session::getTemporaryKey() const {
|
|
|
|
return _dc->getTemporaryKey();
|
|
|
|
}
|
|
|
|
|
|
|
|
AuthKeyPtr Session::getPersistentKey() const {
|
|
|
|
return _dc->getPersistentKey();
|
2019-11-15 13:04:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Session::connectionInited() const {
|
|
|
|
return _dc->connectionInited();
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
void Session::tryToReceive() {
|
2016-02-29 16:53:26 +00:00
|
|
|
if (_killed) {
|
|
|
|
DEBUG_LOG(("Session Error: can't receive in a killed session"));
|
|
|
|
return;
|
|
|
|
}
|
2016-03-24 08:57:11 +00:00
|
|
|
if (paused()) {
|
2015-10-15 10:18:24 +00:00
|
|
|
_needToReceive = true;
|
|
|
|
return;
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
while (true) {
|
2017-04-30 14:23:57 +00:00
|
|
|
auto requestId = mtpRequestId(0);
|
|
|
|
auto isUpdate = false;
|
|
|
|
auto message = SerializedMessage();
|
2014-05-30 08:53:19 +00:00
|
|
|
{
|
2019-11-18 12:53:37 +00:00
|
|
|
QWriteLocker locker(_data->haveReceivedMutex());
|
|
|
|
auto &responses = _data->haveReceivedResponses();
|
2017-04-30 14:23:57 +00:00
|
|
|
auto response = responses.begin();
|
|
|
|
if (response == responses.cend()) {
|
2019-11-18 12:53:37 +00:00
|
|
|
auto &updates = _data->haveReceivedUpdates();
|
2017-04-30 14:23:57 +00:00
|
|
|
auto update = updates.begin();
|
|
|
|
if (update == updates.cend()) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
message = std::move(*update);
|
|
|
|
isUpdate = true;
|
|
|
|
updates.pop_front();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
requestId = response.key();
|
|
|
|
message = std::move(response.value());
|
|
|
|
responses.erase(response);
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
2017-04-30 14:23:57 +00:00
|
|
|
if (isUpdate) {
|
2019-11-14 07:13:17 +00:00
|
|
|
if (_shiftedDcId == BareDcId(_shiftedDcId)) { // call globalCallback only in main session
|
2017-04-30 14:23:57 +00:00
|
|
|
_instance->globalCallback(message.constData(), message.constData() + message.size());
|
2015-04-23 15:50:11 +00:00
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
} else {
|
2017-04-30 14:23:57 +00:00
|
|
|
_instance->execCallback(requestId, message.constData(), message.constData() + message.size());
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
Session::~Session() {
|
2019-11-18 12:53:37 +00:00
|
|
|
if (_myKeyCreation) {
|
|
|
|
releaseKeyCreationOnFail();
|
|
|
|
}
|
2017-08-17 09:06:26 +00:00
|
|
|
Assert(_connection == nullptr);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 08:57:11 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace MTP
|