ZaStoGram_desktop/Telegram/SourceFiles/mtproto/session/private/transport.h
loop-uh 1e19d26187
All checks were successful
Desktop source guards / guards (push) Successful in 12s
Качать файлы через туннель частями по 8 КБ на коротких соединениях
ТСПУ замораживает каждое соединение с Cloudflare примерно после 16 КБ
входящих: на ПК (лог 25.09) ни одна сессия туннеля к DC1 не получила больше
13 КБ, а часть файла 128 КБ целиком не проходила ни разу (send_count=51),
поэтому файлы в «Избранном» стояли на 0.

- Для DC, чей медийный релей подавлен и ушёл в туннель, часть 128 КБ
  собирается из 16 кусков по 8 КБ; для CDN части не делятся.
- До 8 сессий сразу, в каждой один запрос: скорость даёт параллельность.
- Файловое соединение туннеля переоткрывается на границе пакета после
  4 КБ входящих, до заморозки; такие сокеты пишутся одной сводной строкой
  wss_tunnel_rotated, строки переподключения для них не пишутся.
- Туннель подавляется только если после upgrade не пришло ничего: раньше
  три заморозки отправляли DC1 в прямой TCP, который сеть режет целиком,
  и файлы не грузились совсем по две минуты.
2026-09-25 15:01:01 +03:00

166 lines
5.4 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
*/
#pragma once
#include "mtproto/config/mtproto_dc_options.h"
#include "mtproto/proxy/dial_pacer.h"
#include "mtproto/runtime/connection_status_types.h"
#include "mtproto/runtime/runtime_environment.h"
#include "mtproto/transport/connection_abstract.h"
namespace MTP::details {
class SessionPrivate;
class SessionTransport final {
public:
SessionTransport(
not_null<SessionPrivate*> owner,
not_null<RuntimeEnvironment*> runtime,
not_null<QThread*> thread,
uint64 proxyGeneration);
~SessionTransport();
void start();
void connectToServer(bool afterConfig = false);
void requestCDNConfig();
void restartNow();
void migrateProxy(uint64 generation);
void restart();
void doDisconnect();
void destroyAllConnections(
ProxyCloseOrigin origin = ProxyCloseOrigin::OwnerDestroyed);
void onSentSome(uint64 size);
void onReceivedSome();
void startContainerCleanup();
void retryByTimer();
void waitConnectedFailed();
void waitReceivedFailed();
void waitBetterFailed();
void markConnectionOld();
void confirmBestConnection();
void removeTestConnection(not_null<AbstractConnection*> connection);
void setRetryTimeout(int timeout);
void scheduleRetryTimeout(int timeout);
void schedulePing(crl::time timeout);
void scheduleCheckSentRequests(crl::time timeout);
void scheduleClearOldContainers(crl::time timeout, bool repeated);
void resetRetryTimeout();
void noteMtprotoPayloadReceived();
void logInfo(const QString &message) const;
void sendData(
mtpBuffer &&buffer,
AbstractConnection::SendDataContext context);
[[nodiscard]] bool retryTimerActive() const;
[[nodiscard]] bool checkSentRequestsTimerActive() const;
[[nodiscard]] bool clearOldContainersTimerActive() const;
[[nodiscard]] int retryTimeout() const;
[[nodiscard]] qint64 retryWillFinish() const;
[[nodiscard]] AbstractConnection *connection() const;
[[nodiscard]] bool hasReceivedData() const;
[[nodiscard]] mtpBuffer takeReceivedData();
[[nodiscard]] QString activeTransport() const;
[[nodiscard]] QString connectionTag() const;
[[nodiscard]] crl::time connectionPingTime() const;
[[nodiscard]] AbstractConnection::TransportServiceRequest serviceRequest()
const;
[[nodiscard]] bool serviceRequestNeeded(
AbstractConnection::TransportServiceRequest request) const;
[[nodiscard]] mtpBuffer prepareSecurePacket(
uint64 keyId,
MTPint128 msgKey,
uint32 size) const;
[[nodiscard]] bool empty() const;
[[nodiscard]] ProxyConnectionAttempt currentProxyAttempt() const;
// Reconnecting after a planned rotation of a tunnel file connection:
// the routine connect/ready lines are not logged for it.
[[nodiscard]] bool quietReconnect() const {
return _quietReconnect;
}
private:
struct TestConnection {
ConnectionPointer data;
int priority = 0;
QString endpoint;
ProxyConnectionUse mtproxyUse = ProxyConnectionUse::Main;
ProxyConnectionAttempt mtproxyAttempt;
crl::time mtproxyAttemptStartedAt = 0;
// Held from the moment the attempt is queued until the proxy either
// relays a Telegram reply or the attempt dies with the entry.
ProxyDialLease mtproxyDial;
crl::time mtproxyDialDelay = 0;
};
struct ConnectionState {
ConnectionPointer connection;
ProxyConnectionUse mtproxyUse = ProxyConnectionUse::Main;
ProxyConnectionAttempt mtproxyAttempt;
crl::time mtproxyAttemptStartedAt = 0;
uint64 proxyGeneration = 0;
bool mtprotoDataReceived = false;
int mtprotoSilentTimeouts = 0;
// -404 received through a WEB proxy stream since the key last
// decrypted a reply, see handleError().
int webKeyNotFoundStrikes = 0;
std::vector<TestConnection> testConnections;
crl::time startedConnectingAt = 0;
};
struct TimingState {
TimingState(
not_null<RuntimeEnvironment*> runtime,
not_null<SessionTransport*> owner,
not_null<QThread*> thread);
RuntimeTimer retryTimer;
int retryTimeout = 1;
qint64 retryWillFinish = 0;
RuntimeTimer oldConnectionTimer;
bool oldConnection = true;
RuntimeTimer waitForConnectedTimer;
RuntimeTimer waitForReceivedTimer;
RuntimeTimer waitForBetterTimer;
crl::time waitForReceived = 0;
crl::time waitForReceivedStartedAt = 0;
QString waitForReceivedDetails;
bool waitForReceivedExtended = false;
crl::time waitForConnected = 0;
crl::time waitForConnectedArmed = 0;
crl::time firstSentAt = -1;
RuntimeTimer pingSender;
RuntimeTimer checkSentRequestsTimer;
RuntimeTimer clearOldContainersTimer;
};
[[nodiscard]] ProxyConnectionUse classifyEndpointUse() const;
[[nodiscard]] bool appendTestConnection(
DcOptions::Variants::Protocol protocol,
const QString &ip,
int port,
const bytes::vector &protocolSecret,
bool protocolForFiles);
void connectingTimedOut();
[[nodiscard]] bool webProxy() const;
[[nodiscard]] bool extendWebProxyReceiveWait();
void handleError(int errorCode);
void onError(
not_null<AbstractConnection*> connection,
qint32 errorCode);
void onConnected(not_null<AbstractConnection*> connection);
void onDisconnected(not_null<AbstractConnection*> connection);
void clearTestConnections();
void armWaitForConnectedTimer();
const not_null<SessionPrivate*> _owner;
ConnectionState _state;
bool _quietReconnect = false;
TimingState _timing;
};
} // namespace MTP::details