All checks were successful
Desktop source guards / guards (push) Successful in 12s
ТСПУ замораживает каждое соединение с Cloudflare примерно после 16 КБ входящих: на ПК (лог 25.09) ни одна сессия туннеля к DC1 не получила больше 13 КБ, а часть файла 128 КБ целиком не проходила ни разу (send_count=51), поэтому файлы в «Избранном» стояли на 0. - Для DC, чей медийный релей подавлен и ушёл в туннель, часть 128 КБ собирается из 16 кусков по 8 КБ; для CDN части не делятся. - До 8 сессий сразу, в каждой один запрос: скорость даёт параллельность. - Файловое соединение туннеля переоткрывается на границе пакета после 4 КБ входящих, до заморозки; такие сокеты пишутся одной сводной строкой wss_tunnel_rotated, строки переподключения для них не пишутся. - Туннель подавляется только если после upgrade не пришло ничего: раньше три заморозки отправляли DC1 в прямой TCP, который сеть режет целиком, и файлы не грузились совсем по две минуты.
210 lines
5.9 KiB
C++
210 lines
5.9 KiB
C++
/*
|
|
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/session/private/session_private.h"
|
|
#include "mtproto/session/private/timings.h"
|
|
|
|
#include "mtproto/instance/mtp_instance.h"
|
|
#include "mtproto/proxy/diagnostics.h"
|
|
|
|
namespace MTP::details {
|
|
|
|
SessionTransport::TimingState::TimingState(
|
|
not_null<RuntimeEnvironment*> runtime,
|
|
not_null<SessionTransport*> owner,
|
|
not_null<QThread*> thread)
|
|
: retryTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->retryByTimer(); }))
|
|
, oldConnectionTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->markConnectionOld(); }))
|
|
, waitForConnectedTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->waitConnectedFailed(); }))
|
|
, waitForReceivedTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->waitReceivedFailed(); }))
|
|
, waitForBetterTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->waitBetterFailed(); }))
|
|
, waitForReceived(kMinReceiveTimeout)
|
|
, waitForConnected(kMinConnectedTimeout)
|
|
, pingSender(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->_owner->sendPingByTimer(); }))
|
|
, checkSentRequestsTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->_owner->checkSentRequests(); }))
|
|
, clearOldContainersTimer(runtime->async().makeTimer(
|
|
thread,
|
|
[=] { owner->_owner->_messageHandler.clearOldContainers(); })) {
|
|
}
|
|
|
|
SessionTransport::SessionTransport(
|
|
not_null<SessionPrivate*> owner,
|
|
not_null<RuntimeEnvironment*> runtime,
|
|
not_null<QThread*> thread,
|
|
uint64 proxyGeneration)
|
|
: _owner(owner)
|
|
, _timing(runtime, this, thread) {
|
|
_state.proxyGeneration = proxyGeneration;
|
|
_state.mtproxyAttempt = { .proxyGeneration = proxyGeneration };
|
|
}
|
|
|
|
SessionTransport::~SessionTransport() = default;
|
|
|
|
void SessionTransport::start() {
|
|
connectToServer();
|
|
}
|
|
|
|
void SessionTransport::setRetryTimeout(int timeout) {
|
|
_timing.retryTimeout = timeout;
|
|
}
|
|
|
|
void SessionTransport::scheduleRetryTimeout(int timeout) {
|
|
_timing.retryTimeout = timeout;
|
|
_timing.retryTimer.callOnce(_timing.retryTimeout);
|
|
_timing.retryWillFinish = crl::now() + _timing.retryTimeout;
|
|
}
|
|
|
|
void SessionTransport::schedulePing(crl::time timeout) {
|
|
_timing.pingSender.callOnce(timeout);
|
|
}
|
|
|
|
void SessionTransport::scheduleCheckSentRequests(crl::time timeout) {
|
|
_timing.checkSentRequestsTimer.callOnce(timeout);
|
|
}
|
|
|
|
void SessionTransport::scheduleClearOldContainers(
|
|
crl::time timeout,
|
|
bool repeated) {
|
|
if (repeated) {
|
|
_timing.clearOldContainersTimer.callEach(timeout);
|
|
} else {
|
|
_timing.clearOldContainersTimer.callOnce(timeout);
|
|
}
|
|
}
|
|
|
|
void SessionTransport::resetRetryTimeout() {
|
|
_timing.retryTimeout = 1;
|
|
}
|
|
|
|
bool SessionTransport::retryTimerActive() const {
|
|
return _timing.retryTimer.isActive();
|
|
}
|
|
|
|
bool SessionTransport::checkSentRequestsTimerActive() const {
|
|
return _timing.checkSentRequestsTimer.isActive();
|
|
}
|
|
|
|
bool SessionTransport::clearOldContainersTimerActive() const {
|
|
return _timing.clearOldContainersTimer.isActive();
|
|
}
|
|
|
|
int SessionTransport::retryTimeout() const {
|
|
return _timing.retryTimeout;
|
|
}
|
|
|
|
qint64 SessionTransport::retryWillFinish() const {
|
|
return _timing.retryWillFinish;
|
|
}
|
|
|
|
AbstractConnection *SessionTransport::connection() const {
|
|
return _state.connection.get();
|
|
}
|
|
|
|
bool SessionTransport::hasReceivedData() const {
|
|
return _state.connection && !_state.connection->received().empty();
|
|
}
|
|
|
|
mtpBuffer SessionTransport::takeReceivedData() {
|
|
Assert(_state.connection != nullptr);
|
|
Assert(!_state.connection->received().empty());
|
|
|
|
auto result = std::move(_state.connection->received().front());
|
|
_state.connection->received().pop_front();
|
|
return result;
|
|
}
|
|
|
|
QString SessionTransport::activeTransport() const {
|
|
return _state.connection ? _state.connection->transport() : QString();
|
|
}
|
|
|
|
QString SessionTransport::connectionTag() const {
|
|
return _state.connection ? _state.connection->tag() : u"none"_q;
|
|
}
|
|
|
|
crl::time SessionTransport::connectionPingTime() const {
|
|
return _state.connection ? _state.connection->pingTime() : 0;
|
|
}
|
|
|
|
auto SessionTransport::serviceRequest() const
|
|
-> AbstractConnection::TransportServiceRequest {
|
|
Assert(_state.connection != nullptr);
|
|
return _state.connection->serviceRequest();
|
|
}
|
|
|
|
bool SessionTransport::serviceRequestNeeded(
|
|
AbstractConnection::TransportServiceRequest request) const {
|
|
return _state.connection && _state.connection->serviceRequestNeeded(request);
|
|
}
|
|
|
|
mtpBuffer SessionTransport::prepareSecurePacket(
|
|
uint64 keyId,
|
|
MTPint128 msgKey,
|
|
uint32 size) const {
|
|
Assert(_state.connection != nullptr);
|
|
return _state.connection->prepareSecurePacket(keyId, msgKey, size);
|
|
}
|
|
|
|
void SessionTransport::sendData(
|
|
mtpBuffer &&buffer,
|
|
AbstractConnection::SendDataContext context) {
|
|
Assert(_state.connection != nullptr);
|
|
_state.connection->sendData(std::move(buffer), context);
|
|
}
|
|
|
|
void SessionTransport::logInfo(const QString &message) const {
|
|
Assert(_state.connection != nullptr);
|
|
_state.connection->logInfo(message);
|
|
}
|
|
|
|
bool SessionTransport::empty() const {
|
|
return !_state.connection && _state.testConnections.empty();
|
|
}
|
|
|
|
void SessionTransport::startContainerCleanup() {
|
|
_timing.clearOldContainersTimer.callEach(kSentContainerLives);
|
|
}
|
|
|
|
void SessionTransport::noteMtprotoPayloadReceived() {
|
|
_timing.retryTimeout = 1;
|
|
const auto firstPayload = !_state.mtprotoDataReceived;
|
|
_state.webKeyNotFoundStrikes = 0;
|
|
if (firstPayload) {
|
|
_state.mtprotoDataReceived = true;
|
|
_state.mtprotoSilentTimeouts = 0;
|
|
_owner->logMtprotoEvent(
|
|
ProxyDiagnosticsPhase::MtpFirstDataReceived,
|
|
ProxyDiagnosticsSeverity::Info,
|
|
u"first mtproto payload received"_q);
|
|
_quietReconnect = false;
|
|
}
|
|
if (_state.connection) {
|
|
_state.connection->markProxyMtprotoPayloadReceived();
|
|
}
|
|
_state.startedConnectingAt = crl::time(0);
|
|
}
|
|
|
|
ProxyConnectionAttempt SessionTransport::currentProxyAttempt() const {
|
|
return _state.connection
|
|
? _state.connection->proxyConnectionAttempt()
|
|
: _state.mtproxyAttempt;
|
|
}
|
|
|
|
} // namespace MTP::details
|