| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845 |
- /*
- 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/mtproto_dc_options.h"
- #include "mtproto/details/mtproto_rsa_public_key.h"
- #include "mtproto/facade.h"
- #include "mtproto/connection_tcp.h"
- #include "storage/serialize_common.h"
- #include <QtCore/QFile>
- #include <QtCore/QRegularExpression>
- namespace MTP {
- namespace {
- constexpr auto kVersion = 2;
- using namespace details;
- struct BuiltInDc {
- int id;
- const char *ip;
- int port;
- };
- const BuiltInDc kBuiltInDcs[] = {
- { 1, "149.154.175.50" , 443 },
- { 2, "149.154.167.51" , 443 },
- { 2, "95.161.76.100" , 443 },
- { 3, "149.154.175.100", 443 },
- { 4, "149.154.167.91" , 443 },
- { 5, "149.154.171.5" , 443 },
- };
- const BuiltInDc kBuiltInDcsIPv6[] = {
- { 1, "2001:0b28:f23d:f001:0000:0000:0000:000a", 443 },
- { 2, "2001:067c:04e8:f002:0000:0000:0000:000a", 443 },
- { 3, "2001:0b28:f23d:f003:0000:0000:0000:000a", 443 },
- { 4, "2001:067c:04e8:f004:0000:0000:0000:000a", 443 },
- { 5, "2001:0b28:f23f:f005:0000:0000:0000:000a", 443 },
- };
- const BuiltInDc kBuiltInDcsTest[] = {
- { 1, "149.154.175.10" , 443 },
- { 2, "149.154.167.40" , 443 },
- { 3, "149.154.175.117", 443 }
- };
- const BuiltInDc kBuiltInDcsIPv6Test[] = {
- { 1, "2001:0b28:f23d:f001:0000:0000:0000:000e", 443 },
- { 2, "2001:067c:04e8:f002:0000:0000:0000:000e", 443 },
- { 3, "2001:0b28:f23d:f003:0000:0000:0000:000e", 443 }
- };
- const char *kTestPublicRSAKeys[] = { "\
- -----BEGIN RSA PUBLIC KEY-----\n\
- MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n\
- yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n\
- plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n\
- j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n\
- aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n\
- j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n\
- -----END RSA PUBLIC KEY-----" };
- const char *kPublicRSAKeys[] = { "\
- -----BEGIN RSA PUBLIC KEY-----\n\
- MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n\
- 5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n\
- 62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n\
- +aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n\
- t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n\
- 5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n\
- -----END RSA PUBLIC KEY-----" };
- } // namespace
- class DcOptions::WriteLocker {
- public:
- WriteLocker(not_null<DcOptions*> that)
- : _that(that)
- , _lock(&_that->_useThroughLockers) {
- }
- void unlock() {
- _lock.unlock();
- }
- ~WriteLocker() {
- _that->computeCdnDcIds();
- }
- private:
- not_null<DcOptions*> _that;
- QWriteLocker _lock;
- };
- class DcOptions::ReadLocker {
- public:
- ReadLocker(not_null<const DcOptions*> that)
- : _lock(&that->_useThroughLockers) {
- }
- void unlock() {
- _lock.unlock();
- }
- private:
- QReadLocker _lock;
- };
- DcOptions::DcOptions(Environment environment)
- : _environment(environment) {
- constructFromBuiltIn();
- }
- DcOptions::DcOptions(const DcOptions &other)
- : _environment(other._environment)
- , _data(other._data)
- , _cdnDcIds(other._cdnDcIds)
- , _publicKeys(other._publicKeys)
- , _cdnPublicKeys(other._cdnPublicKeys)
- , _immutable(other._immutable) {
- }
- DcOptions::~DcOptions() = default;
- bool DcOptions::ValidateSecret(bytes::const_span secret) {
- // See also TcpConnection::Protocol::Create.
- return (secret.size() >= 21 && secret[0] == bytes::type(0xEE))
- || (secret.size() == 17 && secret[0] == bytes::type(0xDD))
- || (secret.size() == 16)
- || secret.empty();
- }
- void DcOptions::readBuiltInPublicKeys() {
- const auto builtin = (_environment == Environment::Test)
- ? gsl::make_span(kTestPublicRSAKeys)
- : gsl::make_span(kPublicRSAKeys);
- for (const auto key : builtin) {
- const auto keyBytes = bytes::make_span(key, strlen(key));
- auto parsed = RSAPublicKey(keyBytes);
- if (parsed.valid()) {
- _publicKeys.emplace(parsed.fingerprint(), std::move(parsed));
- } else {
- LOG(("MTP Error: could not read this public RSA key:"));
- LOG((key));
- }
- }
- }
- Environment DcOptions::environment() const {
- return _environment;
- }
- bool DcOptions::isTestMode() const {
- return (_environment != Environment::Production);
- }
- void DcOptions::constructFromBuiltIn() {
- WriteLocker lock(this);
- _data.clear();
- readBuiltInPublicKeys();
- const auto list = isTestMode()
- ? gsl::make_span(kBuiltInDcsTest)
- : gsl::make_span(kBuiltInDcs).subspan(0);
- for (const auto &entry : list) {
- const auto flags = Flag::f_static | 0;
- applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
- DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3"
- ).arg(entry.id
- ).arg(entry.ip
- ).arg(entry.port));
- }
- const auto listv6 = isTestMode()
- ? gsl::make_span(kBuiltInDcsIPv6Test)
- : gsl::make_span(kBuiltInDcsIPv6).subspan(0);
- for (const auto &entry : listv6) {
- const auto flags = Flag::f_static | Flag::f_ipv6;
- applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
- DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: "
- "%2:%3"
- ).arg(entry.id
- ).arg(entry.ip
- ).arg(entry.port));
- }
- }
- void DcOptions::processFromList(
- const QVector<MTPDcOption> &options,
- bool overwrite) {
- if (options.empty() || _immutable) {
- return;
- }
- auto data = [&] {
- if (overwrite) {
- return base::flat_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;
- }
- 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 = bytes::make_vector(option.vsecret().value_or_empty());
- ApplyOneOption(data, dcId, flags, ip, port, secret);
- }
- const auto difference = [&] {
- WriteLocker lock(this);
- auto result = CountOptionsDifference(_data, data);
- if (!result.empty()) {
- _data = std::move(data);
- }
- return result;
- }();
- for (const auto dcId : difference) {
- _changed.fire_copy(dcId);
- }
- }
- void DcOptions::setFromList(const MTPVector<MTPDcOption> &options) {
- processFromList(options.v, true);
- }
- void DcOptions::addFromList(const MTPVector<MTPDcOption> &options) {
- processFromList(options.v, false);
- }
- void DcOptions::addFromOther(DcOptions &&options) {
- if (this == &options || _immutable) {
- return;
- }
- auto idsChanged = std::vector<DcId>();
- {
- ReadLocker lock(&options);
- if (options._data.empty()) {
- return;
- }
- idsChanged.reserve(options._data.size());
- {
- WriteLocker lock(this);
- 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)) {
- result = true;
- }
- }
- return result;
- };
- for (const auto &item : base::take(options._data)) {
- if (changed(item.second)) {
- idsChanged.push_back(item.first);
- }
- }
- for (auto &item : options._cdnPublicKeys) {
- for (auto &entry : item.second) {
- _cdnPublicKeys[item.first].insert(std::move(entry));
- }
- }
- }
- }
- for (const auto dcId : idsChanged) {
- _changed.fire_copy(dcId);
- }
- }
- void DcOptions::constructAddOne(
- int id,
- Flags flags,
- const std::string &ip,
- int port,
- const bytes::vector &secret) {
- WriteLocker lock(this);
- applyOneGuarded(BareDcId(id), flags, ip, port, secret);
- }
- bool DcOptions::applyOneGuarded(
- DcId dcId,
- Flags flags,
- const std::string &ip,
- int port,
- const bytes::vector &secret) {
- return ApplyOneOption(_data, dcId, flags, ip, port, secret);
- }
- bool DcOptions::ApplyOneOption(
- base::flat_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.emplace_back(dcId, flags, ip, port, secret);
- } else {
- data.emplace(dcId, std::vector<Endpoint>(
- 1,
- Endpoint(dcId, flags, ip, port, secret)));
- }
- return true;
- }
- std::vector<DcId> DcOptions::CountOptionsDifference(
- const base::flat_map<DcId, std::vector<Endpoint>> &a,
- const base::flat_map<DcId, std::vector<Endpoint>> &b) {
- auto result = std::vector<DcId>();
- 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.
- return DcOptions(_environment).serialize();
- }
- ReadLocker lock(this);
- auto size = sizeof(qint32);
- // Dc options.
- auto optionsCount = 0;
- size += sizeof(qint32);
- for (const auto &item : _data) {
- if (isTemporaryDcId(item.first)) {
- continue;
- }
- for (const auto &endpoint : item.second) {
- ++optionsCount;
- // id + flags + port
- size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
- size += sizeof(qint32) + endpoint.ip.size();
- size += sizeof(qint32) + endpoint.secret.size();
- }
- }
- // CDN public keys.
- auto count = 0;
- for (auto &keysInDc : _cdnPublicKeys) {
- count += keysInDc.second.size();
- }
- struct SerializedPublicKey {
- DcId dcId;
- bytes::vector n;
- bytes::vector e;
- };
- std::vector<SerializedPublicKey> publicKeys;
- publicKeys.reserve(count);
- size += sizeof(qint32);
- for (const auto &keysInDc : _cdnPublicKeys) {
- for (const auto &entry : keysInDc.second) {
- publicKeys.push_back({
- keysInDc.first,
- entry.second.getN(),
- entry.second.getE()
- });
- size += sizeof(qint32)
- + Serialize::bytesSize(publicKeys.back().n)
- + Serialize::bytesSize(publicKeys.back().e);
- }
- }
- auto result = QByteArray();
- result.reserve(size);
- {
- QDataStream stream(&result, QIODevice::WriteOnly);
- stream.setVersion(QDataStream::Qt_5_1);
- stream << qint32(-kVersion);
- // Dc options.
- stream << qint32(optionsCount);
- for (const auto &item : _data) {
- if (isTemporaryDcId(item.first)) {
- continue;
- }
- 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*>(endpoint.secret.data()),
- endpoint.secret.size());
- }
- }
- // CDN public keys.
- stream << qint32(publicKeys.size());
- for (auto &key : publicKeys) {
- stream << qint32(key.dcId)
- << Serialize::bytes(key.n)
- << Serialize::bytes(key.e);
- }
- }
- return result;
- }
- bool DcOptions::constructFromSerialized(const QByteArray &serialized) {
- QDataStream stream(serialized);
- stream.setVersion(QDataStream::Qt_5_1);
- auto minusVersion = qint32(0);
- stream >> minusVersion;
- const auto version = (minusVersion < 0) ? (-minusVersion) : 0;
- auto count = qint32(0);
- if (version > 0) {
- stream >> count;
- } else {
- count = minusVersion;
- }
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: Bad data for DcOptions::constructFromSerialized()"));
- return false;
- }
- WriteLocker lock(this);
- _data.clear();
- for (auto i = 0; i != count; ++i) {
- qint32 id = 0, flags = 0, port = 0, ipSize = 0;
- stream >> id >> flags >> port >> ipSize;
- // https://stackoverflow.com/questions/1076714/max-length-for-client-ip-address
- constexpr auto kMaxIpSize = 45;
- if (ipSize <= 0 || ipSize > kMaxIpSize) {
- LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
- return false;
- }
- auto ip = std::string(ipSize, ' ');
- stream.readRawData(ip.data(), ipSize);
- constexpr auto kMaxSecretSize = 32;
- auto secret = bytes::vector();
- if (version > 0) {
- auto secretSize = qint32(0);
- stream >> secretSize;
- if (secretSize < 0 || secretSize > kMaxSecretSize) {
- LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
- return false;
- } else if (secretSize > 0) {
- secret.resize(secretSize);
- stream.readRawData(
- reinterpret_cast<char*>(secret.data()),
- secretSize);
- }
- }
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
- return false;
- }
- applyOneGuarded(
- DcId(id),
- Flags::from_raw(flags),
- ip,
- port,
- secret);
- }
- // Read CDN config
- if (!stream.atEnd() && version > 1) {
- auto count = qint32(0);
- stream >> count;
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: Bad data for CDN config in DcOptions::constructFromSerialized()"));
- return false;
- }
- for (auto i = 0; i != count; ++i) {
- qint32 dcId = 0;
- bytes::vector n, e;
- stream >> dcId >> Serialize::bytes(n) >> Serialize::bytes(e);
- if (stream.status() != QDataStream::Ok) {
- LOG(("MTP Error: Bad data for CDN config inside DcOptions::constructFromSerialized()"));
- return false;
- }
- auto key = RSAPublicKey(n, e);
- if (key.valid()) {
- _cdnPublicKeys[dcId].emplace(key.fingerprint(), std::move(key));
- } else {
- LOG(("MTP Error: Could not read valid CDN public key."));
- return false;
- }
- }
- }
- return true;
- }
- rpl::producer<DcId> DcOptions::changed() const {
- return _changed.events();
- }
- rpl::producer<> DcOptions::cdnConfigChanged() const {
- return _cdnConfigChanged.events();
- }
- std::vector<DcId> DcOptions::configEnumDcIds() const {
- auto result = std::vector<DcId>();
- {
- ReadLocker lock(this);
- result.reserve(_data.size());
- for (auto &item : _data) {
- const auto dcId = item.first;
- Assert(!item.second.empty());
- if (!isCdnDc(item.second.front().flags)
- && !isTemporaryDcId(dcId)) {
- result.push_back(dcId);
- }
- }
- }
- ranges::sort(result);
- return result;
- }
- DcType DcOptions::dcType(ShiftedDcId shiftedDcId) const {
- if (isTemporaryDcId(shiftedDcId)) {
- return DcType::Temporary;
- }
- ReadLocker lock(this);
- if (_cdnDcIds.find(BareDcId(shiftedDcId)) != _cdnDcIds.cend()) {
- return DcType::Cdn;
- }
- const auto dcId = BareDcId(shiftedDcId);
- if (isMediaClusterDcId(shiftedDcId) && hasMediaOnlyOptionsFor(dcId)) {
- return DcType::MediaCluster;
- }
- return DcType::Regular;
- }
- void DcOptions::setCDNConfig(const MTPDcdnConfig &config) {
- WriteLocker lock(this);
- _cdnPublicKeys.clear();
- for (const auto &key : config.vpublic_keys().v) {
- key.match([&](const MTPDcdnPublicKey &data) {
- const auto keyBytes = bytes::make_span(data.vpublic_key().v);
- auto key = RSAPublicKey(keyBytes);
- if (key.valid()) {
- _cdnPublicKeys[data.vdc_id().v].emplace(
- key.fingerprint(),
- std::move(key));
- } else {
- LOG(("MTP Error: could not read this public RSA key:"));
- LOG((qs(data.vpublic_key())));
- }
- });
- }
- lock.unlock();
- _cdnConfigChanged.fire({});
- }
- bool DcOptions::hasCDNKeysForDc(DcId dcId) const {
- ReadLocker lock(this);
- return _cdnPublicKeys.find(dcId) != _cdnPublicKeys.cend();
- }
- RSAPublicKey DcOptions::getDcRSAKey(
- DcId dcId,
- const QVector<MTPlong> &fingerprints) const {
- const auto findKey = [&](
- const base::flat_map<uint64, RSAPublicKey> &keys) {
- for (const auto &fingerprint : fingerprints) {
- const auto it = keys.find(static_cast<uint64>(fingerprint.v));
- if (it != keys.cend()) {
- return it->second;
- }
- }
- return RSAPublicKey();
- };
- {
- ReadLocker lock(this);
- const auto it = _cdnPublicKeys.find(dcId);
- if (it != _cdnPublicKeys.cend()) {
- return findKey(it->second);
- }
- }
- return findKey(_publicKeys);
- }
- auto DcOptions::lookup(
- DcId dcId,
- DcType type,
- bool throughProxy) const -> Variants {
- using Flag = Flag;
- auto result = Variants();
- ReadLocker lock(this);
- 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 (type != DcType::MediaCluster
- && (flags & Flag::f_media_only)) {
- continue;
- } else if (!ValidateSecret(endpoint.secret)) {
- 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::MediaCluster) {
- FilterIfHasWithFlag(result, Flag::f_media_only);
- }
- if (throughProxy) {
- FilterIfHasWithFlag(result, Flag::f_static);
- }
- return result;
- }
- bool DcOptions::hasMediaOnlyOptionsFor(DcId dcId) const {
- ReadLocker lock(this);
- const auto i = _data.find(dcId);
- if (i == end(_data)) {
- return false;
- }
- for (const auto &endpoint : i->second) {
- const auto flags = endpoint.flags;
- if (flags & Flag::f_media_only) {
- return true;
- }
- }
- return false;
- }
- 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::any_of(list, is);
- };
- for (auto &byAddress : variants.data) {
- for (auto &list : byAddress) {
- if (has(list)) {
- list = ranges::views::all(
- list
- ) | ranges::views::filter(
- is
- ) | ranges::to_vector;
- }
- }
- }
- }
- void DcOptions::computeCdnDcIds() {
- _cdnDcIds.clear();
- for (auto &item : _data) {
- Assert(!item.second.empty());
- if (item.second.front().flags & Flag::f_cdn) {
- _cdnDcIds.insert(BareDcId(item.first));
- }
- }
- }
- bool DcOptions::loadFromFile(const QString &path) {
- QVector<MTPDcOption> options;
- QFile f(path);
- if (!f.open(QIODevice::ReadOnly)) {
- LOG(("MTP Error: could not read '%1'").arg(path));
- return false;
- }
- QTextStream stream(&f);
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- stream.setCodec("UTF-8");
- #endif // Qt < 6.0.0
- while (!stream.atEnd()) {
- static const auto RegExp = QRegularExpression(R"(\s)");
- auto line = stream.readLine();
- auto components = line.split(RegExp, Qt::SkipEmptyParts);
- if (components.isEmpty() || components[0].startsWith('#')) {
- continue;
- }
- auto error = [line] {
- LOG(("MTP Error: in .tdesktop-endpoints expected 'dcId host port [tcpo_only] [media_only]', got '%1'").arg(line));
- return false;
- };
- if (components.size() < 3) {
- return error();
- }
- auto dcId = components[0].toInt();
- auto ip = components[1];
- auto port = components[2].toInt();
- auto host = QHostAddress();
- if (dcId <= 0 || dcId >= kDcShift || !host.setAddress(ip) || port <= 0) {
- return error();
- }
- auto flags = Flags(0);
- if (host.protocol() == QAbstractSocket::IPv6Protocol) {
- flags |= Flag::f_ipv6;
- }
- for (auto &option : components.mid(3)) {
- if (option.startsWith('#')) {
- break;
- } else if (option == u"tcpo_only"_q) {
- flags |= Flag::f_tcpo_only;
- } else if (option == u"media_only"_q) {
- flags |= Flag::f_media_only;
- } else {
- return error();
- }
- }
- options.push_back(MTP_dcOption(
- MTP_flags(flags),
- MTP_int(dcId),
- MTP_string(ip),
- MTP_int(port),
- MTPbytes()));
- }
- if (options.isEmpty()) {
- LOG(("MTP Error: in .tdesktop-endpoints expected at least one endpoint being provided."));
- return false;
- }
- _immutable = false;
- setFromList(MTP_vector<MTPDcOption>(options));
- _immutable = true;
- return true;
- }
- bool DcOptions::writeToFile(const QString &path) const {
- QFile f(path);
- if (!f.open(QIODevice::WriteOnly)) {
- return false;
- }
- QTextStream stream(&f);
- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- stream.setCodec("UTF-8");
- #endif // Qt < 6.0.0
- ReadLocker lock(this);
- for (const auto &item : _data) {
- for (const auto &option : item.second) {
- stream
- << option.id
- << ' '
- << QString::fromStdString(option.ip)
- << ' ' << option.port;
- if (option.flags & Flag::f_tcpo_only) {
- stream << " tcpo_only";
- }
- if (option.flags & Flag::f_media_only) {
- stream << " media_only";
- }
- stream << '\n';
- }
- }
- return true;
- }
- } // namespace MTP
|