@@ -39,6 +39,24 @@
*/
# define NET_PHY_CHECK_INTERVAL_MS 5000U /* PHY 状态定期检查间隔(ms) */
/* N34 E6 实验插桩(U15 失配频率,docs/网络/N34-自愈审计/实验方案.md §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。
* ⚠ 必须定义在文件最前部:bring_up 的 armed 日志与 net_poll 探测环两处消费。 */
# define NET_U15_PROBE 0
# if NET_U15_PROBE
# define NET_U15_PROBE_PERIOD 32U /* 每 32 轮 net_poll 探测一次(≈32ms) */
# define NET_U15_PROBE_LOG_MS 3600000U /* 命中日志每小时至多 1 条 */
static uint32_t s_u15_round ; /* net_poll 轮次计数 */
static uint32_t s_u15_hits ; /* 累计确认命中次数(判据数据) */
static uint32_t s_u15_last_log ; /* 上次命中日志时刻(tick) */
static uint8_t s_u15_cand [ NET_MAX_SOCKETS ] ; /* 两级确认的候选标记(per-socket) */
# endif
/*
* 全局变量定义区 - 尽量避免使用全局变量
*/
@@ -235,7 +253,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
* 2. 启用 TCP Server 多连接模式(bit1=1),设置 TCP MSS、重传参数、KeepAlive 参数
* 3. 配置 IP/网关/子网掩码,或启用 DHCP
* 4. 初始化 CH395F 协议栈并使能 PING 响应
* 5. mac 非空且非全零:初始化**之前**设置 MAC(§9.2.1 ①,Trap 24 ;
* 5. mac 非空且非全零:初始化**之前**设置 MAC(§9.2.1 ①,TRAP-NET-19 ;
* 写芯片 EEPROM,每上电重放同值幂等)
*/
int net_init ( const char * ip , const char * mask , const char * gateway , const uint8_t * mac ) {
@@ -260,7 +278,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
ch395f_reset ( ) ;
/* 芯片版本留痕 + 0-6 版本门控(N34 阶段0,§5.52 表):bit3 SOCKET_CLOSE
* 需芯片 ≥0x46、TCP_SERVER 需 ≥0x44。本台架芯片实测 ≥0x46(Trap 25 定案
* 需芯片 ≥0x46、TCP_SERVER 需 ≥0x44。本台架芯片实测 ≥0x46(TRAP-NET-20 定案
* SOCKET_CLOSE 实际生效);门控防批次漂移——版本不足则**拒置 bit3**
* (退回芯片自动关断语义)并 [ERR] 留痕,不静默带病运行 */
uint8_t chip_ver = ch395f_get_version ( ) ;
@@ -276,18 +294,18 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
DBG_INFO ( " ch395f ver=0x%02X fun_para=0x%02X " , chip_ver , fun_para ) ;
/* 功能参数(§5.52 表):bit3=1 SOCKET_CLOSE——DISCONNECT/TIMEOUT 后芯片
* 不清缓冲,由 MCU 读出残留数据后再关 Socket(Trap 25 三次定案的排空契约);
* 不清缓冲,由 MCU 读出残留数据后再关 Socket(TRAP-NET-20 三次定案的排空契约);
* bit1=0 TCP_SERVER 多连接模式不用(本项目单连接模型:每监听器独占一个
* Socket,监听转数据通道);bit0 保留必须为 0——旧注释"bit0=1 多 Socket
* 模式"手册与网络资料均无出处(多 Socket 由 SN 命令族寻址实现,与 FUN_PARA
* 无关),且违反保留位规定 → 0x09 改 0x08( 2026-10-11 定案:官方手册
* V1C/V1E/V2.2/V2.3 的 bit0 全是保留位,官方例程 bit0=0 下 Socket 0~7 照常
* 可用、FTP 例程本身就传 0x08;证据链见 Trap 18「定案更正」 ,
* 可用、FTP 例程本身就传 0x08;证据链见 TRAP-NET-15 ,
* 0x08 下的多 Socket 台架复测登记 N-31) */
ch395f_set_fun_para ( fun_para ) ;
/* 设置 TCP MSS:维持 1024(512 裕量方案未采纳,当年支撑它的台架判据不可信,
* 已随 TC-NET-604 结案为非缺陷一并撤回(2026-09-23,见 Trap 21 )) */
* 已随 TC-NET-604 结案为非缺陷一并撤回(2026-09-23)) */
/* 手册(§5.45):内部缓冲共 48 块 × 512B = 24KB,每 Socket 分配 6 块(接收 4 块 = 2KB + 发送 2 块 = 1KB) */
/* 块布局固定(与 MSS 解耦);MSS=1024 为满足布局的最大值(接收 = 2×MSS),
* 真值源为 ch395f.h 的 CH395F_TCP_MSS */
@@ -347,7 +365,7 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
/* 每 Socket 6 块:接收 CH395F_RECV_BLOCKS(=4 块=2KB) + 发送 CH395F_SEND_BLOCKS(=2 块=1KB),用满 48 块 */
/* recv_start = i× 6, send_start = recv_start+4; Socket 7 占块 42~47,恰好用尽 0~47,互不重叠 */
/* 布局以手册 §5.45 为准;若实际芯片为其它缓冲规格需重新核算 */
/* Trap 01:先配数据 Socket 1~7,再配监听 Socket 0 */
/* TRAP-NET- 01:先配数据 Socket 1~7,再配监听 Socket 0 */
uint8_t blocks_per_socket = ( uint8_t ) ( CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS ) ;
for ( int i = NET_MAX_SOCKETS - 1 ; i > = 0 ; i - - ) {
uint8_t recv_start = ( uint8_t ) ( i * blocks_per_socket ) ;
@@ -424,21 +442,6 @@ static void net_bench_cmd_log(char tag, int sock, int detail) {
}
# endif
/* N34 E6 实验插桩(U15 失配频率,docs/网络/N34-自愈审计/实验方案.md §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 = 产品构建零成本(编译剔除)**。 */
# define NET_U15_PROBE 0
# if NET_U15_PROBE
# define NET_U15_PROBE_PERIOD 32U /* 每 32 轮 net_poll 探测一次(≈32ms) */
# define NET_U15_PROBE_LOG_MS 3600000U /* 命中日志每小时至多 1 条 */
static uint32_t s_u15_round ; /* net_poll 轮次计数 */
static uint32_t s_u15_hits ; /* 累计命中次数(判据数据) */
static uint32_t s_u15_last_log ; /* 上次命中日志时刻(tick) */
# endif
/*
* 函数功能:轮询 CH395F 中断状态,更新 Socket 连接状态并处理事件
* 入口参数:无
@@ -576,26 +579,39 @@ int net_poll(void) {
}
# if NET_U15_PROBE
/* E6 探测(宏说明见文件上方 ):RX 非空而 readable=0 = RECV_OK 中断丢失
* 的数据面形态。独立于上面的缓存刷新环:GET_RECV_LEN 是独立 SPI。 */
/* E6 探测(宏说明见文件前部 ):RX 非空而 readable=0 = RECV_OK 中断丢失
* 的数据面形态。**两级确认去良性竞态**:数据刚到、本轮中断尚未读取的
* 竞态窗(≤1 个 poll)会在下一探测轮自然消失;丢中断则持续存在直到
* 盲收/超时。候选轮标记 → 下一探测轮仍成立才计确认命中。排除 CLOSED:
* closed-with-data 是已知被救回形态,非 U15 假设对象。独立于上面的
* 缓存刷新环:GET_RECV_LEN 是独立 SPI。 */
s_u15_round + + ;
if ( ( s_u15_round % NET_U15_PROBE_PERIOD ) = = 0U ) {
for ( int i = 0 ; i < NET_MAX_SOCKETS ; i + + ) {
uint16_t rlen ;
if ( s_net_socks [ i ] . in_use = = 0U ) {
s_u15_cand [ i ] = 0U ;
continue ;
}
rlen = ch395f_get_recv_len ( ( uint8_t ) i ) ;
if ( ( rlen > 0U ) & & ( s_net_socks [ i ] . readable = = 0U ) ) {
s_u15_hits + + ;
/* 首次命中必打(last_log=0 会被 uptime<1h 抑制);此后每小时 ≤1 条 */
if ( ( s_u15_hits = = 1U ) | |
( ( uint32_t ) ( HAL_GetTick ( ) - s_u15_last_log ) > = NET_U15_PROBE_LOG_MS ) ) {
s_u15_last_log = HAL_GetTick ( ) ;
DBG_INFO ( " U15 probe: sock%d rx=%u readable=0 hits=%lu " ,
i , ( unsigned int ) rlen , ( unsigned long ) s_u15_hits ) ;
if ( ( rlen > 0U ) & & ( s_net_socks [ i ] . readable = = 0U ) & &
( s_net_socks [ i ] . state = = NET_SOCK_STATE_ESTABLISHED ) ) {
if ( s_u15_cand [ i ] ! = 0U ) {
s_u15_cand [ i ] = 0U ;
s_u15_hits + + ;
/* 首次命中必打(last_log=0 会被 uptime<1h 抑制);此后每小时 ≤1 条 */
if ( ( s_u15_hits = = 1U ) | |
( ( uint32_t ) ( HAL_GetTick ( ) - s_u15_last_log ) > = NET_U15_PROBE_LOG_MS ) ) {
s_u15_last_log = HAL_GetTick ( ) ;
DBG_INFO ( " U15 probe: sock%d rx=%u readable=0 hits=%lu " ,
i , ( unsigned int ) rlen , ( unsigned long ) s_u15_hits ) ;
}
} else {
s_u15_cand [ i ] = 1U ;
}
} else {
s_u15_cand [ i ] = 0U ;
}
}
}
@@ -615,7 +631,7 @@ int net_poll(void) {
# define NET_RECON_STABLE_DEATH 4U /* 形态① 连接已失(M3 让位窗 400ms,勿改小) */
/*
* 函数功能:芯片/本层 socket 状态周期对账(Trap 22 丢中断自愈)+ 监听器 pump
* 函数功能:芯片/本层 socket 状态周期对账(TRAP-NET-17 丢中断自愈)+ 监听器 pump
* ( N-32 P2)—— N34 阶段 3 合并为单一 100ms tick( docs/网络/N34-自愈审计/实施方案.md §5 项 1)
* 入口参数:无
* 出口参数:无
@@ -712,7 +728,7 @@ static void net_reconcile_tick(void) {
} else if ( p_sock - > state = = NET_SOCK_STATE_LISTENING ) {
if ( c . tcp_state = = CH395F_TCP_ESTABLISHED ) {
/* ② 本层 LISTENING 而芯片已完成握手(丢 CONNECT 中断)→ 补做 accept
* N-30( Trap 25 )幽灵态甄别:拆链收尾窗口内芯片假报 ESTABLISHED,
* N-30( TRAP-NET-20 )幽灵态甄别:拆链收尾窗口内芯片假报 ESTABLISHED,
* 回读对端端口 = 上一条连接端口 → 不补 accept(补了会把数据发给
* 已死的旧连接 = 生产 LIST#4 数据被吞的直接成因),等拆净或新 SYN。
* 这是本 tick 唯一的按需 SPI(仅形态②命中时发) */
@@ -737,7 +753,7 @@ static void net_reconcile_tick(void) {
* 被动修正零风险:不去抖、不占冷却(原 pump 同口径) */
DBG_INFO ( " sock%d reconcile: chip listening, resync CLOSED->LISTENING (U11) " , i ) ;
p_sock - > state = NET_SOCK_STATE_LISTENING ;
/* N-30( Trap 25 ):死连接对端端口转登幽灵甄别基准 + 探针计数清零
/* N-30( TRAP-NET-20 ):死连接对端端口转登幽灵甄别基准 + 探针计数清零
* —— 芯片监听器未被重开,芯片侧对端信息可能仍是上一条连接的,
* 必须转登为基准,否则形态② 的幽灵拦截会失效 */
p_sock - > last_peer_port = p_sock - > remote_port ;
@@ -787,7 +803,7 @@ static void net_reconcile_tick(void) {
i , c . open , c . tcp_state ) ;
/* 仅修 MCU 侧;新连接的 CONNECT 中断会把两侧重新同步 */
p_sock - > state = NET_SOCK_STATE_LISTENING ;
/* N-30( Trap 25 ):死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
/* N-30( TRAP-NET-20 ):死连接对端端口转登幽灵甄别基准 + 探针计数清零 */
p_sock - > last_peer_port = p_sock - > remote_port ;
p_sock - > lost_conn_seen = 0U ;
/* 取消本 fd 在死连接上的挂起 recv(必通知,防调用方挂死) */
@@ -811,7 +827,7 @@ static void net_reconcile_tick(void) {
/*
* 函数功能:netTask 主循环核心 —— 自愈 tick 宿主 + 消息队列分派器。每轮
* 先跑三个非阻塞自愈 tick(D10 重监听 / L3 挂起 recv /
* Trap 22 状态对账),再非阻塞排空队列按 msg.type 分派到 _locked 实现。
* TRAP-NET-17 状态对账),再非阻塞排空队列按 msg.type 分派到 _locked 实现。
* 入口参数:无
* 出口参数:无
* 返回值:无(void);消息结果经 xTaskNotify 通知值回传(成功=字节数/描述符,
@@ -823,7 +839,7 @@ static void net_reconcile_tick(void) {
* 节拍重试 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 22 + pump 合并,N34 阶段 3):每 100ms 对账
* 4. net_reconcile_tick( TRAP-NET-17 + pump 合并,N34 阶段 3):每 100ms 对账
* ①②⑤ + ③④ 重建 + U11 重同步,判据读驱动状态缓存(net_poll 每轮
* 全量刷新,E2 背书);去抖分级(②=1 轮/③④⑤=2 轮/①=4 轮,M3 让位窗)
* + 1s 冷却;重建失败进 D10 重试队列,reconciler 不重复催
@@ -841,11 +857,11 @@ void net_process_messages(void) {
}
/* 三个非阻塞自愈 tick 置于消息处理之前:断连后即使无应用消息,监听器也能自主恢复 */
/* D10 重监听重试(Trap 09):沉降后重开芯片监听器 */
/* D10 重监听重试(TRAP-NET- 09):沉降后重开芯片监听器 */
net_listener_retry_tick ( ) ;
/* L3 挂起 recv 完成检查:数据到达 / 到点 / 断连时通知调用方 */
net_pending_tick ( ) ;
/* Trap 22 状态对账 + 监听器 pump(N34 阶段 3 合并单一 100ms tick):
/* TRAP-NET-17 状态对账 + 监听器 pump(N34 阶段 3 合并单一 100ms tick):
* 判据读驱动缓存(net_poll 每轮全量刷新),①②⑤ 失同步 + ③④ 重建 +
* U11 重同步全部在此(本层唯一周期重建入口,N-32 P2 单一所有者) */
net_reconcile_tick ( ) ;
@@ -1083,7 +1099,7 @@ int net_socket(int domain, int type) {
* net_setblocking(fd, 0) 显式设置)。close 的 memset 会清零本字段,
* 新 fd 必须在此显式置 1(同 released_abnormal 的"不得继承"纪律) */
p_sock - > blocking = 1 ;
/* 新 fd 不得继承上一条连接的释放原因(Trap 23 待办 #3) */
/* 新 fd 不得继承上一条连接的释放原因(TRAP-NET-18 待办 #3) */
p_sock - > released_abnormal = 0 ;
/* N-32( P1):新 fd 不得继承"上一条会话已结束"电平(否则新建即 EOF,
* 消费侧连数据都收不到)——与 released_abnormal 同理,显式清零 */
@@ -1157,7 +1173,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
uint8_t status ;
/* net_init 已为全部 8 个 Socket 分配缓冲;此处仅对 Socket 4~7 兜底重设,
* 使用与 net_init 相同的布局(固定 6 块/Socket,与 MSS 解耦,见 net_init / Trap 21 ) */
* 使用与 net_init 相同的布局(固定 6 块/Socket,与 MSS 解耦,见 net_init) */
if ( sockfd > = 4 ) {
/* 每 Socket 块数 = 接收 + 发送 */
uint8_t blocks_per_socket = ( uint8_t ) ( CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS ) ;
@@ -1218,7 +1234,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
* 2. 内部序列=E4 定案:读空 RX -> CLOSE -> 排空事件(quiescent) ->
* 轮询 byte0=00H; WAIT_CLOSE 内置 LISTEN 态二段 CLOSE 补发
* (E2 补充发现:一次 CLOSE 只拆监听 byte0 恒 05)
* 3. 超时留痕返 -1,调用方按原语义兜底(Trap 09 重试环 / close 放行)
* 3. 超时留痕返 -1,调用方按原语义兜底(TRAP-NET- 09 重试环 / close 放行)
*/
static int net_sock_reset_sync ( int sockfd , ch395f_reset_mode_t mode ) {
/* 起始时刻(600ms 上限基准) */
@@ -1252,7 +1268,7 @@ static int net_sock_reset_sync(int sockfd, ch395f_reset_mode_t mode) {
* 出口参数:无
* 返回值:0 - 成功,-1 - 失败 int
* 限定条件:sockfd 已绑定且为 TCP; netTask 上下文
* 函数说明:1. 芯片侧 open + TCP_LISTEN(端口=控制块 local_port; open 失败重试 3 次,见 Trap 09)
* 函数说明:1. 芯片侧 open + TCP_LISTEN(端口=控制块 local_port; open 失败重试 3 次,见 TRAP-NET- 09)
* 2. 成功置 LISTENING 并启用 auto_relisten( BSD 风格监听常驻)
* 3. 启动监听前清**本 Socket** 中断状态寄存器(读即清),防残留误触发;
* 全局中断寄存器交 net_poll 集中读清(B3,详见函数体内注释)
@@ -1281,11 +1297,11 @@ int net_listen_locked(int sockfd) {
/* 本地端口 = 控制块 local_port */
ch395f_set_sour_port ( sockfd , p_sock - > local_port ) ;
/* CH395F 关闭 Socket 后需延时才能重新打开(Trap 09),故失败重试最多 3 次。
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET- 09),故失败重试最多 3 次。
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,Trap 09 语义保留 */
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET- 09 语义保留 */
for ( int open_try = 0 ; open_try < 3 ; open_try + + ) {
/* 尝试打开芯片侧 Socket */
status = ch395f_open_socket ( sockfd ) ;
@@ -1315,7 +1331,7 @@ int net_listen_locked(int sockfd) {
p_sock - > state = NET_SOCK_STATE_LISTENING ;
/* 单连接模式:连接断开后由 net 层自动回到 LISTEN(模拟 BSD 监听常驻) */
p_sock - > auto_relisten = 1 ;
/* N-30( Trap 25 ):新监听会话,丢中断去抖计数清零 */
/* N-30( TRAP-NET-20 ):新监听会话,丢中断去抖计数清零 */
p_sock - > lost_conn_seen = 0U ;
/* 读即清:仅本 Socket 的中断状态——丢弃上一条会话残留的 DISCONNECT/
* TIMEOUT,避免监听刚开始就误触发事件。
@@ -1326,10 +1342,10 @@ int net_listen_locked(int sockfd) {
* (芯片无按位清除手段),而 net_poll 只在**全局位置位时**才去读该
* Socket 的 SINT(见 :469 门控)→ 全量清等于把别的在用 Socket 的门一并
* 焊死,其 CONNECT/DISCONNECT 等边沿事件永久丢失(RECV 属条件位,下轮
* 可补回,见 Trap 08)。
* 可补回,见 TRAP-NET- 08)。
* 全局寄存器交 net_poll 集中读清(AGENTS 模块约定:所有 CH395F 中断经
* net_poll 集中读取并清除);本 Socket 残留的全局位被 net_poll 读到时
* SINT 已为 0,无害了结。Trap 14/17/23 指定的两级预清落在
* SINT 已为 0,无害了结。TRAP-NET-12/-18 指定的两级预清落在
* net_connect_locked / net_close_locked / relisten 隔离段,均为单 Socket,
* 本次未动。 */
( void ) ch395f_get_sock_int_status ( ( uint8_t ) sockfd ) ;
@@ -1405,7 +1421,7 @@ int net_listen(int sockfd) {
* (芯片状态寄存器 → ESTABLISHED)但 **CONNECT 中断被丢**——纯事件驱动的 accept
* 永远等不到 → 数据被吞 / 425。固定沉降延时、Socket 轮换、listen 后 close 重试、
* 缓冲重分配均已被实验证伪;唯一有效 = "中断 + 状态轮询"双信源(修复组 15/15
* 全过,机制触发 5 次全部救回)。→ CH395F_Trap_Records.md Trap 25
* 全过,机制触发 5 次全部救回)。→ CH395F_Trap_Records.md TRAP-NET-20
* 幽灵态甄别:拆链窗口内芯片也会直接假报 ESTABLISHED(旧连接未拆净),此时回读
* 对端端口 = 上一条连接端口;新连接临时端口几乎必然不同 → 端口相同不 accept,
* 等旧连接拆净 / 新 SYN 到达(新连接若也丢中断,后续轮询以新端口命中)。 */
@@ -1441,7 +1457,7 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
/* 对端端口(小端 2 字节) */
uint16_t peer = ( uint16_t ) ( remote [ 4 ] | ( remote [ 5 ] < < 8 ) ) ;
/* 幽灵甄别:仅"端口非零且 = 上一条连接端口"才判幽灵拦截;
* peer==0(芯片对端端口提交滞后,Trap 15 同类)不拦截——宁可补 accept
* peer==0(芯片对端端口提交滞后,TRAP-NET-13 同类)不拦截——宁可补 accept
* 也不退回丢中断死等(2026-10-11 验证轮实测:peer==0 拦截把首连接
* 丢中断的原有对账救援也挡死,LIST#1 卡满 20s,比修复前更糟) */
if ( ( peer ! = 0U ) & & ( peer = = p_sock - > last_peer_port ) ) {
@@ -1466,9 +1482,9 @@ static void net_lost_connect_probe(net_sock_t *p_sock) {
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
* 限定条件:Socket 处于 LISTENING 状态
* 函数说明:1. 单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
* 2. 等待期叠加芯片状态轮询探针(丢 CONNECT 中断自愈,Trap 25 )
* 2. 等待期叠加芯片状态轮询探针(丢 CONNECT 中断自愈,TRAP-NET-20 )
* 3. CLOSED + 芯片 RX 缓冲有残留数据:接受"已关但可读"连接排空
* ( FUN_PARA §5.52 ② 保留现场契约,Trap 25 三次定案)
* ( FUN_PARA §5.52 ② 保留现场契约,TRAP-NET-20 三次定案)
*/
static int net_accept_locked ( int sockfd , struct net_sockaddr * addr , int * addrlen ) {
/* 监听 Socket 控制块 */
@@ -1484,7 +1500,7 @@ static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen
/* 先轮询一次:把状态机刷新到芯片侧最新状态 */
net_poll ( ) ;
/* N-30( Trap 25 ):监听等待期兼做芯片状态第二信源——丢 CONNECT 中断时
/* N-30( TRAP-NET-20 ):监听等待期兼做芯片状态第二信源——丢 CONNECT 中断时
* 去抖补 accept(裸机台架实证:拆链窗口丢中断是数据被吞/425 的主根因,
* 纯事件等待无自愈可能;详见 net_lost_connect_probe 区块注释) */
if ( p_listen_sock - > state = = NET_SOCK_STATE_LISTENING ) {
@@ -1683,7 +1699,7 @@ int net_listener_armed(int sockfd) {
* 函数说明:1. ESTABLISHED → 看 readable( net_poll 在 RECV_OK 置位、读空清零)
* 2. 非 ESTABLISHED / 描述符失效一律返回 1:必须让上层真的 recv 一次
* 拿到 EOF/错误并复位自身状态,门掉它会把"连接已不存在"永久藏住
* 3. ⚠ readable 仅由 RECV_OK 中断置位,Trap 22 对账不含"RX 非空但
* 3. ⚠ readable 仅由 RECV_OK 中断置位,TRAP-NET-17 对账不含"RX 非空但
* readable=0" → 中断丢失时本函数恒返 0,调用方须保留低频兜底 recv
*/
int net_can_read ( int sockfd ) {
@@ -1780,7 +1796,7 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen) {
* 限定条件:net_init() 已调用;必须在 netTask 上下文中调用
* 函数说明:1. 校验控制块(in_use、TCP 类型、地址参数)并保存对端地址
* 2. 芯片侧 OPEN(失败重试 3 次,每次失败走 sock_reset 确定性排渣,
* 见 Trap 09 / P2b)+ 配置源/目的端口与目的 IP
* 见 TRAP-NET- 09 / P2b)+ 配置源/目的端口与目的 IP
* 3. 清本 Socket 残留中断状态(丢弃上一条连接遗留的 DISCONNECT)
* 4. 发起 TCP_CONNECT(驱动内已轮询 CMD_STATUS)并置 CONNECTING;
* 命令级被拒立即关 Socket 返 -1, TCP 层成败仍由 CONNECT/TIMEOUT 裁定
@@ -1831,11 +1847,11 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
/* 设置协议类型为 TCP */
ch395f_set_proto_type ( sockfd , CH395F_PROTO_TYPE_TCP ) ;
/* CH395F 关闭 Socket 后需延时才能重新打开(Trap 09),故失败重试最多 3 次。
/* CH395F 关闭 Socket 后需延时才能重新打开(TRAP-NET- 09),故失败重试最多 3 次。
* P2b 收口(N34 阶段 3):原"close + 盲等 500ms"改**确定性排渣**——
* sock_reset(读空 RX -> CLOSE -> 排空事件 -> 等 byte0=00H,内置 LISTEN
* 态二段 CLOSE 补发;E4 定案 60 轮实证复位后 open 必成)。GRACEFUL
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,Trap 09 语义保留 */
* 最短等 100ms ≪ 原 500ms 盲等;复位失败/超时仍走下一轮重试,TRAP-NET- 09 语义保留 */
for ( int open_try = 0 ; open_try < 3 ; open_try + + ) {
/* 尝试打开芯片侧 Socket */
status = ch395f_open_socket ( sockfd ) ;
@@ -1928,7 +1944,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
*/
# define NET_DMA_MAX_PAYLOAD ((int)CH395F_SPI_DMA_MAX_PAYLOAD)
/* 单次写入 CH395F 发送 FIFO 的最大字节数:受硬件发送缓冲(CH395F_SEND_BUF_SIZE_BYTES=1KB)
* 与 SPI DMA 载荷(NET_DMA_MAX_PAYLOAD=2KB) 双重限制,以硬件发送缓冲为硬上限(见 Trap 20 ),
* 与 SPI DMA 载荷(NET_DMA_MAX_PAYLOAD=2KB) 双重限制,以硬件发送缓冲为硬上限(见 TRAP-NET-16 ),
* 否则单次写 2KB/4KB 会写穿 1KB 发送 FIFO。 */
# define NET_SEND_CHUNK_MAX ((int)CH395F_SEND_BUF_SIZE_BYTES < NET_DMA_MAX_PAYLOAD ? \
(int)CH395F_SEND_BUF_SIZE_BYTES : NET_DMA_MAX_PAYLOAD)
@@ -1941,7 +1957,7 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
* 出口参数:无
* 返回值:实际发送字节数(>= 0);-1 表示参数无效或 Socket 未连接 int
* 限定条件:p_sock 非空;Socket 处于 ESTABLISHED 状态;netTask 上下文
* 函数说明:1. 按 NET_SEND_CHUNK_MAX(硬件发送缓冲上限,见 Trap 20 )分块写入 CH395F 发送 FIFO
* 函数说明:1. 按 NET_SEND_CHUNK_MAX(硬件发送缓冲上限,见 TRAP-NET-16 )分块写入 CH395F 发送 FIFO
* 2. 发送前等待 send_ready 置位,超时返回已发送字节数
* 3. 每写完一块等待 SENBUF_FREE 中断(send_ready 清零后重新置位,§5.32/§5.23①)
* 4. 发送中途断连(状态非 ESTABLISHED)→ 立即失败并返回已发字节
@@ -1972,7 +1988,7 @@ static int net_send_locked(net_sock_t *p_sock, const void *buf, int len) {
while ( sent < len ) {
/* 剩余待发字节 */
int chunk = len - sent ;
/* 单块以硬件发送缓冲为上限(Trap 20 :防写穿 1KB FIFO) */
/* 单块以硬件发送缓冲为上限(TRAP-NET-16 :防写穿 1KB FIFO) */
if ( chunk > NET_SEND_CHUNK_MAX ) {
chunk = NET_SEND_CHUNK_MAX ;
}
@@ -2095,7 +2111,7 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
ch395f_read_recv_buf ( sockfd , ( uint8_t * ) buf , ( uint16_t ) read_len ) ;
/* 累计接收字节统计 */
p_sock - > recv_bytes + = ( uint32_t ) read_len ;
/* 已消费数据(部分读安全:手册 §5.34 未读数据保留可续读,旧"Trap 13
/* 已消费数据(部分读安全:手册 §5.34 未读数据保留可续读,旧"部分读归零
* 部分读归零"已降级为未证实历史观察;下一次 RECV_OK 重新置 readable) */
p_sock - > readable = 0 ;
/* 返回本次读出字节数 */
@@ -2159,8 +2175,8 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags,
* (INT# 电平触发链保证缓冲有数据时每轮重读 SINT 重位置位)
* ② 到点(仅当登记时带显式预算 net_recv_to;无限等待登记无 deadline)→ NET_ERR_TIMEDOUT
* ——这是调用方策略的正常兑现,不是伪造
* ③ CLOSED:先排空(bit3=1 芯片断连后残数据留缓冲待 MCU 读——Trap 25 排空契约;
* 旧注归 Trap 13 已随其 复核注降级)→ 有数据按数据完成,否则 EOF(0) + 自动重监听
* ③ CLOSED:先排空(bit3=1 芯片断连后残数据留缓冲待 MCU 读——TRAP-NET-20 排空契约;
* 旧注归"部分读归零"机理、 已随复核注降级)→ 有数据按数据完成,否则 EOF(0) + 自动重监听
* 其他状态(CONNECTING/LISTENING/…)保持等待状态迁移(CONNECT→ESTABLISHED 是合法路径;
* 陈旧 resync 由显式取消处理)——不做状态推断取消,避免误杀正在建链的等待
* tripwire( N34 阶段 1.5 降级):挂起超 60s = "完成逻辑缺位"探针 → 只 [ERR] 留痕一次,
@@ -2366,9 +2382,9 @@ static void net_pending_tick(void) {
/* 非阻塞:失败由 D10 重试轮询接管(N-32 §10:入口收敛到 net_listener_try) */
( void ) net_listener_try ( i ) ;
}
/* Trap 23 待办 #3:异常释放(TIMEOUT/RST)不是正常 EOF(对端未发正常 FIN)
/* TRAP-NET-18 待办 #3:异常释放(TIMEOUT/RST)不是正常 EOF(对端未发正常 FIN)
* → 以连接重置了结:应用(lftpd STOR)对异常结束回 5xx 而非误报 226;
* 正常 FIN( DISCONNECT)仍回 0(在途 FIN 与正常完成不可区分——协议边界,见 Trap 23 记录) */
* 正常 FIN( DISCONNECT)仍回 0(在途 FIN 与正常完成不可区分——协议边界,见 TRAP-NET-18 记录) */
/* 异常释放:以连接重置了结(回 5xx,不误报 226) */
if ( p_sock - > released_abnormal ! = 0U ) {
/* 异常释放(错误码由 net_pending_complete 记入本任务槽位) */
@@ -2527,7 +2543,7 @@ static void net_pending_settle_close(net_sock_t *p_sock) {
* (唯一读者=net_poll;原循环读全局会焊死其它 Socket 事件位)
* 3. 快路径:芯片已 CLOSED(byte0=00H)→ 跳过复位只清残留事件
* 4. 复位超时照常放行(同原 500ms 超时容忍;后续 relisten 由
* Trap 09 open 重试环吸收)
* TRAP-NET- 09 open 重试环吸收)
*/
static int net_close_locked ( net_sock_t * p_sock ) {
/* 由控制块指针反推描述符 */
@@ -2546,7 +2562,7 @@ static int net_close_locked(net_sock_t *p_sock) {
}
/* 清零控制块(memset 0 = 释放本 fd 全部状态) */
/* N-30( Trap 25 ):幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
/* N-30( TRAP-NET-20 ):幽灵甄别基准跨 fd 释放保留(幽灵属芯片 Socket 级状态,
* 与 fd 复用无关——close 后新 listen 落在同一芯片 Socket 上仍可能撞幽灵) */
uint16_t keep_peer = p_sock - > remote_port ;
memset ( p_sock , 0 , sizeof ( net_sock_t ) ) ;
@@ -2570,7 +2586,7 @@ static int net_close_locked(net_sock_t *p_sock) {
* ( PC 内核自动 ACK keepalive,僵尸判不死),单连接监听被永久
* 占住;应用又不得 net_close 监听 fd(毁监听)——本函数补上
* "拆连接不拆监听"的应用侧形态
* 2. 拆除=sock_reset QUARANTINE( Trap 23 异常释放语义:FIN + 排渣 +
* 2. 拆除=sock_reset QUARANTINE( TRAP-NET-18 异常释放语义:FIN + 排渣 +
* 排空事件(quiescent) + 等 byte0=00H,内置二段 CLOSE 补发)
* 3. auto_relisten(监听型 fd):收口 CLOSED 后即时 net_listener_try
* (芯片已 CLOSED 直接 open 必成,E4 定案;失败交 D10 重试 +
@@ -2585,7 +2601,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
/* L3:先了结本 fd 挂起 recv(排空/取消 + 必通知),再拆芯片会话 */
net_pending_settle_close ( p_sock ) ;
/* 确定性拆除(异常释放 → QUARANTINE 400ms 底,Trap 23 语义) */
/* 确定性拆除(异常释放 → QUARANTINE 400ms 底,TRAP-NET-18 语义) */
if ( net_sock_reset_sync ( sockfd , CH395F_RESET_QUARANTINE ) ! = 0 ) {
DBG_ERROR ( " sock%d drop_conn: sock_reset not done " , sockfd ) ;
/* 超时继续收口本层;芯片侧交 reconciler/pump 对账接管 */
@@ -2594,7 +2610,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 25 ):新会话起点,丢中断去抖计数清零 */
/* N-30( TRAP-NET-20 ):新会话起点,丢中断去抖计数清零 */
p_sock - > lost_conn_seen = 0U ;
if ( p_sock - > auto_relisten ) {
@@ -2619,7 +2635,7 @@ static int net_drop_conn_locked(net_sock_t *p_sock) {
* ( netTask 阻塞在 xTaskNotifyWait 而无人处理消息);netTask 内请直接用 net_send_locked()
* 2. Socket 须处于 ESTABLISHED 状态
* 3. net_init() + MX_FREERTOS_Init() 已执行,netMsgQueueHandle 已由 net_init 创建
* 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 Trap 16 )
* 函数说明:1. 所有 CH395F SPI 访问只允许在 netTask 内串行执行(见 TRAP-NET-14 )
* 2. 本函数不直接触碰 SPI,而是把发送请求打包成 net_msg_t 投递到 netMsgQueueHandle
* 3. netTask 的 net_process_messages() 取出并在 netTask 上下文调用 net_send_locked() 真正写 CH395F
* 4. 调用方经 FreeRTOS TaskNotify 阻塞等待处理结果,对外呈现"同步发送"语义
@@ -3049,7 +3065,7 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
while ( sent < len ) {
/* 剩余待发字节 */
int chunk = len - sent ;
/* 单块以硬件发送缓冲为上限(Trap 20 ) */
/* 单块以硬件发送缓冲为上限(TRAP-NET-16 ) */
if ( chunk > NET_SEND_CHUNK_MAX ) {
chunk = NET_SEND_CHUNK_MAX ;
}
@@ -3442,6 +3458,9 @@ uint32_t net_inet_addr(const char *cp) {
* 返回值:成功返回 buf 指针;buf 为 NULL 时返回 NULL char *
* 限定条件:buf 非空且长度足够(>= 16 字节)
* 函数说明:1. 先经 NET_NTOHL 转为主机字节序再格式化输出
* 2. ⚠ 段序(N34 E13 §6 修复):NTOHL 后主机序数值的高字节才是
* 点分第一段(192.168.1.100 → 0xC0A80164 → "192.168.1.100")。
* 原实现低段在前,显示成字节反转的 "100.1.168.192"
*/
char * net_inet_ntoa ( uint32_t addr , char * buf ) {
/* 网络序 → 主机序 */
@@ -3452,12 +3471,12 @@ char *net_inet_ntoa(uint32_t addr, char *buf) {
return NULL ;
}
/* 四段格式化为点分十进制(最低 段在前,16B 缓冲) */
/* 四段格式化为点分十进制(高 段在前,16B 缓冲) */
snprintf ( buf , 16 , " %lu.%lu.%lu.%lu " ,
( unsigned long ) ( naddr & 0xFF ) ,
( unsigned long ) ( ( naddr > > 8 ) & 0xFF ) ,
( unsigned long ) ( ( naddr > > 24 ) & 0xFF ) ,
( unsigned long ) ( ( naddr > > 16 ) & 0xFF ) ,
( unsigned long ) ( ( naddr > > 24 ) & 0xFF ) ) ;
( unsigned long ) ( ( naddr > > 8 ) & 0xFF ) ,
( unsigned long ) ( naddr & 0xFF ) ) ;
/* 返回输出缓冲 */
return buf ;
@@ -3656,7 +3675,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
/* 监听态:DISCONNECT 落在监听器上 */
if ( p_sock - > state = = NET_SOCK_STATE_LISTENING ) {
/* Trap 22 / N-6:监听态收到 DISCONNECT——bit3=1( 0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
/* TRAP-NET-17 / N-6:监听态收到 DISCONNECT——bit3=1( 0x08)下芯片**不**关该 Socket(停 0x05/0x00,芯片 TCP 侧已 CLOSED);不重开则此后所有 SYN 全被拒 = 监听永久死亡;
* 触发 = 断连后 <~1s 快速复连时 CONNECT 中断未上报(控制块滞留 LISTENING)后该连接断开(2026-09-23 生产固件复现);
* N-32 P2:本分支**只回读留痕、不再 relisten** —— 重建统一交
* net_reconcile_tick 形态③(每 100 ms 读驱动缓存,监听失位即重建)。原处直接
@@ -3695,7 +3714,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
}
/* F-NET-17 M3( N34 实验 2026-10-13):矛盾态可疑门——芯片 Socket 仍 OPEN(0x05)
* 而 TCP 槽 0x00 且本层 ESTABLISHED = 逻辑矛盾(活连接应 0x04):陈旧 DISCONNECT
* (拆链完成滞后锁存,Trap 14 )与"真断开恰被旧拆链覆写槽"在 D20 上不可分辨
* (拆链完成滞后锁存,TRAP-NET-12 )与"真断开恰被旧拆链覆写槽"在 D20 上不可分辨
* (结构性失明,F-NET-15 Q1)。处置:不吃边沿,置可疑电平返回,交对账①
* ( ESTABLISHED + 芯片 TCP==CLOSED)电平去抖再入本函数(N34 阶段 3 合并
* 后=4× 100ms, NET_RECON_STABLE_DEATH,让位租约 400ms 不变 + 冷却):
@@ -3724,9 +3743,9 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
* 留给 net_recv_locked 把剩余数据读出来再关,置 CLOSED 等待应用重新监听 */
DBG_INFO ( " sock%d DISCONNECTED, releasing (chip st=0x%02X/0x%02X) " ,
p_sock - > ch395_sock , st [ 0 ] , st [ 1 ] ) ;
/* Trap 23 推广(2026-09-24 台架实证):正常 DISCONNECT 释放留下的芯片收尾状态
/* TRAP-NET-18 推广(2026-09-24 台架实证):正常 DISCONNECT 释放留下的芯片收尾状态
* 会在复用同一 fd 的下一条连接上以"伪 DISCONNECT"形式投递(实测 accept 后约 10~20ms)→ 该连接被提前释放,应用把已到的 2048B 当整份文件并回报 226;
* 仅**本连接收过数据**时登记沉降(实测触发源 = 收过数据的数据通道被关闭),纯连接即关/只发不收的连接免沉降,保住 Trap 22 的快速复连时序(:21 @0ms ×50 全通过) */
* 仅**本连接收过数据**时登记沉降(实测触发源 = 收过数据的数据通道被关闭),纯连接即关/只发不收的连接免沉降,保住 TRAP-NET-17 的快速复连时序(:21 @0ms ×50 全通过) */
/* F-NET-15 M1( N34 实验 2026-10-12):沉降**无条件**登记。原 recv_bytes!=0 门的
* 受害者由事件时序定义(accept 后 ~20ms 被陈旧 DISCONNECT 杀 → recv_bytes==0 是
* 构造性必然),门对"残渣循环自持"形态失效(n30_repro 背靠背 9/10 失败,E1 实测);
@@ -3749,7 +3768,7 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
* recv 的 DONTWAIT 快路径先返数据(recv_len>0 优先),数据尽后判据
* 落到本标志 → 仍得 EOF,不因排空慢而漏报 */
p_sock - > session_dead = 1U ;
/* N-30( Trap 25 ):登记本连接对端端口(幽灵态甄别基准,须在状态
/* N-30( TRAP-NET-20 ):登记本连接对端端口(幽灵态甄别基准,须在状态
* 迁移前记录——remote_port 此刻仍有效,relisten 清零) */
p_sock - > last_peer_port = p_sock - > remote_port ;
/* 状态 → CLOSED */
@@ -3776,11 +3795,11 @@ static void handle_disconnect_event(net_sock_t *p_sock) {
* 限定条件:net_poll() 检测到 RECV_OK 中断后调用;netTask 上下文
* 函数说明:1. 仅触发 NET_EVENT_DATA_RECEIVED 回调通知上层
* 2. 不在此读取 recv_len:单一读取点归 net_recv_locked(省一次 SPI
* 查询;Trap 13 时代的"读取冲突"顾虑已随复核注降级,结构保留)
* 查询;旧"部分读归零" 时代的"读取冲突"顾虑已随复核注降级,结构保留)
*/
static void handle_recv_event ( net_sock_t * p_sock ) {
/* RECV_OK 中断已触发,直接通知上层。不在此读 recv_len,
* 单一读取点在 net_recv_locked(省 SPI;原 Trap 13 顾虑已降级) */
* 单一读取点在 net_recv_locked(省 SPI;原"部分读归零" 顾虑已降级) */
/* 置可读标志,供 net_select 在无 SPI 访问下判读 */
p_sock - > readable = 1 ;
/* 触发数据到达事件回调 */
@@ -3825,7 +3844,7 @@ static void handle_timeout_event(net_sock_t *p_sock) {
} else if ( p_sock - > state = = NET_SOCK_STATE_ESTABLISHED ) {
/* 已建立连接超时 */
DBG_ERROR ( " sock%d TIMEOUT " , p_sock - > ch395_sock ) ;
/* Trap 23 :异常释放(TIMEOUT,例如客户端中止上传)→ 复监听前隔离,
/* TRAP-NET-18 :异常释放(TIMEOUT,例如客户端中止上传)→ 复监听前隔离,
* 等对端在途数据落尽并排空 RX 残渣(详见 net_relisten_locked 区块注释) */
{
/* 反推描述符 */
@@ -3836,11 +3855,11 @@ static void handle_timeout_event(net_sock_t *p_sock) {
net_listener_settle ( qfd , NET_LISTENER_SETTLE_QUARANTINE ) ;
}
}
/* Trap 23 待办 #3:标记异常释放——L3 挂起 recv 排空断连后以
/* TRAP-NET-18 待办 #3:标记异常释放——L3 挂起 recv 排空断连后以
* NET_ERR_CONNRESET 了结(而非 EOF),应用(lftpd STOR)回报 5xx
* 而非误报 226(见 net_pending_tick 断连分支) */
p_sock - > released_abnormal = 1U ;
/* N-30( Trap 25 ):异常释放同样登记对端端口(幽灵甄别基准) */
/* N-30( TRAP-NET-20 ):异常释放同样登记对端端口(幽灵甄别基准) */
p_sock - > last_peer_port = p_sock - > remote_port ;
/* N-32(P1 不变量 I):异常结束同样是"本会话已结束"电平(TIMEOUT/RST
* 已在下方 requarantine,本标志只表达"会话结束了"这一事实,与
@@ -3982,3 +4001,55 @@ int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen) {
/* 成功(0) */
return 0 ;
}
/*
* 函数功能:获取 Socket 对端地址(IP + Port)—— N34 E13 §6 lftpd 对端显示收口
* 入口参数:sockfd - socket 描述符 int
* 出口参数:addr - 输出:对端地址 struct net_sockaddr *
* addrlen - 输入输出:地址结构体长度 int *
* 返回值:0 - 成功,-1 - 失败(NOTCONN:尚无 CONNECT 事件回读过对端) int
* 限定条件:socket 已连接(standalone accept / connect 成功后)
* 函数说明:1. 数据源=CONNECT 事件时 ch395f_get_remot_ipp 回读并缓存的
* remote_ip/remote_port( net_types.h),**不发 SPI**
* 2. 单连接模型下监听 fd 转数据通道后同样有效(对端=刚接入的客户端)
*/
int net_getpeername ( int sockfd , struct net_sockaddr * addr , int * addrlen ) {
/* 描述符越界 → BADF */
if ( sockfd < 0 | | sockfd > = NET_MAX_SOCKETS ) {
return NET_ERR_RETURN_1 ( NET_ERR_BADF ) ;
}
/* 控制块(const:本函数只读 Socket 信息) */
const net_sock_t * p_sock = & s_net_socks [ sockfd ] ;
/* 未在用 → BADF */
if ( ! p_sock - > in_use ) {
return NET_ERR_RETURN_1 ( NET_ERR_BADF ) ;
}
/* 输出参数无效(NULL 或长度不足)→ INVAL */
if ( addr = = NULL | | addrlen = = NULL | | * addrlen < ( int ) sizeof ( struct net_sockaddr_in ) ) {
return NET_ERR_RETURN_1 ( NET_ERR_INVAL ) ;
}
/* 尚无对端(未连接/未收到 CONNECT 回读)→ NOTCONN */
if ( p_sock - > remote_port = = 0U ) {
return NET_ERR_RETURN_1 ( NET_ERR_NOTCONN ) ;
}
/* 强转为 IPv4 地址结构体 */
struct net_sockaddr_in * p_addr_in = ( struct net_sockaddr_in * ) addr ;
/* 清零地址结构体(防御:全部字段归零) */
memset ( p_addr_in , 0 , sizeof ( struct net_sockaddr_in ) ) ;
/* 地址族 = IPv4 */
p_addr_in - > sin_family = NET_AF_INET ;
/* 对端端口(主机序 → 网络序) */
p_addr_in - > sin_port = net_htons ( p_sock - > remote_port ) ;
/* 对端 IP:CONNECT 时已按网络序缓存,直传 */
p_addr_in - > sin_addr . s_addr = p_sock - > remote_ip ;
/* 回填结构体长度 */
* addrlen = sizeof ( struct net_sockaddr_in ) ;
/* 成功(0) */
return 0 ;
}