All checks were successful
Desktop source guards / guards (push) Successful in 8s
Every MTProto session through a WEB proxy is a stream on a single
carrier whose relay keeps one FIFO per direction. Bulk media and
uploads filled that FIFO, every session's own 4-8s receive timer then
fired at once, and the reconnects piled new OPENs behind the same
backlog.
- Uplink: a scheduler serves interactive streams first, download
requests next and uploads round-robin in 64 KiB frames, with at most
1 MiB of upload bytes uncredited by the relay (one bounded batch in
front of a chat request); a burst guard keeps uploads from starving.
- Downlink: download streams keep only a share of a 2 MiB credit budget
(256 KiB..1 MiB each) instead of the full 4 MiB window, so media waits
in the backend's TCP buffers rather than in front of chat replies.
- Liveness: a WEB session asks the carrier before dropping its stream.
It waits while its request is still queued or the downlink is busy,
fails when the pipe is quiet for 8s after delivery, busy for 30s, or
after 64s total. A carrier with bytes outstanding and no relay
progress for 20s is recovered once, for all streams.
- A WEB session opens one stream instead of racing identical ones, and
a -404 on a WEB stream reconnects first; only a second -404 before any
reply decrypts destroys the temporary key.
- Uploads and downloads use at most two sessions per DC through a WEB
proxy, and slow upload parts are no longer cancelled and moved.
- web_carrier diagnostics report carrier state, stalls, per-class
stream and queue counts, credit and throughput every 10s of activity.
The policy lives in web_proxy_flow.{h,cpp} and is covered by the new
test_web_proxy_flow target and a source guard.
116 lines
3 KiB
C++
116 lines
3 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/transport/connection_abstract.h"
|
|
#include "mtproto/auth/mtproto_auth_key.h"
|
|
|
|
namespace MTP {
|
|
namespace details {
|
|
|
|
class AbstractSocket;
|
|
enum class HandshakePhase;
|
|
|
|
class TcpConnection : public AbstractConnection {
|
|
public:
|
|
TcpConnection(
|
|
not_null<RuntimeEnvironment*> runtime,
|
|
QThread *thread,
|
|
const ProxyData &proxy,
|
|
const ProxyStealthOptions &stealth);
|
|
|
|
ConnectionPointer clone(const ProxyData &proxy) override;
|
|
|
|
crl::time pingTime() const override;
|
|
crl::time fullConnectTimeout() const override;
|
|
void sendData(mtpBuffer &&buffer, SendDataContext context) override;
|
|
void disconnectFromServer() override;
|
|
void connectToServer(
|
|
const QString &address,
|
|
int port,
|
|
const bytes::vector &protocolSecret,
|
|
int16 protocolDcId,
|
|
bool protocolForFiles,
|
|
ConnectionStartContext context = {}) override;
|
|
void timedOut() override;
|
|
void markProxyMtprotoPayloadReceived() override;
|
|
HandshakePhase handshakePhase() const override;
|
|
ProxyConnectionAttempt proxyConnectionAttempt() const override;
|
|
ProxyTransportFailure proxyTransportFailure() const override;
|
|
ReceiveWaitVerdict receiveWaitVerdict(
|
|
crl::time waitStartedAt) const override;
|
|
bool isConnected() const override;
|
|
|
|
int32 debugState() const override;
|
|
|
|
QString transport() const override;
|
|
QString tag() const override;
|
|
|
|
~TcpConnection();
|
|
|
|
private:
|
|
enum class Status {
|
|
Waiting = 0,
|
|
Ready,
|
|
Finished,
|
|
};
|
|
|
|
void socketRead();
|
|
bytes::const_span prepareConnectionStartPrefix(bytes::span buffer);
|
|
|
|
void socketPacket(bytes::const_span bytes);
|
|
|
|
void socketConnected();
|
|
void socketDisconnected();
|
|
void socketError(int errorCode);
|
|
void socketProgress(HandshakePhase phase);
|
|
|
|
mtpBuffer parsePacket(bytes::const_span bytes);
|
|
void ensureAvailableInBuffer(int amount);
|
|
static uint32 fourCharsToUInt(char ch1, char ch2, char ch3, char ch4) {
|
|
char ch[4] = { ch1, ch2, ch3, ch4 };
|
|
return binary::Read<uint32>(bytes::make_span(ch));
|
|
}
|
|
|
|
const ProxyStealthOptions _stealth;
|
|
ProxyConnectionAttempt _mtproxyAttempt;
|
|
MtProxyAttemptPlan _mtproxyPlan;
|
|
ProxyTransportFailure _timeoutFailure;
|
|
crl::time _mtproxyAttemptStartedAt = 0;
|
|
std::unique_ptr<AbstractSocket> _socket;
|
|
bool _connectionStarted = false;
|
|
|
|
int _offsetBytes = 0;
|
|
int _readBytes = 0;
|
|
int _leftBytes = 0;
|
|
bytes::vector _smallBuffer;
|
|
bytes::vector _largeBuffer;
|
|
bool _usingLargeBuffer = false;
|
|
|
|
uchar _sendKey[CTRState::KeySize];
|
|
CTRState _sendState;
|
|
uchar _receiveKey[CTRState::KeySize];
|
|
CTRState _receiveState;
|
|
class Protocol;
|
|
std::unique_ptr<Protocol> _protocol;
|
|
int16 _protocolDcId = 0;
|
|
|
|
Status _status = Status::Waiting;
|
|
MTPint128 _checkNonce;
|
|
|
|
QString _address;
|
|
int32 _port = 0;
|
|
crl::time _pingTime = 0;
|
|
|
|
rpl::lifetime _connectedLifetime;
|
|
rpl::lifetime _lifetime;
|
|
|
|
};
|
|
|
|
} // namespace details
|
|
} // namespace MTP
|