Try all available endpoints from config.

This commit is contained in:
John Preston 2018-05-02 22:07:34 +03:00
parent df4daca15b
commit 95fee543ec
7 changed files with 255 additions and 318 deletions

View File

@ -1108,7 +1108,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
checker->connectToServer( checker->connectToServer(
QString::fromStdString(endpoints.front().ip), QString::fromStdString(endpoints.front().ip),
endpoints.front().port, endpoints.front().port,
endpoints.front().protocolSecret, endpoints.front().secret,
dcId); dcId);
} }
}; };

View File

@ -52,7 +52,7 @@ mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
} }
DcId ConfigLoader::specialToRealDcId(DcId specialDcId) { DcId ConfigLoader::specialToRealDcId(DcId specialDcId) {
return Instance::Config::kTemporaryMainDc + specialDcId; return getTemporaryIdFromRealDcId(specialDcId);
} }
void ConfigLoader::terminateRequest() { void ConfigLoader::terminateRequest() {
@ -139,15 +139,18 @@ void ConfigLoader::sendSpecialRequest() {
const auto weak = base::make_weak(this); const auto weak = base::make_weak(this);
const auto index = rand_value<uint32>() % _specialEndpoints.size(); const auto index = rand_value<uint32>() % _specialEndpoints.size();
const auto secret = bytes::vector();
const auto endpoint = _specialEndpoints.begin() + index; const auto endpoint = _specialEndpoints.begin() + index;
_specialEnumCurrent = specialToRealDcId(endpoint->dcId); _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( _instance->dcOptions()->constructAddOne(
_specialEnumCurrent, _specialEnumCurrent,
MTPDdcOption::Flag::f_tcpo_only, flags,
endpoint->ip, endpoint->ip,
endpoint->port, endpoint->port,
secret); endpoint->secret);
_specialEnumRequest = _instance->send( _specialEnumRequest = _instance->send(
MTPhelp_GetConfig(), MTPhelp_GetConfig(),
rpcDone([weak](const MTPConfig &result) { rpcDone([weak](const MTPConfig &result) {

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h" #include "base/timer.h"
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "base/bytes.h"
#include "mtproto/rpc_sender.h" #include "mtproto/rpc_sender.h"
namespace MTP { namespace MTP {
@ -45,6 +46,7 @@ private:
DcId dcId; DcId dcId;
std::string ip; std::string ip;
int port; int port;
bytes::vector secret;
}; };
friend bool operator==(const SpecialEndpoint &a, const SpecialEndpoint &b); friend bool operator==(const SpecialEndpoint &a, const SpecialEndpoint &b);
std::unique_ptr<SpecialConfigRequest> _specialLoader; std::unique_ptr<SpecialConfigRequest> _specialLoader;

View File

@ -415,7 +415,6 @@ ConnectionPrivate::ConnectionPrivate(
, _state(DisconnectedState) , _state(DisconnectedState)
, _shiftedDcId(shiftedDcId) , _shiftedDcId(shiftedDcId)
, _owner(owner) , _owner(owner)
, _configWasFineAt(getms(true))
, _retryTimer(thread, [=] { retryByTimer(); }) , _retryTimer(thread, [=] { retryByTimer(); })
, _oldConnectionTimer(thread, [=] { markConnectionOld(); }) , _oldConnectionTimer(thread, [=] { markConnectionOld(); })
, _waitForConnectedTimer(thread, [=] { waitConnectedFailed(); }) , _waitForConnectedTimer(thread, [=] { waitConnectedFailed(); })
@ -1120,7 +1119,7 @@ void ConnectionPrivate::connectToServer(bool afterConfig) {
static_cast<Variants::Protocol>(protocol), static_cast<Variants::Protocol>(protocol),
QString::fromStdString(endpoint.ip), QString::fromStdString(endpoint.ip),
endpoint.port, endpoint.port,
endpoint.protocolSecret); endpoint.secret);
} }
} }
} }
@ -1142,7 +1141,9 @@ void ConnectionPrivate::connectToServer(bool afterConfig) {
return; return;
} }
if (getms(true) - _configWasFineAt > kRequestConfigTimeout) { if (!_startedConnectingAt) {
_startedConnectingAt = getms(true);
} else if (getms(true) - _startedConnectingAt > kRequestConfigTimeout) {
InvokeQueued(_instance, [instance = _instance] { InvokeQueued(_instance, [instance = _instance] {
instance->requestConfigIfOld(); instance->requestConfigIfOld();
}); });
@ -1549,6 +1550,7 @@ void ConnectionPrivate::handleReceived() {
DEBUG_LOG(("MTP Info: marked auth key as checked")); DEBUG_LOG(("MTP Info: marked auth key as checked"));
sessionData->setCheckedKey(true); sessionData->setCheckedKey(true);
} }
_startedConnectingAt = TimeMs(0);
if (!wasConnected) { if (!wasConnected) {
if (getState() == ConnectedState) { if (getState() == ConnectedState) {
@ -2456,8 +2458,6 @@ void ConnectionPrivate::updateAuthKey() {
QReadLocker lockFinished(&sessionDataMutex); QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData || !_connection) return; if (!sessionData || !_connection) return;
_configWasFineAt = getms(true);
DEBUG_LOG(("AuthKey Info: Connection updating key from Session, dc %1").arg(_shiftedDcId)); DEBUG_LOG(("AuthKey Info: Connection updating key from Session, dc %1").arg(_shiftedDcId));
uint64 newKeyId = 0; uint64 newKeyId = 0;
{ {

View File

@ -227,7 +227,7 @@ private:
not_null<Connection*> _owner; not_null<Connection*> _owner;
ConnectionPointer _connection; ConnectionPointer _connection;
std::vector<TestConnection> _testConnections; std::vector<TestConnection> _testConnections;
TimeMs _configWasFineAt = 0; TimeMs _startedConnectingAt = 0;
base::Timer _retryTimer; // exp retry timer base::Timer _retryTimer; // exp retry timer
int _retryTimeout = 1; int _retryTimeout = 1;

View File

@ -62,7 +62,9 @@ AQIDAQAB\n\
class DcOptions::WriteLocker { class DcOptions::WriteLocker {
public: public:
WriteLocker(DcOptions *that) : _that(that), _lock(&_that->_useThroughLockers) { WriteLocker(not_null<DcOptions*> that)
: _that(that)
, _lock(&_that->_useThroughLockers) {
} }
~WriteLocker() { ~WriteLocker() {
_that->computeCdnDcIds(); _that->computeCdnDcIds();
@ -76,7 +78,8 @@ private:
class DcOptions::ReadLocker { class DcOptions::ReadLocker {
public: public:
ReadLocker(const DcOptions *that) : _lock(&that->_useThroughLockers) { ReadLocker(not_null<const DcOptions*> that)
: _lock(&that->_useThroughLockers) {
} }
private: private:
@ -105,28 +108,18 @@ void DcOptions::constructFromBuiltIn() {
auto bdcs = builtInDcs(); auto bdcs = builtInDcs();
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) { for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
const auto flags = MTPDdcOption::Flags(0); const auto flags = Flag::f_static | 0;
const auto bdc = bdcs[i]; const auto bdc = bdcs[i];
const auto idWithShift = MTP::shiftDcId(bdc.id, flags); applyOneGuarded(bdc.id, flags, bdc.ip, bdc.port, {});
_data.emplace(
idWithShift,
std::vector<Option>(
1,
Option(bdc.id, flags, bdc.ip, bdc.port, {})));
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: " DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: "
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port)); "%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
} }
auto bdcsipv6 = builtInDcsIPv6(); auto bdcsipv6 = builtInDcsIPv6();
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) { for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
const auto flags = MTPDdcOption::Flags(MTPDdcOption::Flag::f_ipv6); const auto flags = Flag::f_static | Flag::f_ipv6;
const auto bdc = bdcsipv6[i]; const auto bdc = bdcsipv6[i];
const auto idWithShift = MTP::shiftDcId(bdc.id, flags); applyOneGuarded(bdc.id, flags, bdc.ip, bdc.port, {});
_data.emplace(
idWithShift,
std::vector<Option>(
1,
Option(bdc.id, flags, bdc.ip, bdc.port, {})));
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: " DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: "
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port)); "%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
} }
@ -139,62 +132,42 @@ void DcOptions::processFromList(
return; return;
} }
auto idsChanged = std::vector<DcId>(); auto data = [&] {
idsChanged.reserve(options.size());
auto shiftedIdsProcessed = std::vector<ShiftedDcId>();
shiftedIdsProcessed.reserve(options.size());
{
WriteLocker lock(this);
if (overwrite) { if (overwrite) {
idsChanged.reserve(_data.size()); return std::map<DcId, std::vector<Endpoint>>();
}
ReadLocker lock(this);
return _data;
}();
for (auto &mtpOption : options) {
if (mtpOption.type() != mtpc_dcOption) {
LOG(("Wrong type in DcOptions: %1").arg(mtpOption.type()));
continue;
} }
for (auto &mtpOption : options) {
if (mtpOption.type() != mtpc_dcOption) {
LOG(("Wrong type in DcOptions: %1").arg(mtpOption.type()));
continue;
}
auto &option = mtpOption.c_dcOption(); auto &option = mtpOption.c_dcOption();
auto dcId = option.vid.v; auto dcId = option.vid.v;
auto flags = option.vflags.v; auto flags = option.vflags.v;
auto dcIdWithShift = MTP::shiftDcId(dcId, flags); auto ip = std::string(
if (overwrite) { option.vip_address.v.constData(),
if (!base::contains(shiftedIdsProcessed, dcIdWithShift)) { option.vip_address.v.size());
shiftedIdsProcessed.push_back(dcIdWithShift); auto port = option.vport.v;
_data.erase(dcIdWithShift); auto secret = option.has_secret()
} ? bytes::make_vector(option.vsecret.v)
} : bytes::vector();
auto ip = std::string( ApplyOneOption(data, dcId, flags, ip, port, secret);
option.vip_address.v.constData(),
option.vip_address.v.size());
auto port = option.vport.v;
auto secret = option.has_secret()
? bytes::make_vector(option.vsecret.v)
: bytes::vector();
if (applyOneGuarded(dcId, flags, ip, port, secret)) {
if (!base::contains(idsChanged, dcId)) {
idsChanged.push_back(dcId);
}
}
}
if (overwrite && shiftedIdsProcessed.size() < _data.size()) {
for (auto i = _data.begin(); i != _data.end();) {
if (base::contains(shiftedIdsProcessed, i->first)) {
++i;
} else {
const auto &options = i->second;
Assert(!options.empty());
if (!base::contains(idsChanged, options.front().id)) {
idsChanged.push_back(options.front().id);
}
i = _data.erase(i);
}
}
}
} }
if (!idsChanged.empty()) { auto difference = [&] {
_changed.notify(std::move(idsChanged)); WriteLocker lock(this);
auto result = CountOptionsDifference(_data, data);
if (!result.empty()) {
_data = std::move(data);
}
return result;
}();
if (!difference.empty()) {
_changed.notify(std::move(difference));
} }
} }
@ -221,23 +194,28 @@ void DcOptions::addFromOther(DcOptions &&options) {
idsChanged.reserve(options._data.size()); idsChanged.reserve(options._data.size());
{ {
WriteLocker lock(this); WriteLocker lock(this);
for (const auto &item : base::take(options._data)) { const auto changed = [&](const std::vector<Endpoint> &list) {
for (const auto &option : item.second) { auto result = false;
const auto dcId = option.id; for (const auto &endpoint : list) {
const auto flags = option.flags; const auto dcId = endpoint.id;
const auto &ip = option.ip; const auto flags = endpoint.flags;
const auto port = option.port; const auto &ip = endpoint.ip;
const auto &secret = option.secret; const auto port = endpoint.port;
const auto &secret = endpoint.secret;
if (applyOneGuarded(dcId, flags, ip, port, secret)) { if (applyOneGuarded(dcId, flags, ip, port, secret)) {
if (!base::contains(idsChanged, dcId)) { result = true;
idsChanged.push_back(dcId);
}
} }
} }
return result;
};
for (const auto &item : base::take(options._data)) {
if (changed(item.second)) {
idsChanged.push_back(item.first);
}
} }
for (auto &keysForDc : options._cdnPublicKeys) { for (auto &item : options._cdnPublicKeys) {
for (auto &entry : keysForDc.second) { for (auto &entry : item.second) {
_cdnPublicKeys[keysForDc.first].insert(std::move(entry)); _cdnPublicKeys[item.first].insert(std::move(entry));
} }
} }
} }
@ -250,7 +228,7 @@ void DcOptions::addFromOther(DcOptions &&options) {
void DcOptions::constructAddOne( void DcOptions::constructAddOne(
int id, int id,
MTPDdcOption::Flags flags, Flags flags,
const std::string &ip, const std::string &ip,
int port, int port,
const bytes::vector &secret) { const bytes::vector &secret) {
@ -260,27 +238,87 @@ void DcOptions::constructAddOne(
bool DcOptions::applyOneGuarded( bool DcOptions::applyOneGuarded(
DcId dcId, DcId dcId,
MTPDdcOption::Flags flags, Flags flags,
const std::string &ip, const std::string &ip,
int port, int port,
const bytes::vector &secret) { const bytes::vector &secret) {
auto dcIdWithShift = MTP::shiftDcId(dcId, flags); return ApplyOneOption(_data, dcId, flags, ip, port, secret);
auto i = _data.find(dcIdWithShift); }
if (i != _data.cend()) {
for (auto &option : i->second) { bool DcOptions::ApplyOneOption(
if (option.ip == ip && option.port == port) { std::map<DcId, std::vector<Endpoint>> &data,
DcId dcId,
Flags flags,
const std::string &ip,
int port,
const bytes::vector &secret) {
auto i = data.find(dcId);
if (i != data.cend()) {
for (auto &endpoint : i->second) {
if (endpoint.ip == ip && endpoint.port == port) {
return false; return false;
} }
} }
i->second.push_back(Option(dcId, flags, ip, port, secret)); i->second.push_back(Endpoint(dcId, flags, ip, port, secret));
} else { } else {
_data.emplace(dcIdWithShift, std::vector<Option>( data.emplace(dcId, std::vector<Endpoint>(
1, 1,
Option(dcId, flags, ip, port, secret))); Endpoint(dcId, flags, ip, port, secret)));
} }
return true; return true;
} }
auto DcOptions::CountOptionsDifference(
const std::map<DcId, std::vector<Endpoint>> &a,
const std::map<DcId, std::vector<Endpoint>> &b) -> Ids {
auto result = Ids();
const auto find = [](
const std::vector<Endpoint> &where,
const Endpoint &what) {
for (const auto &endpoint : where) {
if (endpoint.ip == what.ip && endpoint.port == what.port) {
return true;
}
}
return false;
};
const auto equal = [&](
const std::vector<Endpoint> &m,
const std::vector<Endpoint> &n) {
if (m.size() != n.size()) {
return false;
}
for (const auto &endpoint : m) {
if (!find(n, endpoint)) {
return false;
}
}
return true;
};
auto i = begin(a);
auto j = begin(b);
const auto max = std::numeric_limits<DcId>::max();
while (i != end(a) || j != end(b)) {
const auto aId = (i == end(a)) ? max : i->first;
const auto bId = (j == end(b)) ? max : j->first;
if (aId < bId) {
result.push_back(aId);
++i;
} else if (bId < aId) {
result.push_back(bId);
++j;
} else {
if (!equal(i->second, j->second)) {
result.push_back(aId);
}
++i;
++j;
}
}
return result;
}
QByteArray DcOptions::serialize() const { QByteArray DcOptions::serialize() const {
if (_immutable) { if (_immutable) {
// Don't write the overriden options to our settings. // Don't write the overriden options to our settings.
@ -298,12 +336,12 @@ QByteArray DcOptions::serialize() const {
if (isTemporaryDcId(item.first)) { if (isTemporaryDcId(item.first)) {
continue; continue;
} }
for (const auto &option : item.second) { for (const auto &endpoint : item.second) {
++optionsCount; ++optionsCount;
// id + flags + port // id + flags + port
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32); size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
size += sizeof(qint32) + option.ip.size(); size += sizeof(qint32) + endpoint.ip.size();
size += sizeof(qint32) + option.secret.size(); size += sizeof(qint32) + endpoint.secret.size();
} }
} }
@ -348,16 +386,16 @@ QByteArray DcOptions::serialize() const {
if (isTemporaryDcId(item.first)) { if (isTemporaryDcId(item.first)) {
continue; continue;
} }
for (const auto &option : item.second) { for (const auto &endpoint : item.second) {
stream << qint32(option.id) stream << qint32(endpoint.id)
<< qint32(option.flags) << qint32(endpoint.flags)
<< qint32(option.port) << qint32(endpoint.port)
<< qint32(option.ip.size()); << qint32(endpoint.ip.size());
stream.writeRawData(option.ip.data(), option.ip.size()); stream.writeRawData(endpoint.ip.data(), endpoint.ip.size());
stream << qint32(option.secret.size()); stream << qint32(endpoint.secret.size());
stream.writeRawData( stream.writeRawData(
reinterpret_cast<const char*>(option.secret.data()), reinterpret_cast<const char*>(endpoint.secret.data()),
option.secret.size()); endpoint.secret.size());
} }
} }
@ -404,7 +442,7 @@ void DcOptions::constructFromSerialized(const QByteArray &serialized) {
return; return;
} }
std::string ip(ipSize, ' '); auto ip = std::string(ipSize, ' ');
stream.readRawData(ip.data(), ipSize); stream.readRawData(ip.data(), ipSize);
constexpr auto kMaxSecretSize = 32; constexpr auto kMaxSecretSize = 32;
@ -430,7 +468,7 @@ void DcOptions::constructFromSerialized(const QByteArray &serialized) {
applyOneGuarded( applyOneGuarded(
DcId(id), DcId(id),
MTPDdcOption::Flags::from_raw(flags), Flags::from_raw(flags),
ip, ip,
port, port,
secret); secret);
@ -470,11 +508,10 @@ DcOptions::Ids DcOptions::configEnumDcIds() const {
ReadLocker lock(this); ReadLocker lock(this);
result.reserve(_data.size()); result.reserve(_data.size());
for (auto &item : _data) { for (auto &item : _data) {
const auto dcId = bareDcId(item.first); const auto dcId = item.first;
Assert(!item.second.empty()); Assert(!item.second.empty());
if (!isCdnDc(item.second.front().flags) if (!isCdnDc(item.second.front().flags)
&& !isTemporaryDcId(item.first) && !isTemporaryDcId(dcId)) {
&& !base::contains(result, dcId)) {
result.push_back(dcId); result.push_back(dcId);
} }
} }
@ -542,186 +579,72 @@ bool DcOptions::getDcRSAKey(DcId dcId, const QVector<MTPlong> &fingerprints, int
return findKey(_publicKeys); return findKey(_publicKeys);
} }
DcOptions::Variants DcOptions::lookup( auto DcOptions::lookup(
DcId dcId, DcId dcId,
DcType type, DcType type,
bool throughProxy) const { bool throughProxy) const -> Variants {
auto lookupDesiredFlags = [&](int address, int protocol) -> std::vector<MTPDdcOption::Flags> { using Flag = Flag;
switch (type) {
case DcType::Regular:
case DcType::Temporary: {
switch (address) {
case Variants::IPv4: {
switch (protocol) {
case Variants::Tcp: return {
// Regular TCP IPv4
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | 0),
throughProxy ? (MTPDdcOption::Flag::f_static | 0) : MTPDdcOption::Flags(0),
(MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
(MTPDdcOption::Flag::f_tcpo_only | 0),
0
};
case Variants::Http: return {
// Regular HTTP IPv4
throughProxy ? (MTPDdcOption::Flag::f_static | 0) : MTPDdcOption::Flags(0),
0,
};
}
} break;
case Variants::IPv6: {
switch (protocol) {
case Variants::Tcp: return {
// Regular TCP IPv6
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_ipv6 | 0),
(MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_ipv6 | 0),
};
case Variants::Http: return {
// Regular HTTP IPv6
throughProxy ? (MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_ipv6 | 0),
(MTPDdcOption::Flag::f_ipv6 | 0),
};
}
} break;
}
} break;
case DcType::MediaDownload: {
switch (address) {
case Variants::IPv4: {
switch (protocol) {
case Variants::Tcp: return {
// Media download TCP IPv4
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | 0),
(MTPDdcOption::Flag::f_media_only | 0),
throughProxy ? (MTPDdcOption::Flag::f_static | 0) : MTPDdcOption::Flags(0),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | 0),
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only) : (MTPDdcOption::Flag::f_media_only | 0),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | 0) : (MTPDdcOption::Flag::f_media_only | 0),
0,
};
case Variants::Http: return {
// Media download HTTP IPv4
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | 0),
(MTPDdcOption::Flag::f_media_only | 0),
throughProxy ? (MTPDdcOption::Flag::f_static | 0) : MTPDdcOption::Flags(0),
0,
};
}
} break;
case Variants::IPv6: {
switch (protocol) {
case Variants::Tcp: return {
// Media download TCP IPv6
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_ipv6 | 0),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_ipv6 | 0)
};
case Variants::Http: return {
// Media download HTTP IPv6
throughProxy ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6),
throughProxy ? (MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_ipv6 | 0),
(MTPDdcOption::Flag::f_ipv6 | 0),
};
}
} break;
}
} break;
case DcType::Cdn: {
switch (address) {
case Variants::IPv4: {
switch (protocol) {
case Variants::Tcp: return {
// CDN TCP IPv4
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | 0),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_tcpo_only),
(MTPDdcOption::Flag::f_cdn | 0),
};
case Variants::Http: return {
// CDN HTTP IPv4
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | 0),
(MTPDdcOption::Flag::f_cdn | 0),
};
}
} break;
case Variants::IPv6: {
switch (protocol) {
case Variants::Tcp: return {
// CDN TCP IPv6
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_tcpo_only),
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_secret | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6),
};
case Variants::Http: return {
// CDN HTTP IPv6
throughProxy ? (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6 | MTPDdcOption::Flag::f_static) : (MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6),
(MTPDdcOption::Flag::f_cdn | MTPDdcOption::Flag::f_ipv6),
};
}
} break;
}
} break;
}
Unexpected("Bad type / address / protocol");
};
auto result = Variants(); auto result = Variants();
{ {
ReadLocker lock(this); ReadLocker lock(this);
for (auto address = 0; address != Variants::AddressTypeCount; ++address) { const auto i = _data.find(dcId);
for (auto protocol = 0; protocol != Variants::ProtocolCount; ++protocol) { if (i == end(_data)) {
auto desiredFlags = lookupDesiredFlags(address, protocol); return result;
for (auto flags : desiredFlags) { }
const auto shift = static_cast<int>(flags); for (const auto &endpoint : i->second) {
const auto it = _data.find(shiftDcId(dcId, shift)); const auto flags = endpoint.flags;
if (it != _data.cend()) { if (type == DcType::Cdn && !(flags & Flag::f_cdn)) {
for (const auto &option : it->second) { continue;
result.data[address][protocol].push_back({ } else if (throughProxy && !(flags & Flag::f_static)) {
option.ip, continue;
option.port,
option.secret
});
}
break;
}
}
} }
if (type != DcType::MediaDownload
&& (flags & Flag::f_media_only)) {
continue;
}
const auto address = (flags & Flag::f_ipv6)
? Variants::IPv6
: Variants::IPv4;
result.data[address][Variants::Tcp].push_back(endpoint);
if (!(flags & (Flag::f_tcpo_only | Flag::f_secret))) {
result.data[address][Variants::Http].push_back(endpoint);
}
}
if (type == DcType::MediaDownload) {
FilterIfHasWithFlag(result, Flag::f_media_only);
}
if (throughProxy) {
FilterIfHasWithFlag(result, Flag::f_static);
} }
} }
return result; return result;
} }
void DcOptions::FilterIfHasWithFlag(Variants &variants, Flag flag) {
const auto is = [&](const Endpoint &endpoint) {
return (endpoint.flags & flag) != 0;
};
const auto has = [&](const std::vector<Endpoint> &list) {
return ranges::find_if(list, is) != end(list);
};
for (auto &byAddress : variants.data) {
for (auto &list : byAddress) {
if (has(list)) {
list = ranges::view::all(
list
) | ranges::view::filter(
is
) | ranges::to_vector;
}
}
}
}
void DcOptions::computeCdnDcIds() { void DcOptions::computeCdnDcIds() {
_cdnDcIds.clear(); _cdnDcIds.clear();
for (auto &item : _data) { for (auto &item : _data) {
Assert(!item.second.empty()); Assert(!item.second.empty());
if (item.second.front().flags & MTPDdcOption::Flag::f_cdn) { if (item.second.front().flags & Flag::f_cdn) {
_cdnDcIds.insert(bareDcId(item.first)); _cdnDcIds.insert(bareDcId(item.first));
} }
} }
@ -758,17 +681,17 @@ bool DcOptions::loadFromFile(const QString &path) {
if (dcId <= 0 || dcId >= internal::kDcShift || !host.setAddress(ip) || port <= 0) { if (dcId <= 0 || dcId >= internal::kDcShift || !host.setAddress(ip) || port <= 0) {
return error(); return error();
} }
auto flags = MTPDdcOption::Flags(0); auto flags = Flags(0);
if (host.protocol() == QAbstractSocket::IPv6Protocol) { if (host.protocol() == QAbstractSocket::IPv6Protocol) {
flags |= MTPDdcOption::Flag::f_ipv6; flags |= Flag::f_ipv6;
} }
for (auto &option : components.mid(3)) { for (auto &option : components.mid(3)) {
if (option.startsWith('#')) { if (option.startsWith('#')) {
break; break;
} else if (option == qstr("tcpo_only")) { } else if (option == qstr("tcpo_only")) {
flags |= MTPDdcOption::Flag::f_tcpo_only; flags |= Flag::f_tcpo_only;
} else if (option == qstr("media_only")) { } else if (option == qstr("media_only")) {
flags |= MTPDdcOption::Flag::f_media_only; flags |= Flag::f_media_only;
} else { } else {
return error(); return error();
} }
@ -808,10 +731,10 @@ bool DcOptions::writeToFile(const QString &path) const {
<< ' ' << ' '
<< QString::fromStdString(option.ip) << QString::fromStdString(option.ip)
<< ' ' << option.port; << ' ' << option.port;
if (option.flags & MTPDdcOption::Flag::f_tcpo_only) { if (option.flags & Flag::f_tcpo_only) {
stream << " tcpo_only"; stream << " tcpo_only";
} }
if (option.flags & MTPDdcOption::Flag::f_media_only) { if (option.flags & Flag::f_media_only) {
stream << " media_only"; stream << " media_only";
} }
stream << '\n'; stream << '\n';

View File

@ -24,12 +24,36 @@ enum class DcType {
}; };
class DcOptions { class DcOptions {
public: public:
using Flag = MTPDdcOption::Flag;
using Flags = MTPDdcOption::Flags;
struct Endpoint {
Endpoint(
DcId id,
Flags flags,
const std::string &ip,
int port,
const bytes::vector &secret)
: id(id)
, flags(flags)
, ip(ip)
, port(port)
, secret(secret) {
}
DcId id;
Flags flags;
std::string ip;
int port;
bytes::vector secret;
};
// construct methods don't notify "changed" subscribers. // construct methods don't notify "changed" subscribers.
void constructFromSerialized(const QByteArray &serialized); void constructFromSerialized(const QByteArray &serialized);
void constructFromBuiltIn(); void constructFromBuiltIn();
void constructAddOne( void constructAddOne(
int id, int id,
MTPDdcOption::Flags flags, Flags flags,
const std::string &ip, const std::string &ip,
int port, int port,
const bytes::vector &secret); const bytes::vector &secret);
@ -45,11 +69,6 @@ public:
Ids configEnumDcIds() const; Ids configEnumDcIds() const;
struct Endpoint {
std::string ip;
int port = 0;
bytes::vector protocolSecret;
};
struct Variants { struct Variants {
enum Address { enum Address {
IPv4 = 0, IPv4 = 0,
@ -75,33 +94,23 @@ public:
bool writeToFile(const QString &path) const; bool writeToFile(const QString &path) const;
private: private:
struct Option {
Option(
DcId id,
MTPDdcOption::Flags flags,
const std::string &ip,
int port,
const bytes::vector &secret)
: id(id)
, flags(flags)
, ip(ip)
, port(port)
, secret(secret) {
}
DcId id;
MTPDdcOption::Flags flags;
std::string ip;
int port;
bytes::vector secret;
};
bool applyOneGuarded( bool applyOneGuarded(
DcId dcId, DcId dcId,
MTPDdcOption::Flags flags, Flags flags,
const std::string &ip, const std::string &ip,
int port, int port,
const bytes::vector &secret); const bytes::vector &secret);
static bool ApplyOneOption(
std::map<DcId, std::vector<Endpoint>> &data,
DcId dcId,
Flags flags,
const std::string &ip,
int port,
const bytes::vector &secret);
static Ids CountOptionsDifference(
const std::map<DcId, std::vector<Endpoint>> &a,
const std::map<DcId, std::vector<Endpoint>> &b);
static void FilterIfHasWithFlag(Variants &variants, Flag flag);
void processFromList(const QVector<MTPDcOption> &options, bool overwrite); void processFromList(const QVector<MTPDcOption> &options, bool overwrite);
void computeCdnDcIds(); void computeCdnDcIds();
@ -114,7 +123,7 @@ private:
class ReadLocker; class ReadLocker;
friend class ReadLocker; friend class ReadLocker;
std::map<ShiftedDcId, std::vector<Option>> _data; std::map<DcId, std::vector<Endpoint>> _data;
std::set<DcId> _cdnDcIds; std::set<DcId> _cdnDcIds;
std::map<uint64, internal::RSAPublicKey> _publicKeys; std::map<uint64, internal::RSAPublicKey> _publicKeys;
std::map<DcId, std::map<uint64, internal::RSAPublicKey>> _cdnPublicKeys; std::map<DcId, std::map<uint64, internal::RSAPublicKey>> _cdnPublicKeys;