session.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "mtproto/session.h"
  8. #include "mtproto/details/mtproto_dcenter.h"
  9. #include "mtproto/session_private.h"
  10. #include "mtproto/mtproto_auth_key.h"
  11. #include "core/application.h"
  12. #include "core/core_settings.h"
  13. #include "base/unixtime.h"
  14. namespace MTP {
  15. namespace details {
  16. SessionOptions::SessionOptions(
  17. const QString &systemLangCode,
  18. const QString &cloudLangCode,
  19. const QString &langPackName,
  20. const ProxyData &proxy,
  21. bool useIPv4,
  22. bool useIPv6,
  23. bool useHttp,
  24. bool useTcp)
  25. : systemLangCode(systemLangCode)
  26. , cloudLangCode(cloudLangCode)
  27. , langPackName(langPackName)
  28. , proxy(proxy)
  29. , useIPv4(useIPv4)
  30. , useIPv6(useIPv6)
  31. , useHttp(useHttp)
  32. , useTcp(useTcp) {
  33. }
  34. template <typename Callback>
  35. void SessionData::withSession(Callback &&callback) {
  36. QMutexLocker lock(&_ownerMutex);
  37. if (const auto session = _owner) {
  38. InvokeQueued(session, [
  39. session,
  40. callback = std::forward<Callback>(callback)
  41. ] {
  42. callback(session);
  43. });
  44. }
  45. }
  46. void SessionData::notifyConnectionInited(const SessionOptions &options) {
  47. // #TODO race
  48. const auto current = this->options();
  49. if (current.cloudLangCode == _options.cloudLangCode
  50. && current.systemLangCode == _options.systemLangCode
  51. && current.langPackName == _options.langPackName
  52. && current.proxy == _options.proxy) {
  53. QMutexLocker lock(&_ownerMutex);
  54. if (_owner) {
  55. _owner->notifyDcConnectionInited();
  56. }
  57. }
  58. }
  59. void SessionData::queueTryToReceive() {
  60. withSession([](not_null<Session*> session) {
  61. session->tryToReceive();
  62. });
  63. }
  64. void SessionData::queueNeedToResumeAndSend() {
  65. withSession([](not_null<Session*> session) {
  66. session->needToResumeAndSend();
  67. });
  68. }
  69. void SessionData::queueConnectionStateChange(int newState) {
  70. withSession([=](not_null<Session*> session) {
  71. session->connectionStateChange(newState);
  72. });
  73. }
  74. void SessionData::queueResetDone() {
  75. withSession([](not_null<Session*> session) {
  76. session->resetDone();
  77. });
  78. }
  79. void SessionData::queueSendAnything(crl::time msCanWait) {
  80. withSession([=](not_null<Session*> session) {
  81. session->sendAnything(msCanWait);
  82. });
  83. }
  84. bool SessionData::connectionInited() const {
  85. QMutexLocker lock(&_ownerMutex);
  86. return _owner ? _owner->connectionInited() : false;
  87. }
  88. AuthKeyPtr SessionData::getTemporaryKey(TemporaryKeyType type) const {
  89. QMutexLocker lock(&_ownerMutex);
  90. return _owner ? _owner->getTemporaryKey(type) : nullptr;
  91. }
  92. AuthKeyPtr SessionData::getPersistentKey() const {
  93. QMutexLocker lock(&_ownerMutex);
  94. return _owner ? _owner->getPersistentKey() : nullptr;
  95. }
  96. CreatingKeyType SessionData::acquireKeyCreation(DcType type) {
  97. QMutexLocker lock(&_ownerMutex);
  98. return _owner ? _owner->acquireKeyCreation(type) : CreatingKeyType::None;
  99. }
  100. bool SessionData::releaseKeyCreationOnDone(
  101. const AuthKeyPtr &temporaryKey,
  102. const AuthKeyPtr &persistentKeyUsedForBind) {
  103. QMutexLocker lock(&_ownerMutex);
  104. return _owner
  105. ? _owner->releaseKeyCreationOnDone(
  106. temporaryKey,
  107. persistentKeyUsedForBind)
  108. : false;
  109. }
  110. bool SessionData::releaseCdnKeyCreationOnDone(
  111. const AuthKeyPtr &temporaryKey) {
  112. QMutexLocker lock(&_ownerMutex);
  113. return _owner
  114. ? _owner->releaseCdnKeyCreationOnDone(temporaryKey)
  115. : false;
  116. }
  117. void SessionData::releaseKeyCreationOnFail() {
  118. QMutexLocker lock(&_ownerMutex);
  119. if (_owner) {
  120. _owner->releaseKeyCreationOnFail();
  121. }
  122. }
  123. void SessionData::destroyTemporaryKey(uint64 keyId) {
  124. QMutexLocker lock(&_ownerMutex);
  125. if (_owner) {
  126. _owner->destroyTemporaryKey(keyId);
  127. }
  128. }
  129. void SessionData::detach() {
  130. QMutexLocker lock(&_ownerMutex);
  131. _owner = nullptr;
  132. }
  133. Session::Session(
  134. not_null<Instance*> instance,
  135. not_null<QThread*> thread,
  136. ShiftedDcId shiftedDcId,
  137. not_null<Dcenter*> dc)
  138. : _instance(instance)
  139. , _shiftedDcId(shiftedDcId)
  140. , _dc(dc)
  141. , _data(std::make_shared<SessionData>(this))
  142. , _thread(thread)
  143. , _sender([=] { needToResumeAndSend(); }) {
  144. refreshOptions();
  145. watchDcKeyChanges();
  146. watchDcOptionsChanges();
  147. start();
  148. }
  149. Session::~Session() {
  150. Expects(!_private);
  151. if (_myKeyCreation != CreatingKeyType::None) {
  152. releaseKeyCreationOnFail();
  153. }
  154. }
  155. void Session::watchDcKeyChanges() {
  156. _instance->dcTemporaryKeyChanged(
  157. ) | rpl::filter([=](DcId dcId) {
  158. return (dcId == _shiftedDcId) || (dcId == BareDcId(_shiftedDcId));
  159. }) | rpl::start_with_next([=] {
  160. DEBUG_LOG(("AuthKey Info: dcTemporaryKeyChanged in Session %1"
  161. ).arg(_shiftedDcId));
  162. if (const auto captured = _private) {
  163. InvokeQueued(captured, [=] {
  164. DEBUG_LOG(("AuthKey Info: calling Connection::updateAuthKey in Session %1"
  165. ).arg(_shiftedDcId));
  166. captured->updateAuthKey();
  167. });
  168. }
  169. }, _lifetime);
  170. }
  171. void Session::watchDcOptionsChanges() {
  172. _instance->dcOptions().changed(
  173. ) | rpl::filter([=](DcId dcId) {
  174. return (BareDcId(_shiftedDcId) == dcId) && (_private != nullptr);
  175. }) | rpl::start_with_next([=] {
  176. InvokeQueued(_private, [captured = _private] {
  177. captured->dcOptionsChanged();
  178. });
  179. }, _lifetime);
  180. _instance->dcOptions().cdnConfigChanged(
  181. ) | rpl::filter([=] {
  182. return (_private != nullptr)
  183. && (_instance->dcOptions().dcType(_shiftedDcId) == DcType::Cdn);
  184. }) | rpl::start_with_next([=] {
  185. InvokeQueued(_private, [captured = _private] {
  186. captured->cdnConfigChanged();
  187. });
  188. }, _lifetime);
  189. }
  190. void Session::start() {
  191. killConnection();
  192. _private = new SessionPrivate(
  193. _instance,
  194. _thread.get(),
  195. _data,
  196. _shiftedDcId);
  197. }
  198. void Session::restart() {
  199. if (_killed) {
  200. DEBUG_LOG(("Session Error: can't restart a killed session"));
  201. return;
  202. }
  203. refreshOptions();
  204. if (const auto captured = _private) {
  205. InvokeQueued(captured, [=] {
  206. captured->restartNow();
  207. });
  208. }
  209. }
  210. void Session::refreshOptions() {
  211. auto &settings = Core::App().settings().proxy();
  212. const auto &proxy = settings.selected();
  213. const auto isEnabled = settings.isEnabled();
  214. const auto proxyType = (isEnabled ? proxy.type : ProxyData::Type::None);
  215. const auto useTcp = (proxyType != ProxyData::Type::Http);
  216. const auto useHttp = (proxyType != ProxyData::Type::Mtproto);
  217. const auto useIPv4 = true;
  218. const auto useIPv6 = settings.tryIPv6();
  219. _data->setOptions(SessionOptions(
  220. _instance->systemLangCode(),
  221. _instance->cloudLangCode(),
  222. _instance->langPackName(),
  223. (isEnabled ? proxy : ProxyData()),
  224. useIPv4,
  225. useIPv6,
  226. useHttp,
  227. useTcp));
  228. }
  229. void Session::reInitConnection() {
  230. setConnectionNotInited();
  231. restart();
  232. }
  233. void Session::setConnectionNotInited() {
  234. _dc->setConnectionInited(false);
  235. }
  236. void Session::stop() {
  237. if (_killed) {
  238. DEBUG_LOG(("Session Error: can't stop a killed session"));
  239. return;
  240. }
  241. DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(_shiftedDcId));
  242. killConnection();
  243. }
  244. void Session::kill() {
  245. stop();
  246. _killed = true;
  247. _data->detach();
  248. DEBUG_LOG(("Session Info: marked session dcWithShift %1 as killed").arg(_shiftedDcId));
  249. }
  250. void Session::unpaused() {
  251. if (_needToReceive) {
  252. _needToReceive = false;
  253. InvokeQueued(this, [=] {
  254. tryToReceive();
  255. });
  256. }
  257. }
  258. void Session::sendAnything(crl::time msCanWait) {
  259. if (_killed) {
  260. DEBUG_LOG(("Session Error: can't send anything in a killed session"));
  261. return;
  262. }
  263. const auto ms = crl::now();
  264. if (_msSendCall) {
  265. if (ms > _msSendCall + _msWait) {
  266. _msWait = 0;
  267. } else {
  268. _msWait = (_msSendCall + _msWait) - ms;
  269. if (_msWait > msCanWait) {
  270. _msWait = msCanWait;
  271. }
  272. }
  273. } else {
  274. _msWait = msCanWait;
  275. }
  276. if (_msWait) {
  277. DEBUG_LOG(("MTP Info: dcWithShift %1 can wait for %2ms from current %3").arg(_shiftedDcId).arg(_msWait).arg(_msSendCall));
  278. _msSendCall = ms;
  279. _sender.callOnce(_msWait);
  280. } else {
  281. DEBUG_LOG(("MTP Info: dcWithShift %1 stopped send timer, can wait for %2ms from current %3").arg(_shiftedDcId).arg(_msWait).arg(_msSendCall));
  282. _sender.cancel();
  283. _msSendCall = 0;
  284. needToResumeAndSend();
  285. }
  286. }
  287. void Session::needToResumeAndSend() {
  288. if (_killed) {
  289. DEBUG_LOG(("Session Info: can't resume a killed session"));
  290. return;
  291. }
  292. if (!_private) {
  293. DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(_shiftedDcId));
  294. start();
  295. }
  296. const auto captured = _private;
  297. const auto ping = base::take(_ping);
  298. InvokeQueued(captured, [=] {
  299. if (ping) {
  300. captured->sendPingForce();
  301. } else {
  302. captured->tryToSend();
  303. }
  304. });
  305. }
  306. void Session::connectionStateChange(int newState) {
  307. _instance->onStateChange(_shiftedDcId, newState);
  308. }
  309. void Session::resetDone() {
  310. _instance->onSessionReset(_shiftedDcId);
  311. }
  312. void Session::cancel(mtpRequestId requestId, mtpMsgId msgId) {
  313. if (requestId) {
  314. QWriteLocker locker(_data->toSendMutex());
  315. _data->toSendMap().remove(requestId);
  316. }
  317. if (msgId) {
  318. QWriteLocker locker(_data->haveSentMutex());
  319. _data->haveSentMap().remove(msgId);
  320. }
  321. }
  322. void Session::ping() {
  323. _ping = true;
  324. sendAnything();
  325. }
  326. int32 Session::requestState(mtpRequestId requestId) const {
  327. int32 result = MTP::RequestSent;
  328. bool connected = false;
  329. if (_private) {
  330. const auto s = _private->getState();
  331. if (s == ConnectedState) {
  332. connected = true;
  333. } else if (s == ConnectingState || s == DisconnectedState) {
  334. if (result < 0 || result == MTP::RequestSent) {
  335. result = MTP::RequestConnecting;
  336. }
  337. } else if (s < 0) {
  338. if ((result < 0 && s > result) || result == MTP::RequestSent) {
  339. result = s;
  340. }
  341. }
  342. }
  343. if (!connected) {
  344. return result;
  345. } else if (!requestId) {
  346. return MTP::RequestSent;
  347. }
  348. QWriteLocker locker(_data->toSendMutex());
  349. return _data->toSendMap().contains(requestId)
  350. ? MTP::RequestSending
  351. : MTP::RequestSent;
  352. }
  353. int32 Session::getState() const {
  354. int32 result = -86400000;
  355. if (_private) {
  356. const auto s = _private->getState();
  357. if (s == ConnectedState
  358. || s == ConnectingState
  359. || s == DisconnectedState) {
  360. return s;
  361. } else if (s < 0) {
  362. if (result < 0 && s > result) {
  363. result = s;
  364. }
  365. }
  366. }
  367. if (result == -86400000) {
  368. result = DisconnectedState;
  369. }
  370. return result;
  371. }
  372. QString Session::transport() const {
  373. return _private ? _private->transport() : QString();
  374. }
  375. void Session::sendPrepared(
  376. const SerializedRequest &request,
  377. crl::time msCanWait) {
  378. DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1"
  379. ).arg(msCanWait));
  380. {
  381. QWriteLocker locker(_data->toSendMutex());
  382. _data->toSendMap().emplace(request->requestId, request);
  383. *(mtpMsgId*)(request->data() + 4) = 0;
  384. *(request->data() + 6) = 0;
  385. }
  386. DEBUG_LOG(("MTP Info: added, requestId %1").arg(request->requestId));
  387. if (msCanWait >= 0) {
  388. InvokeQueued(this, [=] {
  389. sendAnything(msCanWait);
  390. });
  391. }
  392. }
  393. CreatingKeyType Session::acquireKeyCreation(DcType type) {
  394. Expects(_myKeyCreation == CreatingKeyType::None);
  395. _myKeyCreation = _dc->acquireKeyCreation(type);
  396. return _myKeyCreation;
  397. }
  398. bool Session::releaseKeyCreationOnDone(
  399. const AuthKeyPtr &temporaryKey,
  400. const AuthKeyPtr &persistentKeyUsedForBind) {
  401. Expects(_myKeyCreation != CreatingKeyType::None);
  402. Expects(persistentKeyUsedForBind != nullptr);
  403. return releaseGenericKeyCreationOnDone(
  404. temporaryKey,
  405. persistentKeyUsedForBind);
  406. }
  407. bool Session::releaseCdnKeyCreationOnDone(
  408. const AuthKeyPtr &temporaryKey) {
  409. Expects(_myKeyCreation == CreatingKeyType::TemporaryRegular);
  410. return releaseGenericKeyCreationOnDone(temporaryKey, nullptr);
  411. }
  412. bool Session::releaseGenericKeyCreationOnDone(
  413. const AuthKeyPtr &temporaryKey,
  414. const AuthKeyPtr &persistentKeyUsedForBind) {
  415. const auto wasKeyCreation = std::exchange(
  416. _myKeyCreation,
  417. CreatingKeyType::None);
  418. const auto result = _dc->releaseKeyCreationOnDone(
  419. wasKeyCreation,
  420. temporaryKey,
  421. persistentKeyUsedForBind);
  422. if (!result) {
  423. DEBUG_LOG(("AuthKey Info: Persistent key changed "
  424. "while binding temporary, dcWithShift %1"
  425. ).arg(_shiftedDcId));
  426. return false;
  427. }
  428. DEBUG_LOG(("AuthKey Info: Session key bound, setting, dcWithShift %1"
  429. ).arg(_shiftedDcId));
  430. const auto dcId = _dc->id();
  431. const auto instance = _instance;
  432. InvokeQueued(instance, [=] {
  433. if (wasKeyCreation == CreatingKeyType::Persistent) {
  434. instance->dcPersistentKeyChanged(dcId, persistentKeyUsedForBind);
  435. } else {
  436. instance->dcTemporaryKeyChanged(dcId);
  437. }
  438. });
  439. return true;
  440. }
  441. void Session::releaseKeyCreationOnFail() {
  442. Expects(_myKeyCreation != CreatingKeyType::None);
  443. const auto wasKeyCreation = std::exchange(
  444. _myKeyCreation,
  445. CreatingKeyType::None);
  446. _dc->releaseKeyCreationOnFail(wasKeyCreation);
  447. }
  448. void Session::notifyDcConnectionInited() {
  449. DEBUG_LOG(("MTP Info: MTProtoDC::connectionWasInited(), dcWithShift %1"
  450. ).arg(_shiftedDcId));
  451. _dc->setConnectionInited();
  452. }
  453. void Session::destroyTemporaryKey(uint64 keyId) {
  454. if (!_dc->destroyTemporaryKey(keyId)) {
  455. return;
  456. }
  457. const auto dcId = _dc->id();
  458. const auto instance = _instance;
  459. InvokeQueued(instance, [=] {
  460. instance->dcTemporaryKeyChanged(dcId);
  461. });
  462. }
  463. int32 Session::getDcWithShift() const {
  464. return _shiftedDcId;
  465. }
  466. AuthKeyPtr Session::getTemporaryKey(TemporaryKeyType type) const {
  467. return _dc->getTemporaryKey(type);
  468. }
  469. AuthKeyPtr Session::getPersistentKey() const {
  470. return _dc->getPersistentKey();
  471. }
  472. bool Session::connectionInited() const {
  473. return _dc->connectionInited();
  474. }
  475. void Session::tryToReceive() {
  476. if (_killed) {
  477. DEBUG_LOG(("Session Error: can't receive in a killed session"));
  478. return;
  479. }
  480. if (paused()) {
  481. _needToReceive = true;
  482. return;
  483. }
  484. while (true) {
  485. auto lock = QWriteLocker(_data->haveReceivedMutex());
  486. const auto messages = base::take(_data->haveReceivedMessages());
  487. lock.unlock();
  488. if (messages.empty()) {
  489. break;
  490. }
  491. const auto guard = QPointer<Session>(this);
  492. const auto instance = QPointer<Instance>(_instance);
  493. const auto main = (_shiftedDcId == BareDcId(_shiftedDcId));
  494. for (const auto &message : messages) {
  495. if (message.requestId) {
  496. instance->processCallback(message);
  497. } else if (main) {
  498. // Process updates only in main session.
  499. instance->processUpdate(message);
  500. }
  501. if (!instance) {
  502. return;
  503. }
  504. }
  505. if (!guard) {
  506. break;
  507. }
  508. }
  509. }
  510. void Session::killConnection() {
  511. if (!_private) {
  512. return;
  513. }
  514. base::take(_private)->deleteLater();
  515. Ensures(_private == nullptr);
  516. }
  517. } // namespace details
  518. } // namespace MTP