mirror of
https://github.com/by-sonic/tglock.git
synced 2026-09-05 18:16:09 +03:00
Оба направления туннеля обслуживал один `select!` с пометкой `biased`. `biased` опрашивает ветки строго по порядку: пока в первой — «Telegram → клиент» — есть данные, до второй очередь не доходит вообще. При непрерывном потоке вниз, то есть при первичной синхронизации телефона или загрузке медиа, исходящие пакеты клиента не читались. Второй дефект в том же цикле: одна задача на оба направления. `tcp_w.write_all` ждёт, пока клиент разберёт присланное, и всё это время не опрашивается чтение от клиента. Телефон по Wi-Fi разбирает поток медленнее, чем Telegram Desktop на той же машине через loopback, — отсюда асимметрия «на компьютере работает, на телефоне нет». Для MTProto это фатально: клиент обязан слать подтверждения, а за каждым следующим куском файла — свой `upload.getFile`. Первый запрос уходит, дальше идёт поток вниз, и следующие запросы наверх не попадают. Снаружи это выглядит как «Подключено» при живом туннеле, нулевых сбоях и нулевых отклонениях: чаты на месте, иконки не грузятся, отправка виснет с часиками. Направления разделены на две независимые половины: `ws.split()` плюс `CryptoContext::split()`, потому что шифры направлений независимы — два потока AES-CTR со своими ключами. Ping приходит в читающую половину, а отвечает на него пишущая, через канал на четыре слота: владелец отправляющей половины должен оставаться ровно один. Два теста, падающие на beta.11: за пять секунд непрерывной загрузки наверх не уходит ни одного байта, и клиент, не успевающий читать, замораживает собственную отправку. Снятие одного `biased` чинит только первый — это и показывает, что дефекта два. Co-authored-by: by-sonic <171230345+by-sonic@users.noreply.github.com>
This commit is contained in:
@@ -116,6 +116,38 @@ LAN-режим превращал бы машину в открытый прок
|
||||
Счётчик `ws_failures` от них отличается тем, что растёт после успешного
|
||||
рукопожатия с клиентом: там договорились с клиентом, но не смогли с Telegram.
|
||||
|
||||
## Туннель: два независимых направления
|
||||
|
||||
Каждое клиентское соединение получает свой WebSocket-туннель, и внутри него
|
||||
данные идут в обе стороны сразу. До 2.0.0-beta.12 оба направления обслуживал
|
||||
один `select!` с пометкой `biased`, и это давало два дефекта, снаружи
|
||||
выглядевших одинаково: «Подключено», а ничего не идёт.
|
||||
|
||||
`biased` опрашивает ветки строго по порядку. Пока в первой — «Telegram →
|
||||
клиент» — есть данные, до второй очередь не доходит вообще. То есть при
|
||||
непрерывном потоке вниз (первичная синхронизация телефона, загрузка медиа)
|
||||
исходящие пакеты клиента не читались.
|
||||
|
||||
Второй дефект — одна задача на оба направления. `tcp_w.write_all` ждёт, пока
|
||||
клиент разберёт присланное, и всё это время не опрашивается чтение от клиента.
|
||||
Телефон по Wi-Fi разбирает поток медленнее, чем Telegram Desktop на той же
|
||||
машине через loopback, — отсюда асимметрия «на компьютере работает, на телефоне
|
||||
нет» из #42.
|
||||
|
||||
Для MTProto это фатально: клиент обязан слать подтверждения, а за каждым
|
||||
следующим куском файла — свой `upload.getFile`. Первый запрос уходит, дальше
|
||||
идёт поток вниз, и следующие запросы наверх не попадают. Загрузка встаёт при
|
||||
живом туннеле, нулевых сбоях и нулевых отклонениях — ровно картина из #32.
|
||||
|
||||
Теперь это две независимые половины: `ws.split()` плюс `CryptoContext::split()`,
|
||||
потому что шифры направлений независимы — два потока AES-CTR со своими ключами.
|
||||
Ping приходит в читающую половину, а отвечает на него пишущая, через канал на
|
||||
четыре слота: владелец отправляющей половины должен оставаться ровно один.
|
||||
|
||||
Оба дефекта закрыты тестами, которые падают на beta.11. Первый: за пять секунд
|
||||
непрерывной загрузки наверх не уходит ни одного байта. Второй: клиент, не
|
||||
успевающий читать, замораживает собственную отправку.
|
||||
|
||||
## Учёт состояния
|
||||
|
||||
`Stats::ws` считает **установленные** туннели: счётчик поднимается после
|
||||
|
||||
Reference in New Issue
Block a user