Move some more code to lib_mtproto.

This commit is contained in:
John Preston 2019-12-02 16:10:19 +03:00
parent 718de09aa6
commit 91f50e8bdc
51 changed files with 792 additions and 752 deletions

View File

@ -1059,7 +1059,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
item.state = ItemState::Checking;
const auto setup = [&](Checker &checker, const bytes::vector &secret) {
checker = MTP::internal::AbstractConnection::Create(
checker = MTP::details::AbstractConnection::Create(
mtproto,
type,
QThread::currentThread(),
@ -1107,7 +1107,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
}
void ProxiesBoxController::setupChecker(int id, const Checker &checker) {
using Connection = MTP::internal::AbstractConnection;
using Connection = MTP::details::AbstractConnection;
const auto pointer = checker.get();
pointer->connect(pointer, &Connection::connected, [=] {
const auto item = findById(id);

View File

@ -75,7 +75,7 @@ public:
~ProxiesBoxController();
private:
using Checker = MTP::internal::ConnectionPointer;
using Checker = MTP::details::ConnectionPointer;
struct Item {
int id = 0;
ProxyData data;

View File

@ -14,7 +14,7 @@ from generate_tl import generate
generate({
'namespaces': {
'creator': 'MTP::internal',
'creator': 'MTP::details',
},
'prefixes': {
'type': 'MTP',

View File

@ -184,9 +184,9 @@ void Application::run() {
style::ShortAnimationPlaying(
) | rpl::start_with_next([=](bool playing) {
if (playing) {
MTP::internal::pause();
MTP::details::pause();
} else {
MTP::internal::unpause();
MTP::details::unpause();
}
}, _lifetime);

View File

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/concurrent_sender.h"
#include "mtproto/mtproto_concurrent_sender.h"
namespace Export {
namespace Data {

View File

@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/type_traits.h"
#include "base/observer.h"
#include "base/call_delayed.h"
#include "ui/effects/animation_value.h"
#include "mtproto/mtproto_proxy_data.h"
class History;

View File

@ -7,14 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/config_loader.h"
#include "mtproto/special_config_request.h"
#include "mtproto/facade.h"
#include "mtproto/dc_options.h"
#include "mtproto/mtp_instance.h"
#include "mtproto/special_config_request.h"
#include "facades.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
@ -215,5 +215,5 @@ void ConfigLoader::specialConfigLoaded(const MTPConfig &result) {
_instance->dcOptions()->setFromList(data.vdc_options());
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -14,10 +14,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace MTP {
class SpecialConfigRequest;
class Instance;
namespace internal {
namespace details {
class SpecialConfigRequest;
class ConfigLoader : public base::has_weak_ptr {
public:
@ -76,5 +77,5 @@ inline bool operator==(const ConfigLoader::SpecialEndpoint &a, const ConfigLoade
return (a.dcId == b.dcId) && (a.ip == b.ip) && (a.port == b.port);
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/openssl_help.h"
namespace MTP {
namespace internal {
namespace details {
ConnectionPointer::ConnectionPointer() = default;
@ -194,5 +194,5 @@ uint32 AbstractConnection::extendedNotSecurePadding() const {
: 0;
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -18,7 +18,7 @@ namespace MTP {
class Instance;
namespace internal {
namespace details {
struct ConnectionOptions;
@ -195,5 +195,5 @@ mtpBuffer AbstractConnection::prepareNotSecurePacket(
return result;
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_url.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kForceHttpPort = 80;
@ -246,5 +246,5 @@ QUrl HttpConnection::url() const {
return QUrl(pattern.arg(_address).arg(kForceHttpPort));
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtNetwork/QNetworkReply>
namespace MTP {
namespace internal {
namespace details {
class HttpConnection : public AbstractConnection {
public:
@ -64,5 +64,5 @@ private:
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtp_instance.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kOneConnectionTimeout = 4000;
@ -256,5 +256,5 @@ QString ResolvingConnection::tag() const {
return _child ? _child->tag() : QString();
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
namespace MTP {
namespace internal {
namespace details {
class ResolvingConnection : public AbstractConnection {
public:
@ -67,5 +67,5 @@ private:
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/connection_tcp.h"
#include "mtproto/mtproto_abstract_socket.h"
#include "mtproto/details/mtproto_abstract_socket.h"
#include "base/bytes.h"
#include "base/openssl_help.h"
#include "base/qthelp_url.h"
@ -17,7 +17,7 @@ extern "C" {
} // extern "C"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kPacketSizeMax = int(0x01000000 * sizeof(mtpPrime));
@ -665,5 +665,5 @@ void TcpConnection::socketError() {
TcpConnection::~TcpConnection() = default;
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtproto_auth_key.h"
namespace MTP {
namespace internal {
namespace details {
class AbstractSocket;
@ -98,5 +98,5 @@ private:
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -7,13 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/dc_options.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "mtproto/facade.h"
#include "storage/serialize_common.h"
#include "mtproto/connection_tcp.h"
#include "storage/serialize_common.h"
namespace MTP {
namespace {
using namespace details;
const char *(PublicRSAKeys[]) = { "\
-----BEGIN RSA PUBLIC KEY-----\n\
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\
@ -102,6 +105,8 @@ DcOptions::DcOptions() {
constructFromBuiltIn();
}
DcOptions::~DcOptions() = default;
bool DcOptions::ValidateSecret(bytes::const_span secret) {
// See also TcpConnection::Protocol::Create.
return (secret.size() >= 21 && secret[0] == bytes::type(0xEE))
@ -113,7 +118,7 @@ bool DcOptions::ValidateSecret(bytes::const_span secret) {
void DcOptions::readBuiltInPublicKeys() {
for (const auto key : PublicRSAKeys) {
const auto keyBytes = bytes::make_span(key, strlen(key));
auto parsed = internal::RSAPublicKey(keyBytes);
auto parsed = RSAPublicKey(keyBytes);
if (parsed.valid()) {
_publicKeys.emplace(parsed.fingerprint(), std::move(parsed));
} else {
@ -512,7 +517,7 @@ void DcOptions::constructFromSerialized(const QByteArray &serialized) {
return;
}
auto key = internal::RSAPublicKey(n, e);
auto key = RSAPublicKey(n, e);
if (key.valid()) {
_cdnPublicKeys[dcId].emplace(key.fingerprint(), std::move(key));
} else {
@ -569,7 +574,7 @@ void DcOptions::setCDNConfig(const MTPDcdnConfig &config) {
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 = internal::RSAPublicKey(keyBytes);
auto key = RSAPublicKey(keyBytes);
if (key.valid()) {
_cdnPublicKeys[data.vdc_id().v].emplace(
key.fingerprint(),
@ -590,18 +595,17 @@ bool DcOptions::hasCDNKeysForDc(DcId dcId) const {
return _cdnPublicKeys.find(dcId) != _cdnPublicKeys.cend();
}
internal::RSAPublicKey DcOptions::getDcRSAKey(
RSAPublicKey DcOptions::getDcRSAKey(
DcId dcId,
const QVector<MTPlong> &fingerprints) const {
const auto findKey = [&](
const std::map<uint64, internal::RSAPublicKey> &keys) {
const auto findKey = [&](const std::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 internal::RSAPublicKey();
return RSAPublicKey();
};
{
ReadLocker lock(this);

View File

@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/observer.h"
#include "base/bytes.h"
#include "mtproto/mtproto_rsa_public_key.h"
#include <QtCore/QReadWriteLock>
#include <string>
@ -18,6 +17,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <set>
namespace MTP {
namespace details {
class RSAPublicKey;
} // namespace details
enum class DcType {
Regular,
@ -52,6 +54,7 @@ public:
};
DcOptions();
~DcOptions();
[[nodiscard]] static bool ValidateSecret(bytes::const_span secret);
@ -95,7 +98,7 @@ public:
void setCDNConfig(const MTPDcdnConfig &config);
[[nodiscard]] bool hasCDNKeysForDc(DcId dcId) const;
[[nodiscard]] internal::RSAPublicKey getDcRSAKey(
[[nodiscard]] details::RSAPublicKey getDcRSAKey(
DcId dcId,
const QVector<MTPlong> &fingerprints) const;
@ -137,8 +140,8 @@ private:
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;
std::map<uint64, details::RSAPublicKey> _publicKeys;
std::map<DcId, std::map<uint64, details::RSAPublicKey>> _cdnPublicKeys;
mutable QReadWriteLock _useThroughLockers;
rpl::event_stream<DcId> _changed;

View File

@ -5,13 +5,12 @@ 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_abstract_socket.h"
#include "mtproto/details/mtproto_abstract_socket.h"
#include "mtproto/mtproto_tcp_socket.h"
#include "mtproto/mtproto_tls_socket.h"
#include "mtproto/details/mtproto_tcp_socket.h"
#include "mtproto/details/mtproto_tls_socket.h"
namespace MTP {
namespace internal {
namespace MTP::details {
std::unique_ptr<AbstractSocket> AbstractSocket::Create(
not_null<QThread*> thread,
@ -24,5 +23,4 @@ std::unique_ptr<AbstractSocket> AbstractSocket::Create(
}
}
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -10,8 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/bytes.h"
#include "base/basic_types.h"
namespace MTP {
namespace internal {
namespace MTP::details {
class AbstractSocket : protected QObject {
public:
@ -62,5 +61,4 @@ protected:
};
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/details/mtproto_dc_key_creator.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "mtproto/connection_abstract.h"
#include "mtproto/mtproto_dh_utils.h"
#include "base/openssl_help.h"

View File

@ -19,8 +19,6 @@ class DcOptions;
namespace MTP::details {
using namespace ::MTP::internal;
struct DcKeyRequest {
TimeId temporaryExpiresIn = 0;
bool persistentNeeded = false;

View File

@ -5,17 +5,16 @@ 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/dcenter.h"
#include "mtproto/details/mtproto_dcenter.h"
#include "mtproto/facade.h"
#include "mtproto/mtproto_auth_key.h"
#include "mtproto/dc_options.h"
#include "mtproto/mtp_instance.h"
#include "mtproto/special_config_request.h"
#include "storage/localstorage.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
@ -165,5 +164,5 @@ void Dcenter::releaseKeyCreationOnFail(CreatingKeyType type) {
_creatingKeys[IndexByType(type)] = false;
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -7,13 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <QtCore/QReadWriteLock>
namespace MTP {
class Instance;
class AuthKey;
using AuthKeyPtr = std::shared_ptr<AuthKey>;
namespace internal {
namespace details {
enum class TemporaryKeyType {
Regular,
@ -61,5 +63,5 @@ private:
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -0,0 +1,362 @@
/*
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/details/mtproto_domain_resolver.h"
#include "base/openssl_help.h"
#include "base/invoke_queued.h"
#include "base/call_delayed.h"
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <range/v3/algorithm/shuffle.hpp>
#include <range/v3/algorithm/reverse.hpp>
#include <range/v3/algorithm/remove.hpp>
#include <random>
namespace MTP::details {
namespace {
constexpr auto kSendNextTimeout = crl::time(800);
constexpr auto kMinTimeToLive = 10 * crl::time(1000);
constexpr auto kMaxTimeToLive = 300 * crl::time(1000);
} // namespace
const std::vector<QString> &DnsDomains() {
static const auto kResult = std::vector<QString>{
"google.com",
"www.google.com",
"google.ru",
"www.google.ru",
};
return kResult;
}
QString GenerateDnsRandomPadding() {
constexpr char kValid[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
auto result = QString();
const auto count = [&] {
constexpr auto kMinPadding = 13;
constexpr auto kMaxPadding = 128;
while (true) {
const auto result = 1 + (openssl::RandomValue<uchar>() / 2);
Assert(result <= kMaxPadding);
if (result >= kMinPadding) {
return result;
}
}
}();
result.resize(count);
for (auto &ch : result) {
ch = kValid[openssl::RandomValue<uchar>() % (sizeof(kValid) - 1)];
}
return result;
}
QByteArray DnsUserAgent() {
static const auto kResult = QByteArray(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/77.0.3865.90 Safari/537.36");
return kResult;
}
std::vector<DnsEntry> ParseDnsResponse(
const QByteArray &bytes,
std::optional<int> typeRestriction) {
// Read and store to "result" all the data bytes from the response:
// { ..,
// "Answer": [
// { .., "data": "bytes1", "TTL": int, .. },
// { .., "data": "bytes2", "TTL": int, .. }
// ],
// .. }
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
const auto document = QJsonDocument::fromJson(bytes, &error);
if (error.error != QJsonParseError::NoError) {
LOG(("Config Error: Failed to parse dns response JSON, error: %1"
).arg(error.errorString()));
return {};
} else if (!document.isObject()) {
LOG(("Config Error: Not an object received in dns response JSON."));
return {};
}
const auto response = document.object();
const auto answerIt = response.find("Answer");
if (answerIt == response.constEnd()) {
LOG(("Config Error: Could not find Answer in dns response JSON."));
return {};
} else if (!(*answerIt).isArray()) {
LOG(("Config Error: Not an array received "
"in Answer in dns response JSON."));
return {};
}
auto result = std::vector<DnsEntry>();
for (const auto elem : (*answerIt).toArray()) {
if (!elem.isObject()) {
LOG(("Config Error: Not an object found "
"in Answer array in dns response JSON."));
continue;
}
const auto object = elem.toObject();
if (typeRestriction) {
const auto typeIt = object.find("type");
const auto type = int(std::round((*typeIt).toDouble()));
if (!(*typeIt).isDouble()) {
LOG(("Config Error: Not a number in type field "
"in Answer array in dns response JSON."));
continue;
} else if (type != *typeRestriction) {
continue;
}
}
const auto dataIt = object.find("data");
if (dataIt == object.constEnd()) {
LOG(("Config Error: Could not find data "
"in Answer array entry in dns response JSON."));
continue;
} else if (!(*dataIt).isString()) {
LOG(("Config Error: Not a string data found "
"in Answer array entry in dns response JSON."));
continue;
}
const auto ttlIt = object.find("TTL");
const auto ttl = (ttlIt != object.constEnd())
? crl::time(std::round((*ttlIt).toDouble()))
: crl::time(0);
result.push_back({ (*dataIt).toString(), ttl });
}
return result;
}
ServiceWebRequest::ServiceWebRequest(not_null<QNetworkReply*> reply)
: reply(reply.get()) {
}
ServiceWebRequest::ServiceWebRequest(ServiceWebRequest &&other)
: reply(base::take(other.reply)) {
}
ServiceWebRequest &ServiceWebRequest::operator=(ServiceWebRequest &&other) {
if (reply != other.reply) {
destroy();
reply = base::take(other.reply);
}
return *this;
}
void ServiceWebRequest::destroy() {
if (const auto value = base::take(reply)) {
value->disconnect(
value,
&QNetworkReply::finished,
nullptr,
nullptr);
value->abort();
value->deleteLater();
}
}
ServiceWebRequest::~ServiceWebRequest() {
if (reply) {
reply->deleteLater();
}
}
DomainResolver::DomainResolver(Fn<void(
const QString &host,
const QStringList &ips,
crl::time expireAt)> callback)
: _callback(std::move(callback)) {
_manager.setProxy(QNetworkProxy::NoProxy);
}
void DomainResolver::resolve(const QString &domain) {
resolve({ domain, false });
resolve({ domain, true });
}
void DomainResolver::resolve(const AttemptKey &key) {
if (_attempts.find(key) != end(_attempts)) {
return;
} else if (_requests.find(key) != end(_requests)) {
return;
}
const auto i = _cache.find(key);
_lastTimestamp = crl::now();
if (i != end(_cache) && i->second.expireAt > _lastTimestamp) {
checkExpireAndPushResult(key.domain);
return;
}
auto attempts = std::vector<Attempt>();
auto domains = DnsDomains();
std::random_device rd;
ranges::shuffle(domains, std::mt19937(rd()));
const auto takeDomain = [&] {
const auto result = domains.back();
domains.pop_back();
return result;
};
const auto shuffle = [&](int from, int till) {
Expects(till > from);
ranges::shuffle(
begin(attempts) + from,
begin(attempts) + till,
std::mt19937(rd()));
};
attempts.push_back({ Type::Google, "dns.google.com" });
attempts.push_back({ Type::Google, takeDomain(), "dns" });
attempts.push_back({ Type::Mozilla, "mozilla.cloudflare-dns.com" });
while (!domains.empty()) {
attempts.push_back({ Type::Google, takeDomain(), "dns" });
}
shuffle(0, 2);
ranges::reverse(attempts); // We go from last to first.
_attempts.emplace(key, Attempts{ std::move(attempts) });
sendNextRequest(key);
}
void DomainResolver::checkExpireAndPushResult(const QString &domain) {
const auto ipv4 = _cache.find({ domain, false });
if (ipv4 == end(_cache) || ipv4->second.expireAt <= _lastTimestamp) {
return;
}
auto result = ipv4->second;
const auto ipv6 = _cache.find({ domain, true });
if (ipv6 != end(_cache) && ipv6->second.expireAt > _lastTimestamp) {
result.ips.append(ipv6->second.ips);
accumulate_min(result.expireAt, ipv6->second.expireAt);
}
InvokeQueued(this, [=] {
_callback(domain, result.ips, result.expireAt);
});
}
void DomainResolver::sendNextRequest(const AttemptKey &key) {
auto i = _attempts.find(key);
if (i == end(_attempts)) {
return;
}
auto &attempts = i->second;
auto &list = attempts.list;
const auto attempt = list.back();
list.pop_back();
if (!list.empty()) {
base::call_delayed(kSendNextTimeout, &attempts.guard, [=] {
sendNextRequest(key);
});
}
performRequest(key, attempt);
}
void DomainResolver::performRequest(
const AttemptKey &key,
const Attempt &attempt) {
auto url = QUrl();
url.setScheme("https");
auto request = QNetworkRequest();
switch (attempt.type) {
case Type::Mozilla: {
url.setHost(attempt.data);
url.setPath("/dns-query");
url.setQuery(QStringLiteral("name=%1&type=%2&random_padding=%3"
).arg(key.domain
).arg(key.ipv6 ? 28 : 1
).arg(GenerateDnsRandomPadding()));
request.setRawHeader("accept", "application/dns-json");
} break;
case Type::Google: {
url.setHost(attempt.data);
url.setPath("/resolve");
url.setQuery(QStringLiteral("name=%1&type=%2&random_padding=%3"
).arg(key.domain
).arg(key.ipv6 ? 28 : 1
).arg(GenerateDnsRandomPadding()));
if (!attempt.host.isEmpty()) {
const auto host = attempt.host + ".google.com";
request.setRawHeader("Host", host.toLatin1());
}
} break;
default: Unexpected("Type in SpecialConfigRequest::performRequest.");
}
request.setUrl(url);
request.setRawHeader("User-Agent", DnsUserAgent());
const auto i = _requests.emplace(
key,
std::vector<ServiceWebRequest>()).first;
const auto reply = i->second.emplace_back(
_manager.get(request)
).reply;
connect(reply, &QNetworkReply::finished, this, [=] {
requestFinished(key, reply);
});
}
void DomainResolver::requestFinished(
const AttemptKey &key,
not_null<QNetworkReply*> reply) {
const auto result = finalizeRequest(key, reply);
const auto response = ParseDnsResponse(result);
if (response.empty()) {
return;
}
_requests.erase(key);
_attempts.erase(key);
auto entry = CacheEntry();
auto ttl = kMaxTimeToLive;
for (const auto &item : response) {
entry.ips.push_back(item.data);
ttl = std::min(
ttl,
std::max(item.TTL * crl::time(1000), kMinTimeToLive));
}
_lastTimestamp = crl::now();
entry.expireAt = _lastTimestamp + ttl;
_cache[key] = std::move(entry);
checkExpireAndPushResult(key.domain);
}
QByteArray DomainResolver::finalizeRequest(
const AttemptKey &key,
not_null<QNetworkReply*> reply) {
if (reply->error() != QNetworkReply::NoError) {
LOG(("Resolve Error: Failed to get response, error: %2 (%3)"
).arg(reply->errorString()
).arg(reply->error()));
}
const auto result = reply->readAll();
const auto i = _requests.find(key);
if (i != end(_requests)) {
auto &requests = i->second;
const auto from = ranges::remove(
requests,
reply,
[](const ServiceWebRequest &request) { return request.reply; });
requests.erase(from, end(requests));
if (requests.empty()) {
_requests.erase(i);
}
}
return result;
}
} // namespace MTP::details

View File

@ -0,0 +1,106 @@
/*
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
*/
#pragma once
#include "base/weak_ptr.h"
#include <QtCore/QPointer>
#include <QtNetwork/QNetworkReply>
#include <optional>
namespace MTP::details {
[[nodiscard]] const std::vector<QString> &DnsDomains();
[[nodiscard]] QString GenerateDnsRandomPadding();
[[nodiscard]] QByteArray DnsUserAgent();
struct DnsEntry {
QString data;
crl::time TTL = 0;
};
[[nodiscard]] std::vector<DnsEntry> ParseDnsResponse(
const QByteArray &bytes,
std::optional<int> typeRestriction = std::nullopt);
struct ServiceWebRequest {
ServiceWebRequest(not_null<QNetworkReply*> reply);
ServiceWebRequest(ServiceWebRequest &&other);
ServiceWebRequest &operator=(ServiceWebRequest &&other);
~ServiceWebRequest();
void destroy();
QPointer<QNetworkReply> reply;
};
class DomainResolver : public QObject {
public:
DomainResolver(Fn<void(
const QString &domain,
const QStringList &ips,
crl::time expireAt)> callback);
void resolve(const QString &domain);
private:
enum class Type {
Mozilla,
Google,
};
struct Attempt {
Type type;
QString data;
QString host;
};
struct AttemptKey {
QString domain;
bool ipv6 = false;
inline bool operator<(const AttemptKey &other) const {
return (domain < other.domain)
|| (domain == other.domain && !ipv6 && other.ipv6);
}
inline bool operator==(const AttemptKey &other) const {
return (domain == other.domain) && (ipv6 == other.ipv6);
}
};
struct CacheEntry {
QStringList ips;
crl::time expireAt = 0;
};
struct Attempts {
std::vector<Attempt> list;
base::has_weak_ptr guard;
};
void resolve(const AttemptKey &key);
void sendNextRequest(const AttemptKey &key);
void performRequest(const AttemptKey &key, const Attempt &attempt);
void checkExpireAndPushResult(const QString &domain);
void requestFinished(
const AttemptKey &key,
not_null<QNetworkReply*> reply);
QByteArray finalizeRequest(
const AttemptKey &key,
not_null<QNetworkReply*> reply);
Fn<void(
const QString &domain,
const QStringList &ips,
crl::time expireAt)> _callback;
QNetworkAccessManager _manager;
std::map<AttemptKey, Attempts> _attempts;
std::map<AttemptKey, std::vector<ServiceWebRequest>> _requests;
std::map<AttemptKey, CacheEntry> _cache;
crl::time _lastTimestamp = 0;
};
} // namespace MTP::details

View File

@ -5,12 +5,11 @@ 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_rsa_public_key.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "base/openssl_help.h"
namespace MTP {
namespace internal {
namespace MTP::details {
namespace {
#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
@ -292,5 +291,4 @@ bytes::vector RSAPublicKey::encryptOAEPpadding(
return _private->encryptOAEPpadding(data);
}
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -9,8 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/bytes.h"
namespace MTP {
namespace internal {
namespace MTP::details {
// this class holds an RSA public key and can encrypt fixed-size messages with it
class RSAPublicKey final {
@ -47,5 +46,4 @@ private:
};
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -11,7 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <crl/crl_time.h>
namespace MTP::details {
namespace MTP {
namespace details {
class RequestData;
class SerializedRequest;
@ -44,7 +45,7 @@ public:
template <
typename Request,
typename = std::enable_if_t<tl::is_boxed_v<Request>>>
static SerializedRequest Serialize(const Request &request);
static SerializedRequest Serialize(const Request &request);
// For template MTP requests and MTPBoxed instantiation.
template <typename Accumulator>
@ -102,4 +103,5 @@ SerializedRequest SerializedRequest::Serialize(const Request &request) {
return serialized;
}
} // namespace MTP::details
} // namespace details
} // namespace MTP

View File

@ -5,12 +5,11 @@ 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_tcp_socket.h"
#include "mtproto/details/mtproto_tcp_socket.h"
#include "base/invoke_queued.h"
namespace MTP {
namespace internal {
namespace MTP::details {
TcpSocket::TcpSocket(not_null<QThread*> thread, const QNetworkProxy &proxy)
: AbstractSocket(thread) {
@ -153,5 +152,4 @@ void TcpSocket::handleError(int errorCode) {
_error.fire({});
}
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -7,10 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/mtproto_abstract_socket.h"
#include "mtproto/details/mtproto_abstract_socket.h"
namespace MTP {
namespace internal {
namespace MTP::details {
class TcpSocket final : public AbstractSocket {
public:
@ -35,5 +34,4 @@ private:
};
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -5,9 +5,9 @@ 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_tls_socket.h"
#include "mtproto/details/mtproto_tls_socket.h"
#include "mtproto/mtproto_tcp_socket.h"
#include "mtproto/details/mtproto_tcp_socket.h"
#include "base/openssl_help.h"
#include "base/bytes.h"
#include "base/invoke_queued.h"
@ -16,8 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QtEndian>
#include <range/v3/algorithm/reverse.hpp>
namespace MTP {
namespace internal {
namespace MTP::details {
namespace {
constexpr auto kMaxGrease = 8;
@ -778,5 +777,4 @@ void TlsSocket::handleError(int errorCode) {
_error.fire({});
}
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -7,10 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/mtproto_abstract_socket.h"
#include "mtproto/details/mtproto_abstract_socket.h"
namespace MTP {
namespace internal {
namespace MTP::details {
class TlsSocket final : public AbstractSocket {
public:
@ -64,5 +63,4 @@ private:
};
} // namespace internal
} // namespace MTP
} // namespace MTP::details

View File

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_account.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
int PauseLevel = 0;
@ -36,7 +36,7 @@ void unpause() {
}
}
} // namespace internal
} // namespace details
Instance *MainInstance() {
return Core::IsAppLaunched()

View File

@ -11,13 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtp_instance.h"
namespace MTP {
namespace internal {
namespace details {
[[nodiscard]] bool paused();
void pause();
void unpause();
} // namespace internal
} // namespace details
// send(MTPhelp_GetConfig(), MTP::configDcId(dc)) - for dc enumeration
constexpr ShiftedDcId configDcId(DcId dcId) {
@ -37,23 +37,24 @@ constexpr ShiftedDcId updaterDcId(DcId dcId) {
constexpr auto kDownloadSessionsCount = 2;
constexpr auto kUploadSessionsCount = 2;
namespace internal {
namespace details {
constexpr ShiftedDcId downloadDcId(DcId dcId, int index) {
static_assert(kDownloadSessionsCount < kMaxMediaDcCount, "Too large MTPDownloadSessionsCount!");
return ShiftDcId(dcId, kBaseDownloadDcShift + index);
};
} // namespace internal
} // namespace details
// send(req, callbacks, MTP::downloadDcId(dc, index)) - for download shifted dc id
inline ShiftedDcId downloadDcId(DcId dcId, int index) {
Expects(index >= 0 && index < kDownloadSessionsCount);
return internal::downloadDcId(dcId, index);
return details::downloadDcId(dcId, index);
}
inline constexpr bool isDownloadDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::downloadDcId(0, 0)) && (shiftedDcId < internal::downloadDcId(0, kDownloadSessionsCount - 1) + kDcShift);
return (shiftedDcId >= details::downloadDcId(0, 0))
&& (shiftedDcId < details::downloadDcId(0, kDownloadSessionsCount - 1) + kDcShift);
}
inline bool isCdnDc(MTPDdcOption::Flags flags) {
@ -75,25 +76,26 @@ inline DcId getTemporaryIdFromRealDcId(ShiftedDcId shiftedDcId) {
return (dcId < Instance::Config::kTemporaryMainDc) ? (dcId + Instance::Config::kTemporaryMainDc) : 0;
}
namespace internal {
namespace details {
constexpr ShiftedDcId uploadDcId(DcId dcId, int index) {
static_assert(kUploadSessionsCount < kMaxMediaDcCount, "Too large MTPUploadSessionsCount!");
return ShiftDcId(dcId, kBaseUploadDcShift + index);
};
} // namespace internal
} // namespace details
// send(req, callbacks, MTP::uploadDcId(index)) - for upload shifted dc id
// uploading always to the main dc so BareDcId(result) == 0
inline ShiftedDcId uploadDcId(int index) {
Expects(index >= 0 && index < kUploadSessionsCount);
return internal::uploadDcId(0, index);
return details::uploadDcId(0, index);
};
constexpr bool isUploadDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, kUploadSessionsCount - 1) + kDcShift);
return (shiftedDcId >= details::uploadDcId(0, 0))
&& (shiftedDcId < details::uploadDcId(0, kUploadSessionsCount - 1) + kDcShift);
}
inline ShiftedDcId destroyKeyNextDcId(ShiftedDcId shiftedDcId) {

View File

@ -7,14 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/mtp_instance.h"
#include "mtproto/details/mtproto_dcenter.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "mtproto/special_config_request.h"
#include "mtproto/session.h"
#include "mtproto/dc_options.h"
#include "mtproto/dcenter.h"
#include "mtproto/config_loader.h"
#include "mtproto/special_config_request.h"
#include "mtproto/connection.h"
#include "mtproto/sender.h"
#include "mtproto/mtproto_rsa_public_key.h"
#include "storage/localstorage.h"
#include "calls/calls_instance.h"
#include "main/main_session.h" // Session::Exists.
@ -35,14 +34,13 @@ constexpr auto kConfigBecomesOldIn = 2 * 60 * crl::time(1000);
constexpr auto kConfigBecomesOldForBlockedIn = 8 * crl::time(1000);
constexpr auto kCheckKeyEach = 60 * crl::time(1000);
using namespace internal;
using namespace details;
std::atomic<int> GlobalAtomicRequestId = 0;
} // namespace
namespace internal {
namespace details {
int GetNextRequestId() {
const auto result = ++GlobalAtomicRequestId;
@ -52,7 +50,7 @@ int GetNextRequestId() {
return result;
}
} // namespace internal
} // namespace details
class Instance::Private : private Sender {
public:

View File

@ -11,14 +11,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/details/mtproto_serialized_request.h"
namespace MTP {
namespace internal {
namespace details {
class Dcenter;
class Session;
[[nodiscard]] int GetNextRequestId();
} // namespace internal
} // namespace details
class DcOptions;
class AuthKey;
@ -131,7 +131,7 @@ public:
ShiftedDcId shiftedDcId = 0,
crl::time msCanWait = 0,
mtpRequestId afterRequestId = 0) {
const auto requestId = internal::GetNextRequestId();
const auto requestId = details::GetNextRequestId();
sendSerialized(
requestId,
details::SerializedRequest::Serialize(request),
@ -162,7 +162,7 @@ public:
mtpRequestId sendProtocolMessage(
ShiftedDcId shiftedDcId,
const Request &request) {
const auto requestId = internal::GetNextRequestId();
const auto requestId = details::GetNextRequestId();
sendRequest(
requestId,
details::SerializedRequest::Serialize(request),

View File

@ -5,7 +5,7 @@ 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/concurrent_sender.h"
#include "mtproto/mtproto_concurrent_sender.h"
#include "mtproto/mtp_instance.h"
#include "mtproto/mtproto_rpc_sender.h"
@ -135,7 +135,7 @@ void ConcurrentSender::RequestBuilder::setAfter(
}
mtpRequestId ConcurrentSender::RequestBuilder::send() {
const auto requestId = internal::GetNextRequestId();
const auto requestId = details::GetNextRequestId();
const auto dcId = _dcId;
const auto msCanWait = _canWait;
const auto afterRequestId = _afterRequestId;

View File

@ -7,13 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/details/callable.h>
#include "base/bytes.h"
#include "base/weak_ptr.h"
#include "base/flat_map.h"
#include "mtproto/core_types.h"
#include "mtproto/details/mtproto_serialized_request.h"
#include <rpl/details/callable.h>
#ifndef _DEBUG
#define MTP_SENDER_USE_GENERIC_HANDLERS
#endif // !_DEBUG

View File

@ -7,18 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/session.h"
#include "mtproto/connection.h"
#include "mtproto/dcenter.h"
#include "mtproto/details/mtproto_dcenter.h"
#include "mtproto/session_private.h"
#include "mtproto/mtproto_auth_key.h"
#include "base/unixtime.h"
#include "base/openssl_help.h"
#include "core/crash_reports.h"
#include "facades.h"
namespace MTP {
namespace internal {
namespace details {
ConnectionOptions::ConnectionOptions(
SessionOptions::SessionOptions(
const QString &systemLangCode,
const QString &cloudLangCode,
const QString &langPackName,
@ -50,9 +49,9 @@ void SessionData::withSession(Callback &&callback) {
}
}
void SessionData::notifyConnectionInited(const ConnectionOptions &options) {
void SessionData::notifyConnectionInited(const SessionOptions &options) {
// #TODO race
const auto current = connectionOptions();
const auto current = this->options();
if (current.cloudLangCode == _options.cloudLangCode
&& current.systemLangCode == _options.systemLangCode
&& current.langPackName == _options.langPackName
@ -163,7 +162,7 @@ Session::Session(
}
Session::~Session() {
Expects(!_connection);
Expects(!_private);
if (_myKeyCreation != CreatingKeyType::None) {
releaseKeyCreationOnFail();
@ -177,11 +176,11 @@ void Session::watchDcKeyChanges() {
}) | rpl::start_with_next([=] {
DEBUG_LOG(("AuthKey Info: dcTemporaryKeyChanged in Session %1"
).arg(_shiftedDcId));
if (const auto connection = _connection) {
InvokeQueued(connection, [=] {
if (const auto captured = _private) {
InvokeQueued(captured, [=] {
DEBUG_LOG(("AuthKey Info: calling Connection::updateAuthKey in Session %1"
).arg(_shiftedDcId));
connection->updateAuthKey();
captured->updateAuthKey();
});
}
}, _lifetime);
@ -190,20 +189,20 @@ void Session::watchDcKeyChanges() {
void Session::watchDcOptionsChanges() {
_instance->dcOptions()->changed(
) | rpl::filter([=](DcId dcId) {
return (BareDcId(_shiftedDcId) == dcId) && (_connection != nullptr);
return (BareDcId(_shiftedDcId) == dcId) && (_private != nullptr);
}) | rpl::start_with_next([=] {
InvokeQueued(_connection, [connection = _connection] {
connection->dcOptionsChanged();
InvokeQueued(_private, [captured = _private] {
captured->dcOptionsChanged();
});
}, _lifetime);
if (_instance->dcOptions()->dcType(_shiftedDcId) == DcType::Cdn) {
_instance->dcOptions()->cdnConfigChanged(
) | rpl::filter([=] {
return (_connection != nullptr);
return (_private != nullptr);
}) | rpl::start_with_next([=] {
InvokeQueued(_connection, [connection = _connection] {
connection->cdnConfigChanged();
InvokeQueued(_private, [captured = _private] {
captured->cdnConfigChanged();
});
}, _lifetime);
}
@ -211,7 +210,7 @@ void Session::watchDcOptionsChanges() {
void Session::start() {
killConnection();
_connection = new Connection(
_private = new SessionPrivate(
_instance,
_thread.get(),
_data,
@ -231,9 +230,9 @@ void Session::restart() {
return;
}
refreshOptions();
if (const auto connection = _connection) {
InvokeQueued(connection, [=] {
connection->restartNow();
if (const auto captured = _private) {
InvokeQueued(captured, [=] {
captured->restartNow();
});
}
}
@ -248,7 +247,7 @@ void Session::refreshOptions() {
const auto useHttp = (proxyType != ProxyData::Type::Mtproto);
const auto useIPv4 = true;
const auto useIPv6 = Global::TryIPv6();
_data->setConnectionOptions(ConnectionOptions(
_data->setOptions(SessionOptions(
_instance->systemLangCode(),
_instance->cloudLangCode(),
_instance->langPackName(),
@ -326,17 +325,17 @@ void Session::needToResumeAndSend() {
DEBUG_LOG(("Session Info: can't resume a killed session"));
return;
}
if (!_connection) {
if (!_private) {
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(_shiftedDcId));
start();
}
const auto connection = _connection;
const auto captured = _private;
const auto ping = base::take(_ping);
InvokeQueued(connection, [=] {
InvokeQueued(captured, [=] {
if (ping) {
connection->sendPingForce();
captured->sendPingForce();
} else {
connection->tryToSend();
captured->tryToSend();
}
});
}
@ -369,8 +368,8 @@ int32 Session::requestState(mtpRequestId requestId) const {
int32 result = MTP::RequestSent;
bool connected = false;
if (_connection) {
const auto s = _connection->getState();
if (_private) {
const auto s = _private->getState();
if (s == ConnectedState) {
connected = true;
} else if (s == ConnectingState || s == DisconnectedState) {
@ -398,8 +397,8 @@ int32 Session::requestState(mtpRequestId requestId) const {
int32 Session::getState() const {
int32 result = -86400000;
if (_connection) {
const auto s = _connection->getState();
if (_private) {
const auto s = _private->getState();
if (s == ConnectedState) {
return s;
} else if (s == ConnectingState || s == DisconnectedState) {
@ -419,11 +418,11 @@ int32 Session::getState() const {
}
QString Session::transport() const {
return _connection ? _connection->transport() : QString();
return _private ? _private->transport() : QString();
}
void Session::sendPrepared(
const details::SerializedRequest &request,
const SerializedRequest &request,
crl::time msCanWait) {
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1"
).arg(msCanWait));
@ -563,14 +562,14 @@ void Session::tryToReceive() {
}
void Session::killConnection() {
if (!_connection) {
if (!_private) {
return;
}
base::take(_connection)->deleteLater();
base::take(_private)->deleteLater();
Ensures(_connection == nullptr);
Ensures(_private == nullptr);
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -20,17 +20,17 @@ class Instance;
class AuthKey;
using AuthKeyPtr = std::shared_ptr<AuthKey>;
namespace internal {
namespace details {
class Dcenter;
class Connection;
class SessionPrivate;
enum class TemporaryKeyType;
enum class CreatingKeyType;
struct ConnectionOptions {
ConnectionOptions() = default;
ConnectionOptions(
struct SessionOptions {
SessionOptions() = default;
SessionOptions(
const QString &systemLangCode,
const QString &cloudLangCode,
const QString &langPackName,
@ -39,8 +39,6 @@ struct ConnectionOptions {
bool useIPv6,
bool useHttp,
bool useTcp);
ConnectionOptions(const ConnectionOptions &other) = default;
ConnectionOptions &operator=(const ConnectionOptions &other) = default;
QString systemLangCode;
QString cloudLangCode;
@ -54,17 +52,17 @@ struct ConnectionOptions {
};
class Session;
class SessionData {
class SessionData final {
public:
explicit SessionData(not_null<Session*> creator) : _owner(creator) {
}
void notifyConnectionInited(const ConnectionOptions &options);
void setConnectionOptions(ConnectionOptions options) {
void notifyConnectionInited(const SessionOptions &options);
void setOptions(SessionOptions options) {
QWriteLocker locker(&_optionsLock);
_options = options;
}
[[nodiscard]] ConnectionOptions connectionOptions() const {
[[nodiscard]] SessionOptions options() const {
QReadLocker locker(&_optionsLock);
return _options;
}
@ -79,10 +77,10 @@ public:
return &_haveReceivedLock;
}
base::flat_map<mtpRequestId, details::SerializedRequest> &toSendMap() {
base::flat_map<mtpRequestId, SerializedRequest> &toSendMap() {
return _toSend;
}
base::flat_map<mtpMsgId, details::SerializedRequest> &haveSentMap() {
base::flat_map<mtpMsgId, SerializedRequest> &haveSentMap() {
return _haveSent;
}
base::flat_map<mtpRequestId, mtpBuffer> &haveReceivedResponses() {
@ -92,7 +90,7 @@ public:
return _receivedUpdates;
}
// Connection -> Session interface.
// SessionPrivate -> Session interface.
void queueTryToReceive();
void queueNeedToResumeAndSend();
void queueConnectionStateChange(int newState);
@ -118,13 +116,13 @@ private:
Session *_owner = nullptr;
mutable QMutex _ownerMutex;
ConnectionOptions _options;
SessionOptions _options;
mutable QReadWriteLock _optionsLock;
base::flat_map<mtpRequestId, details::SerializedRequest> _toSend; // map of request_id -> request, that is waiting to be sent
base::flat_map<mtpRequestId, SerializedRequest> _toSend; // map of request_id -> request, that is waiting to be sent
QReadWriteLock _toSendLock;
base::flat_map<mtpMsgId, details::SerializedRequest> _haveSent; // map of msg_id -> request, that was sent
base::flat_map<mtpMsgId, SerializedRequest> _haveSent; // map of msg_id -> request, that was sent
QReadWriteLock _haveSentLock;
base::flat_map<mtpRequestId, mtpBuffer> _receivedResponses; // map of request_id -> response that should be processed in the main thread
@ -133,7 +131,7 @@ private:
};
class Session : public QObject {
class Session final : public QObject {
public:
// Main thread.
Session(
@ -159,10 +157,10 @@ public:
[[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const;
[[nodiscard]] bool connectionInited() const;
void sendPrepared(
const details::SerializedRequest &request,
const SerializedRequest &request,
crl::time msCanWait = 0);
// Connection thread.
// SessionPrivate thread.
[[nodiscard]] CreatingKeyType acquireKeyCreation(TemporaryKeyType type);
[[nodiscard]] bool releaseKeyCreationOnDone(
const AuthKeyPtr &temporaryKey,
@ -201,7 +199,7 @@ private:
const std::shared_ptr<SessionData> _data;
const not_null<QThread*> _thread;
Connection *_connection = nullptr;
SessionPrivate *_private = nullptr;
bool _killed = false;
bool _needToReceive = false;
@ -221,5 +219,5 @@ private:
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -5,26 +5,23 @@ 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/connection.h"
#include "mtproto/session_private.h"
#include "mtproto/details/mtproto_bound_key_creator.h"
#include "mtproto/details/mtproto_dcenter.h"
#include "mtproto/details/mtproto_dump_to_text.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "mtproto/session.h"
#include "mtproto/mtproto_rsa_public_key.h"
#include "mtproto/mtproto_rpc_sender.h"
#include "mtproto/dc_options.h"
#include "mtproto/dcenter.h"
#include "mtproto/connection_abstract.h"
#include "zlib.h"
#include "core/application.h"
#include "core/launcher.h"
#include "lang/lang_keys.h"
#include "base/openssl_help.h"
#include "base/qthelp_url.h"
#include "base/unixtime.h"
#include "zlib.h"
namespace MTP {
namespace internal {
namespace details {
namespace {
constexpr auto kIntSize = static_cast<int>(sizeof(mtpPrime));
@ -42,6 +39,7 @@ constexpr auto kBindKeyAdditionalExpiresTimeout = TimeId(30);
constexpr auto kTestModeDcIdShift = 10000;
constexpr auto kCheckSentRequestsEach = 1 * crl::time(1000);
constexpr auto kKeyOldEnoughForDestroy = 60 * crl::time(1000);
constexpr auto kSentContainerLives = 600 * crl::time(1000);
// If we can't connect for this time we will ask _instance to update config.
constexpr auto kRequestConfigTimeout = 8 * crl::time(1000);
@ -56,7 +54,8 @@ constexpr auto kCheckSentRequestTimeout = 10 * crl::time(1000);
// when resending request or checking its state.
constexpr auto kSendStateRequestWaiting = crl::time(1000);
constexpr auto kSentContainerLives = 600 * crl::time(1000);
// How much time to wait for some more requests, when sending msg acks.
constexpr auto kAckSendWaiting = 10 * crl::time(1000);
using namespace details;
@ -113,7 +112,7 @@ void WrapInvokeAfter(
} // namespace
Connection::Connection(
SessionPrivate::SessionPrivate(
not_null<Instance*> instance,
not_null<QThread*> thread,
std::shared_ptr<SessionData> data,
@ -144,7 +143,7 @@ Connection::Connection(
});
}
Connection::~Connection() {
SessionPrivate::~SessionPrivate() {
releaseKeyCreationOnFail();
doDisconnect();
@ -152,7 +151,7 @@ Connection::~Connection() {
Expects(_testConnections.empty());
}
void Connection::appendTestConnection(
void SessionPrivate::appendTestConnection(
DcOptions::Variants::Protocol protocol,
const QString &ip,
int port,
@ -168,7 +167,7 @@ void Connection::appendTestConnection(
protocol,
thread(),
protocolSecret,
_connectionOptions->proxy),
_options->proxy),
priority
});
const auto weak = _testConnections.back().data.get();
@ -201,7 +200,7 @@ void Connection::appendTestConnection(
});
}
int16 Connection::getProtocolDcId() const {
int16 SessionPrivate::getProtocolDcId() const {
const auto dcId = BareDcId(_shiftedDcId);
const auto simpleDcId = isTemporaryDcId(dcId)
? getRealIdFromTemporaryDcId(dcId)
@ -214,7 +213,7 @@ int16 Connection::getProtocolDcId() const {
: testedDcId;
}
void Connection::checkSentRequests() {
void SessionPrivate::checkSentRequests() {
clearOldContainers();
auto restarting = false;
@ -246,7 +245,7 @@ void Connection::checkSentRequests() {
}
}
void Connection::clearOldContainers() {
void SessionPrivate::clearOldContainers() {
auto resent = false;
const auto now = crl::now();
for (auto i = _sentContainers.begin(); i != _sentContainers.end();) {
@ -274,7 +273,7 @@ void Connection::clearOldContainers() {
}
}
void Connection::destroyAllConnections() {
void SessionPrivate::destroyAllConnections() {
clearUnboundKeyCreator();
_waitForBetterTimer.cancel();
_waitForReceivedTimer.cancel();
@ -283,20 +282,20 @@ void Connection::destroyAllConnections() {
_connection = nullptr;
}
void Connection::cdnConfigChanged() {
void SessionPrivate::cdnConfigChanged() {
connectToServer(true);
}
int32 Connection::getShiftedDcId() const {
int32 SessionPrivate::getShiftedDcId() const {
return _shiftedDcId;
}
void Connection::dcOptionsChanged() {
void SessionPrivate::dcOptionsChanged() {
_retryTimeout = 1;
connectToServer(true);
}
int32 Connection::getState() const {
int32 SessionPrivate::getState() const {
QReadLocker lock(&_stateMutex);
int32 result = _state;
if (_state < 0) {
@ -310,17 +309,17 @@ int32 Connection::getState() const {
return result;
}
QString Connection::transport() const {
QString SessionPrivate::transport() const {
QReadLocker lock(&_stateMutex);
if (!_connection || (_state < 0)) {
return QString();
}
Assert(_connectionOptions != nullptr);
Assert(_options != nullptr);
return _connection->transport();
}
bool Connection::setState(int state, int ifState) {
bool SessionPrivate::setState(int state, int ifState) {
if (ifState != kUpdateStateAlways) {
QReadLocker lock(&_stateMutex);
if (_state != ifState) {
@ -344,7 +343,7 @@ bool Connection::setState(int state, int ifState) {
return true;
}
void Connection::resetSession() {
void SessionPrivate::resetSession() {
MTP_LOG(_shiftedDcId, ("Resetting session!"));
_needSessionReset = false;
@ -354,7 +353,7 @@ void Connection::resetSession() {
_sessionData->queueResetDone();
}
void Connection::changeSessionId() {
void SessionPrivate::changeSessionId() {
auto sessionId = _sessionId;
do {
sessionId = openssl::RandomValue<uint64>();
@ -371,13 +370,13 @@ void Connection::changeSessionId() {
_receivedMessageIds.clear();
}
uint32 Connection::nextRequestSeqNumber(bool needAck) {
uint32 SessionPrivate::nextRequestSeqNumber(bool needAck) {
const auto result = _messagesCounter;
_messagesCounter += (needAck ? 1 : 0);
return result * 2 + (needAck ? 1 : 0);
}
bool Connection::realDcTypeChanged() {
bool SessionPrivate::realDcTypeChanged() {
const auto now = _instance->dcOptions()->dcType(_shiftedDcId);
if (_realDcType == now) {
return false;
@ -386,7 +385,7 @@ bool Connection::realDcTypeChanged() {
return true;
}
bool Connection::markSessionAsStarted() {
bool SessionPrivate::markSessionAsStarted() {
if (_sessionMarkedAsStarted) {
return false;
}
@ -394,7 +393,7 @@ bool Connection::markSessionAsStarted() {
return true;
}
mtpMsgId Connection::prepareToSend(
mtpMsgId SessionPrivate::prepareToSend(
SerializedRequest &request,
mtpMsgId currentLastId,
bool forceNewMsgId) {
@ -419,7 +418,7 @@ mtpMsgId Connection::prepareToSend(
return currentLastId;
}
mtpMsgId Connection::replaceMsgId(SerializedRequest &request, mtpMsgId newId) {
mtpMsgId SessionPrivate::replaceMsgId(SerializedRequest &request, mtpMsgId newId) {
Expects(request->size() > 8);
const auto oldMsgId = request.getMsgId();
@ -472,7 +471,7 @@ mtpMsgId Connection::replaceMsgId(SerializedRequest &request, mtpMsgId newId) {
return newId;
}
mtpMsgId Connection::placeToContainer(
mtpMsgId SessionPrivate::placeToContainer(
SerializedRequest &toSendRequest,
mtpMsgId &bigMsgId,
bool forceNewMsgId,
@ -489,7 +488,7 @@ mtpMsgId Connection::placeToContainer(
return msgId;
}
void Connection::tryToSend() {
void SessionPrivate::tryToSend() {
DEBUG_LOG(("MTP Info: tryToSend for dc %1.").arg(_shiftedDcId));
if (!_connection) {
DEBUG_LOG(("MTP Info: not yet connected in dc %1.").arg(_shiftedDcId));
@ -591,10 +590,10 @@ void Connection::tryToSend() {
MTPInitConnection<SerializedRequest> initWrapper;
int32 initSize = 0, initSizeInInts = 0;
if (needsLayer) {
Assert(_connectionOptions != nullptr);
const auto systemLangCode = _connectionOptions->systemLangCode;
const auto cloudLangCode = _connectionOptions->cloudLangCode;
const auto langPackName = _connectionOptions->langPackName;
Assert(_options != nullptr);
const auto systemLangCode = _options->systemLangCode;
const auto cloudLangCode = _options->cloudLangCode;
const auto langPackName = _options->langPackName;
const auto deviceModel = (_currentDcType == DcType::Cdn)
? "n/a"
: _instance->deviceModel();
@ -610,12 +609,12 @@ void Connection::tryToSend() {
#else // OS_MAC_STORE || OS_WIN_STORE
const auto appVersion = QString::fromLatin1(AppVersionStr);
#endif // OS_MAC_STORE || OS_WIN_STORE
const auto proxyType = _connectionOptions->proxy.type;
const auto proxyType = _options->proxy.type;
const auto mtprotoProxy = (proxyType == ProxyData::Type::Mtproto);
const auto clientProxyFields = mtprotoProxy
? MTP_inputClientProxy(
MTP_string(_connectionOptions->proxy.host),
MTP_int(_connectionOptions->proxy.port))
MTP_string(_options->proxy.host),
MTP_int(_options->proxy.port))
: MTPInputClientProxy();
using Flag = MTPInitConnection<SerializedRequest>::Flag;
initWrapper = MTPInitConnection<SerializedRequest>(
@ -720,7 +719,7 @@ void Connection::tryToSend() {
auto wrappedRequest = SerializedRequest::Prepare(toSendSize);
memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length
wrappedRequest->push_back(mtpc_invokeWithLayer);
wrappedRequest->push_back(internal::CurrentLayer);
wrappedRequest->push_back(kCurrentLayer);
initWrapper.write<mtpBuffer>(*wrappedRequest);
wrappedRequest->resize(wrappedRequest->size() + noWrapSize);
memcpy(wrappedRequest->data() + wrappedRequest->size() - noWrapSize, toSendRequest->constData() + 8, noWrapSize * sizeof(mtpPrime));
@ -752,7 +751,7 @@ void Connection::tryToSend() {
if (willNeedInit) {
initSerialized.reserve(initSizeInInts);
initSerialized.push_back(mtpc_invokeWithLayer);
initSerialized.push_back(internal::CurrentLayer);
initSerialized.push_back(kCurrentLayer);
initWrapper.write<mtpBuffer>(initSerialized);
}
// prepare container + each in invoke after
@ -879,7 +878,7 @@ void Connection::tryToSend() {
sendSecureRequest(std::move(toSendRequest), needAnyResponse);
}
void Connection::retryByTimer() {
void SessionPrivate::retryByTimer() {
if (_retryTimeout < 3) {
++_retryTimeout;
} else if (_retryTimeout == 3) {
@ -890,13 +889,13 @@ void Connection::retryByTimer() {
connectToServer();
}
void Connection::restartNow() {
void SessionPrivate::restartNow() {
_retryTimeout = 1;
_retryTimer.cancel();
restart();
}
void Connection::connectToServer(bool afterConfig) {
void SessionPrivate::connectToServer(bool afterConfig) {
if (afterConfig && (!_testConnections.empty() || _connection)) {
return;
}
@ -908,8 +907,7 @@ void Connection::connectToServer(bool afterConfig) {
return;
}
_connectionOptions = std::make_unique<ConnectionOptions>(
_sessionData->connectionOptions());
_options = std::make_unique<SessionOptions>(_sessionData->options());
const auto bareDc = BareDcId(_shiftedDcId);
@ -920,7 +918,7 @@ void Connection::connectToServer(bool afterConfig) {
return;
}
}
if (_connectionOptions->proxy.type == ProxyData::Type::Mtproto) {
if (_options->proxy.type == ProxyData::Type::Mtproto) {
// host, port, secret for mtproto proxy are taken from proxy.
appendTestConnection(DcOptions::Variants::Tcp, {}, 0, {});
} else {
@ -929,11 +927,11 @@ void Connection::connectToServer(bool afterConfig) {
const auto variants = _instance->dcOptions()->lookup(
bareDc,
_currentDcType,
_connectionOptions->proxy.type != ProxyData::Type::None);
const auto useIPv4 = special ? true : _connectionOptions->useIPv4;
const auto useIPv6 = special ? false : _connectionOptions->useIPv6;
const auto useTcp = special ? true : _connectionOptions->useTcp;
const auto useHttp = special ? false : _connectionOptions->useHttp;
_options->proxy.type != ProxyData::Type::None);
const auto useIPv4 = special ? true : _options->useIPv4;
const auto useIPv6 = special ? false : _options->useIPv6;
const auto useTcp = special ? true : _options->useTcp;
const auto useHttp = special ? false : _options->useHttp;
const auto skipAddress = !useIPv4
? Variants::IPv4
: !useIPv6
@ -1001,7 +999,7 @@ void Connection::connectToServer(bool afterConfig) {
_waitForConnectedTimer.callOnce(_waitForConnected);
}
void Connection::restart() {
void SessionPrivate::restart() {
DEBUG_LOG(("MTP Info: restarting Connection"));
_waitForReceivedTimer.cancel();
@ -1021,7 +1019,7 @@ void Connection::restart() {
setState(-_retryTimeout);
}
void Connection::onSentSome(uint64 size) {
void SessionPrivate::onSentSome(uint64 size) {
if (!_waitForReceivedTimer.isActive()) {
auto remain = static_cast<uint64>(_waitForReceived);
if (!_oldConnection) {
@ -1042,7 +1040,7 @@ void Connection::onSentSome(uint64 size) {
if (!_firstSentAt) _firstSentAt = crl::now();
}
void Connection::onReceivedSome() {
void SessionPrivate::onReceivedSome() {
if (_oldConnection) {
_oldConnection = false;
DEBUG_LOG(("This connection marked as not old!"));
@ -1060,13 +1058,13 @@ void Connection::onReceivedSome() {
}
}
void Connection::markConnectionOld() {
void SessionPrivate::markConnectionOld() {
_oldConnection = true;
_waitForReceived = kMinReceiveTimeout;
DEBUG_LOG(("This connection marked as old! _waitForReceived now %1ms").arg(_waitForReceived));
}
void Connection::sendPingByTimer() {
void SessionPrivate::sendPingByTimer() {
if (_pingId) {
// _pingSendAt: when to send next ping (lastPingAt + kPingSendAfter)
// could be equal to zero.
@ -1085,7 +1083,7 @@ void Connection::sendPingByTimer() {
}
}
void Connection::sendPingForce() {
void SessionPrivate::sendPingForce() {
DEBUG_LOG(("MTP Info: send ping force for dcWithShift %1.").arg(_shiftedDcId));
if (!_pingId) {
_pingSendAt = 0;
@ -1094,10 +1092,10 @@ void Connection::sendPingForce() {
}
}
void Connection::waitReceivedFailed() {
Expects(_connectionOptions != nullptr);
void SessionPrivate::waitReceivedFailed() {
Expects(_options != nullptr);
if (!_connectionOptions->useTcp) {
if (!_options->useTcp) {
return;
}
@ -1114,7 +1112,7 @@ void Connection::waitReceivedFailed() {
InvokeQueued(this, [=] { connectToServer(); });
}
void Connection::waitConnectedFailed() {
void SessionPrivate::waitConnectedFailed() {
DEBUG_LOG(("MTP Info: can't connect in %1ms").arg(_waitForConnected));
auto maxTimeout = kMaxConnectedTimeout;
for (const auto &connection : _testConnections) {
@ -1130,29 +1128,29 @@ void Connection::waitConnectedFailed() {
InvokeQueued(this, [=] { connectToServer(); });
}
void Connection::waitBetterFailed() {
void SessionPrivate::waitBetterFailed() {
confirmBestConnection();
}
void Connection::connectingTimedOut() {
void SessionPrivate::connectingTimedOut() {
for (const auto &connection : _testConnections) {
connection.data->timedOut();
}
doDisconnect();
}
void Connection::doDisconnect() {
void SessionPrivate::doDisconnect() {
destroyAllConnections();
setState(DisconnectedState);
}
void Connection::requestCDNConfig() {
void SessionPrivate::requestCDNConfig() {
InvokeQueued(_instance, [instance = _instance] {
instance->requestCDNConfig();
});
}
void Connection::handleReceived() {
void SessionPrivate::handleReceived() {
Expects(_encryptionKey != nullptr);
onReceivedSome();
@ -1303,7 +1301,7 @@ void Connection::handleReceived() {
auto end = from + (messageLength / kIntSize);
auto sfrom = decryptedInts + 4U; // msg_id + seq_no + length + message
MTP_LOG(_shiftedDcId, ("Recv: ")
+ details::DumpToText(sfrom, end)
+ DumpToText(sfrom, end)
+ QString(" (protocolDcId:%1,key:%2)"
).arg(getProtocolDcId()
).arg(_encryptionKey->keyId()));
@ -1352,7 +1350,7 @@ void Connection::handleReceived() {
}
}
Connection::HandleResult Connection::handleOneReceived(
SessionPrivate::HandleResult SessionPrivate::handleOneReceived(
const mtpPrime *from,
const mtpPrime *end,
uint64 msgId,
@ -1733,7 +1731,7 @@ Connection::HandleResult Connection::handleOneReceived(
// the initConnection, so we're not sure yet that it was inited.
// Wait till a good response is received.
} else {
_sessionData->notifyConnectionInited(*_connectionOptions);
_sessionData->notifyConnectionInited(*_options);
}
requestsAcked(ids, true);
@ -1850,7 +1848,7 @@ Connection::HandleResult Connection::handleOneReceived(
return HandleResult::Success;
}
Connection::HandleResult Connection::handleBindResponse(
SessionPrivate::HandleResult SessionPrivate::handleBindResponse(
mtpMsgId requestMsgId,
const mtpBuffer &response) {
if (!_keyCreator || !_bindMsgId || _bindMsgId != requestMsgId) {
@ -1878,7 +1876,7 @@ Connection::HandleResult Connection::handleBindResponse(
Unexpected("Result of BoundKeyCreator::handleBindResponse.");
}
mtpBuffer Connection::ungzip(const mtpPrime *from, const mtpPrime *end) const {
mtpBuffer SessionPrivate::ungzip(const mtpPrime *from, const mtpPrime *end) const {
mtpBuffer result; // * 4 because of mtpPrime type
result.resize(0);
@ -1930,7 +1928,7 @@ mtpBuffer Connection::ungzip(const mtpPrime *from, const mtpPrime *end) const {
return result;
}
bool Connection::requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt) {
bool SessionPrivate::requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt) {
uint32 idsCount = ids.size();
for (uint32 i = 0; i < idsCount; ++i) {
@ -1945,7 +1943,7 @@ bool Connection::requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTi
return false;
}
void Connection::requestsAcked(const QVector<MTPlong> &ids, bool byResponse) {
void SessionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byResponse) {
uint32 idsCount = ids.size();
DEBUG_LOG(("Message Info: requests acked, ids %1").arg(LogIdsVector(ids)));
@ -2027,7 +2025,7 @@ void Connection::requestsAcked(const QVector<MTPlong> &ids, bool byResponse) {
}
}
void Connection::handleMsgsStates(const QVector<MTPlong> &ids, const QByteArray &states) {
void SessionPrivate::handleMsgsStates(const QVector<MTPlong> &ids, const QByteArray &states) {
const auto idsCount = ids.size();
if (!idsCount) {
DEBUG_LOG(("Message Info: void ids vector in handleMsgsStates()"));
@ -2072,7 +2070,7 @@ void Connection::handleMsgsStates(const QVector<MTPlong> &ids, const QByteArray
requestsAcked(acked);
}
void Connection::clearSpecialMsgId(mtpMsgId msgId) {
void SessionPrivate::clearSpecialMsgId(mtpMsgId msgId) {
if (msgId == _pingMsgId) {
_pingMsgId = 0;
_pingId = 0;
@ -2081,7 +2079,7 @@ void Connection::clearSpecialMsgId(mtpMsgId msgId) {
}
}
void Connection::resend(
void SessionPrivate::resend(
mtpMsgId msgId,
crl::time msCanWait,
bool forceContainer) {
@ -2121,7 +2119,7 @@ void Connection::resend(
}
}
void Connection::resendAll() {
void SessionPrivate::resendAll() {
auto lock = QWriteLocker(_sessionData->haveSentMutex());
auto haveSent = base::take(_sessionData->haveSentMap());
lock.unlock();
@ -2141,7 +2139,7 @@ void Connection::resendAll() {
_sessionData->queueSendAnything();
}
void Connection::onConnected(
void SessionPrivate::onConnected(
not_null<AbstractConnection*> connection) {
disconnect(connection, &AbstractConnection::connected, nullptr, nullptr);
if (!connection->isConnected()) {
@ -2175,7 +2173,7 @@ void Connection::onConnected(
}
}
void Connection::onDisconnected(
void SessionPrivate::onDisconnected(
not_null<AbstractConnection*> connection) {
removeTestConnection(connection);
@ -2187,7 +2185,7 @@ void Connection::onDisconnected(
}
}
void Connection::confirmBestConnection() {
void SessionPrivate::confirmBestConnection() {
if (_waitForBetterTimer.isActive()) {
return;
}
@ -2211,7 +2209,7 @@ void Connection::confirmBestConnection() {
checkAuthKey();
}
void Connection::removeTestConnection(
void SessionPrivate::removeTestConnection(
not_null<AbstractConnection*> connection) {
_testConnections.erase(
ranges::remove(
@ -2221,7 +2219,7 @@ void Connection::removeTestConnection(
end(_testConnections));
}
void Connection::checkAuthKey() {
void SessionPrivate::checkAuthKey() {
if (_keyId) {
authKeyChecked();
} else if (_instance->isKeysDestroyer()) {
@ -2232,7 +2230,7 @@ void Connection::checkAuthKey() {
}
}
void Connection::updateAuthKey() {
void SessionPrivate::updateAuthKey() {
if (_instance->isKeysDestroyer() || _keyCreator || !_connection) {
return;
}
@ -2250,7 +2248,7 @@ void Connection::updateAuthKey() {
}
}
void Connection::setCurrentKeyId(uint64 newKeyId) {
void SessionPrivate::setCurrentKeyId(uint64 newKeyId) {
if (_keyId == newKeyId) {
return;
}
@ -2260,7 +2258,7 @@ void Connection::setCurrentKeyId(uint64 newKeyId) {
changeSessionId();
}
void Connection::applyAuthKey(AuthKeyPtr &&encryptionKey) {
void SessionPrivate::applyAuthKey(AuthKeyPtr &&encryptionKey) {
_encryptionKey = std::move(encryptionKey);
const auto newKeyId = _encryptionKey ? _encryptionKey->keyId() : 0;
if (_keyId) {
@ -2302,7 +2300,7 @@ void Connection::applyAuthKey(AuthKeyPtr &&encryptionKey) {
}
}
bool Connection::destroyOldEnoughPersistentKey() {
bool SessionPrivate::destroyOldEnoughPersistentKey() {
Expects(_keyCreator != nullptr);
const auto key = _keyCreator->bindPersistentKey();
@ -2321,7 +2319,7 @@ bool Connection::destroyOldEnoughPersistentKey() {
return true;
}
DcType Connection::tryAcquireKeyCreation() {
DcType SessionPrivate::tryAcquireKeyCreation() {
if (_keyCreator) {
return _currentDcType;
} else if (_instance->isKeysDestroyer()) {
@ -2395,7 +2393,7 @@ DcType Connection::tryAcquireKeyCreation() {
return forceUseRegular ? DcType::Regular : _realDcType;
}
void Connection::authKeyChecked() {
void SessionPrivate::authKeyChecked() {
connect(_connection, &AbstractConnection::receivedData, [=] {
handleReceived();
});
@ -2408,7 +2406,7 @@ void Connection::authKeyChecked() {
_sessionData->queueNeedToResumeAndSend();
}
void Connection::onError(
void SessionPrivate::onError(
not_null<AbstractConnection*> connection,
qint32 errorCode) {
if (errorCode == -429) {
@ -2428,7 +2426,7 @@ void Connection::onError(
}
}
void Connection::handleError(int errorCode) {
void SessionPrivate::handleError(int errorCode) {
destroyAllConnections();
_waitForConnectedTimer.cancel();
@ -2440,7 +2438,7 @@ void Connection::handleError(int errorCode) {
}
}
void Connection::destroyTemporaryKey() {
void SessionPrivate::destroyTemporaryKey() {
if (_instance->isKeysDestroyer()) {
LOG(("MTP Info: -404 error received in destroyer %1, assuming key was destroyed.").arg(_shiftedDcId));
_instance->keyWasPossiblyDestroyed(_shiftedDcId);
@ -2455,7 +2453,7 @@ void Connection::destroyTemporaryKey() {
restart();
}
bool Connection::sendSecureRequest(
bool SessionPrivate::sendSecureRequest(
SerializedRequest &&request,
bool needAnyResponse) {
#ifdef TDESKTOP_MTPROTO_OLD
@ -2480,7 +2478,7 @@ bool Connection::sendSecureRequest(
auto from = request->constData() + 4;
MTP_LOG(_shiftedDcId, ("Send: ")
+ details::DumpToText(from, from + messageSize)
+ DumpToText(from, from + messageSize)
+ QString(" (protocolDcId:%1,key:%2)"
).arg(getProtocolDcId()
).arg(_encryptionKey->keyId()));
@ -2539,7 +2537,7 @@ bool Connection::sendSecureRequest(
return true;
}
mtpRequestId Connection::wasSent(mtpMsgId msgId) const {
mtpRequestId SessionPrivate::wasSent(mtpMsgId msgId) const {
if (msgId == _pingMsgId || msgId == _bindMsgId) {
return mtpRequestId(0xFFFFFFFF);
}
@ -2566,13 +2564,13 @@ mtpRequestId Connection::wasSent(mtpMsgId msgId) const {
return 0;
}
void Connection::clearUnboundKeyCreator() {
void SessionPrivate::clearUnboundKeyCreator() {
if (_keyCreator) {
_keyCreator->stop();
}
}
void Connection::releaseKeyCreationOnFail() {
void SessionPrivate::releaseKeyCreationOnFail() {
if (!_keyCreator) {
return;
}
@ -2580,5 +2578,5 @@ void Connection::releaseKeyCreationOnFail() {
_sessionData->releaseKeyCreationOnFail();
}
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -21,26 +21,23 @@ namespace details {
class BoundKeyCreator;
} // namespace details
// How much time to wait for some more requests, when sending msg acks.
constexpr auto kAckSendWaiting = 10 * crl::time(1000);
class Instance;
namespace internal {
namespace details {
class AbstractConnection;
class SessionData;
class RSAPublicKey;
struct ConnectionOptions;
struct SessionOptions;
class Connection : public QObject {
class SessionPrivate final : public QObject {
public:
Connection(
SessionPrivate(
not_null<Instance*> instance,
not_null<QThread*> thread,
std::shared_ptr<SessionData> data,
ShiftedDcId shiftedDcId);
~Connection();
~SessionPrivate();
[[nodiscard]] int32 getShiftedDcId() const;
void dcOptionsChanged();
@ -106,20 +103,20 @@ private:
void clearOldContainers();
mtpMsgId placeToContainer(
details::SerializedRequest &toSendRequest,
SerializedRequest &toSendRequest,
mtpMsgId &bigMsgId,
bool forceNewMsgId,
details::SerializedRequest &req);
SerializedRequest &req);
mtpMsgId prepareToSend(
details::SerializedRequest &request,
SerializedRequest &request,
mtpMsgId currentLastId,
bool forceNewMsgId);
mtpMsgId replaceMsgId(
details::SerializedRequest &request,
SerializedRequest &request,
mtpMsgId newId);
bool sendSecureRequest(
details::SerializedRequest &&request,
SerializedRequest &&request,
bool needAnyResponse);
mtpRequestId wasSent(mtpMsgId msgId) const;
@ -205,7 +202,7 @@ private:
base::Timer _checkSentRequestsTimer;
std::shared_ptr<SessionData> _sessionData;
std::unique_ptr<ConnectionOptions> _connectionOptions;
std::unique_ptr<SessionOptions> _options;
AuthKeyPtr _encryptionKey;
uint64 _keyId = 0;
uint64 _sessionId = 0;
@ -216,16 +213,16 @@ private:
QVector<MTPlong> _ackRequestData;
QVector<MTPlong> _resendRequestData;
base::flat_set<mtpMsgId> _stateRequestData;
details::ReceivedIdsManager _receivedMessageIds;
ReceivedIdsManager _receivedMessageIds;
base::flat_map<mtpMsgId, mtpRequestId> _resendingIds;
base::flat_map<mtpMsgId, mtpRequestId> _ackedIds;
base::flat_map<mtpMsgId, details::SerializedRequest> _stateAndResendRequests;
base::flat_map<mtpMsgId, SerializedRequest> _stateAndResendRequests;
base::flat_map<mtpMsgId, SentContainer> _sentContainers;
std::unique_ptr<details::BoundKeyCreator> _keyCreator;
std::unique_ptr<BoundKeyCreator> _keyCreator;
mtpMsgId _bindMsgId = 0;
};
} // namespace internal
} // namespace details
} // namespace MTP

View File

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/special_config_request.h"
#include "mtproto/mtproto_rsa_public_key.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include "mtproto/dc_options.h"
#include "mtproto/mtproto_auth_key.h"
#include "base/unixtime.h"
@ -19,16 +19,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
extern "C" {
#include <openssl/aes.h>
} // extern "C"
namespace MTP {
namespace MTP::details {
namespace {
constexpr auto kSendNextTimeout = crl::time(800);
constexpr auto kMinTimeToLive = 10 * crl::time(1000);
constexpr auto kMaxTimeToLive = 300 * crl::time(1000);
constexpr auto kPublicKey = str_const("\
-----BEGIN RSA PUBLIC KEY-----\n\
@ -41,9 +35,6 @@ Y1hZCxdv6cs5UnW9+PWvS+WIbkh+GaWYxwIDAQAB\n\
-----END RSA PUBLIC KEY-----\
");
constexpr auto kUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36";
const auto kRemoteProject = "peak-vista-421";
const auto kFireProject = "reserve-5a846";
const auto kConfigKey = "ipconfig";
@ -51,21 +42,6 @@ const auto kConfigSubKey = "v3";
const auto kApiKey = "AIzaSyC2-kAkpDsroixRXw-sTw-Wfqo4NxjMwwM";
const auto kAppId = "1:560508485281:web:4ee13a6af4e84d49e67ae0";
struct DnsEntry {
QString data;
crl::time TTL = 0;
};
const std::vector<QString> &DnsDomains() {
static auto result = std::vector<QString>{
qsl("google.com"),
qsl("www.google.com"),
qsl("google.ru"),
qsl("www.google.ru"),
};
return result;
}
QString ApiDomain(const QString &service) {
return service + ".googleapis.com";
}
@ -103,99 +79,6 @@ bool CheckPhoneByPrefixesRules(const QString &phone, const QString &rules) {
return result;
}
QString GenerateRandomPadding() {
constexpr char kValid[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
auto result = QString();
const auto count = [&] {
constexpr auto kMinPadding = 13;
constexpr auto kMaxPadding = 128;
while (true) {
const auto result = 1 + (rand_value<uchar>() / 2);
Assert(result <= kMaxPadding);
if (result >= kMinPadding) {
return result;
}
}
}();
result.resize(count);
for (auto &ch : result) {
ch = kValid[rand_value<uchar>() % (sizeof(kValid) - 1)];
}
return result;
}
std::vector<DnsEntry> ParseDnsResponse(
const QByteArray &bytes,
std::optional<int> typeRestriction = std::nullopt) {
// Read and store to "result" all the data bytes from the response:
// { ..,
// "Answer": [
// { .., "data": "bytes1", "TTL": int, .. },
// { .., "data": "bytes2", "TTL": int, .. }
// ],
// .. }
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
const auto document = QJsonDocument::fromJson(bytes, &error);
if (error.error != QJsonParseError::NoError) {
LOG(("Config Error: Failed to parse dns response JSON, error: %1"
).arg(error.errorString()));
return {};
} else if (!document.isObject()) {
LOG(("Config Error: Not an object received in dns response JSON."));
return {};
}
const auto response = document.object();
const auto answerIt = response.find(qsl("Answer"));
if (answerIt == response.constEnd()) {
LOG(("Config Error: Could not find Answer in dns response JSON."));
return {};
} else if (!(*answerIt).isArray()) {
LOG(("Config Error: Not an array received "
"in Answer in dns response JSON."));
return {};
}
auto result = std::vector<DnsEntry>();
for (const auto elem : (*answerIt).toArray()) {
if (!elem.isObject()) {
LOG(("Config Error: Not an object found "
"in Answer array in dns response JSON."));
continue;
}
const auto object = elem.toObject();
if (typeRestriction) {
const auto typeIt = object.find(qsl("type"));
const auto type = int(std::round((*typeIt).toDouble()));
if (!(*typeIt).isDouble()) {
LOG(("Config Error: Not a number in type field "
"in Answer array in dns response JSON."));
continue;
} else if (type != *typeRestriction) {
continue;
}
}
const auto dataIt = object.find(qsl("data"));
if (dataIt == object.constEnd()) {
LOG(("Config Error: Could not find data "
"in Answer array entry in dns response JSON."));
continue;
} else if (!(*dataIt).isString()) {
LOG(("Config Error: Not a string data found "
"in Answer array entry in dns response JSON."));
continue;
}
const auto ttlIt = object.find(qsl("TTL"));
const auto ttl = (ttlIt != object.constEnd())
? crl::time(std::round((*ttlIt).toDouble()))
: crl::time(0);
result.push_back({ (*dataIt).toString(), ttl });
}
return result;
}
QByteArray ConcatenateDnsTxtFields(const std::vector<DnsEntry> &response) {
auto entries = QMap<int, QString>();
for (const auto &entry : response) {
@ -299,40 +182,6 @@ QByteArray ParseRealtimeResponse(const QByteArray &bytes) {
} // namespace
ServiceWebRequest::ServiceWebRequest(not_null<QNetworkReply*> reply)
: reply(reply.get()) {
}
ServiceWebRequest::ServiceWebRequest(ServiceWebRequest &&other)
: reply(base::take(other.reply)) {
}
ServiceWebRequest &ServiceWebRequest::operator=(ServiceWebRequest &&other) {
if (reply != other.reply) {
destroy();
reply = base::take(other.reply);
}
return *this;
}
void ServiceWebRequest::destroy() {
if (const auto value = base::take(reply)) {
value->disconnect(
value,
&QNetworkReply::finished,
nullptr,
nullptr);
value->abort();
value->deleteLater();
}
}
ServiceWebRequest::~ServiceWebRequest() {
if (reply) {
reply->deleteLater();
}
}
SpecialConfigRequest::SpecialConfigRequest(
Fn<void(
DcId dcId,
@ -435,7 +284,7 @@ void SpecialConfigRequest::performRequest(const Attempt &attempt) {
url.setPath(qsl("/dns-query"));
url.setQuery(qsl("name=%1&type=16&random_padding=%2"
).arg(Global::TxtDomainString()
).arg(GenerateRandomPadding()));
).arg(GenerateDnsRandomPadding()));
request.setRawHeader("accept", "application/dns-json");
} break;
case Type::Google: {
@ -443,7 +292,7 @@ void SpecialConfigRequest::performRequest(const Attempt &attempt) {
url.setPath(qsl("/resolve"));
url.setQuery(qsl("name=%1&type=ANY&random_padding=%2"
).arg(Global::TxtDomainString()
).arg(GenerateRandomPadding()));
).arg(GenerateDnsRandomPadding()));
if (!attempt.host.isEmpty()) {
const auto host = attempt.host + ".google.com";
request.setRawHeader("Host", host.toLatin1());
@ -479,7 +328,7 @@ void SpecialConfigRequest::performRequest(const Attempt &attempt) {
default: Unexpected("Type in SpecialConfigRequest::performRequest.");
}
request.setUrl(url);
request.setRawHeader("User-Agent", kUserAgent);
request.setRawHeader("User-Agent", DnsUserAgent());
const auto reply = _requests.emplace_back(payload.isEmpty()
? _manager.get(request)
: _manager.post(request, payload)
@ -587,7 +436,7 @@ bool SpecialConfigRequest::decryptSimpleConfig(const QByteArray &bytes) {
return false;
}
auto publicKey = internal::RSAPublicKey(bytes::make_span(
auto publicKey = details::RSAPublicKey(bytes::make_span(
kPublicKey.c_str(),
kPublicKey.size()));
auto decrypted = publicKey.decrypt(bytes::make_span(decodedBytes));
@ -693,190 +542,4 @@ void SpecialConfigRequest::handleResponse(const QByteArray &bytes) {
_callback(0, std::string(), 0, {});
}
DomainResolver::DomainResolver(Fn<void(
const QString &host,
const QStringList &ips,
crl::time expireAt)> callback)
: _callback(std::move(callback)) {
_manager.setProxy(QNetworkProxy::NoProxy);
}
void DomainResolver::resolve(const QString &domain) {
resolve({ domain, false });
resolve({ domain, true });
}
void DomainResolver::resolve(const AttemptKey &key) {
if (_attempts.find(key) != end(_attempts)) {
return;
} else if (_requests.find(key) != end(_requests)) {
return;
}
const auto i = _cache.find(key);
_lastTimestamp = crl::now();
if (i != end(_cache) && i->second.expireAt > _lastTimestamp) {
checkExpireAndPushResult(key.domain);
return;
}
auto attempts = std::vector<Attempt>();
auto domains = DnsDomains();
std::random_device rd;
ranges::shuffle(domains, std::mt19937(rd()));
const auto takeDomain = [&] {
const auto result = domains.back();
domains.pop_back();
return result;
};
const auto shuffle = [&](int from, int till) {
Expects(till > from);
ranges::shuffle(
begin(attempts) + from,
begin(attempts) + till,
std::mt19937(rd()));
};
attempts.push_back({ Type::Google, "dns.google.com" });
attempts.push_back({ Type::Google, takeDomain(), "dns" });
attempts.push_back({ Type::Mozilla, "mozilla.cloudflare-dns.com" });
while (!domains.empty()) {
attempts.push_back({ Type::Google, takeDomain(), "dns" });
}
shuffle(0, 2);
ranges::reverse(attempts); // We go from last to first.
_attempts.emplace(key, Attempts{ std::move(attempts) });
sendNextRequest(key);
}
void DomainResolver::checkExpireAndPushResult(const QString &domain) {
const auto ipv4 = _cache.find({ domain, false });
if (ipv4 == end(_cache) || ipv4->second.expireAt <= _lastTimestamp) {
return;
}
auto result = ipv4->second;
const auto ipv6 = _cache.find({ domain, true });
if (ipv6 != end(_cache) && ipv6->second.expireAt > _lastTimestamp) {
result.ips.append(ipv6->second.ips);
accumulate_min(result.expireAt, ipv6->second.expireAt);
}
InvokeQueued(this, [=] {
_callback(domain, result.ips, result.expireAt);
});
}
void DomainResolver::sendNextRequest(const AttemptKey &key) {
auto i = _attempts.find(key);
if (i == end(_attempts)) {
return;
}
auto &attempts = i->second;
auto &list = attempts.list;
const auto attempt = list.back();
list.pop_back();
if (!list.empty()) {
base::call_delayed(kSendNextTimeout, &attempts.guard, [=] {
sendNextRequest(key);
});
}
performRequest(key, attempt);
}
void DomainResolver::performRequest(
const AttemptKey &key,
const Attempt &attempt) {
auto url = QUrl();
url.setScheme(qsl("https"));
auto request = QNetworkRequest();
switch (attempt.type) {
case Type::Mozilla: {
url.setHost(attempt.data);
url.setPath(qsl("/dns-query"));
url.setQuery(qsl("name=%1&type=%2&random_padding=%3"
).arg(key.domain
).arg(key.ipv6 ? 28 : 1
).arg(GenerateRandomPadding()));
request.setRawHeader("accept", "application/dns-json");
} break;
case Type::Google: {
url.setHost(attempt.data);
url.setPath(qsl("/resolve"));
url.setQuery(qsl("name=%1&type=%2&random_padding=%3"
).arg(key.domain
).arg(key.ipv6 ? 28 : 1
).arg(GenerateRandomPadding()));
if (!attempt.host.isEmpty()) {
const auto host = attempt.host + ".google.com";
request.setRawHeader("Host", host.toLatin1());
}
} break;
default: Unexpected("Type in SpecialConfigRequest::performRequest.");
}
request.setUrl(url);
request.setRawHeader("User-Agent", kUserAgent);
const auto i = _requests.emplace(
key,
std::vector<ServiceWebRequest>()).first;
const auto reply = i->second.emplace_back(
_manager.get(request)
).reply;
connect(reply, &QNetworkReply::finished, this, [=] {
requestFinished(key, reply);
});
}
void DomainResolver::requestFinished(
const AttemptKey &key,
not_null<QNetworkReply*> reply) {
const auto result = finalizeRequest(key, reply);
const auto response = ParseDnsResponse(result);
if (response.empty()) {
return;
}
_requests.erase(key);
_attempts.erase(key);
auto entry = CacheEntry();
auto ttl = kMaxTimeToLive;
for (const auto &item : response) {
entry.ips.push_back(item.data);
accumulate_min(ttl, std::max(
item.TTL * crl::time(1000),
kMinTimeToLive));
}
_lastTimestamp = crl::now();
entry.expireAt = _lastTimestamp + ttl;
_cache[key] = std::move(entry);
checkExpireAndPushResult(key.domain);
}
QByteArray DomainResolver::finalizeRequest(
const AttemptKey &key,
not_null<QNetworkReply*> reply) {
if (reply->error() != QNetworkReply::NoError) {
LOG(("Resolve Error: Failed to get response, error: %2 (%3)"
).arg(reply->errorString()
).arg(reply->error()));
}
const auto result = reply->readAll();
const auto i = _requests.find(key);
if (i != end(_requests)) {
auto &requests = i->second;
const auto from = ranges::remove(
requests,
reply,
[](const ServiceWebRequest &request) { return request.reply; });
requests.erase(from, end(requests));
if (requests.empty()) {
_requests.erase(i);
}
}
return result;
}
} // namespace MTP
} // namespace MTP::details

View File

@ -7,24 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/details/mtproto_domain_resolver.h"
#include "base/bytes.h"
#include "base/weak_ptr.h"
#include <QtCore/QPointer>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkAccessManager>
namespace MTP {
struct ServiceWebRequest {
ServiceWebRequest(not_null<QNetworkReply*> reply);
ServiceWebRequest(ServiceWebRequest &&other);
ServiceWebRequest &operator=(ServiceWebRequest &&other);
~ServiceWebRequest();
void destroy();
QPointer<QNetworkReply> reply;
};
namespace MTP::details {
class SpecialConfigRequest : public QObject {
public:
@ -83,71 +74,4 @@ private:
};
class DomainResolver : public QObject {
public:
DomainResolver(Fn<void(
const QString &domain,
const QStringList &ips,
crl::time expireAt)> callback);
void resolve(const QString &domain);
private:
enum class Type {
Mozilla,
Google,
};
struct Attempt {
Type type;
QString data;
QString host;
};
struct AttemptKey {
QString domain;
bool ipv6 = false;
inline bool operator<(const AttemptKey &other) const {
return (domain < other.domain)
|| (domain == other.domain && !ipv6 && other.ipv6);
}
inline bool operator==(const AttemptKey &other) const {
return (domain == other.domain) && (ipv6 == other.ipv6);
}
};
struct CacheEntry {
QStringList ips;
crl::time expireAt = 0;
};
struct Attempts {
std::vector<Attempt> list;
base::has_weak_ptr guard;
};
void resolve(const AttemptKey &key);
void sendNextRequest(const AttemptKey &key);
void performRequest(const AttemptKey &key, const Attempt &attempt);
void checkExpireAndPushResult(const QString &domain);
void requestFinished(
const AttemptKey &key,
not_null<QNetworkReply*> reply);
QByteArray finalizeRequest(
const AttemptKey &key,
not_null<QNetworkReply*> reply);
Fn<void(
const QString &domain,
const QStringList &ips,
crl::time expireAt)> _callback;
QNetworkAccessManager _manager;
std::map<AttemptKey, Attempts> _attempts;
std::map<AttemptKey, std::vector<ServiceWebRequest>> _requests;
std::map<AttemptKey, CacheEntry> _cache;
crl::time _lastTimestamp = 0;
};
} // namespace MTP
} // namespace MTP::details

View File

@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "passport/passport_encryption.h"
#include "base/openssl_help.h"
#include "mtproto/mtproto_rsa_public_key.h"
#include "mtproto/details/mtproto_rsa_public_key.h"
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
@ -429,7 +429,7 @@ uint64 CountSecureSecretId(bytes::const_span secret) {
bytes::vector EncryptCredentialsSecret(
bytes::const_span secret,
bytes::const_span publicKey) {
const auto key = MTP::internal::RSAPublicKey(publicKey);
const auto key = MTP::details::RSAPublicKey(publicKey);
return key.encryptOAEPpadding(secret);
}

View File

@ -15,7 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "storage/localstorage.h"
#include "platform/platform_file_utilities.h"
#include "mtproto/connection.h" // for MTP::kAckSendWaiting
#include "main/main_session.h"
#include "apiwrap.h"
#include "core/crash_reports.h"
@ -28,7 +27,7 @@ namespace Storage {
namespace {
// How much time without download causes additional session kill.
constexpr auto kKillSessionTimeout = crl::time(5000);
constexpr auto kKillSessionTimeout = 15 * crl::time(1000);
// Max 16 file parts downloaded at the same time, 128 KB each.
constexpr auto kMaxFileQueries = 16;
@ -75,11 +74,10 @@ void Downloader::killDownloadSessionsStart(MTP::DcId dcId) {
if (!_killDownloadSessionTimes.contains(dcId)) {
_killDownloadSessionTimes.emplace(
dcId,
crl::now() + MTP::kAckSendWaiting + kKillSessionTimeout);
crl::now() + kKillSessionTimeout);
}
if (!_killDownloadSessionsTimer.isActive()) {
_killDownloadSessionsTimer.callOnce(
MTP::kAckSendWaiting + kKillSessionTimeout + 5);
_killDownloadSessionsTimer.callOnce(kKillSessionTimeout + 5);
}
}
@ -92,16 +90,17 @@ void Downloader::killDownloadSessionsStop(MTP::DcId dcId) {
}
void Downloader::killDownloadSessions() {
auto ms = crl::now(), left = MTP::kAckSendWaiting + kKillSessionTimeout;
const auto now = crl::now();
auto left = kKillSessionTimeout;
for (auto i = _killDownloadSessionTimes.begin(); i != _killDownloadSessionTimes.end(); ) {
if (i->second <= ms) {
if (i->second <= now) {
for (int j = 0; j < MTP::kDownloadSessionsCount; ++j) {
MTP::stopSession(MTP::downloadDcId(i->first, j));
}
i = _killDownloadSessionTimes.erase(i);
} else {
if (i->second - ms < left) {
left = i->second - ms;
if (i->second - now < left) {
left = i->second - now;
}
++i;
}

View File

@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localimageloader.h"
#include "storage/file_download.h"
#include "mtproto/connection.h" // for MTP::kAckSendWaiting
#include "data/data_document.h"
#include "data/data_photo.h"
#include "data/data_session.h"
@ -42,7 +41,7 @@ constexpr auto kDocumentUploadPartSize4 = 512 * 1024;
constexpr auto kUploadRequestInterval = crl::time(500);
// How much time without upload causes additional session kill.
constexpr auto kKillSessionTimeout = crl::time(5000);
constexpr auto kKillSessionTimeout = 15 * crl::time(000);
} // namespace
@ -256,8 +255,7 @@ void Uploader::sendNext() {
bool stopping = stopSessionsTimer.isActive();
if (queue.empty()) {
if (!stopping) {
stopSessionsTimer.start(
MTP::kAckSendWaiting + kKillSessionTimeout);
stopSessionsTimer.start(kKillSessionTimeout);
}
return;
}

View File

@ -34,34 +34,40 @@
'<(src_loc)',
],
'sources': [
'<(src_loc)/mtproto/details/mtproto_abstract_socket.cpp',
'<(src_loc)/mtproto/details/mtproto_abstract_socket.h',
'<(src_loc)/mtproto/details/mtproto_bound_key_creator.cpp',
'<(src_loc)/mtproto/details/mtproto_bound_key_creator.h',
'<(src_loc)/mtproto/details/mtproto_dc_key_binder.cpp',
'<(src_loc)/mtproto/details/mtproto_dc_key_binder.h',
'<(src_loc)/mtproto/details/mtproto_dc_key_creator.cpp',
'<(src_loc)/mtproto/details/mtproto_dc_key_creator.h',
'<(src_loc)/mtproto/details/mtproto_dcenter.cpp',
'<(src_loc)/mtproto/details/mtproto_dcenter.h',
'<(src_loc)/mtproto/details/mtproto_domain_resolver.cpp',
'<(src_loc)/mtproto/details/mtproto_domain_resolver.h',
'<(src_loc)/mtproto/details/mtproto_dump_to_text.cpp',
'<(src_loc)/mtproto/details/mtproto_dump_to_text.h',
'<(src_loc)/mtproto/details/mtproto_received_ids_manager.cpp',
'<(src_loc)/mtproto/details/mtproto_received_ids_manager.h',
'<(src_loc)/mtproto/details/mtproto_rsa_public_key.cpp',
'<(src_loc)/mtproto/details/mtproto_rsa_public_key.h',
'<(src_loc)/mtproto/details/mtproto_serialized_request.cpp',
'<(src_loc)/mtproto/details/mtproto_serialized_request.h',
'<(src_loc)/mtproto/mtproto_abstract_socket.cpp',
'<(src_loc)/mtproto/mtproto_abstract_socket.h',
'<(src_loc)/mtproto/details/mtproto_tcp_socket.cpp',
'<(src_loc)/mtproto/details/mtproto_tcp_socket.h',
'<(src_loc)/mtproto/details/mtproto_tls_socket.cpp',
'<(src_loc)/mtproto/details/mtproto_tls_socket.h',
'<(src_loc)/mtproto/mtproto_auth_key.cpp',
'<(src_loc)/mtproto/mtproto_auth_key.h',
'<(src_loc)/mtproto/mtproto_concurrent_sender.cpp',
'<(src_loc)/mtproto/mtproto_concurrent_sender.h',
'<(src_loc)/mtproto/mtproto_dh_utils.cpp',
'<(src_loc)/mtproto/mtproto_dh_utils.h',
'<(src_loc)/mtproto/mtproto_proxy_data.cpp',
'<(src_loc)/mtproto/mtproto_proxy_data.h',
'<(src_loc)/mtproto/mtproto_rsa_public_key.cpp',
'<(src_loc)/mtproto/mtproto_rsa_public_key.h',
'<(src_loc)/mtproto/mtproto_rpc_sender.cpp',
'<(src_loc)/mtproto/mtproto_rpc_sender.h',
'<(src_loc)/mtproto/mtproto_tcp_socket.cpp',
'<(src_loc)/mtproto/mtproto_tcp_socket.h',
'<(src_loc)/mtproto/mtproto_tls_socket.cpp',
'<(src_loc)/mtproto/mtproto_tls_socket.h',
],
}],
}

View File

@ -537,12 +537,8 @@
<(src_loc)/media/view/media_view_group_thumbs.h
<(src_loc)/media/view/media_view_overlay_widget.cpp
<(src_loc)/media/view/media_view_overlay_widget.h
<(src_loc)/mtproto/concurrent_sender.cpp
<(src_loc)/mtproto/concurrent_sender.h
<(src_loc)/mtproto/config_loader.cpp
<(src_loc)/mtproto/config_loader.h
<(src_loc)/mtproto/connection.cpp
<(src_loc)/mtproto/connection.h
<(src_loc)/mtproto/connection_abstract.cpp
<(src_loc)/mtproto/connection_abstract.h
<(src_loc)/mtproto/connection_http.cpp
@ -552,8 +548,6 @@
<(src_loc)/mtproto/connection_tcp.cpp
<(src_loc)/mtproto/connection_tcp.h
<(src_loc)/mtproto/core_types.h
<(src_loc)/mtproto/dcenter.cpp
<(src_loc)/mtproto/dcenter.h
<(src_loc)/mtproto/dc_options.cpp
<(src_loc)/mtproto/dc_options.h
<(src_loc)/mtproto/dedicated_file_loader.cpp
@ -565,6 +559,8 @@
<(src_loc)/mtproto/sender.h
<(src_loc)/mtproto/session.cpp
<(src_loc)/mtproto/session.h
<(src_loc)/mtproto/session_private.cpp
<(src_loc)/mtproto/session_private.h
<(src_loc)/mtproto/special_config_request.cpp
<(src_loc)/mtproto/special_config_request.h
<(src_loc)/mtproto/type_utils.h

@ -1 +1 @@
Subproject commit 13918d5b5c4611ef1563a13ac1daf4d2c77c5f49
Subproject commit 10cddc61a6c5b6cd896ba014fc187d15f5267be3