mirror of
https://github.com/by-sonic/tglock.git
synced 2026-11-05 23:31:58 +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:
@@ -43,6 +43,49 @@ impl CryptoContext {
|
||||
self.telegram_decrypt.apply_keystream(data);
|
||||
self.client_encrypt.apply_keystream(data);
|
||||
}
|
||||
|
||||
/// Разделить шифры по направлениям, чтобы туннель шёл в обе стороны сразу.
|
||||
///
|
||||
/// Направления независимы: это два потока AES-CTR со своими ключами, и ни
|
||||
/// один байт одного не влияет на другой.
|
||||
pub fn split(self) -> (Upstream, Downstream) {
|
||||
(
|
||||
Upstream {
|
||||
client_decrypt: self.client_decrypt,
|
||||
telegram_encrypt: self.telegram_encrypt,
|
||||
},
|
||||
Downstream {
|
||||
telegram_decrypt: self.telegram_decrypt,
|
||||
client_encrypt: self.client_encrypt,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Шифры направления «клиент -> Telegram».
|
||||
pub struct Upstream {
|
||||
client_decrypt: AesCtr,
|
||||
telegram_encrypt: AesCtr,
|
||||
}
|
||||
|
||||
impl Upstream {
|
||||
pub fn apply(&mut self, data: &mut [u8]) {
|
||||
self.client_decrypt.apply_keystream(data);
|
||||
self.telegram_encrypt.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// Шифры направления «Telegram -> клиент».
|
||||
pub struct Downstream {
|
||||
telegram_decrypt: AesCtr,
|
||||
client_encrypt: AesCtr,
|
||||
}
|
||||
|
||||
impl Downstream {
|
||||
pub fn apply(&mut self, data: &mut [u8]) {
|
||||
self.telegram_decrypt.apply_keystream(data);
|
||||
self.client_encrypt.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_secret() -> [u8; 16] {
|
||||
|
||||
Reference in New Issue
Block a user