| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "mtproto/session.h"
- #include "mtproto/details/mtproto_dcenter.h"
- #include "mtproto/session_private.h"
- #include "mtproto/mtproto_auth_key.h"
- #include "core/application.h"
- #include "core/core_settings.h"
- #include "base/unixtime.h"
- namespace MTP {
- namespace details {
- SessionOptions::SessionOptions(
- const QString &systemLangCode,
- const QString &cloudLangCode,
- const QString &langPackName,
- const ProxyData &proxy,
- bool useIPv4,
- bool useIPv6,
- bool useHttp,
- bool useTcp)
- : systemLangCode(systemLangCode)
- , cloudLangCode(cloudLangCode)
- , langPackName(langPackName)
- , proxy(proxy)
- , useIPv4(useIPv4)
- , useIPv6(useIPv6)
- , useHttp(useHttp)
- , useTcp(useTcp) {
- }
- 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);
- });
- }
- }
- void SessionData::notifyConnectionInited(const SessionOptions &options) {
- // #TODO race
- const auto current = this->options();
- if (current.cloudLangCode == _options.cloudLangCode
- && current.systemLangCode == _options.systemLangCode
- && current.langPackName == _options.langPackName
- && current.proxy == _options.proxy) {
- QMutexLocker lock(&_ownerMutex);
- if (_owner) {
- _owner->notifyDcConnectionInited();
- }
- }
- }
- 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);
- });
- }
- bool SessionData::connectionInited() const {
- QMutexLocker lock(&_ownerMutex);
- return _owner ? _owner->connectionInited() : false;
- }
- AuthKeyPtr SessionData::getTemporaryKey(TemporaryKeyType type) const {
- QMutexLocker lock(&_ownerMutex);
- return _owner ? _owner->getTemporaryKey(type) : nullptr;
- }
- AuthKeyPtr SessionData::getPersistentKey() const {
- QMutexLocker lock(&_ownerMutex);
- return _owner ? _owner->getPersistentKey() : nullptr;
- }
- CreatingKeyType SessionData::acquireKeyCreation(DcType type) {
- QMutexLocker lock(&_ownerMutex);
- return _owner ? _owner->acquireKeyCreation(type) : CreatingKeyType::None;
- }
- bool SessionData::releaseKeyCreationOnDone(
- const AuthKeyPtr &temporaryKey,
- const AuthKeyPtr &persistentKeyUsedForBind) {
- QMutexLocker lock(&_ownerMutex);
- return _owner
- ? _owner->releaseKeyCreationOnDone(
- temporaryKey,
- persistentKeyUsedForBind)
- : false;
- }
- bool SessionData::releaseCdnKeyCreationOnDone(
- const AuthKeyPtr &temporaryKey) {
- QMutexLocker lock(&_ownerMutex);
- return _owner
- ? _owner->releaseCdnKeyCreationOnDone(temporaryKey)
- : false;
- }
- void SessionData::releaseKeyCreationOnFail() {
- QMutexLocker lock(&_ownerMutex);
- if (_owner) {
- _owner->releaseKeyCreationOnFail();
- }
- }
- void SessionData::destroyTemporaryKey(uint64 keyId) {
- QMutexLocker lock(&_ownerMutex);
- if (_owner) {
- _owner->destroyTemporaryKey(keyId);
- }
- }
- void SessionData::detach() {
- QMutexLocker lock(&_ownerMutex);
- _owner = nullptr;
- }
- Session::Session(
- not_null<Instance*> instance,
- not_null<QThread*> thread,
- ShiftedDcId shiftedDcId,
- not_null<Dcenter*> dc)
- : _instance(instance)
- , _shiftedDcId(shiftedDcId)
- , _dc(dc)
- , _data(std::make_shared<SessionData>(this))
- , _thread(thread)
- , _sender([=] { needToResumeAndSend(); }) {
- refreshOptions();
- watchDcKeyChanges();
- watchDcOptionsChanges();
- start();
- }
- Session::~Session() {
- Expects(!_private);
- if (_myKeyCreation != CreatingKeyType::None) {
- releaseKeyCreationOnFail();
- }
- }
- void Session::watchDcKeyChanges() {
- _instance->dcTemporaryKeyChanged(
- ) | rpl::filter([=](DcId dcId) {
- return (dcId == _shiftedDcId) || (dcId == BareDcId(_shiftedDcId));
- }) | rpl::start_with_next([=] {
- DEBUG_LOG(("AuthKey Info: dcTemporaryKeyChanged in Session %1"
- ).arg(_shiftedDcId));
- if (const auto captured = _private) {
- InvokeQueued(captured, [=] {
- DEBUG_LOG(("AuthKey Info: calling Connection::updateAuthKey in Session %1"
- ).arg(_shiftedDcId));
- captured->updateAuthKey();
- });
- }
- }, _lifetime);
- }
- void Session::watchDcOptionsChanges() {
- _instance->dcOptions().changed(
- ) | rpl::filter([=](DcId dcId) {
- return (BareDcId(_shiftedDcId) == dcId) && (_private != nullptr);
- }) | rpl::start_with_next([=] {
- InvokeQueued(_private, [captured = _private] {
- captured->dcOptionsChanged();
- });
- }, _lifetime);
- _instance->dcOptions().cdnConfigChanged(
- ) | rpl::filter([=] {
- return (_private != nullptr)
- && (_instance->dcOptions().dcType(_shiftedDcId) == DcType::Cdn);
- }) | rpl::start_with_next([=] {
- InvokeQueued(_private, [captured = _private] {
- captured->cdnConfigChanged();
- });
- }, _lifetime);
- }
- void Session::start() {
- killConnection();
- _private = new SessionPrivate(
- _instance,
- _thread.get(),
- _data,
- _shiftedDcId);
- }
- void Session::restart() {
- if (_killed) {
- DEBUG_LOG(("Session Error: can't restart a killed session"));
- return;
- }
- refreshOptions();
- if (const auto captured = _private) {
- InvokeQueued(captured, [=] {
- captured->restartNow();
- });
- }
- }
- void Session::refreshOptions() {
- auto &settings = Core::App().settings().proxy();
- const auto &proxy = settings.selected();
- const auto isEnabled = settings.isEnabled();
- const auto proxyType = (isEnabled ? proxy.type : ProxyData::Type::None);
- const auto useTcp = (proxyType != ProxyData::Type::Http);
- const auto useHttp = (proxyType != ProxyData::Type::Mtproto);
- const auto useIPv4 = true;
- const auto useIPv6 = settings.tryIPv6();
- _data->setOptions(SessionOptions(
- _instance->systemLangCode(),
- _instance->cloudLangCode(),
- _instance->langPackName(),
- (isEnabled ? proxy : ProxyData()),
- useIPv4,
- useIPv6,
- useHttp,
- useTcp));
- }
- void Session::reInitConnection() {
- setConnectionNotInited();
- restart();
- }
- void Session::setConnectionNotInited() {
- _dc->setConnectionInited(false);
- }
- void Session::stop() {
- if (_killed) {
- DEBUG_LOG(("Session Error: can't stop a killed session"));
- return;
- }
- DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(_shiftedDcId));
- killConnection();
- }
- void Session::kill() {
- stop();
- _killed = true;
- _data->detach();
- DEBUG_LOG(("Session Info: marked session dcWithShift %1 as killed").arg(_shiftedDcId));
- }
- void Session::unpaused() {
- if (_needToReceive) {
- _needToReceive = false;
- InvokeQueued(this, [=] {
- tryToReceive();
- });
- }
- }
- void Session::sendAnything(crl::time msCanWait) {
- if (_killed) {
- DEBUG_LOG(("Session Error: can't send anything in a killed session"));
- return;
- }
- const auto ms = crl::now();
- if (_msSendCall) {
- if (ms > _msSendCall + _msWait) {
- _msWait = 0;
- } else {
- _msWait = (_msSendCall + _msWait) - ms;
- if (_msWait > msCanWait) {
- _msWait = msCanWait;
- }
- }
- } else {
- _msWait = msCanWait;
- }
- 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);
- } else {
- 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;
- needToResumeAndSend();
- }
- }
- void Session::needToResumeAndSend() {
- if (_killed) {
- DEBUG_LOG(("Session Info: can't resume a killed session"));
- return;
- }
- if (!_private) {
- DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(_shiftedDcId));
- start();
- }
- const auto captured = _private;
- const auto ping = base::take(_ping);
- InvokeQueued(captured, [=] {
- if (ping) {
- captured->sendPingForce();
- } else {
- captured->tryToSend();
- }
- });
- }
- void Session::connectionStateChange(int newState) {
- _instance->onStateChange(_shiftedDcId, newState);
- }
- void Session::resetDone() {
- _instance->onSessionReset(_shiftedDcId);
- }
- void Session::cancel(mtpRequestId requestId, mtpMsgId msgId) {
- if (requestId) {
- QWriteLocker locker(_data->toSendMutex());
- _data->toSendMap().remove(requestId);
- }
- if (msgId) {
- QWriteLocker locker(_data->haveSentMutex());
- _data->haveSentMap().remove(msgId);
- }
- }
- void Session::ping() {
- _ping = true;
- sendAnything();
- }
- int32 Session::requestState(mtpRequestId requestId) const {
- int32 result = MTP::RequestSent;
- bool connected = false;
- if (_private) {
- const auto s = _private->getState();
- if (s == ConnectedState) {
- connected = true;
- } else if (s == ConnectingState || s == DisconnectedState) {
- if (result < 0 || result == MTP::RequestSent) {
- result = MTP::RequestConnecting;
- }
- } else if (s < 0) {
- if ((result < 0 && s > result) || result == MTP::RequestSent) {
- result = s;
- }
- }
- }
- if (!connected) {
- return result;
- } else if (!requestId) {
- return MTP::RequestSent;
- }
- QWriteLocker locker(_data->toSendMutex());
- return _data->toSendMap().contains(requestId)
- ? MTP::RequestSending
- : MTP::RequestSent;
- }
- int32 Session::getState() const {
- int32 result = -86400000;
- if (_private) {
- const auto s = _private->getState();
- if (s == ConnectedState
- || s == ConnectingState
- || s == DisconnectedState) {
- return s;
- } else if (s < 0) {
- if (result < 0 && s > result) {
- result = s;
- }
- }
- }
- if (result == -86400000) {
- result = DisconnectedState;
- }
- return result;
- }
- QString Session::transport() const {
- return _private ? _private->transport() : QString();
- }
- void Session::sendPrepared(
- const SerializedRequest &request,
- crl::time msCanWait) {
- DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1"
- ).arg(msCanWait));
- {
- QWriteLocker locker(_data->toSendMutex());
- _data->toSendMap().emplace(request->requestId, request);
- *(mtpMsgId*)(request->data() + 4) = 0;
- *(request->data() + 6) = 0;
- }
- DEBUG_LOG(("MTP Info: added, requestId %1").arg(request->requestId));
- if (msCanWait >= 0) {
- InvokeQueued(this, [=] {
- sendAnything(msCanWait);
- });
- }
- }
- CreatingKeyType Session::acquireKeyCreation(DcType type) {
- Expects(_myKeyCreation == CreatingKeyType::None);
- _myKeyCreation = _dc->acquireKeyCreation(type);
- return _myKeyCreation;
- }
- bool Session::releaseKeyCreationOnDone(
- const AuthKeyPtr &temporaryKey,
- const AuthKeyPtr &persistentKeyUsedForBind) {
- Expects(_myKeyCreation != CreatingKeyType::None);
- Expects(persistentKeyUsedForBind != nullptr);
- return releaseGenericKeyCreationOnDone(
- temporaryKey,
- persistentKeyUsedForBind);
- }
- bool Session::releaseCdnKeyCreationOnDone(
- const AuthKeyPtr &temporaryKey) {
- Expects(_myKeyCreation == CreatingKeyType::TemporaryRegular);
- return releaseGenericKeyCreationOnDone(temporaryKey, nullptr);
- }
- bool Session::releaseGenericKeyCreationOnDone(
- const AuthKeyPtr &temporaryKey,
- const AuthKeyPtr &persistentKeyUsedForBind) {
- const auto wasKeyCreation = std::exchange(
- _myKeyCreation,
- CreatingKeyType::None);
- const auto result = _dc->releaseKeyCreationOnDone(
- wasKeyCreation,
- temporaryKey,
- persistentKeyUsedForBind);
- if (!result) {
- DEBUG_LOG(("AuthKey Info: Persistent key changed "
- "while binding temporary, dcWithShift %1"
- ).arg(_shiftedDcId));
- return false;
- }
- DEBUG_LOG(("AuthKey Info: Session key bound, setting, dcWithShift %1"
- ).arg(_shiftedDcId));
- const auto dcId = _dc->id();
- const auto instance = _instance;
- InvokeQueued(instance, [=] {
- if (wasKeyCreation == CreatingKeyType::Persistent) {
- instance->dcPersistentKeyChanged(dcId, persistentKeyUsedForBind);
- } else {
- instance->dcTemporaryKeyChanged(dcId);
- }
- });
- return true;
- }
- void Session::releaseKeyCreationOnFail() {
- Expects(_myKeyCreation != CreatingKeyType::None);
- const auto wasKeyCreation = std::exchange(
- _myKeyCreation,
- CreatingKeyType::None);
- _dc->releaseKeyCreationOnFail(wasKeyCreation);
- }
- void Session::notifyDcConnectionInited() {
- DEBUG_LOG(("MTP Info: MTProtoDC::connectionWasInited(), dcWithShift %1"
- ).arg(_shiftedDcId));
- _dc->setConnectionInited();
- }
- void Session::destroyTemporaryKey(uint64 keyId) {
- if (!_dc->destroyTemporaryKey(keyId)) {
- return;
- }
- const auto dcId = _dc->id();
- const auto instance = _instance;
- InvokeQueued(instance, [=] {
- instance->dcTemporaryKeyChanged(dcId);
- });
- }
- int32 Session::getDcWithShift() const {
- return _shiftedDcId;
- }
- AuthKeyPtr Session::getTemporaryKey(TemporaryKeyType type) const {
- return _dc->getTemporaryKey(type);
- }
- AuthKeyPtr Session::getPersistentKey() const {
- return _dc->getPersistentKey();
- }
- bool Session::connectionInited() const {
- return _dc->connectionInited();
- }
- void Session::tryToReceive() {
- if (_killed) {
- DEBUG_LOG(("Session Error: can't receive in a killed session"));
- return;
- }
- if (paused()) {
- _needToReceive = true;
- return;
- }
- while (true) {
- auto lock = QWriteLocker(_data->haveReceivedMutex());
- const auto messages = base::take(_data->haveReceivedMessages());
- lock.unlock();
- if (messages.empty()) {
- break;
- }
- const auto guard = QPointer<Session>(this);
- const auto instance = QPointer<Instance>(_instance);
- const auto main = (_shiftedDcId == BareDcId(_shiftedDcId));
- for (const auto &message : messages) {
- if (message.requestId) {
- instance->processCallback(message);
- } else if (main) {
- // Process updates only in main session.
- instance->processUpdate(message);
- }
- if (!instance) {
- return;
- }
- }
- if (!guard) {
- break;
- }
- }
- }
- void Session::killConnection() {
- if (!_private) {
- return;
- }
- base::take(_private)->deleteLater();
- Ensures(_private == nullptr);
- }
- } // namespace details
- } // namespace MTP
|