fix(log,net): 处置主机单测照出的 10 条现状,撤销 1 条误报
用户裁定「全部修」。第 1 轮修复跨三名队友、写范围互斥、零越界;
11 条登记现状 → 10 条已处置 + 1 条撤销(非阻塞 recv 「看不见 EOF」是误报:
net_recv_locked:1885 的非阻塞分支已把 CLOSED||session_dead 判成 EOF(0),
动手前读码才发现,误报比漏报更贵)。
存储与日志(App/log/sys_log_mcu.c、soe_store.c、cfg_file_store_mcu.c、sys_log.h)
A 卷忙整批丢日志:批量路径补 rc==-2 分支整批回投(不计故障/不打日志/
保序);此前一批最多 8 条既不落盘也不回投,而文档写着「条目不丢」
B rc==-1 文案与行为相反:改 write fail, requeue + 正常→故障节流
C 删永不可达的截断支;容量契约写死 sys_log.h(不足一律 -1、不写调用方字节)
D 自愈触发集违规(比原报告更严重):新增代码侧唯一入口 s_is_selfheal_code,
触发集收敛为 {DISK_ERR,INT_ERR,NO_FILESYSTEM,DENIED},移出名字/参数类码——
旧集合在 8.3 同名同因下每轮删一次自己的历史日志且永不自愈,正是存储架构
§10.1 第 10 条严禁的归集;soe_store 侧同源取更保守子集(打开失败绝不 unlink)
E 注释里的 FR_NO_SYSTEM 不存在,改 FR_NOT_READY / FR_NO_FILESYSTEM
F syslog_post 满态留痕节流(A 修好后「队列常驻满」成必然场景,不修等于用
新刷屏换掉静默丢);丢弃语义一字未改
NET(net_socket.c/.h、net_types.h、net_socket_sim.c、lftpd.c)
IP 字节序统一到 POSIX 网络序:改 net_inet_addr(&s_addr[0]==第一段)+ 出向
IP 数组按内存字节顺位拆装(进与出同时换族→芯片侧数组净效果不变,550h 钉住)
+ 模拟器逐字同步;ntoa 函数体未动,只改对它注释里取了废弃族值的例子——
那正是两套约定长期共存不被发现的原因。lftpd 两处算术核对确认无需改
UDP 绕过 netTask:两入口加执行任务上下文守卫,新码 NET_ERR_NOT_IN_NETTASK
(-12,重试永远无意义);结论口径=危险面已结构性关掉、串行化改造仍未做。
附带关掉第二条更隐蔽的路:非 netTask 自旋 recvfrom 期间控制块被 close 并
把同一 sockfd 分给新会话→旧自旋者消费新会话数据报
控制台(console_log.c/.h):冷却改独立 s_con_cooling 标志(旧写法在 tick==0 那
拍冷却等于没记);con_append 的判空位+推进 head+整行拷贝收进同一临界区(旧
为区外 check-then-act,环 >95% 满时可静默覆盖且既不打 [ERR] 也不计 dropped);
Instance==NULL 与僵尸通道分诊(未初始化绝不 reinit);三本账分离 + 新读口
dbg_console_tx_timeout();[ERR] 行改为发成功才销账
测试:net_socket 452、console_log 127、sys_log_mcu 104、soe_store 27、
cfg_file_store_mcu 34;回归 net_listener 34 / net_events 34 / net_pending 43 /
net_select 22 / lftpd 35 / lftpd_inet 28 / lftpd_io 33 / iec104_serv 28 /
nand_port 149 / vol_lock 33 / soe 32 / cfg_file 151 全绿。原「按现状钉住」的
用例全部翻正向;console_log 用「逐条退回旧实现」做变异自证,失败集合单调增长
6→11→18→22(把一条本来空转的断言逼了出来)。
游标抬升:TC-NETSOCK-545→560、TC-SYSLOG-100→107、TC-CONLOG-135→167。
文档:控制台设计说明 §4.1 口径与 §13-O2 销项 + v1.5;运行与自检记录 §4.4/§4.5
四条;存储架构 §10.1 第 10 条推论(指向 s_is_selfheal_code);TRAP-NET-21 后续
条目;BSD 指南新增 §9.0 s_addr 唯一约定;覆盖率口径 §9「第 1 轮修复处置」表 +
后续项 5 条 + 台架复验 7 条 + 新坑 8 条 + 变更记录。
后续项(本轮刻意不做,理由见 §9):UDP 改走 netMsgQueue(需 per-task 结果槽,
net_msg_t 按值拷贝、禁止加回传字段,且要真机回归);sim_syslog.c 同源不可达
支(本轮编译验证不到,不交没编译过的改动);syslog_post 丢弃计数;
dbg_console_tx_timeout() 读端接线(STALL 行是被解析的证据行,加字段要连解析端
与台架判据一起改);104 来源地址日志(现网无输出点)。
gate: @build 0 errors 0 warnings(Code=213720 RO=18860 RW=1204 ZI=131500)。
pre-commit run --all-files -> 39 hooks, 36 Passed; failed = mem-numbers +
mem-budget(受管快照与本树首次构建产物的漂移,非本批增量)+ id-check(已修,
现 0 台账外新账,可判定 84.63% > 基线 82.6%)。实测水位 RW_IRAM1 57.4%、
RW_CCM 87.9%,均低于 92% 红线;RAM/Flash 本批增量为数个 static 变量。
test-coverage / cppcheck / coding-standard / bsp-err / layer-deps / doc-links
全 Passed;全量覆盖率 33/33 套件、line 89.3%、func 92.3%、逐文件下降 0。
按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
This commit is contained in:
@@ -545,6 +545,10 @@ static int cmd_pasv(lftpd_client_t *client, const char *arg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* s_addr 是网络序整数(本层唯一约定,见 net_inet_addr 的声明处),这里
|
||||
* 先转主机序再按高字节到低字节拆 = 线序顺位,PASV 227 的 IP 文本因此正确
|
||||
* (TRAP-NET-21 已定案"双重反转恰好正确,勿误判";2026-10-24 字节序统一后复核:
|
||||
* 本行不属于被统一掉的那一族,语义未变,勿"顺手改对"成直接拆 s_addr) */
|
||||
uint32_t ip = net_htonl(local_addr.sin_addr.s_addr);
|
||||
send_simple_response(client->socket, 227, STATUS_227,
|
||||
(ip >> 24) & 0xff,
|
||||
|
||||
@@ -78,6 +78,14 @@ static volatile uint32_t s_net_generation = 0; /* 网络代次号:网络
|
||||
*/
|
||||
static osMessageQueueId_t s_net_msg_queue;
|
||||
|
||||
/*
|
||||
* 本层执行任务句柄(= net_init 的调用者,NET 层为 netTask、硬件层为 testTask)
|
||||
* 与 net_pending_capture_owner() 同一时刻、同一语义捕获,判据也一致。
|
||||
* 用途见 net_ctx_is_owner_task():给"绕过消息队列直调芯片"的接口把危险面关掉。
|
||||
* 捕获前恒 NULL(net_init 未跑)——那时任何 socket 都不存在,判空放行即可。
|
||||
*/
|
||||
static TaskHandle_t s_net_owner_task;
|
||||
|
||||
/*
|
||||
* 函数功能:绑定消息队列句柄(本模块是该句柄的唯一使用者)
|
||||
* 入口参数:queue_id - 已创建的消息队列句柄
|
||||
@@ -87,6 +95,30 @@ static osMessageQueueId_t s_net_msg_queue;
|
||||
* 真出现两处绑定时,说明有人新加了调用点,此时保留先绑的那个并把后来者
|
||||
* 拒掉,比静默换句柄(已入队的请求会留在旧队列里永不处理)更容易暴露。
|
||||
*/
|
||||
/*
|
||||
* 函数功能:判当前上下文是否本层执行任务(netTask / 硬件层的 testTask)
|
||||
* 入口参数:无
|
||||
* 出口参数:无
|
||||
* 返回值:1 - 是本层执行任务(或未捕获,见下);0 - 明确不是(应拒绝直调芯片)
|
||||
* 限定条件:net_init 之后判据才有效
|
||||
* 函数说明:给 net_sendto / net_recvfrom 这类**绕过消息队列、在调用方上下文里
|
||||
* 直接 net_poll + 读写芯片缓冲**的接口把危险面结构性关掉:非执行任务
|
||||
* 调用会与本层的 net_poll 抢同一根 SPI2(TRAP-NET-14 的根因形态),
|
||||
* 而 SPI 事务没有跨任务互斥(ch395f_spi_begin/end 只是片选与分频)。
|
||||
* 刻意**不做**成"排队改写":recvfrom 要把源地址交回调用方,按 AGENTS
|
||||
* 不能塞进按值拷贝的 net_msg_t,真要串行化得设计 per-task 结果槽,
|
||||
* 那是需要真机回归的独立工程(2026-10-24 定案:本轮先把危险面关掉,串行化留后续)。
|
||||
* 未捕获(net_init 未跑)时返回 1:那时任何 socket 都不存在,
|
||||
* 调用只会先在参数检查上拿到 BADF,不构成绕过。
|
||||
*/
|
||||
static uint8_t net_ctx_is_owner_task(void) {
|
||||
if (s_net_owner_task == NULL) {
|
||||
return 1U;
|
||||
}
|
||||
/* 内核未启动/中断上下文里句柄为 NULL:与执行任务不等 → 判不是(不得碰 SPI) */
|
||||
return (xTaskGetCurrentTaskHandle() == s_net_owner_task) ? 1U : 0U;
|
||||
}
|
||||
|
||||
int net_msg_queue_adopt(osMessageQueueId_t queue_id) {
|
||||
if (queue_id == NULL) {
|
||||
return -1;
|
||||
@@ -253,6 +285,9 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
net_set_errno(NET_OK);
|
||||
s_net_initialized = 0;
|
||||
net_pending_capture_owner(); /* 执行任务 = net_init 调用者(NET 层 = netTask / 硬件层 = testTask) */
|
||||
/* 同一时刻捕获本层自己的执行任务句柄(net_ctx_is_owner_task 的判据;
|
||||
* 必须与上面同源,否则两张守卫会各认一个"谁是 netTask") */
|
||||
s_net_owner_task = xTaskGetCurrentTaskHandle();
|
||||
|
||||
/* 检查 CH395F 芯片 */
|
||||
if (ch395f_check_exist() != CH395F_STATUS_OK) {
|
||||
@@ -1561,14 +1596,16 @@ static int net_connect_locked(int sockfd, const struct net_sockaddr *addr, int a
|
||||
p_sock->remote_ip = p_addr_in->sin_addr.s_addr;
|
||||
p_sock->remote_port = net_ntohs(p_addr_in->sin_port);
|
||||
|
||||
/* 转换 IP 为数组格式(大端/网络字节序,与 ch395f set_des_ip 期望一致,
|
||||
* 同 Phase2 phase2_tc201 的 test_parse_ip 结果 [192,168,1,2]) */
|
||||
p_sock->remote_ip_arr[0] = (uint8_t)(p_sock->remote_ip >> 24);
|
||||
/* 最高字节 → [0](大端序) */
|
||||
p_sock->remote_ip_arr[1] = (uint8_t)(p_sock->remote_ip >> 16);
|
||||
p_sock->remote_ip_arr[2] = (uint8_t)(p_sock->remote_ip >> 8);
|
||||
/* 最低字节 → [3] */
|
||||
p_sock->remote_ip_arr[3] = (uint8_t)(p_sock->remote_ip);
|
||||
/* 转换 IP 为数组格式(芯片要的是**线序**数组:[0]=第一段,与 ch395f_set_des_ip
|
||||
* 期望一致,同 Phase2 phase2_tc201 的 test_parse_ip 结果 [192,168,1,2])。
|
||||
* s_addr 是网络序整数,其**内存字节顺位**就是线序(2026-10-24 定案:全仓 s_addr 只此一族),
|
||||
* 所以这里按字节顺位取、不做数值右移:旧写法 remote_ip_arr[0] = remote_ip >> 24
|
||||
* 取的是数值的最高字节,只配得上当时那套「第一段在最高字节」的 inet_addr;
|
||||
* inet_addr 已改成 POSIX 网络序后,右移写法会把地址拆成 [100,1,168,192] 反序,
|
||||
* 表现为「连谁都不知去哪了」。用 memcpy 取顺位与 net_events.c 填 remote_ip_arr
|
||||
* 的写法同一形制(那边一直就是线序顺位),两端不再各说一套。 */
|
||||
(void)memcpy(p_sock->remote_ip_arr, &p_sock->remote_ip,
|
||||
sizeof(p_sock->remote_ip_arr));
|
||||
|
||||
/* 配置 CH395F Socket:先 OPEN 再写源/目的端口(避免 open 复位寄存器) */
|
||||
/* 设置协议类型为 TCP */
|
||||
@@ -2429,27 +2466,34 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
return NET_ERR_RETURN_1(NET_ERR_BADF);
|
||||
}
|
||||
|
||||
/* 缓冲区无效 → INVAL */
|
||||
/* 缓冲区无效 → INVAL(本块必须留在守卫之前:参数错误先报参数错误) */
|
||||
if (buf == NULL || len <= 0) {
|
||||
return NET_ERR_RETURN_1(NET_ERR_INVAL);
|
||||
}
|
||||
|
||||
/* netTask 上下文守卫:本接口在本任务上下文里直接 net_poll + 读写芯片缓冲,
|
||||
* 非执行任务调用会与本层 net_poll 抢同一根 SPI2(TRAP-NET-14)。放在参数
|
||||
* 校验**之后**:越界/未在用/参数非法这些正常错误路径照旧先报,守卫不吞它们。
|
||||
* 判据与留痕见 net_ctx_is_owner_task()。 */
|
||||
if (net_ctx_is_owner_task() == 0U) {
|
||||
DBG_ERROR("sendto from non-exec task: refused (SPI race, use netTask)");
|
||||
return NET_ERR_RETURN_1(NET_ERR_NOT_IN_NETTASK);
|
||||
}
|
||||
|
||||
/* UDP 模式:设置目标地址 */
|
||||
if (dest_addr != NULL && addrlen >= (int)sizeof(struct net_sockaddr_in)) {
|
||||
/* 强转为 IPv4 地址结构体 */
|
||||
p_addr_in = (const struct net_sockaddr_in *)dest_addr;
|
||||
|
||||
/* 转换 IP 为大端数组(同 TCP 客户端,set_des_ip 期望大端) */
|
||||
/* 大端 IP 数组 */
|
||||
/* 转换 IP 为线序数组(同 TCP 客户端:set_des_ip 要 [0]=第一段)。
|
||||
* s_addr 的内存字节顺位即线序(2026-10-24 定案:全仓 s_addr 只此一族),按顺位取,
|
||||
* 不再按数值右移取最高字节——理由与 net_connect_locked 内同一处相同 */
|
||||
/* 线序 IP 数组 */
|
||||
uint8_t ip_arr[4];
|
||||
/* 目的 IP(网络序 32 位) */
|
||||
uint32_t ip = p_addr_in->sin_addr.s_addr;
|
||||
/* 最高字节 → [0](大端序) */
|
||||
ip_arr[0] = (uint8_t)(ip >> 24);
|
||||
ip_arr[1] = (uint8_t)(ip >> 16);
|
||||
ip_arr[2] = (uint8_t)(ip >> 8);
|
||||
/* 最低字节 → [3] */
|
||||
ip_arr[3] = (uint8_t)(ip);
|
||||
/* 字节顺位拷贝:ip_arr[i] = s_addr 的第 i 个内存字节 */
|
||||
(void)memcpy(ip_arr, &ip, sizeof(ip_arr));
|
||||
|
||||
/* 设置目的 IP */
|
||||
ch395f_set_des_ip(sockfd, ip_arr);
|
||||
@@ -2557,6 +2601,13 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
return NET_ERR_RETURN_1(NET_ERR_INVAL);
|
||||
}
|
||||
|
||||
/* netTask 上下文守卫:本接口自旋 net_poll + 读芯片缓冲,同样只允许执行任务调;
|
||||
* 位置与 net_sendto 同一原则(参数校验之后、任何芯片事务之前) */
|
||||
if (net_ctx_is_owner_task() == 0U) {
|
||||
DBG_ERROR("recvfrom from non-exec task: refused (SPI race, use netTask)");
|
||||
return NET_ERR_RETURN_1(NET_ERR_NOT_IN_NETTASK);
|
||||
}
|
||||
|
||||
/* 轮询直到:有数据 / 非阻塞(阻塞 = 无限等待,无默认预算) */
|
||||
while (1) {
|
||||
/* 轮询一次:更新状态机与可读标志 */
|
||||
@@ -2586,7 +2637,10 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||
/* CH395F UDP 头 [0-1] 数据长度(LE) [2-3] src_port(LE) [4-7] src_ip(§9.2.4 表) */
|
||||
/* 源端口(小端 2 字节 → 主机序 → 网络序) */
|
||||
p_addr_in->sin_port = net_htons((uint16_t)(header[2] | (header[3] << 8)));
|
||||
/* 源 IP(小端 4 字节组装为网络序) */
|
||||
/* 源 IP:芯片给的是线序字节([4]=第一段),按"首段落在最低
|
||||
* 字节"组装即得网络序整数——与本层 s_addr 唯一约定同族
|
||||
* (2026-10-24 定案:全仓 s_addr 只此一族),所以这里**不能再加一次换端**。
|
||||
* 源 IP(小端 4 字节组装为网络序) */
|
||||
p_addr_in->sin_addr.s_addr = ((uint32_t)header[4]) |
|
||||
((uint32_t)header[5] << 8) |
|
||||
((uint32_t)header[6] << 16) |
|
||||
@@ -2819,11 +2873,20 @@ int net_sock_state(int sockfd) {
|
||||
* 出口参数:无
|
||||
* 返回值:网络字节序的 32 位 IP 地址(0 表示参数无效) uint32_t
|
||||
* 限定条件:无
|
||||
* 函数说明:1. 逐段解析十进制数与并小端组装为 32 位值
|
||||
* 2. 转换结果经 NET_HTONL 转为网络字节序
|
||||
* 函数说明:1. 逐段解析并按「第一段在主机序最高字节」累加,再经 NET_HTONL 转网络序,
|
||||
* 使结果满足 POSIX in_addr_t 的不变量:&s_addr 的第 0 个字节 == 点分第一段。
|
||||
* 本文件内 s_addr 只有这一族(2026-10-24:两套 IP 字节序约定统一为 POSIX 网络序):net_inet_ntoa 的
|
||||
* 「先 NTOHL、再高段在前」正是本函数的解析逆运算;net_getsockname、
|
||||
* net_getpeername、net_recvfrom 填的 s_addr 也同族,故三者可直接相等比较。
|
||||
* 2. 小端主机(STM32F407 与 PC 模拟器均是)上 "192.168.1.100" 的数值为
|
||||
* 0x6401A8C0(内存字节 C0 A8 01 64)。旧实现在小端累加后又多做一次
|
||||
* HTONL,得到 0xC0A80164,与 ntoa 不互逆——那是同一文件里的第二套约定,
|
||||
* 已连同其消费者(connect/sendto 的 des_ip 拆装)一起改为本族。
|
||||
* 3. 段值超过 255 时按低 8 位截断(旧实现会把溢出位溅进相邻段,更不可预期);
|
||||
* 非法字符仍按 0 处理,失败返回值维持 0,不改 NET_INADDR_NONE 的语义。
|
||||
*/
|
||||
uint32_t net_inet_addr(const char *cp) {
|
||||
/* 组装出的 32 位地址(主机序,末转网络序) */
|
||||
/* 主机序累加值(第一段最终落在最高字节) */
|
||||
uint32_t addr = 0;
|
||||
/* 段循环索引 */
|
||||
int i;
|
||||
@@ -2842,15 +2905,15 @@ uint32_t net_inet_addr(const char *cp) {
|
||||
val = val * 10 + (*cp - '0');
|
||||
cp++;
|
||||
}
|
||||
/* 本段放入对应字节位(段 0 = 最低字节,小端组装) */
|
||||
addr |= (val << (i * 8));
|
||||
/* 高位先入:第 0 段左移三次后落在最高字节 */
|
||||
addr = (addr << 8) | (val & 0xFFU);
|
||||
/* 跳过分隔符点(末段可无点) */
|
||||
if (*cp == '.') {
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 转网络字节序后返回 */
|
||||
/* 转网络字节序后返回(此时最低地址字节 = 第一段) */
|
||||
return NET_HTONL(addr);
|
||||
}
|
||||
|
||||
@@ -2863,8 +2926,15 @@ uint32_t net_inet_addr(const char *cp) {
|
||||
* 限定条件:buf 非空且长度足够(>= 16 字节)
|
||||
* 函数说明:1. 先经 NET_NTOHL 转为主机字节序再格式化输出
|
||||
* 2. ⚠ 段序(E13 定案 修复):NTOHL 后主机序数值的高字节才是
|
||||
* 点分第一段(192.168.1.100 → 0xC0A80164 → "192.168.1.100")。
|
||||
* 原实现低段在前,显示成字节反转的 "100.1.168.192"
|
||||
* 点分第一段。**入参必须是网络序整数**(&addr 的第 0 字节 = 第一段,
|
||||
* 小端上 192.168.1.100 = 0x6401A8C0,见 net_inet_addr 的约定说明),
|
||||
* 于是 0x6401A8C0 → NTOHL → 0xC0A80164 → 高字节 0xC0 = 192 首段 ✓。
|
||||
* 原实现低段在前,同一入参会显示成字节反转的 "100.1.168.192"。
|
||||
* 3. ⚠ 本注释旧版举的例子写成「192.168.1.100 → 0xC0A80164 → 同串」,
|
||||
* 那个 0xC0A80164 取的是**已废弃的另一族**(当时 net_inet_addr 的返回
|
||||
* 值),按本函数的真实算法它打印出来恰是 "100.1.168.192"。两套 s_addr
|
||||
* 约定能在同一文件里长期共存而不被发现,源头就是这行错例(2026-10-24
|
||||
* 2026-10-24 修正;函数行为未变,只把例子改对)
|
||||
*/
|
||||
char *net_inet_ntoa(uint32_t addr, char *buf) {
|
||||
/* 网络序 → 主机序 */
|
||||
@@ -3076,7 +3146,9 @@ int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||
p_addr_in->sin_family = NET_AF_INET;
|
||||
/* 本地端口(主机序 → 网络序) */
|
||||
p_addr_in->sin_port = net_htons(p_sock->local_port);
|
||||
/* 本地 IP:由 s_local_ip 数组小端组装为 32 位网络序值 */
|
||||
/* 本地 IP:s_local_ip[] 是线序数组([0]=第一段),按"首段落在最低字节"
|
||||
* 组装即得网络序整数 —— 与 net_inet_addr / net_inet_ntoa 同族(2026-10-24 定案),
|
||||
* 故 getsockname 的结果可直接与 inet_addr 的返回值相等比较 */
|
||||
p_addr_in->sin_addr.s_addr = ((uint32_t)s_local_ip[0]) |
|
||||
((uint32_t)s_local_ip[1] << 8) |
|
||||
((uint32_t)s_local_ip[2] << 16) |
|
||||
|
||||
@@ -324,6 +324,8 @@ int net_setblocking(int sockfd, int on);
|
||||
* 3. 用本接口把等待切成 ≤timeout_ms 的片,调用方自行累计总预算:总超时语义不变、单次占用有界
|
||||
* 4. 超时用独立返回码 -2(而非靠 errno 区分)→ 无跨任务 errno 竞态
|
||||
* 5. ⚠ IWDG required_mask 内任务必须走本接口或 net_select(见 net_recv 契约)
|
||||
* 6. 本接口**走消息队列**、任意任务可调用(与 net_recv 同一条路径),
|
||||
* 与 net_recvfrom(仅限执行任务、直调芯片)不是一回事,勿混
|
||||
*/
|
||||
int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms);
|
||||
|
||||
@@ -335,9 +337,26 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms);
|
||||
* flags - 通常为 0
|
||||
* dest_addr - 目标地址
|
||||
* addrlen - 地址长度
|
||||
* 返回值:实际发送字节数,失败返回 -1
|
||||
* 限定条件:socket 已创建,指针非空
|
||||
* 函数说明:设置目标地址后调用 CH395F 发送
|
||||
* 返回值:实际发送字节数 int > 0
|
||||
* -1 失败,精确码经本任务错误码槽给出(net_get_errno()):
|
||||
* NET_ERR_BADF / NET_ERR_INVAL / NET_ERR_TIMEDOUT /
|
||||
* NET_ERR_NOT_IN_NETTASK(调用上下文不对,见「限定条件」)
|
||||
* 限定条件:**仅限本层执行任务(net_init 的调用者,NET 层 = netTask)调用**;
|
||||
* socket 已创建且为 DGRAM;指针非空
|
||||
* 函数说明:1. 设置目标地址后调用 CH395F 发送
|
||||
* 2. ⚠ 本接口**不走消息队列**:它在调用方上下文里直接 net_poll +
|
||||
* 写芯片缓冲,与 net_send/net_recv/net_connect 那一族(入队交 netTask
|
||||
* 串行执行)不是同一条路径。别的任务调用它 = 与本层的 net_poll 抢
|
||||
* 同一根 SPI2(TRAP-NET-14 的根因形态),故加上下文守卫直接拒掉,
|
||||
* 回 NET_ERR_NOT_IN_NETTASK。**该码重试永远无意义**(既非忙也非超时):
|
||||
* 要么把调用挪进执行任务,要么改用走队列的 net_send——没有第三条。
|
||||
* 3. 「把它改成走消息队列」是已知后续项,未做的原因:UDP 的目的地址
|
||||
* 与源地址回传都要穿过 net_msg_t,而 net_msg_t 按值拷入队列、
|
||||
* 错误码只搭任务通知值回来(AGENTS 明文「勿给 net_msg_t 加回传字段」),
|
||||
* 真要串行化得先设计 per-task 结果槽并配真机回归(2026-10-24 定案:
|
||||
* 本轮只把危险面关掉,串行化仍未做)。
|
||||
* 4. 全仓当前**无生产调用者**(只有 test/board 与模拟器),正因如此
|
||||
* 这条守卫要在有人开始用之前就在。
|
||||
*/
|
||||
int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
const struct net_sockaddr *dest_addr, int addrlen);
|
||||
@@ -350,8 +369,12 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||
* flags - 通常为 0;NET_MSG_DONTWAIT 单次强制非阻塞
|
||||
* src_addr - 输出:发送方地址
|
||||
* addrlen - 输入输出:地址长度
|
||||
* 返回值:实际接收字节数,失败返回 -1
|
||||
* 限定条件:socket 已创建,指针非空
|
||||
* 返回值:实际接收字节数(0 = 无数据可报的边界形态见说明) int >= 0
|
||||
* -1 失败,精确码经本任务错误码槽给出(net_get_errno()):
|
||||
* NET_ERR_BADF / NET_ERR_INVAL / NET_ERR_WOULDBLOCK /
|
||||
* NET_ERR_NOT_IN_NETTASK(调用上下文不对,见「限定条件」)
|
||||
* 限定条件:**仅限本层执行任务(net_init 的调用者,NET 层 = netTask)调用**;
|
||||
* socket 已创建且为 DGRAM;指针非空
|
||||
* 函数说明:1. 读取 CH395F 接收缓冲区,获取对端地址
|
||||
* 2. 阻塞语义与 net_recv 同:blocking 属性下无数据
|
||||
* 无限等待,DONTWAIT / 非阻塞属性立即 NET_ERR_WOULDBLOCK;
|
||||
@@ -438,6 +461,16 @@ int net_sock_state(int sockfd);
|
||||
* 返回值:网络字节序 IP,失败返回 0
|
||||
* 限定条件:cp 指针非空
|
||||
* 函数说明:不支持域名解析
|
||||
*
|
||||
* s_addr 的**唯一约定**(2026-10-24 定案:两套 IP 字节序约定统一为 POSIX 网络序;全仓只此一族,勿再引入第二套):
|
||||
* 网络字节序整数 —— &s_addr 的第 0 个内存字节 == 点分第一段。
|
||||
* 小端主机(STM32F407 与 PC 模拟器都是)上 "192.168.1.100" 的数值 = 0x6401A8C0。
|
||||
* 与 net_inet_ntoa 互为逆运算;net_getsockname / net_getpeername / net_recvfrom
|
||||
* 填出来的 s_addr、以及 net_bind / net_connect / net_sendto 收进去的 s_addr
|
||||
* 全在同一族,故可直接做相等比较(旧实现里 inet_addr 与其余四个不互逆,
|
||||
* 曾造成「解析→存储→打印」链路输出反序 IP,见 TRAP-NET-21 与本函数实现注释)。
|
||||
* 另:本层 inet_addr 语义与 BSD 一致——失败回 0,故 "0.0.0.0" 与非法串同值;
|
||||
* 需要区分时用 net_inet_addr 的返回值再判,勿拿 NET_INADDR_NONE 当失败哨兵。
|
||||
*/
|
||||
uint32_t net_inet_addr(const char *cp);
|
||||
|
||||
|
||||
@@ -108,6 +108,15 @@ struct net_sockaddr_in {
|
||||
#define NET_ERR_TIMEDOUT -9 /* 操作超时 */
|
||||
#define NET_ERR_NOSPACE -10 /* 发送缓冲区无空间 */
|
||||
#define NET_ERR_BUSY -11 /* 操作未完成(CH395F BUSY) */
|
||||
/*
|
||||
* 调用方**上下文**不对(不是运行时故障):该接口只允许在 net_init 的执行任务
|
||||
* (NET 层 = netTask / 硬件层 = testTask)里调用,其它任务调用会与本层 net_poll
|
||||
* 抢同一根 SPI(TRAP-NET-14)。与上面各码的区别:BUSY/TIMEDOUT/NOSPACE 换个时刻
|
||||
* 重试有意义,本码**重试永远无意义**——要么改到执行任务里调,要么把动作交回
|
||||
* 消息队列(netMsgQueue),没有第三种。所以它不参与任何"可重试"判定,
|
||||
* 上层见到它应当直接当编程错误处理(详见 net_socket.h net_sendto/net_recvfrom)。
|
||||
*/
|
||||
#define NET_ERR_NOT_IN_NETTASK -12 /* 非执行任务上下文调用(重试无用) */
|
||||
|
||||
/*
|
||||
* Socket 状态枚举(**本层会话投影**,非芯片状态事实源)
|
||||
|
||||
Reference in New Issue
Block a user