connection_resolving.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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/connection_resolving.h"
  8. #include "mtproto/mtp_instance.h"
  9. namespace MTP {
  10. namespace details {
  11. namespace {
  12. constexpr auto kOneConnectionTimeout = 4000;
  13. } // namespace
  14. ResolvingConnection::ResolvingConnection(
  15. not_null<Instance*> instance,
  16. QThread *thread,
  17. const ProxyData &proxy,
  18. ConnectionPointer &&child)
  19. : AbstractConnection(thread, proxy)
  20. , _instance(instance)
  21. , _timeoutTimer([=] { handleError(kErrorCodeOther); }) {
  22. setChild(std::move(child));
  23. if (proxy.resolvedExpireAt < crl::now()) {
  24. const auto host = proxy.host;
  25. connect(
  26. instance,
  27. &Instance::proxyDomainResolved,
  28. this,
  29. &ResolvingConnection::domainResolved,
  30. Qt::QueuedConnection);
  31. InvokeQueued(instance, [=] {
  32. instance->resolveProxyDomain(host);
  33. });
  34. }
  35. if (!proxy.resolvedIPs.empty()) {
  36. refreshChild();
  37. }
  38. }
  39. ConnectionPointer ResolvingConnection::clone(const ProxyData &proxy) {
  40. Unexpected("ResolvingConnection::clone call.");
  41. }
  42. void ResolvingConnection::setChild(ConnectionPointer &&child) {
  43. _child = std::move(child);
  44. connect(
  45. _child,
  46. &AbstractConnection::receivedData,
  47. this,
  48. &ResolvingConnection::handleReceivedData);
  49. connect(
  50. _child,
  51. &AbstractConnection::receivedSome,
  52. this,
  53. &ResolvingConnection::receivedSome);
  54. connect(
  55. _child,
  56. &AbstractConnection::error,
  57. this,
  58. &ResolvingConnection::handleError);
  59. connect(_child,
  60. &AbstractConnection::connected,
  61. this,
  62. &ResolvingConnection::handleConnected);
  63. connect(_child,
  64. &AbstractConnection::disconnected,
  65. this,
  66. &ResolvingConnection::handleDisconnected);
  67. if (_protocolDcId) {
  68. _child->connectToServer(
  69. _address,
  70. _port,
  71. _protocolSecret,
  72. _protocolDcId,
  73. _protocolForFiles);
  74. CONNECTION_LOG_INFO("Resolving connected a new child: "
  75. + _child->debugId());
  76. }
  77. }
  78. void ResolvingConnection::domainResolved(
  79. const QString &host,
  80. const QStringList &ips,
  81. qint64 expireAt) {
  82. if (host != _proxy.host || !_child) {
  83. return;
  84. }
  85. _proxy.resolvedExpireAt = expireAt;
  86. auto index = 0;
  87. for (const auto &ip : ips) {
  88. if (index >= _proxy.resolvedIPs.size()) {
  89. _proxy.resolvedIPs.push_back(ip);
  90. } else if (_proxy.resolvedIPs[index] != ip) {
  91. _proxy.resolvedIPs[index] = ip;
  92. if (_ipIndex >= index) {
  93. _ipIndex = index - 1;
  94. refreshChild();
  95. }
  96. }
  97. ++index;
  98. }
  99. if (index < _proxy.resolvedIPs.size()) {
  100. _proxy.resolvedIPs.resize(index);
  101. if (_ipIndex >= index) {
  102. emitError(kErrorCodeOther);
  103. }
  104. }
  105. if (_ipIndex < 0) {
  106. refreshChild();
  107. }
  108. }
  109. bool ResolvingConnection::refreshChild() {
  110. if (!_child) {
  111. return true;
  112. } else if (++_ipIndex >= _proxy.resolvedIPs.size()) {
  113. return false;
  114. }
  115. setChild(_child->clone(ToDirectIpProxy(_proxy, _ipIndex)));
  116. _timeoutTimer.callOnce(kOneConnectionTimeout);
  117. return true;
  118. }
  119. void ResolvingConnection::emitError(int errorCode) {
  120. _ipIndex = -1;
  121. _child = nullptr;
  122. error(errorCode);
  123. }
  124. void ResolvingConnection::handleError(int errorCode) {
  125. if (_connected) {
  126. emitError(errorCode);
  127. } else if (!_proxy.resolvedIPs.empty()) {
  128. if (!refreshChild()) {
  129. emitError(errorCode);
  130. }
  131. } else {
  132. // Wait for the domain to be resolved.
  133. }
  134. }
  135. void ResolvingConnection::handleDisconnected() {
  136. if (_connected) {
  137. disconnected();
  138. } else {
  139. handleError(kErrorCodeOther);
  140. }
  141. }
  142. void ResolvingConnection::handleReceivedData() {
  143. auto &my = received();
  144. auto &his = _child->received();
  145. for (auto &item : his) {
  146. my.push_back(std::move(item));
  147. }
  148. his.clear();
  149. receivedData();
  150. }
  151. void ResolvingConnection::handleConnected() {
  152. _connected = true;
  153. _timeoutTimer.cancel();
  154. if (_ipIndex >= 0) {
  155. const auto host = _proxy.host;
  156. const auto good = _proxy.resolvedIPs[_ipIndex];
  157. const auto instance = _instance;
  158. InvokeQueued(_instance, [=] {
  159. instance->setGoodProxyDomain(host, good);
  160. });
  161. }
  162. connected();
  163. }
  164. crl::time ResolvingConnection::pingTime() const {
  165. Expects(_child != nullptr);
  166. return _child->pingTime();
  167. }
  168. crl::time ResolvingConnection::fullConnectTimeout() const {
  169. return kOneConnectionTimeout * qMax(int(_proxy.resolvedIPs.size()), 1);
  170. }
  171. void ResolvingConnection::sendData(mtpBuffer &&buffer) {
  172. Expects(_child != nullptr);
  173. _child->sendData(std::move(buffer));
  174. }
  175. void ResolvingConnection::disconnectFromServer() {
  176. _address = QString();
  177. _port = 0;
  178. _protocolSecret = bytes::vector();
  179. _protocolDcId = 0;
  180. if (!_child) {
  181. return;
  182. }
  183. _child->disconnectFromServer();
  184. }
  185. void ResolvingConnection::connectToServer(
  186. const QString &address,
  187. int port,
  188. const bytes::vector &protocolSecret,
  189. int16 protocolDcId,
  190. bool protocolForFiles) {
  191. if (!_child) {
  192. InvokeQueued(this, [=] { emitError(kErrorCodeOther); });
  193. return;
  194. }
  195. _address = address;
  196. _port = port;
  197. _protocolSecret = protocolSecret;
  198. _protocolDcId = protocolDcId;
  199. _protocolForFiles = protocolForFiles;
  200. _child->connectToServer(
  201. address,
  202. port,
  203. protocolSecret,
  204. protocolDcId,
  205. protocolForFiles);
  206. CONNECTION_LOG_INFO("Resolving connected a child: " + _child->debugId());
  207. }
  208. bool ResolvingConnection::isConnected() const {
  209. return _child ? _child->isConnected() : false;
  210. }
  211. int32 ResolvingConnection::debugState() const {
  212. return _child ? _child->debugState() : -1;
  213. }
  214. QString ResolvingConnection::transport() const {
  215. return _child ? _child->transport() : QString();
  216. }
  217. QString ResolvingConnection::tag() const {
  218. return _child ? _child->tag() : QString();
  219. }
  220. } // namespace details
  221. } // namespace MTP