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(
QString::fromStdString(endpoints.front().ip),
endpoints.front().port,
endpoints.front().protocolSecret,
endpoints.front().secret,
dcId);
}
};

View file

@ -52,7 +52,7 @@ mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
}
DcId ConfigLoader::specialToRealDcId(DcId specialDcId) {
return Instance::Config::kTemporaryMainDc + specialDcId;
return getTemporaryIdFromRealDcId(specialDcId);
}
void ConfigLoader::terminateRequest() {
@ -139,15 +139,18 @@ void ConfigLoader::sendSpecialRequest() {
const auto weak = base::make_weak(this);
const auto index = rand_value<uint32>() % _specialEndpoints.size();
const auto secret = bytes::vector();
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,
MTPDdcOption::Flag::f_tcpo_only,
flags,
endpoint->ip,
endpoint->port,
secret);
endpoint->secret);
_specialEnumRequest = _instance->send(
MTPhelp_GetConfig(),
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/weak_ptr.h"
#include "base/bytes.h"
#include "mtproto/rpc_sender.h"
namespace MTP {
@ -45,6 +46,7 @@ private:
DcId dcId;
std::string ip;
int port;
bytes::vector secret;
};
friend bool operator==(const SpecialEndpoint &a, const SpecialEndpoint &b);
std::unique_ptr<SpecialConfigRequest> _specialLoader;

View file

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

View file

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

View file

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

View file

@ -24,12 +24,36 @@ enum class DcType {
};
class DcOptions {
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.
void constructFromSerialized(const QByteArray &serialized);
void constructFromBuiltIn();
void constructAddOne(
int id,
MTPDdcOption::Flags flags,
Flags flags,
const std::string &ip,
int port,
const bytes::vector &secret);
@ -45,11 +69,6 @@ public:
Ids configEnumDcIds() const;
struct Endpoint {
std::string ip;
int port = 0;
bytes::vector protocolSecret;
};
struct Variants {
enum Address {
IPv4 = 0,
@ -75,33 +94,23 @@ public:
bool writeToFile(const QString &path) const;
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(
DcId dcId,
MTPDdcOption::Flags flags,
Flags flags,
const std::string &ip,
int port,
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 computeCdnDcIds();
@ -114,7 +123,7 @@ private:
class ReadLocker;
friend class ReadLocker;
std::map<ShiftedDcId, std::vector<Option>> _data;
std::map<DcId, std::vector<Endpoint>> _data;
std::set<DcId> _cdnDcIds;
std::map<uint64, internal::RSAPublicKey> _publicKeys;
std::map<DcId, std::map<uint64, internal::RSAPublicKey>> _cdnPublicKeys;