| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /*
- 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/config_loader.h"
- #include "base/random.h"
- #include "mtproto/special_config_request.h"
- #include "mtproto/facade.h"
- #include "mtproto/mtproto_dc_options.h"
- #include "mtproto/mtproto_config.h"
- #include "mtproto/mtp_instance.h"
- namespace MTP {
- namespace details {
- namespace {
- constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
- constexpr auto kSpecialRequestTimeoutMs = 6000; // 4 seconds timeout for it to work in a specially requested dc.
- } // namespace
- ConfigLoader::ConfigLoader(
- not_null<Instance*> instance,
- const QString &phone,
- Fn<void(const MTPConfig &result)> onDone,
- FailHandler onFail,
- bool proxyEnabled)
- : _instance(instance)
- , _phone(phone)
- , _proxyEnabled(proxyEnabled)
- , _doneHandler(onDone)
- , _failHandler(onFail) {
- _enumDCTimer.setCallback([this] { enumerate(); });
- _specialEnumTimer.setCallback([this] { sendSpecialRequest(); });
- }
- void ConfigLoader::load() {
- if (!_instance->isKeysDestroyer()) {
- sendRequest(_instance->mainDcId());
- _enumDCTimer.callOnce(kEnumerateDcTimeout);
- } else {
- auto ids = _instance->dcOptions().configEnumDcIds();
- Assert(!ids.empty());
- _enumCurrent = ids.front();
- enumerate();
- }
- }
- mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
- auto done = [done = _doneHandler](const Response &response) {
- auto from = response.reply.constData();
- auto result = MTPConfig();
- if (!result.read(from, from + response.reply.size())) {
- return false;
- }
- done(result);
- return true;
- };
- return _instance->send(
- MTPhelp_GetConfig(),
- std::move(done),
- base::duplicate(_failHandler),
- shiftedDcId);
- }
- DcId ConfigLoader::specialToRealDcId(DcId specialDcId) {
- return getTemporaryIdFromRealDcId(specialDcId);
- }
- void ConfigLoader::terminateRequest() {
- if (_enumRequest) {
- _instance->cancel(base::take(_enumRequest));
- }
- if (_enumCurrent) {
- _instance->killSession(MTP::configDcId(_enumCurrent));
- }
- }
- void ConfigLoader::terminateSpecialRequest() {
- if (_specialEnumRequest) {
- _instance->cancel(base::take(_specialEnumRequest));
- }
- if (_specialEnumCurrent) {
- _instance->killSession(_specialEnumCurrent);
- }
- }
- ConfigLoader::~ConfigLoader() {
- terminateRequest();
- terminateSpecialRequest();
- }
- void ConfigLoader::enumerate() {
- terminateRequest();
- if (!_enumCurrent) {
- _enumCurrent = _instance->mainDcId();
- }
- auto ids = _instance->dcOptions().configEnumDcIds();
- Assert(!ids.empty());
- auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
- if (i == ids.cend() || (++i) == ids.cend()) {
- _enumCurrent = ids.front();
- } else {
- _enumCurrent = *i;
- }
- _enumRequest = sendRequest(MTP::configDcId(_enumCurrent));
- _enumDCTimer.callOnce(kEnumerateDcTimeout);
- refreshSpecialLoader();
- }
- void ConfigLoader::refreshSpecialLoader() {
- if (_proxyEnabled || _instance->isKeysDestroyer()) {
- _specialLoader.reset();
- return;
- }
- if (!_specialLoader
- || (!_specialEnumRequest && _specialEndpoints.empty())) {
- createSpecialLoader();
- }
- }
- void ConfigLoader::setPhone(const QString &phone) {
- if (_phone != phone) {
- _phone = phone;
- if (_specialLoader) {
- createSpecialLoader();
- }
- }
- }
- void ConfigLoader::createSpecialLoader() {
- const auto testMode = _instance->isTestMode();
- _triedSpecialEndpoints.clear();
- _specialLoader = std::make_unique<SpecialConfigRequest>([=](
- DcId dcId,
- const std::string &ip,
- int port,
- bytes::const_span secret) {
- if (ip.empty()) {
- _specialLoader = nullptr;
- } else {
- addSpecialEndpoint(dcId, ip, port, secret);
- }
- }, testMode, _instance->configValues().txtDomainString, _phone);
- }
- void ConfigLoader::addSpecialEndpoint(
- DcId dcId,
- const std::string &ip,
- int port,
- bytes::const_span secret) {
- const auto endpoint = SpecialEndpoint {
- dcId,
- ip,
- port,
- bytes::make_vector(secret)
- };
- if (base::contains(_specialEndpoints, endpoint)
- || base::contains(_triedSpecialEndpoints, endpoint)) {
- return;
- }
- DEBUG_LOG(("MTP Info: Special endpoint received, '%1:%2'").arg(ip.c_str()).arg(port));
- _specialEndpoints.push_back(endpoint);
- if (!_specialEnumTimer.isActive()) {
- _specialEnumTimer.callOnce(1);
- }
- }
- void ConfigLoader::sendSpecialRequest() {
- terminateSpecialRequest();
- if (_proxyEnabled) {
- _specialLoader.reset();
- return;
- }
- if (_specialEndpoints.empty()) {
- refreshSpecialLoader();
- return;
- }
- const auto weak = base::make_weak(this);
- const auto index = base::RandomValue<uint32>() % _specialEndpoints.size();
- const auto endpoint = _specialEndpoints.begin() + index;
- _specialEnumCurrent = specialToRealDcId(endpoint->dcId);
- using Flag = MTPDdcOption::Flag;
- const auto flags = Flag::f_tcpo_only
- | (endpoint->secret.empty() ? Flag(0) : Flag::f_secret);
- _instance->dcOptions().constructAddOne(
- _specialEnumCurrent,
- flags,
- endpoint->ip,
- endpoint->port,
- endpoint->secret);
- _specialEnumRequest = _instance->send(
- MTPhelp_GetConfig(),
- [weak](const Response &response) {
- auto result = MTPConfig();
- auto from = response.reply.constData();
- if (!result.read(from, from + response.reply.size())) {
- return false;
- }
- if (const auto strong = weak.get()) {
- strong->specialConfigLoaded(result);
- }
- return true;
- },
- base::duplicate(_failHandler),
- _specialEnumCurrent);
- _triedSpecialEndpoints.push_back(*endpoint);
- _specialEndpoints.erase(endpoint);
- _specialEnumTimer.callOnce(kSpecialRequestTimeoutMs);
- }
- void ConfigLoader::specialConfigLoaded(const MTPConfig &result) {
- Expects(result.type() == mtpc_config);
- const auto &data = result.c_config();
- if (data.vdc_options().v.empty()) {
- LOG(("MTP Error: config with empty dc_options received!"));
- return;
- }
- // We use special config only for dc options.
- // For everything else we wait for normal config from main dc.
- _instance->dcOptions().setFromList(data.vdc_options());
- }
- void ConfigLoader::setProxyEnabled(bool value) {
- _proxyEnabled = value;
- }
- } // namespace details
- } // namespace MTP
|