6394853fef
实施方案 docs/网络/N34-自愈审计/实施方案.md §5 项1/2/3/5(项4 U15受E6暂缓): - 3a 合并reconciler:net_listener_pump删除,与net_reconcile_tick合并为 单一100ms tick;判据读驱动状态缓存(唯一刷新点=net_poll每轮全量刷新, E2背书18.1us);去抖分级②=1/③④⑤=2/①=4轮(M3让位窗400ms保留)+冷却1s; 链路态订阅留痕(F-DRV-13);探针去抖删除(F-MS-9) - 3b 忙等统一(P2b):listen/connect open重试与close排空循环改 net_sock_reset_sync(驱动sock_reset:读空RX→CLOSE→排空事件→等 byte0=00H,内置LISTEN态二段CLOSE补发);close不再读清全局中断寄存器 (F-NET-7);net_poll每轮步进活跃复位状态机(驱动契约,防搁浅) - 3c 镜像降级:net_sock_state_t声明为本层会话投影,芯片事实源=驱动缓存 - E-02收口:新API net_drop_conn(拆会话保监听,QUARANTINE语义,幂等; 模拟器双端实现;timeSync 30s预算耗尽接入;主机单测TC-TS-027d) 定案:CH395F close无RST,对内核存活不close的对端停FIN_WAIT_2, 监听恢复受限于对端close(Trap 07补充),兜底=E13 keepalive/TIMEOUT 台架全绿(Code=211348 RW=1104 ZI=154232):@test PASS;[STACK] net 1116/3840;Trap22 :7003 50/50+:21三档各50/50;Trap23 RST10/10+FIN5/5; Trap25 n30 11/11;E-02双PASS;iec104 18/18;对时跨会话连续; ftp_regression 11/11;integrity 15/15 SHA;ci_local L0+L0.5全过。
111 lines
4.4 KiB
Python
111 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
||
"""E-02 头阻塞专项台架探针(timeSync 侧,A/B 对照用)。
|
||
|
||
场景(错误码传播审计.md E-02 的 timeSync 触发形态):
|
||
1. 一个"挂起"的对时客户端连上 :8888 后不发任何数据(空闲/故障客户端,
|
||
常见工况)——旧固件在此触发 30s 阻塞 net_recv 独占 netTask,
|
||
全体消费者的队列消息停摆最长 30s;
|
||
2. 2s 后从 PC 发起 FTP(:21) 连接,测 banner 到达时延 = 队列响应性:
|
||
修复前 ≈ 25~30s(队头冻结),修复后 ≈ 数百 ms 内;
|
||
3. 34s 时 30s 总预算应已耗尽:设备拆掉该会话(N34 阶段 3 net_drop_conn:
|
||
FIN 关闭 + 本层收口 + 重监听),随后**本探针模拟守规矩对端**:
|
||
close 自己的 socket;
|
||
4. 芯片回 CLOSED(TC-NET-204 模式 A:TIME_WAIT 过渡 ~150ms)→ relisten,
|
||
:8888 应能再接受新连接(3s 重试窗内);新连接发完整 8 字节 TIME 包 →
|
||
设备应落 "wall clock updated"。
|
||
|
||
⚠ 定案口径(Trap 07 定案更正 2026-10-11 + 实验方案 E13 §5):CH395F close
|
||
**无 RST 语义**。若对端内核存活(app 挂起但 socket 不关,内核自动 ACK FIN),
|
||
芯片停在 FIN_WAIT_2、监听恢复受限于对端 close——探针第 3 步的 close 正是
|
||
模拟"对端配合"这一可恢复边界;不配合场景的兜底是芯片 TIMEOUT/keepalive
|
||
拆僵尸会话(E13 定案,30~90s)。
|
||
|
||
用法: python e02_probe.py <run-tag>
|
||
退出码: 0 = 队列响应性 PASS;1 = FAIL;2 = 探针自身异常
|
||
"""
|
||
import socket
|
||
import sys
|
||
import time
|
||
|
||
DEV = "192.168.1.100"
|
||
tag = sys.argv[1] if len(sys.argv) > 1 else "run"
|
||
|
||
t0 = time.time()
|
||
|
||
|
||
def log(msg):
|
||
print("[%s] %9.3f %s" % (tag, time.time() - t0, msg), flush=True)
|
||
|
||
|
||
def main():
|
||
# 1. 挂起对时客户端:连接后不发任何数据
|
||
ts = socket.create_connection((DEV, 8888), timeout=5)
|
||
log("time-sync conn open (hung client: sends nothing)")
|
||
|
||
# 2. 2s 后测 FTP banner 时延(队列响应性)
|
||
time.sleep(2.0)
|
||
t1 = time.time()
|
||
banner = None
|
||
try:
|
||
ftp = socket.create_connection((DEV, 21), timeout=35)
|
||
banner = ftp.recv(256)
|
||
dt = time.time() - t1
|
||
log("FTP banner after %8.1f ms: %r" % (dt * 1000, banner[:40]))
|
||
ftp.close()
|
||
except Exception as e:
|
||
dt = time.time() - t1
|
||
log("FTP connect FAIL after %8.1f ms: %r" % (dt * 1000, e))
|
||
dt = None
|
||
queue_ok = (banner is not None) and (dt is not None) and (dt < 3.0)
|
||
log("queue responsiveness: %s (banner %s ms)"
|
||
% ("PASS" if queue_ok else "FAIL",
|
||
("%.0f" % (dt * 1000)) if dt is not None else "n/a"))
|
||
|
||
# 3. 等 30s 总预算耗尽(设备应拆会话:FIN + 本层收口 + 重监听)
|
||
remain = 34.0 - (time.time() - t0)
|
||
if remain > 0:
|
||
time.sleep(remain)
|
||
|
||
# 3b. 模拟守规矩对端:设备已发 FIN(drop_conn),本端 close 配合拆链。
|
||
# CH395F close 无 RST 语义(Trap 07 定案更正):不配合的内核存活对端
|
||
# 会把芯片停在 FIN_WAIT_2,监听恢复受限于对端 close——不在本探针判据内。
|
||
try:
|
||
ts.close()
|
||
log("hung client socket closed (cooperate with device FIN)")
|
||
except OSError:
|
||
pass # 设备已先拆连,本地 close 报 ECONNRESET 属预期
|
||
|
||
# 4. 监听应已重建(芯片 TIME_WAIT 过渡 ~150ms + relisten):3s 重试窗
|
||
t2 = time.time()
|
||
listener_ok = False
|
||
ts2 = None
|
||
while time.time() - t2 < 3.0:
|
||
try:
|
||
ts2 = socket.create_connection((DEV, 8888), timeout=2)
|
||
break
|
||
except Exception as e:
|
||
log("second time-sync conn retry: %r" % (e,))
|
||
time.sleep(0.3)
|
||
if ts2 is not None:
|
||
dt2 = time.time() - t2
|
||
epoch = int(time.time())
|
||
log("new time-sync conn in %6.0f ms, sent full TIME packet (epoch=%d)"
|
||
% (dt2 * 1000, epoch))
|
||
ts2.sendall(b"TIME" + epoch.to_bytes(4, "big"))
|
||
time.sleep(1.5) # 留时间给设备处理并打日志
|
||
ts2.close()
|
||
listener_ok = True
|
||
else:
|
||
log("second time-sync conn FAIL (3s window)")
|
||
log("OVERALL: queue=%s listener=%s"
|
||
% ("PASS" if queue_ok else "FAIL", "PASS" if listener_ok else "FAIL"))
|
||
return 0 if (queue_ok and listener_ok) else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
sys.exit(main())
|
||
except Exception as e:
|
||
print("[%s] PROBE ERROR: %r" % (tag, e), flush=True)
|
||
sys.exit(2)
|