ZaStoGram/TMessagesProj/jni/mtproxy/README.md
2026-08-05 19:18:49 +03:00

103 lines
5.7 KiB
Markdown

# MTProxy core module
Self-contained MTProxy/FakeTLS policy engine. Lives at `jni/mtproxy` and
builds as its own CMake static library, `mtproxy_core` (see
`jni/CMakeLists.txt`): it depends only on BoringSSL and PUBLIC-exports
`jni/`, so consumers include it as `"mtproxy/MtProxyX.h"`. The socket/Java
layers link against it; it never links back — the dependency arrow points
one way, into the engine.
Pure logic: phase classification, endpoint/adaptive/recovery policy, the
single retry-hold authority, handshake planning and scheduling, secret
parsing, server-flight parsing, startup timeline, probe coordination,
terminal-diagnostic derivation, failure evidence.
`MtProxyClientHelloPolicy` also owns the pre-send FakeTLS relay contract:
517..4096-byte structural bounds, a 32-byte session id, TLS 1.3 as the
first real cipher after relay-shaped GREASE, exact SNI equality with the
`ee` secret, and the measured-safe effective profile (Yandex by default;
exact Chromium-shaped profiles are withheld).
## Boundary rules (enforced by `Tools/check_mtproxy_module_boundary.py`)
- Files here may include only other `mtproxy/` headers — zero tgnet
headers (the `MT_PROXY_STARTUP_*` handshake limits live in
`MtProxyOptions.h`, not `Defines.h`).
- System/third-party includes are whitelisted (`ALLOWED_SYSTEM` in the
checker); the same surface is stubbed in `Tools/mtproxy_host_stubs`,
so the module compiles standalone on the host:
`python Tools/build_mtproxy_host.py` (MSVC Build Tools; also part of
`check_mtproxy_all.py`). Extend whitelist and stubs together.
- No sockets, no `FileLog`, no `ConnectionsManager`, no JNI. I/O and
logging stay in `ConnectionSocket`/`Connection`; this module only
decides, it never performs.
- `MtProxyPhaseClassification.h` is AUTOGENERATED from
`Tools/mtproxy_phase_contract.py` (single source of truth shared with
Java's `ProxyPhaseClassification.java`). Never edit by hand; run
`Tools/generate_mtproxy_phase_classification.py` after contract changes.
## Migration roadmap (one owner at a time)
1. **Done:** phase/verdict classification generated from one contract
(C++ + Java from `Tools/mtproxy_phase_contract.py`).
2. **Done:** module extracted into this folder with an enforced
dependency boundary; zero project includes; host build
(`Tools/build_mtproxy_host.py`) compiles it standalone.
3. **Done (decision layer):** classification decisions moved into the
module and host-compiled: `MtProxyTerminalDiagnostic` (terminal close
verdict derivation), generated `isLocalSchedulerTimeout` (was a hand
strcmp list in ConnectionSocket). The FakeTLS wire-state structs stay
with the I/O owner (`ConnectionSocketStateMachine`) by design: the
module decides, the socket performs.
4. **Done:** `MtProxyRetryAuthority` is the single owner of
"how long until the next attempt": Connection's exponential reconnect
backoff, the endpoint-cooldown/scheduler-pacing merge and the probe
coordinator hold all converge there.
`check_mtproxy_connection_pattern_modes.py` forbids hold math
re-growing in Connection/ConnectionSocket.
5. **Done (classification ownership):** Java's `ProxyPhasePolicy.classify`
table (kind/keyScope/backoff/rotate) is generated from the contract
(`java_key_scope`/`java_backoff` overrides document the two historical
divergences); checkers assert `mtproxy_phase_contract.java_policy()`
instead of parsing the Java switch.
6. **Done (JNI hold bridge):** the native retry-authority hold rides the
`onProxyConnectionStageChanged` callback as `suggestedReconnectHoldMs`
(Defines delegate → TgNetWrapper JNI → `ProxyConnectionEvent`). When it
is non-zero, `ProxyHealthStore.rememberEndpointFailure` uses it verbatim
(`hold_source=native`) instead of re-deriving from its own clock; the
local clock survives only for Java-origin failures with no native hold
(invalid-secret config failures keep their longer local floor). Native
raises the cooldown into the hold before the event leaves
`publishProxyConnectionStage`.
7. **Done (module promotion):** this folder moved from `tgnet/mtproxy` to
`jni/mtproxy` and became the `mtproxy_core` CMake static library.
8. **Done (host-run unit tests):** `Tools/build_mtproxy_host.py` now links
the module objects with `Tools/mtproxy_host_tests/mtproxy_host_tests.cpp`
and RUNS the binary as part of `check_mtproxy_all.py`. Covered: retry-hold
computation (base/cap/coordinator-merge envelopes), terminal-diagnostic
derivation (pre-I/O preservation, errno split, timeline fallback) and the
generated skip-list invariants, the ClientHello relay contract and the
effective-profile withholding policy. The RAND_bytes stub is a deterministic
xorshift stream — never all-zero (rejection sampling would spin forever)
and never asserted exactly (tests use jitter envelopes).
9. **Done (scheduler is a pure executor):** the sweep-style
`enqueueStale` API was removed outright — background check sweeps are
now impossible by construction, not just forbidden by guards. Checks
are explicit (`enqueueNow` from the UI); per-endpoint cadence is the
native hold via `ProxyHealthStore.nextCheckTime` →
`nextAllowedCheckTime`; the only timing the scheduler owns is
`PROXY_CHECK_SPACING_MS` start-to-start smoothing of its single-active
queue (submission hygiene, not a retry clock — documented in code and
enforced: `check_proxy_check_scheduler.py` forbids `failureBackoffMs`/
`cooldownMs` math in the scheduler and requires the
`nextAllowedCheckTime` gate). The foreground live-ping interval in
`ProxyListActivity` is a deliberate UI-freshness setting, not a retry
clock.
## Next iterations
- Device build/test remains the gate for the Java/JNI changes (no local
NDK or javac verification).