fix(N34): E14 丢中断复核——芯片不丢事件;listen 排事件挪至 LISTEN 前+全局读收口+全库归因更正
48 轮直读 SINT 矩阵(8 周期×6 变体)复核历史"丢中断"说法:芯片侧事件 丢失 = 0。归类:drain 读清消费 3/48(drain-int 探针现场抓获)、门控 竞态 2/48、主机同步 1/48、幽灵态 0/48 未复现。 根除性修复:net_listen_locked / net_listener_try 的排事件读清从 listen 后挪至 LISTEN 命令之前——新连接 CONNECT 落进该窗即被本方读清 吞掉,即"数据被吞"的生产侧自伤机制(台架 3/48 为同形态放大版)。 全局读收口:全局中断寄存器唯一读者 = net_poll(I7);生产/测试/台架 游离全局读全部删除,ch395f.h 声明处加护栏注释。 归因更正:17 文件约 40 处"丢中断"措辞改为"事件未收到/读清消费竞态" (机制全部保留,仅归因更正);设计文档 §5.2 新增 E14 锚点;Trap Records TRAP-NET-17/-20/B3 归因更正段;配图生成器与 SVG 重生成。 台架:事件未收到复核探针保留(drain-int / SINT 补读×3 / 超时归类), 下次跑矩阵自动归类;实验注册(main.c/uvprojx)已完全还原。 验证:@build 0 错误 0 警告;ci_local L0 32/0 + gitlint + L0.5 953/953;doc-links --all --sections-strict 通过;@test PASS(无 [ERR],net init 619ms);回归 :7003 300ms×10 = 10/10、:21 n30×50 = 0/50 失败。
This commit is contained in:
+112
-102
@@ -39,13 +39,13 @@
|
||||
*/
|
||||
#define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔(ms) */
|
||||
|
||||
/* N34 E6 实验插桩(U15 失配频率,docs/网络/N34-自愈审计.md §6 E6):
|
||||
* 假设=「RX 非空但 readable=0」(RECV_OK 中断丢失的数据面形态)在生产真实
|
||||
/* E6 实验插桩(U15 失配频率,docs/网络/网络自愈架构设计.md §4.8;裁决锚点 §5.2 E6):
|
||||
* 假设=「RX 非空但 readable=0」(RECV_OK 事件未收到的数据面形态)在生产真实
|
||||
* 发生。置 1 烧实验固件:net_poll 每 32 轮对在用 fd 发一条 GET_RECV_LEN,
|
||||
* 命中计数 + 低频日志(每小时 ≤1 条防刷屏);跑 24h 常态 + E1 压测。
|
||||
* 判据:命中 >0 → 阶段 3 项 4(U15 内化)立项;=0(含压测)→ 上层 32 轮
|
||||
* 盲收保留现状、U15 登记观察项。**默认 0 = 产品构建零成本(编译剔除)**。
|
||||
* E6 已裁决(2026-10-13,实验方案 E6 结果):命中=0(含压测)→ 项 4 不立项,维持默认 0。
|
||||
* E6 已裁决(2026-10-13,《网络自愈架构设计》§5.2 E6):命中=0(含压测)→ 项 4 不立项,维持默认 0。
|
||||
* ⚠ 必须定义在文件最前部:bring_up 的 armed 日志与 net_poll 探测环两处消费。 */
|
||||
#define NET_U15_PROBE 0
|
||||
#if NET_U15_PROBE
|
||||
@@ -196,7 +196,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
* 按 ①数据 ②到点(仅显式预算) ③断连 顺序检查完成条件并通知调用方(语义逐项对齐旧自旋循环)
|
||||
* 关闭/网络重建/陈旧重同步走显式 settle/cancel 路径(取消必通知,调用方永不挂死)
|
||||
* 公开 API 返回契约不变:>0 字节数 / 0 EOF / -1 错误(错误码经通知值回传)
|
||||
* N34 阶段 1.5:预算归调用方——timeout_ms=0 即无限等待(30s 默认预算已删),
|
||||
* 自愈收敛阶段 1.5:预算归调用方——timeout_ms=0 即无限等待(30s 默认预算已删),
|
||||
* 原"到点 +1s 强制了结"的看门狗降级为 tripwire(只留痕、绝不伪造返回值)
|
||||
*/
|
||||
#define NET_PENDING_REGISTERED 0x70000000 /* 内部哨兵:pending 已登记(分派跳过即时通知;取值不与字节数空间冲突) */
|
||||
@@ -204,7 +204,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
|
||||
typedef struct {
|
||||
uint8_t active; /* 1 = 本 fd 有挂起 recv */
|
||||
uint8_t infinite; /* 1 = 无限等待(无 deadline,N34 阶段 1.5:0 预算 = 永等) */
|
||||
uint8_t infinite; /* 1 = 无限等待(无 deadline,自愈收敛阶段 1.5:0 预算 = 永等) */
|
||||
uint8_t tripwire_logged; /* 1 = 本轮挂起已打过 tripwire(保证只留痕一条) */
|
||||
void *buf; /* 调用方缓冲(仅指针,须保持有效至完成) */
|
||||
int len; /* 缓冲容量 */
|
||||
@@ -277,7 +277,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
/* 复位芯片 */
|
||||
ch395f_reset();
|
||||
|
||||
/* 芯片版本留痕 + 0-6 版本门控(N34 阶段0,§5.52 表):bit3 SOCKET_CLOSE
|
||||
/* 芯片版本留痕 + 0-6 版本门控(自愈收敛阶段0,§5.52 表):bit3 SOCKET_CLOSE
|
||||
* 需芯片 ≥0x46、TCP_SERVER 需 ≥0x44。本台架芯片实测 ≥0x46(TRAP-NET-20 定案
|
||||
* SOCKET_CLOSE 实际生效);门控防批次漂移——版本不足则**拒置 bit3**
|
||||
* (退回芯片自动关断语义)并 [ERR] 留痕,不静默带病运行 */
|
||||
@@ -479,7 +479,7 @@ int net_poll(void) {
|
||||
/* 读取全局中断状态(2 字节):读操作本身会清除 CH395F 中断并使其拉高 INT#,
|
||||
* 若此后仍有新中断,CH395F 会再次拉低 INT#,由下一次 net_poll() 处理 */
|
||||
int_status = ch395f_get_glob_int_status_all();
|
||||
/* N34 阶段 3(F-DRV-13 接线):把全局位喂驱动——bit2 PHY_CHANGE 时驱动
|
||||
/* 自愈收敛阶段 3(F-DRV-13 接线):把全局位喂驱动——bit2 PHY_CHANGE 时驱动
|
||||
* 重读 PHY 更新 link_up 缓存 + 变化计数,net 层在 reconciler 订阅留痕
|
||||
* (运行期拔网线不再静默;不自动重配,重配仍走 UI/配置引擎路径) */
|
||||
ch395f_glob_event_feed(int_status);
|
||||
@@ -561,7 +561,7 @@ int net_poll(void) {
|
||||
/* 因此每次 net_poll() 只处理“一批”,剩余数据在后续轮询中读取 */
|
||||
} while (0);
|
||||
|
||||
/* N34 阶段 3(§5 项 1 基础):每轮全量刷新在用 Socket 的驱动状态缓存
|
||||
/* 自愈收敛阶段 3(§5 项 1 基础):每轮全量刷新在用 Socket 的驱动状态缓存
|
||||
* (唯一刷新点;E2 实测单次回读 18.1us,在用 5~6 个 ≈100us ≪ 1ms 轮询
|
||||
* 周期)。reconciler / 探针 / 镜像降级决策点一律读缓存(
|
||||
* ch395f_sock_state_cached),不再各自发状态 SPI。放在中断处理之后:
|
||||
@@ -569,7 +569,7 @@ int net_poll(void) {
|
||||
for (int i = 0; i < NET_MAX_SOCKETS; i++) {
|
||||
if (s_net_socks[i].in_use != 0U) {
|
||||
(void)ch395f_get_sock_state((uint8_t)i);
|
||||
/* N34 阶段 3(E-02 收口):驱动 sock_reset 状态机在 net_poll 步进
|
||||
/* 自愈收敛阶段 3(E-02 收口):驱动 sock_reset 状态机在 net_poll 步进
|
||||
* (驱动头注释契约"在 net_poll 或测试循环里周期调用")。IDLE 槽位
|
||||
* 纯 RAM 判返回 0 无 SPI;仅活跃复位机做短 SPI。作用:同步包装
|
||||
* (net_sock_reset_sync)600ms 放弃后复位机不搁浅,芯片条件满足
|
||||
@@ -579,9 +579,9 @@ int net_poll(void) {
|
||||
}
|
||||
|
||||
#if NET_U15_PROBE
|
||||
/* E6 探测(宏说明见文件前部):RX 非空而 readable=0 = RECV_OK 中断丢失
|
||||
/* E6 探测(宏说明见文件前部):RX 非空而 readable=0 = RECV_OK 事件未收到
|
||||
* 的数据面形态。**两级确认去良性竞态**:数据刚到、本轮中断尚未读取的
|
||||
* 竞态窗(≤1 个 poll)会在下一探测轮自然消失;丢中断则持续存在直到
|
||||
* 竞态窗(≤1 个 poll)会在下一探测轮自然消失;事件未收到则持续存在直到
|
||||
* 盲收/超时。候选轮标记 → 下一探测轮仍成立才计确认命中。排除 CLOSED:
|
||||
* closed-with-data 是已知被救回形态,非 U15 假设对象。独立于上面的
|
||||
* 缓存刷新环:GET_RECV_LEN 是独立 SPI。 */
|
||||
@@ -621,23 +621,22 @@ int net_poll(void) {
|
||||
return event_count;
|
||||
}
|
||||
|
||||
/* 对账+pump 合并周期(N34 阶段 3:原 200ms 对账 / 100ms pump 合一) */
|
||||
/* 对账+pump 合并周期(自愈收敛阶段 3:原 200ms 对账 / 100ms pump 合一) */
|
||||
#define NET_RECONCILE_PERIOD_MS 100U
|
||||
/* 同一 socket 两次动手的最小间隔(防抖成风暴) */
|
||||
#define NET_RECONCILE_COOLDOWN_MS 1000U
|
||||
/* 分级去抖门槛(单位=轮) */
|
||||
#define NET_RECON_STABLE_ACCEPT 1U /* 形态② 丢 CONNECT 补 accept(幽灵甄别兜底假阳性) */
|
||||
#define NET_RECON_STABLE_ACCEPT 1U /* 形态② CONNECT 事件未收到补 accept(幽灵甄别兜底假阳性) */
|
||||
#define NET_RECON_STABLE_RELISTEN 2U /* 形态③④ 监听失位重建 / ⑤ 静默回收 RESYNC */
|
||||
#define NET_RECON_STABLE_DEATH 4U /* 形态① 连接已失(M3 让位窗 400ms,勿改小) */
|
||||
|
||||
/*
|
||||
* 函数功能:芯片/本层 socket 状态周期对账(TRAP-NET-17 丢中断自愈)+ 监听器 pump
|
||||
* (N-32 P2)—— N34 阶段 3 合并为单一 100ms tick(docs/网络/N34-自愈审计.md §5.5 项 1)
|
||||
* 函数功能:芯片/本层 socket 状态周期对账(TRAP-NET-17 事件面未收到自愈,E14 复核:非芯片丢事件是被读清消费)+ 监听器 pump(N-32 P2)—— 自愈收敛阶段 3 合并为单一 100ms tick(docs/网络/网络自愈架构设计.md §4.1)
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(由 net_process_messages 每轮调用)
|
||||
* 函数说明:1. 芯片快速复连会丢 CONNECT/DISCONNECT 中断,本层无法靠事件自愈
|
||||
* 函数说明:1. 芯片快速复连会收不到 CONNECT/DISCONNECT 事件(读清消费竞态,E14 复核:非芯片丢事件),本层无法靠事件自愈
|
||||
* 2. 判据读**驱动状态缓存**(唯一刷新点=net_poll 每轮全量刷新,E2 实测单次回读 18.1us)
|
||||
* 3. 覆盖形态(原对账①②⑤ + 原 pump③④/U11):
|
||||
* ① 本层 ESTABLISHED 而芯片已无连接 → 按断开处理(只置事实)
|
||||
@@ -702,7 +701,7 @@ static void net_reconcile_tick(void) {
|
||||
int listener_fd = ((p_sock->auto_relisten != 0U) &&
|
||||
(p_sock->type == NET_SOCK_STREAM) &&
|
||||
(p_sock->local_port != 0U));
|
||||
/* 失同步类型:1=连接已失 2=握手已成丢中断 3=监听失位 4=孤儿监听
|
||||
/* 失同步类型:1=连接已失 2=握手已成事件未收到 3=监听失位 4=孤儿监听
|
||||
* 5=芯片静默回收回监听(编号沿用历史口径,U11 重同步不设编号——被动零动作) */
|
||||
int bad = 0;
|
||||
/* 本形态去抖门槛(默认按重建档) */
|
||||
@@ -720,14 +719,14 @@ static void net_reconcile_tick(void) {
|
||||
stable_need = NET_RECON_STABLE_DEATH;
|
||||
} else if ((c.open != CH395F_SOCKET_CLOSED) &&
|
||||
(c.tcp_state == CH395F_TCP_LISTEN)) {
|
||||
/* ⑤(F-NET-2 缺口,N34 阶段1):芯片静默回收——本层 ESTABLISHED
|
||||
/* ⑤(F-NET-2 缺口,自愈收敛阶段1):芯片静默回收——本层 ESTABLISHED
|
||||
* 而芯片已自行把 Socket 收回 LISTEN(0x05/0x01,**不发 DISCONNECT
|
||||
* 中断**,run8 台架实证)→ RESYNC 语义 */
|
||||
bad = 5;
|
||||
}
|
||||
} else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
if (c.tcp_state == CH395F_TCP_ESTABLISHED) {
|
||||
/* ② 本层 LISTENING 而芯片已完成握手(丢 CONNECT 中断)→ 补做 accept
|
||||
/* ② 本层 LISTENING 而芯片已完成握手(CONNECT 事件未收到)→ 补做 accept
|
||||
* N-30(TRAP-NET-20)幽灵态甄别:拆链收尾窗口内芯片假报 ESTABLISHED,
|
||||
* 回读对端端口 = 上一条连接端口 → 不补 accept(补了会把数据发给
|
||||
* 已死的旧连接 = 生产 LIST#4 数据被吞的直接成因),等拆净或新 SYN。
|
||||
@@ -736,7 +735,7 @@ static void net_reconcile_tick(void) {
|
||||
ch395f_get_remot_ipp((uint8_t)i, remote);
|
||||
uint16_t peer = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||
/* 仅"端口非零且 = 上一条连接端口"判幽灵拦截;peer==0 不拦截
|
||||
* (对端端口提交滞后时不得挡掉丢中断救援,见 net_lost_connect_probe 注释) */
|
||||
* (对端端口提交滞后时不得挡掉事件未收口的救援,见 net_lost_connect_probe 注释) */
|
||||
if (!((peer != 0U) && (peer == p_sock->last_peer_port))) {
|
||||
bad = 2;
|
||||
stable_need = NET_RECON_STABLE_ACCEPT;
|
||||
@@ -796,7 +795,7 @@ static void net_reconcile_tick(void) {
|
||||
handle_disconnect_event(p_sock);
|
||||
} else if (bad == 5) {
|
||||
/* 类型⑤:静默回收 → RESYNC 语义(原 NET_MSG_RESYNC_LISTEN 分派体
|
||||
* 原样并入,N34 阶段1;纪律同 U11:**不发任何芯片命令**——
|
||||
* 原样并入,自愈收敛阶段1;纪律同 U11:**不发任何芯片命令**——
|
||||
* 重下发 close/重监听会摧毁芯片侧健康监听器 → 端口永拒,
|
||||
* run8 实证 170s 拒绝) */
|
||||
DBG_INFO("sock%d reconcile: chip re-listened w/o DISCONNECT (0x%02X/0x%02X) -> resync",
|
||||
@@ -838,8 +837,8 @@ static void net_reconcile_tick(void) {
|
||||
* 2. net_listener_retry_tick(D10):断连后按 30ms(NET_RELISTEN_RETRY_MS)
|
||||
* 节拍重试 open+listen,2s 总时限到期放弃留痕;本 fd 有在途挂起 recv 时跳过(L3 保险)
|
||||
* 3. net_pending_tick(L3):按节拍了结挂起 recv(数据/到点[仅显式预算]/断连);
|
||||
* L3 tripwire(N34 阶段 1.5):挂起超 60s 只 DBG_ERROR 留痕一次,不再强制了结/伪造返回值
|
||||
* 4. net_reconcile_tick(TRAP-NET-17 + pump 合并,N34 阶段 3):每 100ms 对账
|
||||
* L3 tripwire(自愈收敛阶段 1.5):挂起超 60s 只 DBG_ERROR 留痕一次,不再强制了结/伪造返回值
|
||||
* 4. net_reconcile_tick(TRAP-NET-17 + pump 合并,自愈收敛阶段 3):每 100ms 对账
|
||||
* ①②⑤ + ③④ 重建 + U11 重同步,判据读驱动状态缓存(net_poll 每轮
|
||||
* 全量刷新,E2 背书);去抖分级(②=1 轮/③④⑤=2 轮/①=4 轮,M3 让位窗)
|
||||
* + 1s 冷却;重建失败进 D10 重试队列,reconciler 不重复催
|
||||
@@ -861,7 +860,7 @@ void net_process_messages(void) {
|
||||
net_listener_retry_tick();
|
||||
/* L3 挂起 recv 完成检查:数据到达 / 到点 / 断连时通知调用方 */
|
||||
net_pending_tick();
|
||||
/* TRAP-NET-17 状态对账 + 监听器 pump(N34 阶段 3 合并单一 100ms tick):
|
||||
/* TRAP-NET-17 状态对账 + 监听器 pump(自愈收敛阶段 3 合并单一 100ms tick):
|
||||
* 判据读驱动缓存(net_poll 每轮全量刷新),①②⑤ 失同步 + ③④ 重建 +
|
||||
* U11 重同步全部在此(本层唯一周期重建入口,N-32 P2 单一所有者) */
|
||||
net_reconcile_tick();
|
||||
@@ -952,7 +951,7 @@ void net_process_messages(void) {
|
||||
break;
|
||||
}
|
||||
case NET_MSG_DROP_CONN: {
|
||||
/* N34 阶段 3(E-02 收口):应用放弃会话的主动拆除(拆连接、保监听) */
|
||||
/* 自愈收敛阶段 3(E-02 收口):应用放弃会话的主动拆除(拆连接、保监听) */
|
||||
net_sock_t *p_sock = net_get_sock(msg.sockfd);
|
||||
if (p_sock == NULL) {
|
||||
/* 描述符无效 → BADF */
|
||||
@@ -971,7 +970,7 @@ void net_process_messages(void) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* N34 阶段1(F-NET-3):NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 两个
|
||||
/* 自愈收敛阶段1(F-NET-3):NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 两个
|
||||
* 手动自愈消息已删——RESYNC 语义并入对账⑤(net_reconcile_tick),
|
||||
* RELISTEN 与 reconciler/D10 完全重叠且对健康监听器是 footgun;
|
||||
* 生产调用者本就为零(仅 test/board Phase 13,已改由自动机制接管) */
|
||||
@@ -1095,7 +1094,7 @@ int net_socket(int domain, int type) {
|
||||
p_sock->send_ready = 1;
|
||||
/* 无可读数据 */
|
||||
p_sock->readable = 0;
|
||||
/* N34 阶段 1.5:阻塞模式默认 = 阻塞(BSD/Python 语义;非阻塞用
|
||||
/* 自愈收敛阶段 1.5:阻塞模式默认 = 阻塞(BSD/Python 语义;非阻塞用
|
||||
* net_setblocking(fd, 0) 显式设置)。close 的 memset 会清零本字段,
|
||||
* 新 fd 必须在此显式置 1(同 released_abnormal 的"不得继承"纪律) */
|
||||
p_sock->blocking = 1;
|
||||
@@ -1222,7 +1221,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:驱动 sock_reset 原语的有界确定性排渣等待(P2b 收口,N34 阶段 3;
|
||||
* 函数功能:驱动 sock_reset 原语的有界确定性排渣等待(P2b 收口,自愈收敛阶段 3;
|
||||
* 替代原"close + 盲等 500ms"式忙等)
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||
* mode - CH395F_RESET_GRACEFUL(等 100ms)/ QUARANTINE(等 400ms)
|
||||
@@ -1298,7 +1297,7 @@ int net_listen_locked(int sockfd) {
|
||||
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
||||
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET-09),故失败重试最多 3 次。
|
||||
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* P2b 收口(自愈收敛阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
|
||||
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET-09 语义保留 */
|
||||
@@ -1316,24 +1315,14 @@ int net_listen_locked(int sockfd) {
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
/* 下发 TCP LISTEN 命令,进入监听状态 */
|
||||
status = ch395f_tcp_listen(sockfd);
|
||||
/* LISTEN 失败 → BUSY */
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
/* 0-3(N34 阶段0,U12 对称):open 已成而 LISTEN 失败必须 close,
|
||||
* 否则芯片 Socket 卡"OPEN 无监听"、后续 open 恒返 USE(同
|
||||
* net_relisten_locked 对应分支) */
|
||||
ch395f_close_socket(sockfd);
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
|
||||
/* 监听 Socket 进入 LISTENING 态 */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
|
||||
p_sock->auto_relisten = 1;
|
||||
/* N-30(TRAP-NET-20):新监听会话,丢中断去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 读即清:仅本 Socket 的中断状态——丢弃上一条会话残留的 DISCONNECT/
|
||||
/* 排事件(读即清)必须在 LISTEN 命令**之前**(E14 复核实验 2026-10-14:
|
||||
* 原形态为 listen 后读清——快速复连时新连接的 CONNECT 在 LISTEN 生效后、
|
||||
* 读清前落进 SINT,被本方读清吞掉,即"CONNECT 事件未收到→数据被吞"的
|
||||
* 生产侧自伤机制(台架矩阵 3/48 被 drain-int 探针现场抓获);芯片侧
|
||||
* 从不丢事件。挪前后若仍有滞后 DISCONNECT 落进新会话,
|
||||
* handle_disconnect_event 的 LISTENING 分支回读状态裁决(状态面为真相),
|
||||
* 无害。
|
||||
* 读即清:仅本 Socket 的中断状态——丢弃上一条会话残留的 DISCONNECT/
|
||||
* TIMEOUT,避免监听刚开始就误触发事件。
|
||||
* ⚠ B3(2026-10-12 审计):此处原为"遍历 8 个 Socket 全清 + 再读清全局",
|
||||
* git 考古证明是多连接时代的调试遗留(e862009bc 无注释引入 → 319d00e3
|
||||
@@ -1350,6 +1339,24 @@ int net_listen_locked(int sockfd) {
|
||||
* 本次未动。 */
|
||||
(void)ch395f_get_sock_int_status((uint8_t)sockfd);
|
||||
|
||||
/* 下发 TCP LISTEN 命令,进入监听状态 */
|
||||
status = ch395f_tcp_listen(sockfd);
|
||||
/* LISTEN 失败 → BUSY */
|
||||
if (status != CH395F_ERR_SUCCESS) {
|
||||
/* 0-3(自愈收敛阶段0,U12 对称):open 已成而 LISTEN 失败必须 close,
|
||||
* 否则芯片 Socket 卡"OPEN 无监听"、后续 open 恒返 USE(同
|
||||
* net_relisten_locked 对应分支) */
|
||||
ch395f_close_socket(sockfd);
|
||||
return NET_ERR_RETURN_1(NET_ERR_BUSY);
|
||||
}
|
||||
|
||||
/* 监听 Socket 进入 LISTENING 态 */
|
||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
|
||||
p_sock->auto_relisten = 1;
|
||||
/* N-30(TRAP-NET-20):新监听会话,事件未收到去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
/* 监听建立完成 */
|
||||
return 0;
|
||||
}
|
||||
@@ -1414,27 +1421,29 @@ int net_listen(int sockfd) {
|
||||
* 限定条件:Socket 处于 LISTENING 状态
|
||||
* 函数说明:单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
|
||||
*/
|
||||
/* ===== N-30 accept 路径"丢 CONNECT 中断"补 accept(2026-10-11 裸机芯片台架实证)=====
|
||||
/* ===== N-30 accept 路径"CONNECT 事件未收到补 accept"(2026-10-11 台架实证;
|
||||
* E14 复核 2026-10-14:事件非芯片侧丢失,是被读清消费——机制不变)=====
|
||||
* 台架结论(剥离 OS/net/FTP 直接对芯片做受控 close→open→listen→connect 矩阵):
|
||||
* 芯片关闭连接后的拆链收尾窗口**变长且不可见**(状态寄存器显示 CLOSED 也不代表
|
||||
* 拆完,实测 >2s 仍可能未拆完);该窗口内重新 listen 后,新连接握手照常完成
|
||||
* (芯片状态寄存器 → ESTABLISHED)但 **CONNECT 中断被丢**——纯事件驱动的 accept
|
||||
* (芯片状态寄存器 → ESTABLISHED)但 **CONNECT 事件未收到**(E14 复核:被读清
|
||||
* 消费竞态吞掉)——纯事件驱动的 accept
|
||||
* 永远等不到 → 数据被吞 / 425。固定沉降延时、Socket 轮换、listen 后 close 重试、
|
||||
* 缓冲重分配均已被实验证伪;唯一有效 = "中断 + 状态轮询"双信源(修复组 15/15
|
||||
* 全过,机制触发 5 次全部救回)。→ CH395F_Trap_Records.md TRAP-NET-20
|
||||
* 幽灵态甄别:拆链窗口内芯片也会直接假报 ESTABLISHED(旧连接未拆净),此时回读
|
||||
* 对端端口 = 上一条连接端口;新连接临时端口几乎必然不同 → 端口相同不 accept,
|
||||
* 等旧连接拆净 / 新 SYN 到达(新连接若也丢中断,后续轮询以新端口命中)。 */
|
||||
* 等旧连接拆净 / 新 SYN 到达(新连接若事件也未收到,后续轮询以新端口命中)。 */
|
||||
|
||||
/*
|
||||
* 函数功能:监听等待期的芯片状态轮询探针——芯片已 ESTABLISHED 而 CONNECT 中断
|
||||
* 未到(丢中断)时补做 accept(复用 CONNECT 事件簿记路径)。
|
||||
* 函数功能:监听等待期的芯片状态轮询探针——芯片已 ESTABLISHED 而 CONNECT 事件
|
||||
* 未收到时补做 accept(复用 CONNECT 事件簿记路径)。
|
||||
* 入口参数:p_sock - 处于 LISTENING 的监听控制块 net_sock_t *
|
||||
* 出口参数:无(命中时 p_sock->state 经 handle_connect_event 转 ESTABLISHED)
|
||||
* 返回值:无
|
||||
* 限定条件:netTask 上下文(net_accept_locked 内调用,其开头已 net_poll(),
|
||||
* 驱动缓存新鲜度有保证)
|
||||
* 函数说明:1. N34 阶段 3(F-MS-9):判据改读**驱动状态缓存**(零 SPI;唯一
|
||||
* 函数说明:1. 自愈收敛阶段 3(F-MS-9):判据改读**驱动状态缓存**(零 SPI;唯一
|
||||
* 刷新点=net_poll),**探针去抖删除**——原去抖防的两类瞬态已
|
||||
* 结构性消除:"刚 listen 尚未生效"显示 TCP=00 永不命中 ESTABLISHED
|
||||
* 门(E2:LISTEN 可见 100% <=10ms 无长尾);拆链窗假 ESTABLISHED
|
||||
@@ -1458,16 +1467,16 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
|
||||
uint16_t peer = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||
/* 幽灵甄别:仅"端口非零且 = 上一条连接端口"才判幽灵拦截;
|
||||
* peer==0(芯片对端端口提交滞后,TRAP-NET-13 同类)不拦截——宁可补 accept
|
||||
* 也不退回丢中断死等(2026-10-11 验证轮实测:peer==0 拦截把首连接
|
||||
* 丢中断的原有对账救援也挡死,LIST#1 卡满 20s,比修复前更糟) */
|
||||
* 也不退回事件未收口的死等(2026-10-11 验证轮实测:peer==0 拦截把首连接
|
||||
* 事件未收到的原有对账救援也挡死,LIST#1 卡满 20s,比修复前更糟) */
|
||||
if ((peer != 0U) && (peer == p_sock->last_peer_port)) {
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
return;
|
||||
}
|
||||
/* N34 阶段 3(F-MS-9):去抖已删(判据读缓存,两类瞬态结构性消除,
|
||||
/* 自愈收敛阶段 3(F-MS-9):去抖已删(判据读缓存,两类瞬态结构性消除,
|
||||
* 见函数头注释 1);lost_conn_seen 仅作 M3 可疑电平标志用,动手前清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
/* 留痕:丢中断自愈命中 */
|
||||
/* 留痕:事件未收到自愈命中 */
|
||||
DBG_INFO("sock%d lost-CONNECT self-accept (peer=%u)",
|
||||
(int)p_sock->ch395_sock, peer);
|
||||
/* 复用 CONNECT 事件的簿记路径(转 ESTABLISHED + 记对端 + 事件回调) */
|
||||
@@ -1482,7 +1491,7 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
|
||||
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
|
||||
* 限定条件:Socket 处于 LISTENING 状态
|
||||
* 函数说明:1. 单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
|
||||
* 2. 等待期叠加芯片状态轮询探针(丢 CONNECT 中断自愈,TRAP-NET-20)
|
||||
* 2. 等待期叠加芯片状态轮询探针(CONNECT 事件未收到自愈,TRAP-NET-20)
|
||||
* 3. CLOSED + 芯片 RX 缓冲有残留数据:接受"已关但可读"连接排空
|
||||
* (FUN_PARA §5.52 ② 保留现场契约,TRAP-NET-20 三次定案)
|
||||
*/
|
||||
@@ -1500,9 +1509,10 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
|
||||
/* 先轮询一次:把状态机刷新到芯片侧最新状态 */
|
||||
net_poll();
|
||||
|
||||
/* N-30(TRAP-NET-20):监听等待期兼做芯片状态第二信源——丢 CONNECT 中断时
|
||||
* 去抖补 accept(裸机台架实证:拆链窗口丢中断是数据被吞/425 的主根因,
|
||||
* 纯事件等待无自愈可能;详见 net_lost_connect_probe 区块注释) */
|
||||
/* N-30(TRAP-NET-20):监听等待期兼做芯片状态第二信源——CONNECT 事件未收到时
|
||||
* 去抖补 accept(台架实证:拆链窗口事件未收到是数据被吞/425 的主根因,
|
||||
* E14 复核:事件非芯片丢失、被读清消费吞掉;纯事件等待无自愈可能;
|
||||
* 详见 net_lost_connect_probe 区块注释) */
|
||||
if (p_listen_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
net_lost_connect_probe(p_listen_sock);
|
||||
}
|
||||
@@ -1621,8 +1631,8 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
return msg.result;
|
||||
}
|
||||
|
||||
/* N34 阶段1(F-NET-4):net_can_accept 已删除——它只认 ESTABLISHED,作为 accept
|
||||
* 门控会把"监听器在服役但本轮还没 CONNECT"的窗口全挡掉(:2404 丢 CONNECT 探针
|
||||
/* 自愈收敛阶段1(F-NET-4):net_can_accept 已删除——它只认 ESTABLISHED,作为 accept
|
||||
* 门控会把"监听器在服役但本轮还没 CONNECT"的窗口全挡掉(:2404 CONNECT 事件补 accept 探针
|
||||
* 因此从不运行,与已修的 :7003 探针失效同型);唯一生产调用者 iec104 已迁
|
||||
* net_listener_armed。net_can_read(RECV 门控)不受影响、保留。 */
|
||||
|
||||
@@ -1634,9 +1644,9 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
* 0 - 未就绪(fd 未分配 / 非监听型 / 正处隔离期以外的不就绪态) int
|
||||
* 限定条件:任意任务上下文;net_init() 已调用
|
||||
* 函数说明:1. N-32(P1 不变量 II):取代已退役的 net_can_accept()(要求
|
||||
* ESTABLISHED,N34 阶段1 删除)作为监听 accept 门控。原门控下
|
||||
* ESTABLISHED,自愈收敛阶段1 删除)作为监听 accept 门控。原门控下
|
||||
* :7003 永不进 net_accept →
|
||||
* net_lost_connect_probe(丢 CONNECT 中断补 accept)对该端口从不运行
|
||||
* net_lost_connect_probe(CONNECT 事件未收到补 accept)对该端口从不运行
|
||||
* (设计文档 §2.3 末"探针失效")
|
||||
* 2. 为什么放行 LISTENING:探针与"closed-but-readable 接受"(:1338)
|
||||
* 只在 net_accept_locked 内部发生,门控挡在外面就永远到不了;
|
||||
@@ -1659,13 +1669,13 @@ int net_listener_armed(int sockfd) {
|
||||
/* 连接已到、应用尚未 accept:单连接模型下 CONNECT 处理(net_poll 分派 /
|
||||
* 探针补 accept / 对账② standalone accept)把监听 fd 转 ESTABLISHED,
|
||||
* 这就是"待 accept"电平——**必须放行**(原 net_can_accept 唯一放行态;
|
||||
* N34 阶段1 i104 台架实证:200ms 任务周期抢不过对账②的 ~400ms 去抖,
|
||||
* 自愈收敛阶段1 i104 台架实证:200ms 任务周期抢不过对账②的 ~400ms 去抖,
|
||||
* 对账②先转 ESTABLISHED → 不放行则应用永不 accept、会话整场饿死)。
|
||||
* 无 RPC 风暴风险:此态下 accept 必返 fd,一次调用即离开本分支 */
|
||||
if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||
return 1;
|
||||
}
|
||||
/* 正常监听态:放行。net_lost_connect_probe(丢 CONNECT 补 accept)与常规
|
||||
/* 正常监听态:放行。net_lost_connect_probe(CONNECT 事件未收到补 accept)与常规
|
||||
* accept 都发生在 net_accept_locked 内部,门控挡在外面就永远到不了 */
|
||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||
return 1;
|
||||
@@ -1700,7 +1710,7 @@ int net_listener_armed(int sockfd) {
|
||||
* 2. 非 ESTABLISHED / 描述符失效一律返回 1:必须让上层真的 recv 一次
|
||||
* 拿到 EOF/错误并复位自身状态,门掉它会把"连接已不存在"永久藏住
|
||||
* 3. ⚠ readable 仅由 RECV_OK 中断置位,TRAP-NET-17 对账不含"RX 非空但
|
||||
* readable=0" → 中断丢失时本函数恒返 0,调用方须保留低频兜底 recv
|
||||
* readable=0" → 事件未收到时本函数恒返 0,调用方须保留低频兜底 recv
|
||||
*/
|
||||
int net_can_read(int sockfd) {
|
||||
/* Socket 控制块(纯 RAM 读,可能为 NULL = 描述符越界或未分配) */
|
||||
@@ -1848,7 +1858,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
||||
|
||||
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET-09),故失败重试最多 3 次。
|
||||
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* P2b 收口(自愈收敛阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
|
||||
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
|
||||
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
|
||||
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET-09 语义保留 */
|
||||
@@ -1869,7 +1879,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
}
|
||||
|
||||
/* 清掉本 Socket 可能残留的中断状态,丢弃上一条连接遗留的 DISCONNECT。
|
||||
* F-NET-7(N34 阶段 3):只清**本 Socket** SINT(驱动护栏原语)——原
|
||||
* F-NET-7(自愈收敛阶段 3):只清**本 Socket** SINT(驱动护栏原语)——原
|
||||
* "再读清全局"会焊死其它在用 Socket 的事件位(全局寄存器唯一读者=net_poll) */
|
||||
(void)ch395f_sock_events((uint8_t)sockfd);
|
||||
|
||||
@@ -2070,7 +2080,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
* buf - 接收缓冲区指针 void *
|
||||
* len - 缓冲区大小 int > 0
|
||||
* flags - 标志位,NET_MSG_DONTWAIT 表示非阻塞 int
|
||||
* timeout_ms - 本次等待预算(0 = 无限等待,N34 阶段 1.5 起无默认值)uint32_t
|
||||
* timeout_ms - 本次等待预算(0 = 无限等待,自愈收敛阶段 1.5 起无默认值)uint32_t
|
||||
* caller - 调用方任务句柄(挂起请求的完成通知目标) TaskHandle_t
|
||||
* 出口参数:buf - 填充接收到的数据
|
||||
* 返回值:实际接收字节数(> 0);0 表示对端关闭;-1 表示出错/非阻塞无数据 int
|
||||
@@ -2078,7 +2088,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
|
||||
* 限定条件:p_sock 非空;netTask 上下文
|
||||
* 函数说明:1. 数据已在(快速路径)→ 立即读出返回,行为与旧实现一致
|
||||
* 2. 非阻塞(NET_MSG_DONTWAIT 单次覆盖 **或** socket blocking 属性为 0,
|
||||
* N34 阶段 1.5 模式属性)无数据立即返回 -1(NET_ERR_WOULDBLOCK)
|
||||
* 自愈收敛阶段 1.5 模式属性)无数据立即返回 -1(NET_ERR_WOULDBLOCK)
|
||||
* 3. 无数据 + 阻塞等待 → 登记挂起请求(L3 pending 化,E-02 结构演进)
|
||||
* 4. netTask 零占用立即返回;完成条件(数据/到点[仅显式预算]/断连)由 net_pending_tick 按主循环节拍检查
|
||||
* 5. 并通知 caller;关闭/网络重建/陈旧重同步由对应路径显式了结(取消必通知)
|
||||
@@ -2095,7 +2105,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
}
|
||||
|
||||
/* 超时来源:只有调用方显式预算(net_recv_to);0 = 无限等待
|
||||
* (N34 阶段 1.5:NET_RECV_TIMEOUT_MS 30s 默认预算已删,API 不强加隐藏值) */
|
||||
* (自愈收敛阶段 1.5:NET_RECV_TIMEOUT_MS 30s 默认预算已删,API 不强加隐藏值) */
|
||||
uint32_t to_ms = timeout_ms;
|
||||
|
||||
/* 先轮询一次:刷新状态机与可读标志 */
|
||||
@@ -2119,7 +2129,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
}
|
||||
|
||||
/* 非阻塞模式:NET_MSG_DONTWAIT 单次覆盖,或 socket 的 blocking 属性为 0
|
||||
* (net_setblocking(fd, 0),N34 阶段 1.5 模式挂控制块属性) */
|
||||
* (net_setblocking(fd, 0),自愈收敛阶段 1.5 模式挂控制块属性) */
|
||||
if ((flags & NET_MSG_DONTWAIT) || (p_sock->blocking == 0U)) {
|
||||
/* 非阻塞且当前无数据:若连接已断开则视为 EOF(0) 并自动重监听,
|
||||
* 否则返回 WOULDBLOCK(-1) 表示暂时无数据 */
|
||||
@@ -2169,7 +2179,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* 2. 清空整个控制块(memset 0),释放该 Socket 资源
|
||||
*/
|
||||
|
||||
/* ===== L3 挂起 recv 请求的实现(一期,2026-09-22;N34 阶段 1.5 语义主流化) =====
|
||||
/* ===== L3 挂起 recv 请求的实现(一期,2026-09-22;自愈收敛阶段 1.5 语义主流化) =====
|
||||
* 完成条件按 ①数据 ②到点(仅显式预算) ③断连 顺序检查(逐项对齐旧自旋循环语义)
|
||||
* ① 数据通道(ESTABLISHED/UDP_OPEN)内 readable 门控 SPI 读——常见无数据路径零额外 SPI 事务
|
||||
* (INT# 电平触发链保证缓冲有数据时每轮重读 SINT 重位置位)
|
||||
@@ -2179,7 +2189,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
|
||||
* 旧注归"部分读归零"机理、已随复核注降级)→ 有数据按数据完成,否则 EOF(0) + 自动重监听
|
||||
* 其他状态(CONNECTING/LISTENING/…)保持等待状态迁移(CONNECT→ESTABLISHED 是合法路径;
|
||||
* 陈旧 resync 由显式取消处理)——不做状态推断取消,避免误杀正在建链的等待
|
||||
* tripwire(N34 阶段 1.5 降级):挂起超 60s = "完成逻辑缺位"探针 → 只 [ERR] 留痕一次,
|
||||
* tripwire(自愈收敛阶段 1.5 降级):挂起超 60s = "完成逻辑缺位"探针 → 只 [ERR] 留痕一次,
|
||||
* **绝不强制了结、绝不伪造 TIMEDOUT 返回值**(唤醒责任在 ①②③ 与显式 cancel 路径)
|
||||
*/
|
||||
|
||||
@@ -2222,7 +2232,7 @@ static void net_pending_complete(int sockfd, int result) {
|
||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||
* buf - 调用方接收缓冲(须保持有效至完成) void *
|
||||
* len - 缓冲容量 int
|
||||
* to_ms - 本次等待预算(0 = 无限等待,N34 阶段 1.5) uint32_t
|
||||
* to_ms - 本次等待预算(0 = 无限等待,自愈收敛阶段 1.5) uint32_t
|
||||
* caller - 调用方任务句柄(完成通知目标) TaskHandle_t
|
||||
* 出口参数:无
|
||||
* 返回值:NET_PENDING_REGISTERED - 登记成功(分派跳过即时通知)
|
||||
@@ -2285,7 +2295,7 @@ static int net_pending_register(int sockfd, void *buf, int len,
|
||||
* 限定条件:netTask 上下文
|
||||
* 函数说明:1. 逐 fd 检查完成条件:数据到达 / 到点(仅显式预算)/ 断连
|
||||
* 2. 完成即经 net_pending_complete 通知并清除
|
||||
* 3. tripwire(N34 阶段 1.5):挂起超 NET_RECV_TRIPWIRE_MS 只 [ERR] 留痕
|
||||
* 3. tripwire(自愈收敛阶段 1.5):挂起超 NET_RECV_TRIPWIRE_MS 只 [ERR] 留痕
|
||||
* 一次("完成逻辑缺位"探针),绝不强制了结、绝不伪造返回值
|
||||
*/
|
||||
static void net_pending_tick(void) {
|
||||
@@ -2338,7 +2348,7 @@ static void net_pending_tick(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ② 到点(仅显式预算登记;无限等待登记无 deadline——N34 阶段 1.5:
|
||||
/* ② 到点(仅显式预算登记;无限等待登记无 deadline——自愈收敛阶段 1.5:
|
||||
* 超时是调用方策略,net_recv_to 的预算在此兑现,不是伪造。
|
||||
* tick 差值按有符号比较,抗回绕) */
|
||||
if ((p->infinite == 0U) && ((int32_t)(now - p->deadline) >= 0)) {
|
||||
@@ -2351,7 +2361,7 @@ static void net_pending_tick(void) {
|
||||
* 判据同 net_recv_locked(N-32 P1 不变量 I):`state == CLOSED ||
|
||||
* session_dead`。只判 CLOSED 时,抢先 relisten 后 ①(要求 ESTABLISHED)
|
||||
* 与 ③(要求 CLOSED) 两头落空 → 挂起的 recv 只能干等 ② deadline 超时
|
||||
* (lftpd 阻塞 recv 的"消费者卡死"原型)。N34 阶段 1.5 后该形态更致命:
|
||||
* (lftpd 阻塞 recv 的"消费者卡死"原型)。自愈收敛阶段 1.5 后该形态更致命:
|
||||
* 无限等待登记没有 ②,漏 ③ = 永久挂死(只剩 tripwire 留痕)——
|
||||
* ③ 与显式 cancel 是无限 recv 的全部唤醒责任方,勿动判据。 */
|
||||
if ((p_sock->state == NET_SOCK_STATE_CLOSED) || (p_sock->session_dead != 0U)) {
|
||||
@@ -2399,7 +2409,7 @@ static void net_pending_tick(void) {
|
||||
|
||||
/* 其他状态:保持等待(见本区块头注释) */
|
||||
|
||||
/* ④ tripwire(N34 阶段 1.5 降级,原"看门狗强制了结"):挂起超 60s =
|
||||
/* ④ tripwire(自愈收敛阶段 1.5 降级,原"看门狗强制了结"):挂起超 60s =
|
||||
* "完成逻辑缺位"探针 → 只 [ERR] 留痕一次,**绝不强制了结、绝不伪造
|
||||
* TIMEDOUT 返回值**(旧实现到点 +1s 兜底伪造 TIMEDOUT,掩盖完成路径
|
||||
* 缺陷;新语义下无限等待本就无预算,伪造返回值反而违背调用方意图)。
|
||||
@@ -2535,7 +2545,7 @@ static void net_pending_settle_close(net_sock_t *p_sock) {
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 关闭成功 int
|
||||
* 限定条件:必须在 netTask 上下文中调用;p_sock 有效
|
||||
* 函数说明:1. P2b 收口(N34 阶段 3):原"close + 500ms 盲等排空循环"改
|
||||
* 函数说明:1. P2b 收口(自愈收敛阶段 3):原"close + 500ms 盲等排空循环"改
|
||||
* **确定性 sock_reset**(读空 RX -> CLOSE(幂等) -> 排空本 Socket
|
||||
* 事件(quiescent) -> 等 byte0=00H,内置 LISTEN 态二段 CLOSE 补发
|
||||
* ——E2 补充发现:一次 CLOSE 只拆监听 byte0 恒 05)
|
||||
@@ -2582,7 +2592,7 @@ static int net_close_locked(net_sock_t *p_sock) {
|
||||
* 出口参数:无
|
||||
* 返回值:0 - 拆除完成(监听型 fd 已重监听或交 D10) int
|
||||
* 限定条件:netTask 上下文;p_sock 在用且为 TCP 流
|
||||
* 函数说明:1. E-02 收口(实验方案 E13 §5):应用放弃的会话若 TCP 仍活
|
||||
* 函数说明:1. E-02 收口(《网络自愈架构设计》§5.2 E13):应用放弃的会话若 TCP 仍活
|
||||
* (PC 内核自动 ACK keepalive,僵尸判不死),单连接监听被永久
|
||||
* 占住;应用又不得 net_close 监听 fd(毁监听)——本函数补上
|
||||
* "拆连接不拆监听"的应用侧形态
|
||||
@@ -2610,7 +2620,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
|
||||
/* 会话簿记收口(保留 fd:不 memset、不动 local_port/auto_relisten) */
|
||||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||||
p_sock->readable = 0U;
|
||||
/* N-30(TRAP-NET-20):新会话起点,丢中断去抖计数清零 */
|
||||
/* N-30(TRAP-NET-20):新会话起点,事件未收到去抖计数清零 */
|
||||
p_sock->lost_conn_seen = 0U;
|
||||
|
||||
if (p_sock->auto_relisten) {
|
||||
@@ -2700,7 +2710,7 @@ int net_send(int sockfd, const void *buf, int len, int flags) {
|
||||
|
||||
/*
|
||||
* 函数功能:接收数据(线程安全版本,通过消息队列委托给 netTask;
|
||||
* **默认无限阻塞**——N34 阶段 1.5 语义主流化,30s 默认预算已删)
|
||||
* **默认无限阻塞**——自愈收敛阶段 1.5 语义主流化,30s 默认预算已删)
|
||||
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
|
||||
* buf - 接收缓冲区指针 void *
|
||||
* len - 缓冲区大小 int > 0
|
||||
@@ -2744,7 +2754,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
|
||||
msg.len = len;
|
||||
/* 标志:0=按 socket 阻塞属性,NET_MSG_DONTWAIT=单次非阻塞 */
|
||||
msg.flags = flags;
|
||||
/* 0 = 无限等待(N34 阶段 1.5:无默认预算;显式预算走 net_recv_to) */
|
||||
/* 0 = 无限等待(自愈收敛阶段 1.5:无默认预算;显式预算走 net_recv_to) */
|
||||
msg.timeout_ms = 0U;
|
||||
/* 调用方任务句柄(netTask 凭它回传回执) */
|
||||
msg.caller = xTaskGetCurrentTaskHandle();
|
||||
@@ -2770,7 +2780,7 @@ int net_recv(int sockfd, void *buf, int len, int flags) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:接收数据(非阻塞具名入口——N34 阶段 1.5 把 NET_MSG_DONTWAIT 路径转正,
|
||||
* 函数功能:接收数据(非阻塞具名入口——自愈收敛阶段 1.5 把 NET_MSG_DONTWAIT 路径转正,
|
||||
* 对齐 BSD recv(MSG_DONTWAIT) / Python recv 非阻塞模式的"名如其义")
|
||||
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
|
||||
* buf - 接收缓冲区指针 void *
|
||||
@@ -2790,7 +2800,7 @@ int net_recv_nb(int sockfd, void *buf, int len) {
|
||||
|
||||
/*
|
||||
* 函数功能:接收数据(带调用方指定超时的阻塞版,用于分片有界读;
|
||||
* N34 阶段 1.5 起为**显式预算**便捷入口,等价 Python settimeout,
|
||||
* 自愈收敛阶段 1.5 起为**显式预算**便捷入口,等价 Python settimeout,
|
||||
* 不再有隐藏默认值)
|
||||
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
|
||||
* buf / len - 接收缓冲与容量 void * / int > 0
|
||||
@@ -2822,7 +2832,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
/* ---- 3. 分片长度检查:timeout_ms = 0 在 netTask 侧意味着"**无限等待**"
|
||||
* (N34 阶段 1.5 删除 30s 默认预算),恰与本接口"有界等待"的存在
|
||||
* (自愈收敛阶段 1.5 删除 30s 默认预算),恰与本接口"有界等待"的存在
|
||||
* 理由相反,直接拒绝 ---- */
|
||||
if (timeout_ms == 0U) {
|
||||
/* 分片长度必须 > 0 */
|
||||
@@ -2944,7 +2954,7 @@ int net_close(int sockfd) {
|
||||
* 2. 场景=应用放弃会话(对时 30s 预算耗尽、协议超时);EOF 路径**不要**调
|
||||
* (net 层 auto_relisten 已接管,见 AGENTS 单连接断开语义)
|
||||
* 函数说明:1. 单连接模型下挂起但 TCP 仍活的客户端会永久占住监听(keepalive
|
||||
* 被 PC 内核自动 ACK 判不死,实验方案 E13 §5);应用不得
|
||||
* 被 PC 内核自动 ACK 判不死,《网络自愈架构设计》§5.2 E13);应用不得
|
||||
* net_close 监听 fd → 本 API 拆连接不拆监听(E-02 收口)
|
||||
* 2. netTask 侧执行 sock_reset QUARANTINE + 监听即时重建(见
|
||||
* net_drop_conn_locked);等待期 netTask 有界占用 ~400-600ms
|
||||
@@ -3131,7 +3141,7 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
* 限定条件:Socket 已创建且为 UDP 类型(SOCK_DGRAM);net_init() 已调用;有数据可用
|
||||
* 函数说明:1. 轮询检查芯片接收缓冲(net_poll + get_recv_len),有数据即返回
|
||||
* 2. UDP 数据报前 8 字节为报文头(源端口+源 IP),据此填充 src_addr
|
||||
* 3. 无数据时(N34 阶段 1.5,与 net_recv 同构):DONTWAIT / 非阻塞属性
|
||||
* 3. 无数据时(自愈收敛阶段 1.5,与 net_recv 同构):DONTWAIT / 非阻塞属性
|
||||
* 立即返回 -1(WOULDBLOCK);阻塞模式**无限等待**(30s 默认预算已删;
|
||||
* 本接口为轮询自旋实现且无生产调用者,受 IWDG 监控的任务勿用无限形态)
|
||||
*/
|
||||
@@ -3158,7 +3168,7 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
return NET_ERR_RETURN_1(NET_ERR_INVAL);
|
||||
}
|
||||
|
||||
/* 轮询直到:有数据 / 非阻塞(N34 阶段 1.5:阻塞 = 无限等待,无默认预算) */
|
||||
/* 轮询直到:有数据 / 非阻塞(自愈收敛阶段 1.5:阻塞 = 无限等待,无默认预算) */
|
||||
while (1) {
|
||||
/* 轮询一次:更新状态机与可读标志 */
|
||||
net_poll();
|
||||
@@ -3211,13 +3221,13 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
}
|
||||
|
||||
/* 非阻塞模式:NET_MSG_DONTWAIT 单次覆盖,或 socket blocking 属性为 0
|
||||
* (N34 阶段 1.5,与 net_recv_locked 同判据):无数据立即返回 */
|
||||
* (自愈收敛阶段 1.5,与 net_recv_locked 同判据):无数据立即返回 */
|
||||
if ((flags & NET_MSG_DONTWAIT) || (p_sock->blocking == 0U)) {
|
||||
/* 置 WOULDBLOCK */
|
||||
return NET_ERR_RETURN_1(NET_ERR_WOULDBLOCK);
|
||||
}
|
||||
|
||||
/* 阻塞模式:无数据继续轮询等待(N34 阶段 1.5:无限等待,无默认预算——
|
||||
/* 阻塞模式:无数据继续轮询等待(自愈收敛阶段 1.5:无限等待,无默认预算——
|
||||
* 旧 NET_RECV_TIMEOUT_MS 30s 兜底已删;唤醒源 = 数据,与 net_recv 的
|
||||
* 差异是本接口为自旋实现,勿在受 IWDG 监控任务中使用无限形态) */
|
||||
}
|
||||
@@ -3324,7 +3334,7 @@ int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 Socket 阻塞/非阻塞**模式属性**(N34 阶段 1.5,模式挂控制块属性,
|
||||
* 函数功能:设置 Socket 阻塞/非阻塞**模式属性**(自愈收敛阶段 1.5,模式挂控制块属性,
|
||||
* 对齐 BSD O_NONBLOCK / Python setblocking)
|
||||
* 入口参数:sockfd - Socket 描述符 int >= 0 && < NET_MAX_SOCKETS
|
||||
* on - 1 = 阻塞(net_socket 默认);0 = 非阻塞 int
|
||||
@@ -3402,7 +3412,7 @@ int net_sock_state(int sockfd) {
|
||||
return (int)s_net_socks[sockfd].state;
|
||||
}
|
||||
|
||||
/* N34 阶段1(F-NET-3):手动自愈 API net_resync_listen / net_relisten 已删除——
|
||||
/* 自愈收敛阶段1(F-NET-3):手动自愈 API net_resync_listen / net_relisten 已删除——
|
||||
* RESYNC 语义并入对账⑤(net_reconcile_tick 自动认领"芯片静默回收回 LISTEN"形态,
|
||||
* 200ms×2 去抖 + 1s 冷却沿用);RELISTEN 与 reconciler/D10 完全重叠且对健康监听器是
|
||||
* footgun(无条件 open→USE→close 自毁 ~1s,原注释自认)。生产调用者本就为零
|
||||
@@ -3458,7 +3468,7 @@ uint32_t net_inet_addr(const char *cp) {
|
||||
* 返回值:成功返回 buf 指针;buf 为 NULL 时返回 NULL char *
|
||||
* 限定条件:buf 非空且长度足够(>= 16 字节)
|
||||
* 函数说明:1. 先经 NET_NTOHL 转为主机字节序再格式化输出
|
||||
* 2. ⚠ 段序(N34 E13 §6 修复):NTOHL 后主机序数值的高字节才是
|
||||
* 2. ⚠ 段序(E13 定案 修复):NTOHL 后主机序数值的高字节才是
|
||||
* 点分第一段(192.168.1.100 → 0xC0A80164 → "192.168.1.100")。
|
||||
* 原实现低段在前,显示成字节反转的 "100.1.168.192"
|
||||
*/
|
||||
@@ -3612,7 +3622,7 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
||||
|
||||
/* §5.56:TCP 服务器须在 CONNECT 后开启 KeepAlive。2026-10-12 曾加后
|
||||
* 撤回(当时仅证明"物理断链"已被 +2s TIM_OUT 快速覆盖,其余场景
|
||||
* 无法注入、未证明);E11(2026-10-13,实验方案.md)用"禁用 PC 网卡"
|
||||
* 无法注入、未证明);E11(2026-10-13,《网络自愈架构设计》)用"禁用 PC 网卡"
|
||||
* 注入"链路在、对端静默"(NAT/黑洞)补上证据链:生产参数 60/5/3
|
||||
* 实测 ≈30 s 判死 → TIM_OUT → QUARANTINE → reconciler 重建;对端存活时
|
||||
* 探测被 ACK、空闲会话不误杀。消费链路现成,按手册位置转正。 */
|
||||
@@ -3712,11 +3722,11 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
/* 直接返回(中断已读清,不会重复上报) */
|
||||
return;
|
||||
}
|
||||
/* F-NET-17 M3(N34 实验 2026-10-13):矛盾态可疑门——芯片 Socket 仍 OPEN(0x05)
|
||||
/* F-NET-17 M3(自愈专项实验 2026-10-13):矛盾态可疑门——芯片 Socket 仍 OPEN(0x05)
|
||||
* 而 TCP 槽 0x00 且本层 ESTABLISHED = 逻辑矛盾(活连接应 0x04):陈旧 DISCONNECT
|
||||
* (拆链完成滞后锁存,TRAP-NET-12)与"真断开恰被旧拆链覆写槽"在 D20 上不可分辨
|
||||
* (结构性失明,F-NET-15 Q1)。处置:不吃边沿,置可疑电平返回,交对账①
|
||||
* (ESTABLISHED + 芯片 TCP==CLOSED)电平去抖再入本函数(N34 阶段 3 合并
|
||||
* (ESTABLISHED + 芯片 TCP==CLOSED)电平去抖再入本函数(自愈收敛阶段 3 合并
|
||||
* 后=4×100ms,NET_RECON_STABLE_DEATH,让位租约 400ms 不变 + 冷却):
|
||||
* flag==1 旁路本门 → 正常释放;连接真活则租约内
|
||||
* 会话正常完成(风暴链掐断,E9a n30 0/50 实证)。
|
||||
@@ -3746,7 +3756,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||
/* TRAP-NET-18 推广(2026-09-24 台架实证):正常 DISCONNECT 释放留下的芯片收尾状态
|
||||
* 会在复用同一 fd 的下一条连接上以"伪 DISCONNECT"形式投递(实测 accept 后约 10~20ms)→ 该连接被提前释放,应用把已到的 2048B 当整份文件并回报 226;
|
||||
* 仅**本连接收过数据**时登记沉降(实测触发源 = 收过数据的数据通道被关闭),纯连接即关/只发不收的连接免沉降,保住 TRAP-NET-17 的快速复连时序(:21 @0ms ×50 全通过) */
|
||||
/* F-NET-15 M1(N34 实验 2026-10-12):沉降**无条件**登记。原 recv_bytes!=0 门的
|
||||
/* F-NET-15 M1(自愈专项实验 2026-10-12):沉降**无条件**登记。原 recv_bytes!=0 门的
|
||||
* 受害者由事件时序定义(accept 后 ~20ms 被陈旧 DISCONNECT 杀 → recv_bytes==0 是
|
||||
* 构造性必然),门对"残渣循环自持"形态失效(n30_repro 背靠背 9/10 失败,E1 实测);
|
||||
* 门原保护目标(:21 @0ms 快复连)已被 N-32 单一重建入口延迟化(恢复窗实测 0.3~1s)架空,
|
||||
@@ -4003,7 +4013,7 @@ int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取 Socket 对端地址(IP + Port)—— N34 E13 §6 lftpd 对端显示收口
|
||||
* 函数功能:获取 Socket 对端地址(IP + Port)—— E13 定案 lftpd 对端显示收口
|
||||
* 入口参数:sockfd - socket 描述符 int
|
||||
* 出口参数:addr - 输出:对端地址 struct net_sockaddr *
|
||||
* addrlen - 输入输出:地址结构体长度 int *
|
||||
|
||||
Reference in New Issue
Block a user