net: индекс подканала — 3 бита (исправлен silently-баг reliable)
Главная причина отсутствия server info: SUBCHANNEL_BITS был 4, из-за чего сервер читал subchannel=1 и 0 фрагментов, молча отбрасывая reliable-поток (net_SignonState не обрабатывался → m_bSendServerInfo не выставлялся). Подтверждено pcap-разбором и дизасмом engine_srv.so (CNetChan::ProcessPacket: lea 0x3(%esi) — ровно 3 бита; and $0x1 — reliable-флаг 0x01).
This commit is contained in:
parent
9cc4daf6b0
commit
50bb36304e
2 changed files with 57 additions and 3 deletions
|
|
@ -31,10 +31,14 @@ pub const FRAGMENT_OFFSET_BITS: usize = 18;
|
|||
pub const MAX_FRAGMENTS_PER_PACKET_BITS: usize = 5;
|
||||
/// Биты максимального размера файла.
|
||||
pub const MAX_FILE_SIZE_BITS: usize = 30;
|
||||
/// Биты номера подканала (в GMod — 4: 16 подканалов).
|
||||
pub const SUBCHANNEL_BITS: usize = 4;
|
||||
/// Биты номера подканала: 3 (8 подканалов, как в Source 2013 / HL2).
|
||||
///
|
||||
/// Проверено по эталонному разбору пакета: при 4 битах сервер читает
|
||||
/// subchannel=1 и «0 фрагментов», молча теряя reliable-данные (из-за этого
|
||||
/// не обрабатывался net_SignonState и не приходил server info).
|
||||
pub const SUBCHANNEL_BITS: usize = 3;
|
||||
|
||||
/// Ширина индекса подканала: GMod — 4 (16 подканалов), Source 2013 — 3.
|
||||
/// Ширина индекса подканала.
|
||||
/// Переопределяется переменной окружения для экспериментов.
|
||||
pub fn subchannel_bits() -> usize {
|
||||
std::env::var("SOURCE_RS_SUBCHANNEL_BITS")
|
||||
|
|
|
|||
|
|
@ -344,3 +344,53 @@ SendServerInfo() ; cl->vfunc(0xd0)
|
|||
- альтернатива для отладки: поднять локальный srcds на незалоченном порту
|
||||
(сейчас мешает сломанный резолвер в системе — `systemd-resolved` не
|
||||
запущен, см. §13).
|
||||
|
||||
### 13.3. НАЙДЕНА ПРИЧИНА: ширина индекса подканала (3 бита, не 4)
|
||||
|
||||
Гипотеза §13.2 оказалась **неверной**: дело не в Steam-авторизации. Настоящая
|
||||
причина — в заголовке reliable-фрагментов.
|
||||
|
||||
**Как обнаружено.** Захвачен трафик живого подключения (`SOURCE_RS_LOG=net=trace`).
|
||||
Сервер подтверждает наши netchan-пакеты (поле ack растёт 0→1→2→…), но в его
|
||||
ответах поле `InReliableState` **всегда равно 0**. Значит сервер принимает
|
||||
заголовок, но **не читает наш reliable-поток**.
|
||||
|
||||
Побитовый разбор нашего hello-пакета:
|
||||
|
||||
```
|
||||
seq=1 ack=0 flags=0x21 csum=0x58df rel=0x0001 chal=0x63896b24
|
||||
payload[191]: 10 bc 01 c5 82 ...
|
||||
```
|
||||
|
||||
| SUBCHANNEL_BITS | прочитанный subchannel | биты потоков | итог |
|
||||
|---|---|---|---|
|
||||
| **4** (было) | **1** | `[0, 0, 0]` | **0 фрагментов → reliable-данные молча отброшены** |
|
||||
| **3** (стало) | **0** | `[1, 0, 0]` | корректный single-block фрагмент |
|
||||
|
||||
При 4 битах сервер читал индекс 1 (несуществующий подканал) и ноль фрагментов
|
||||
→ `net_SignonState` не обрабатывался → `m_bSendServerInfo` не выставлялся →
|
||||
`SendPendingServerInfo` пропускал клиента → **серверный блок не уходил никогда**.
|
||||
|
||||
**Подтверждено дизассемблированием GMod-сервера** (`engine_srv.so`,
|
||||
`CNetChan::ProcessPacket`):
|
||||
|
||||
```
|
||||
189b6f: and $0x1,%esi ; flags & Reliable (0x01) — наш флаг верен
|
||||
189b93: lea 0x3(%esi),%edx ; читаем РОВНО 3 бита индекса подканала
|
||||
```
|
||||
|
||||
То есть `SUBCHANNEL_BITS = 3` (8 подканалов, как в Source 2013/HL2),
|
||||
а не 4. Прежнее значение 4 было ошибочным предположением; из-за него
|
||||
наши надёжные сообщения молча терялись.
|
||||
|
||||
Побочно подтверждено:
|
||||
- reliable-флаг пакета = `0x01` (`and $0x1`) — совпадает с нашим;
|
||||
- флаг challenge = `0x20` — совпадает;
|
||||
- `IN_RELIABLE_STATE_BITS = 16` — совпадает с Source.NET.
|
||||
|
||||
Ограничение `SendPendingServerInfo` (для публичного IP требуется
|
||||
`m_bFullyAuthenticated`) реально, но не блокировало: сервер готов слать данные
|
||||
сразу после разбора нашего reliable-потока. Новый прогон подключения упирается
|
||||
уже в `#GameUI_ServerRejectSteam` — это лимит Steam на частые подключения с
|
||||
одного аккаунта (`k_EBeginAuthSessionResultDuplicateRequest`), а не ошибка
|
||||
клиента.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue