# network.error_timeout_server_state ## Scope 对比认证失败、连接失败、超时、频道状态检查、服务器状态通知和恢复/回到登录界面的完整分支。 ## Reference call chain - `UserInterface/AccountConnector.cpp` - `UserInterface/ServerStateChecker.cpp` - `UserInterface/PythonNetworkStreamPhaseLogin.cpp` - `EterLib/NetStream.cpp` ## Current call chain - `extension/src/net/auth_client.h` - `extension/src/net/classic/classic_session.cpp` - `project/net/channel_status.gd` - `project/net/serverinfo.gd` - `project/app_flow.gd` - `project/ui/reconnect_ui.gd` ## Branch matrix | 场景 | 40250 | 当前端 | 结论 | |---|---|---|---| | auth 失败 | AccountConnector 消费错误并通知 login UI,断开 auth/game 状态 | `login_failed` 返回 AppFlow 登录页;旧 session 清理顺序未完全证明 | PARTIAL | | 连接超时 | `Process`/connector failure 进入 offline/disconnect | `ClassicStream` 与 `NetStream` 均保留 3 秒 non-blocking deadline,并在 socket 可写后再用 `SO_ERROR` 确认连接完成 | MAPPED:仍缺少所有上层失败通知组合证明 | | channel status | `ServerStateChecker` 请求首 channel,解析 count 和 `{port,status}`,逐频道通知 | 当前查询首频道,解析 classic 210;失败时 fallback TCP probe | PARTIAL:功能相近但多了 approximation | | 部分响应 | NetStream 保留接收缓存等待完整状态包 | 当前已缓存状态 body,遇到半条记录会继续等待后续 TCP 数据 | MAPPED:分片行为已补回归测试 | | 空/非法 count | 由包长度和状态处理逻辑拒绝 | `_try_parse_classic` 检查范围;body 内仍需完善负值/超大值保护 | PARTIAL | | 恢复 | 失败后按 connector/server state 回调回到正确 phase | 当前由 AppFlow signal 和 ReconnectUI timer 驱动 | PARTIAL | ## Equivalence matrix | 项目 | 状态 | 证据 | |---|---|---| | Preconditions | PARTIAL | 认证/连接和状态请求有检查;完整失败通知、远端关闭与上层重入仍需补齐 | | Branch structure | PARTIAL | auth/channel/fallback 主分支存在,失败通知和超时分支不同 | | Algorithms/formulas | MAPPED | classic count/record 解析和分片 body 累积已有实现与测试 | | State transition order | PARTIAL | 当前 signal/UI retry,参考 connector/phase offline 回调顺序不同 | | Constants/units | MAPPED | classic/m2dev socket 与 channel probe 均为 3 秒;状态 count 上限为 4096,仍需边界夹具覆盖 | | Timing/event sources | PARTIAL | timer/fallback probe 与参考 network process/state checker 不同 | | Resource/data sources | PARTIAL | serverinfo 推导端口,参考接收显式 channel entries | | Protocol side effects | PARTIAL | 206/210 classic 包存在;fallback TCP probe 是当前扩展副作用 | | Interruption/failure/cleanup | PARTIAL | 连接中断、重复 probe、重试终止仍缺少测试 | ## Deep audit round 2026-09-20 本轮沿 40250 `AccountConnector::Connect/Process`、`CServerStateChecker::Request/Update`、`CPythonNetworkStream::LoginPhase` 和 `CNetworkStream::Process/Connect` 逐分支核对,得到以下结论: 1. 40250 的认证连接通过 `CNetworkStream::Connect` 建立非阻塞 socket,`Process` 用 socket 可写事件确认连接成功,并使用 `m_connectLimitTime` 超时清理;当前 `NetStream` 与 `ClassicStream` 现在都保留 3 秒 deadline,且只有可写事件后才用 `SO_ERROR` 确认完成。连接超时/远端错误的上层通知组合仍需扩展测试。 2. 40250 `CAccountConnector::__AuthState_RecvPhase` 发送 `CG_LOGIN3` 后立即 `ClearLoginInfo()` 清掉密码;当前 `AuthClient` 在构造登录包后清零并清空 `m_pw`,`M2Client::pump_auth()` 同步丢弃 host-side `cfg_pw`,没有 login key 时的空密码重连会被拒绝。该边界已有 loopback 断言。 3. 40250 的 `ServerStateChecker::Request` 只连接首频道并发送一次 `HEADER_CG_STATE_CHECKER`,连接/发送失败时将所有已登记频道通知为关闭;`Update` 收到 `HEADER_GC_RESPOND_CHANNELSTATUS` 后按端口通知并 `Initialize()`。当前 `AppFlow::_probe_channels` 使用 `ChannelStatus` 查询首频道,未知端口则逐频道做额外 TCP probe,属于当前端的 approximation,不是 1:1 分支;多个“检测频道”点击可以并行创建查询节点,未见 in-flight/cancel/generation 保护。 4. 当前状态查询的 206/210 classic 解析已累积 body,负数和大于 4096 的 count 会拒绝;`ChannelStatus` 现在会先取消旧 probe,并在回调重入时固定旧 callback,避免旧结果投递给新请求。自动测试仍未覆盖连接后无响应超时、count=0/截断/尾随包及远端关闭。默认协议和 `MT_PROTOCOL=classic` 两次测试均通过。 5. 当前 AppFlow 登录失败/断线的 signal 分类存在,但账号/游戏连接失败后由 `M2Client` 直接 reset session,再由 AppFlow 重建 Login;这与 40250 的统一 Offline phase / `SetLoginPhase` 顺序不同。`p10_test` 还暴露了 Loading→Game 未隐藏和无 SceneTree 时 char-select timer 空树的测试/生命周期问题,恢复链不能标记为完成。 ## Required tests - auth success/failure、connect refusal、connect timeout、remote close。 - 206/210 完整包、分片包、半条 record、count=0、负值和超大 count。 - channel status 失败后的 fallback、重试上限和回到登录页。 - 同一 session 同时 login/reconnect/probe 的竞态与清理。 ## Evidence run - `godot --headless --path project --script channel_status_test.gd`:PASS。 - `MT_PROTOCOL=classic godot --headless --path project --script channel_status_test.gd`:PASS,覆盖 40250 classic 的 206 请求和 210 响应夹具。 - 认证 loopback 成功路径、密码清除、挂起连接 deadline 已在 `extension/tests/net_loopback_test.cpp` 覆盖;classic transport 的同等 deadline/可写门禁在 `extension/tests/net_classic_stream_test.cpp` 覆盖。 - 当前合同继续 `PARTIAL`:通过的状态包解析测试不能替代 40250 的认证失败、远端关闭、失败通知顺序、count 边界和完整恢复链证据。 ## Active UserInterface server-state checker review - `ServerStateChecker.h`/`ServerStateCheckerModule.cpp` 维护独立 `CNetworkStream`、channel 地址/端口表、Create/AddChannel/Request/Update/Initialize 和 Python window 回调;它是登录前服务器状态探测链,不等同于游戏 session 的重连。 - 当前端 channel status 有 classic packet smoke test,且单个 `ChannelStatus` 的旧 socket/重入 callback 已有清理逻辑;仍没有证明多 channel 请求的超时、远端关闭、失败通知顺序、窗口销毁后回调和与 login phase 的竞态清理一致;本轮纳入 active source 证据,合同仍为 `PARTIAL`。 ## Implementation fix round 2026-09-20 - `AuthClient::on_phase(PHASE_AUTH)` 先把密码拷贝进 `CG_LOGIN3`,随后显式清零并清空 `m_pw`,再检查 `send_packet()`;`M2Client::pump_auth()` 看到同一边界后清空 `cfg_pw`,`reconnect()` 在没有 login key 时拒绝空凭据重试。 - `NetStream` 和 `ClassicStream` 都增加 3000ms non-blocking connect deadline;classic 路径改为 `select` 可写后再 `SO_ERROR`,修复第一次 process 把仍在连接中的 socket 误报 Online 的差异。 - `ChannelStatus` 取消旧 probe、清空 mutable callback 后再发 `done`,支持 callback 内启动下一次查询;`AppFlow` 增加 channel probe in-flight guard。 - 新增/扩展 `net_loopback_test`、`net_classic_stream_test`、`channel_status_test.gd`,覆盖凭据清除、挂起连接 deadline 和 re-entrant probe callback;成功路径及默认/classic 两套状态包夹具通过。 ## Status `PARTIAL`。