ZaStoGram/TMessagesProj/jni/tgnet/ConnectionSocketStateMachine.h
loop-uh 7bbe57aa6d
Some checks failed
ZaStoGram source guards / guards (push) Failing after 32s
Build three ZaStoGram APKs / build (armeabi-v7a, ZaStoGram-standalone-armeabi-v7a, Armv7, armv7) (push) Failing after 2m21s
Build three ZaStoGram APKs / build (arm64-v8a, ZaStoGram-standalone-arm64-v8a, Arm64, arm64) (push) Failing after 2m22s
Build three ZaStoGram APKs / build (x86, ZaStoGram-standalone-x86, X86, x86) (push) Failing after 2m23s
Качать через туннель параллельно и не отключать туннель после заморозки
ТСПУ замораживает каждое соединение с Cloudflare примерно после 16 КБ,
поэтому части по 8 КБ по одной за раз шли очень медленно.

- Через туннель до 8 запросов сразу, по кругу на разных соединениях
  загрузки; DOWNLOAD_CONNECTIONS_COUNT поднят до 8. Каждое соединение
  несёт одну часть и заменяется до заморозки.
- Туннель подавляется только если после upgrade не пришло ничего: раньше
  три заморозки отправляли медиа DC1/DC5 в прямой TCP, который сеть режет
  целиком, и ничего не грузилось по две минуты. Туннель считается рабочим
  после 6 КБ.
- Ротации туннеля пишутся одной сводной строкой wss_tunnel_rotated вместо
  двух строк на каждую часть.
2026-09-25 15:33:58 +03:00

278 lines
9.7 KiB
C++

/*
* This is the source code of tgnet library v. 1.1
* It is licensed under GNU GPL v. 2 or later.
*/
#ifndef CONNECTIONSOCKETSTATEMACHINE_H
#define CONNECTIONSOCKETSTATEMACHINE_H
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdint.h>
#include <time.h>
#include <deque>
#include <memory>
#include <string>
#include <vector>
#include "mtproxy/MtProxyStartupTimeline.h"
#include "wss/WssSocket.h"
class ByteArray;
class ByteStream;
class EventObject;
class NativeByteBuffer;
class Timer;
class ConnectionSocketStateMachine {
public:
enum class LifecycleState : uint8_t {
Idle,
Prepared,
WaitingGate,
TcpConnecting,
EpollRegistered,
ProxyHandshake,
FakeTlsHandshake,
FaketlsHandshake = FakeTlsHandshake,
MtprotoReady,
Closing,
};
enum class TransportMode : uint8_t {
None,
Direct,
Socks5,
PlainMtProxy,
FakeTlsMtProxy,
Wss,
};
enum class TransportSocketPolicy : uint8_t {
None,
NoSocket,
LiveEpoll,
OpenWithoutEpoll,
};
struct ActionRule {
const char *action;
LifecycleState state;
TransportSocketPolicy socketPolicy;
int16_t expectedProxyAuthState;
int16_t expectedTlsState;
bool requireWssTransport;
bool requireWssReady;
};
struct SocketSubstate {
int fd = -1;
struct epoll_event eventMask;
struct sockaddr_in address;
struct sockaddr_in6 address6;
bool isIpv6 = false;
time_t timeout = 12;
int64_t lastEventTime = 0;
EventObject *eventObject = nullptr;
ByteStream *outgoingByteStream = nullptr;
int32_t currentNetworkType = 0;
std::string currentAddress;
uint16_t currentPort = 0;
std::string currentSocksUsername;
std::string currentSocksPassword;
};
struct EpollSubstate {
bool registered = false;
};
struct HostResolveSubstate {
std::string waitingHost;
bool adjustWriteAfterResolve = false;
};
struct NotificationSubstate {
bool connectedSent = false;
bool closeNotified = false;
bool closeDiagnosticSuppressed = false;
bool deadForWrites = false;
bool mtproxySocketConnectedLogged = false;
};
struct SocksSubstate {
uint8_t proxyAuthState = 0;
};
struct FakeTlsSubstate {
int8_t tlsState = 0;
bool tlsHashMismatch = false;
bool serverHelloHmacMismatchObserved = false;
int64_t serverHelloHmacMismatchTime = 0;
bool tlsBufferSized = true;
uint8_t tlsBufferRecordType = 0;
NativeByteBuffer *tlsBuffer = nullptr;
ByteArray *pendingClientHello = nullptr;
uint32_t pendingClientHelloSize = 0;
uint32_t pendingClientHelloOffset = 0;
uint32_t pendingClientHelloFragmentTarget = 0;
uint32_t pendingClientHelloFragmentIndex = 0;
uint32_t pendingClientHelloFragmentCount = 0;
int64_t pendingClientHelloNextWriteTime = 0;
ByteArray *pendingTlsFrame = nullptr;
uint32_t pendingTlsFrameSize = 0;
uint32_t pendingTlsFrameOffset = 0;
uint32_t pendingTlsPayloadSize = 0;
int64_t nextTlsFrameWriteTime = 0;
bool mtproxyFirstTlsFrameSentLogged = false;
bool mtproxyFirstTlsDataReceivedLogged = false;
bool mtproxyFirstPlainDataSentLogged = false;
bool mtproxyFirstPlainDataReceivedLogged = false;
bool firstTransportPacketSent = false;
bool firstTransportPacketReceived = false;
bool dataPathProven = false;
int64_t mtproxyFirstTlsFrameSentTime = 0;
int64_t mtproxyFirstPlainDataSentTime = 0;
int64_t mtproxyFirstDataReceivedTime = 0;
uint32_t mtproxyTlsFrameCompletedCount = 0;
int64_t startupCoverStartTime = 0;
uint32_t startupCoverFrameCount = 0;
bool startupCoverStartedLogged = false;
bool startupCoverEndedLogged = false;
};
struct WssSubstate {
bool active = false;
int32_t datacenterId = 0;
bool mediaConnection = false;
tgnet::wss::Route route;
std::unique_ptr<tgnet::transport::Socket> transport;
// Closed on purpose after one part through the throttled tunnel.
bool tunnelRotating = false;
// Outgoing bytes live in the shared outgoingByteStream, but the relay
// handles only the FIRST MTProto packet of each WebSocket frame and
// silently drops the rest, so the stream must be cut back into frames
// exactly at packet boundaries. Sizes are recorded here as packets are
// queued. Measured 2026-08-09: msgs_ack and req_DH_params sent as two
// frames complete the handshake, the same pair coalesced into one frame
// gets no answer at all.
std::deque<uint32_t> outgoingPacketSizes;
// Сторож «данные отправлены — ответа нет»: время первой порции
// MTProto-байт, реально выпущенной в транспорт на этом соединении.
int64_t firstFrameSentTime = 0;
int64_t openTime = 0;
};
struct AdmissionSubstate {
Timer *timer = nullptr;
bool queued = false;
bool queuePublished = false;
bool active = false;
bool ready = false;
bool ipv6 = false;
uint32_t generation = 0;
uint32_t timerGeneration = 0;
int32_t priority = 0;
int32_t timerMode = 0;
int64_t startTime = 0;
int64_t clientHelloSentTime = 0;
std::string key;
};
struct EndpointGateSubstate {
bool backoffReady = false;
bool tcpConnectActive = false;
bool tcpConnectReady = false;
bool tcpConnectGatePublished = false;
bool dnsCoalesceReady = false;
// The current proxy is the WEB proxy's loopback bridge. Such
// connections never enter the MTProxy endpoint gates above.
bool webProxyBridge = false;
// Bridge listening port and this socket's local port: together they
// name the socket's stream inside WebProxyTransport.
uint16_t webProxyBridgePort = 0;
uint16_t webProxyLocalPort = 0;
// Receive-wait state (ConnectionSocket::deferWebProxyReceiveTimeout):
// the silence the carrier was last asked about, when to ask again and
// the last reason it gave.
int64_t webProxyWaitAnchor = 0;
int64_t webProxyRecheckAt = 0;
int32_t webProxyWaitReason = 0;
};
struct PendingWriteSubstate {
ByteArray *tempBuffer = nullptr;
size_t bytesRead = 0;
bool adjustWriteAfterPreTcpGate = false;
};
struct DiagnosticsSubstate {
LifecycleState lifecycle = LifecycleState::Idle;
TransportMode transportMode = TransportMode::None;
std::string currentSecret;
std::string currentSecretDomain;
std::string currentOriginalSecretDomain;
std::string currentSanitizedSecretDomain;
std::string currentLowercaseSecretDomain;
std::string currentNoTrailingDotSecretDomain;
std::string currentPunycodeSecretDomain;
std::string currentClientHelloSni;
const char *currentSecretKind = "none";
bool currentSecretIsFakeTls = false;
uint32_t currentAllowedSniVariants = 0;
int32_t currentRecipeFamily = 0;
int32_t currentRecipeSniVariant = 0;
int32_t currentRecipeParserVariant = 0;
int32_t currentRecipeClassicVariant = 0;
int32_t currentProxyTlsProfile = 0;
int32_t currentEffectiveProxyTlsProfile = 0;
int32_t currentClientHelloFragmentation = 0;
int32_t currentServerHelloParserMode = 0;
int32_t currentConnectionPatternMode = 0;
int32_t currentRecordSizingMode = 0;
int32_t currentTimingMode = 0;
int32_t currentStartupCoverMode = 0;
std::string currentProxyTlsProfileKey;
std::string currentMtProxyEndpointKey;
std::string currentMtProxyRecipeCacheKey;
std::string currentMtProxyProbeKey;
std::string currentMtProxyNetworkEndpointKey;
std::string currentMtProxyDnsCacheKey;
std::string currentMtProxyAdmissionKey;
std::string proxyCheckDiagnostic = "connection_not_started";
MtProxyStartupTimeline startupTimeline;
};
SocketSubstate socket;
EpollSubstate epoll;
HostResolveSubstate hostResolve;
NotificationSubstate notification;
SocksSubstate socks;
FakeTlsSubstate fakeTls;
WssSubstate wss;
AdmissionSubstate admission;
EndpointGateSubstate endpointGate;
PendingWriteSubstate pendingWrite;
DiagnosticsSubstate diagnostics;
const char *lifecycleName(LifecycleState state) const;
const char *transportModeName(TransportMode mode) const;
const ActionRule *findActionRule(const char *action) const;
bool can(const char *action) const;
bool isAllowedTransition(LifecycleState previous, LifecycleState next) const;
void setLifecycle(LifecycleState next);
void setTransportMode(TransportMode mode);
bool setSocketFd(int fd);
bool setEpollRegistered(bool registered);
bool setProxyAuthState(uint8_t state);
bool setTlsState(int8_t state);
int createNativeSocket(int domain, int type, int protocol);
bool closeNativeSocket(const char *reason);
bool connectNativeSocket(const sockaddr *address, socklen_t addressLen);
bool epollCtlAdd(int epollFd);
bool epollCtlMod(int epollFd);
bool epollCtlDel(int epollFd);
ssize_t sendBytes(const void *bytes, size_t size, int flags);
ssize_t recvBytes(void *bytes, size_t size, int flags);
};
#endif