fff961d803
前置来自 #57 SNTP 调研:旧 net_sendto / net_recvfrom 由调用方直调 SPI 且无限自旋收包,既违约「netTask 是芯片唯一访问者」,又把 IWDG 预算吃在自旋里。 改造面 - 新增 Drivers/BSP/NET/net_udp.c/.h(真机专属,模拟器不编译): bind/set_peer/sendto/recvfrom 四条执行体 + 挂起收包表 + tick; net_msg_type_t 加四型,公开 API 一律「入队 → 睡在通知上」。 - 源地址出参不搭 net_msg_t(按值拷贝,AGENTS 禁加回传字段):改住 net_udp.c 的 per-fd 槽,netTask 就地写回调用方内存,通知值只带 结果码;每条出口都清槽,泄漏 = 该 fd 永久 BUSY。 - 发送复用 net_send_locked,不写第二份分块逻辑;「会话是否已死」 收成一条判据 net_send_state_down()(TCP 看 ESTABLISHED、UDP 看 UDP_OPEN),原先 4 处各写一遍。 - 顺带修掉真缺陷(新条 TRAP-NET-22):旧 sendto 把 DesIP 写成具体 IP,芯片静默切 UDP Client,而旧 recvfrom 无条件剥 8 字节 → SNTP 这类 48 B 应答丢载荷前 8 字节并交出垃圾源地址。加 udp_mode(塞进 原有 padding,sizeof 不变)、bind 恒 SERVER、显式对端 sendto 切 CLIENT、set_peer(fd, NULL) 轻量回 SERVER,仅 SERVER 且 avail >= 8 才剥头。 - 截断定案:一次调用交付一个数据报,buf 装不下的尾巴用 64 B 栈上 scratch 排空(不用 clear_recv_buf——它连后面已到达的包一起丢)。 - 取消点接齐:net_init 重建 cancel_all、net_socket 分配 fd clear、 net_close settle_close + clear、重 bind 前先结算等包者, net_process_messages 第 5 个 tick 位挂 net_udp_tick。 - 收紧两处契约(原实现无生产调用者):UDP 未 bind 一律 -5; net_recv / _nb / _to 拒 DGRAM(绕过剥头就是静默吃 8 字节); NET_ERR_NOT_IN_NETTASK(-12) 退役为历史常量并写明原因。 验证 - 主机单测 test/host/net_socket 全套 616/616 绿(改造前 470):新 分片 ns_s7_udp.c 20 组,改写 440 / 555 / 560 组;覆盖率 net_udp.c 234/236(99.2%)、net_socket.c 956/969(98.7%), scripts/test_coverage_baseline.json 随本提交登记新文件。 - 测试抓到 4 个被测码真 bug:自等守卫误用调用侧谓词、芯片长度被读 两次、槽指针取在 fd 合法性检查之前、重 bind 静默作废等待者。 - Keil ARMCC 0 Error(s) 0 Warning(s);net_udp.o Code 1,358 / ZI 224 (8 fd × 28 B,其余模块零增长),全仓 RW_IRAM1 72.2%;内存台账 受管区按门禁提示用 --write / --update 机器回填,未手改数字。 - pre-commit 全量钩子(含 doc-links、coding-standard、mem-budget、 generated-fresh、bsp-err、registration、nested-comment)全绿。 限度 - 本轮无板子:真机回归 5 条(两端互通、set_peer(NULL) 能否恢复收 广播、截断排空后下一包完整性、挂起 recv 期间 IWDG 余量、bind 写 DesIP 与 open 先后的真芯片效果)已写进覆盖率口径「台架必验」。 - scripts/stack_report.py 退出码 1 是 10-26 起挂在账上的 iec104Task 栈债(margin 1,016 < 1,024,见 docs/代码规范/pre-commit使用说明.md: 122);本轮只让 net_bind 的 UDP 分支多一层静态帧(1,544 → 1,600), netTask margin 1,888 与 timeSyncTask 1,152 不受影响。抬栈要过 mem-budget 台账,不在本分支自行处理。 - 登记簿销项按仓库约定留给主工作树,本分支不动 docs/任务规划/**。
775 lines
42 KiB
C
775 lines
42 KiB
C
/*
|
||
* 模块名称:Network Socket API
|
||
* 模块功能:BSD Socket API 兼容接口,提供 TCP/UDP 网络通信功能,
|
||
* 底层基于 CH395F 以太网协议栈芯片
|
||
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-07-18
|
||
* 修改记录:
|
||
*/
|
||
|
||
#ifndef NET_SOCKET_H
|
||
#define NET_SOCKET_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include "net_types.h"
|
||
|
||
/*
|
||
* OS 相关接口(FreeRTOS 消息队列 / 任务句柄 / netTask 内部 API)仅在启用
|
||
* RTOS 的构建(MCU)编译;纯 PC 模拟器定义 NET_NO_OS 后只保留 BSD Socket 核心 API。
|
||
*/
|
||
#ifndef NET_NO_OS
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "cmsis_os2.h" /* osMessageQueueId_t:net_msg_queue_adopt() 的参数类型 */
|
||
#endif /* NET_NO_OS */
|
||
|
||
#ifndef NET_NO_OS
|
||
/*
|
||
* 消息队列类型定义
|
||
*/
|
||
typedef enum {
|
||
NET_MSG_SEND,
|
||
NET_MSG_RECV,
|
||
NET_MSG_CLOSE,
|
||
NET_MSG_CONNECT,
|
||
NET_MSG_LISTEN,
|
||
NET_MSG_ACCEPT,
|
||
NET_MSG_DROP_CONN, /* 主动拆会话、保监听(见 net_drop_conn) */
|
||
/* UDP 队列化改造(2026-11-03,工单前置 = SNTP 客户端 #57):UDP 三个碰芯片的
|
||
* 动作从"调用方上下文直调 SPI"改为交 netTask 串行执行,字段用法:
|
||
* NET_MSG_UDP_BIND - sockfd + len=本地端口(主机序,0 = 执行体内取动态号)
|
||
* 恒 DesIP=0xFFFFFFFF 服务器模式(bind 不选对端,
|
||
* 客户端模式见 NET_MSG_UDP_PEER / SENDTO 的 addr)
|
||
* NET_MSG_UDP_SENDTO - buf/len=载荷 + addr=本包目的地址(按值拷入,**入参**方向)
|
||
* NET_MSG_UDP_RECVFROM - buf/len=载荷 + timeout_ms=等待预算 + flags
|
||
* ⚠ 源地址出参(src_addr / addrlen 两个指针)**不走本结构**:结构按值拷入
|
||
* 队列,指针若在 int 字段里过桥,64 位主机单测构建会被截断,且违反
|
||
* AGENTS「勿给 net_msg_t 加回传用字段」。改走 net_udp.c 的 per-fd 挂起槽
|
||
* (调用方在入队前登记自己的指针,netTask 完成后写进调用方内存 + 通知值回码),
|
||
* 与 TCP 挂起 recv 把数据直接写进调用方 buf 是同一个模型。
|
||
* 详见 docs/网络/BSD_Socket_API_使用指南.md §6 */
|
||
NET_MSG_UDP_BIND,
|
||
NET_MSG_UDP_SENDTO,
|
||
NET_MSG_UDP_RECVFROM,
|
||
/* 静默回收认领 + 手动自愈 API 退役(docs/网络/网络自愈架构设计.md §4.1、§4.2):
|
||
* NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN 已删——
|
||
* 静默回收由对账⑤自动认领(net_reconcile_tick),重建由 reconciler
|
||
* 形态③④/D10 单一
|
||
* 所有者负责;手动自愈 API 面退役(生产调用者本就为零) */
|
||
/* UDP 模式切换(追加在枚举末尾:既有成员编号是主机单测/板测的钉值对象,
|
||
* 不在中间插入)——addr 按值携带对端则切客户端模式,addrlen == 0 则回
|
||
* 服务器模式;不重开 Socket,只写 DesIP/DesPort,语义见 net_udp_set_peer */
|
||
NET_MSG_UDP_PEER
|
||
} net_msg_type_t;
|
||
|
||
typedef struct {
|
||
net_msg_type_t type; /* 操作类型 */
|
||
int sockfd; /* Socket 描述符 */
|
||
void *buf; /* 数据缓冲区(send/recv) */
|
||
int len; /* 数据长度/缓冲区大小 */
|
||
int flags; /* 接收标志 */
|
||
uint32_t timeout_ms; /* 接收超时(入队方向;0 = 无限等待,无默认预算——
|
||
* NET_RECV_TIMEOUT_MS 30s 默认已删除) */
|
||
TaskHandle_t caller; /* 调用方任务句柄 */
|
||
int result; /* 操作结果 */
|
||
/* 连接参数 */
|
||
struct net_sockaddr_in addr; /* 连接地址 */
|
||
int addrlen; /* 地址长度 */
|
||
} net_msg_t;
|
||
#endif /* NET_NO_OS */
|
||
|
||
#ifndef NET_NO_OS
|
||
/*
|
||
* 函数功能:把消息队列句柄交给本模块持有(**句柄的唯一使用者是 net_socket.c**)
|
||
* 入口参数:queue_id - 已创建的消息队列句柄
|
||
* 返回值:0 = 绑定成功;-1 = 句柄为空、或已绑定过(重复绑定保留首次句柄,不覆盖)
|
||
* 限定条件:必须在 osKernelInitialize() 之后、netTask 启动之前调用一次
|
||
* 函数说明:队列对象本身仍由 CubeMX 在 MX_FREERTOS_Init() 里创建——创建点不能外移,
|
||
* 因为 osKernelInitialize() 之前任何创建类 API 都会杀死启动
|
||
* (docs/架构设计/项目启动顺序管理.md)。外移创建点还会让重新生成把它抹掉。
|
||
* 所以这里用"创建后立刻绑定":调用点见 Src/freertos.c 的
|
||
* USER CODE BEGIN RTOS_QUEUES 区。此前本模块靠对本文件外全局变量的
|
||
* 裸 extern 取用,谁改名或删掉创建语句都不会有提示。
|
||
*/
|
||
int net_msg_queue_adopt(osMessageQueueId_t queue_id);
|
||
#endif /* NET_NO_OS */
|
||
|
||
|
||
/*
|
||
* 网络初始化接口
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式)
|
||
* 入口参数:ip - 本地 IP 地址字符串(点分十进制),NULL 使用 DHCP
|
||
* mask - 子网掩码字符串,NULL 使用默认
|
||
* gateway - 网关地址字符串,NULL 使用默认
|
||
* mac - MAC 地址(6 字节,低字节在前),NULL 或全零使用芯片内置
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:SPI2 已正确初始化
|
||
* 函数说明:必须在所有网络操作之前调用;mac 非空且非全零时在协议栈初始化
|
||
* (CMD_INIT_CH395)之前下发(手册 §9.2.1 步骤①:SET_MAC 写芯片 EEPROM,
|
||
* INIT_CH395 加载 MAC——顺序反了则本次上电不生效,回落芯片内置/上次值)
|
||
*/
|
||
int net_init(const char *ip, const char *mask, const char *gateway, const uint8_t *mac);
|
||
|
||
/*
|
||
* 函数功能:取网络代次号
|
||
* 入口参数:无
|
||
* 返回值:代次号(每次网络重建完成递增) uint32_t
|
||
* 限定条件:无
|
||
* 函数说明:TCP 服务(FTP / 对时 / 远程显示)据此感知"网络已重建"——代次变化
|
||
* 表示旧 Socket 已随芯片复位失效,服务应放弃旧监听并重建。
|
||
* 递增点在 net_stack_bring_up() 末尾(PHY/链路就绪后),避免服务在网络
|
||
* 尚未可用时抢先重建、也避免 uiTask 阻塞在消息队列上。
|
||
*/
|
||
uint32_t net_get_generation(void);
|
||
|
||
/*
|
||
* 函数功能:递增网络代次号(网络重建完成、对外可用时调用)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:net_init() 成功且 PHY/链路就绪后调用(当前仅 net_stack_bring_up)
|
||
* 函数说明:见 net_get_generation()
|
||
*/
|
||
void net_generation_inc(void);
|
||
|
||
/*
|
||
* 函数功能:轮询所有 Socket 状态(必须在主循环中调用)
|
||
* 返回值:有事件发生的 socket 数量
|
||
* 限定条件:net_init() 已调用
|
||
* 函数说明:此函数处理所有 Socket 的中断事件,更新状态,
|
||
* 并触发事件回调。在非阻塞模式下必须定期调用。
|
||
*/
|
||
int net_poll(void);
|
||
|
||
/*
|
||
* 核心 Socket API
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:创建 socket
|
||
* 入口参数:domain - 地址族,仅支持 AF_INET
|
||
* type - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP)
|
||
* 返回值:socket 描述符 (0~7),失败返回 -1
|
||
* 限定条件:net_init() 已调用
|
||
* 函数说明:自动分配空闲 Socket 控制块
|
||
*/
|
||
int net_socket(int domain, int type);
|
||
|
||
/*
|
||
* 函数功能:绑定本地地址和端口
|
||
* 入口参数:sockfd - socket 描述符
|
||
* addr - 本地地址结构体指针
|
||
* addrlen - 地址结构体长度
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已创建且未绑定
|
||
* 函数说明:设置 CH395F 源端口
|
||
*/
|
||
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||
|
||
/*
|
||
* 函数功能:TCP Server 监听
|
||
* 入口参数:sockfd - socket 描述符
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已绑定
|
||
* 函数说明:内部调用 ch395f_tcp_listen,监听 Socket 自身即为数据通道
|
||
*/
|
||
int net_listen(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:TCP Server 接受连接
|
||
* 入口参数:sockfd - 监听 socket 描述符
|
||
* addr - 输出:客户端地址
|
||
* addrlen - 输入输出:地址长度
|
||
* 返回值:新 socket 描述符,失败返回 -1
|
||
* 限定条件:socket 正在监听
|
||
* 函数说明:在非阻塞模式下,如果没有新连接,返回 -1 并设置
|
||
* net_errno 为 NET_ERR_WOULDBLOCK
|
||
*/
|
||
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||
|
||
/* accept 门控迁移(docs/网络/网络自愈架构设计.md §4.2):net_can_accept 已退役——只认 ESTABLISHED 的旧门控会把
|
||
* "监听器在服役、本轮待 CONNECT"窗口全挡掉(CONNECT 事件补 accept 探针因此从不运行);
|
||
* 监听 accept 门控统一用 net_listener_armed(),recv 门控 net_can_read() 保留。 */
|
||
|
||
/*
|
||
* 函数功能:查询监听 Socket 是否处于"应该尝试 accept"的就绪态(**纯 RAM 读,不发起 RPC**)
|
||
* 入口参数:sockfd - 监听 Socket 描述符 int
|
||
* 出口参数:无
|
||
* 返回值:1 - 就绪(ESTABLISHED 待 accept / LISTENING / CLOSED+auto_relisten
|
||
* +残留数据);0 - 不就绪 int
|
||
* 限定条件:net_init() 已调用;任意任务上下文
|
||
* 函数说明:1. 不变量 II(单一重建所有者;补齐 ESTABLISHED 放行):取代已退役的
|
||
* `net_can_accept()`(只认 ESTABLISHED)作为监听 accept 门控——原门控使
|
||
* :7003 永不进 `net_accept()`,
|
||
* `net_lost_connect_probe`(CONNECT 事件未收到补 accept,TRAP-NET-20 实证的
|
||
* "数据被吞/425"主根因修复)对该端口等于从未运行
|
||
* 2. 放行 LISTENING:探针与 "closed-but-readable 接受" 都发生在
|
||
* `net_accept_locked` **内部**,门控挡在外面就永远到不了
|
||
* 2b. 放行 ESTABLISHED(i104 台架实证):单连接模型下 CONNECT 处理
|
||
* (net_poll 分派 / 探针补 accept / 对账② standalone accept)把监听 fd
|
||
* 转 ESTABLISHED,这正是"待 accept"电平——漏放行则任务周期慢的消费者
|
||
* (i104 200ms 抢不过对账② ~400ms 去抖)永不 accept、会话整场饿死
|
||
* (实测全 18 项 FAIL)。此态 accept 必返 fd,无风暴风险
|
||
* 3. 放行 CLOSED+auto_relisten **且 readable≠0**(有残留数据):
|
||
* 保住 TRAP-NET-20 的 "closed-but-readable" 接受;**无残留时必须返回 0**,
|
||
* 否则调用方会在整个 CLOSED 窗口内每轮发起 `net_accept`(RPC 无上界)
|
||
* → 队列积压 → 喂不上狗(2026-10-12 P2a 台架实测 48 条 task stall)。
|
||
* 重建由 `net_reconcile_tick` 形态③④ 负责,调用方无需催促
|
||
* 4. 与已退役 `net_can_accept` 的关系:本函数 = 其 ESTABLISHED 放行态
|
||
* ∪ LISTENING ∪ CLOSED+残留;回答"这个监听器这一轮**值不值得**发起
|
||
* 一次 accept",而非"一定有连接"
|
||
* 5. 跨任务读单字,同 `net_can_read` 的最坏情形论证
|
||
*/
|
||
int net_listener_armed(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:查询 Socket 是否"值得发一次 recv"(**纯 RAM 读,不发起 RPC**)
|
||
* 入口参数:sockfd - Socket 描述符 int
|
||
* 出口参数:无
|
||
* 返回值:1 - 应发 recv(有数据可读,或连接已非 ESTABLISHED 需发 recv 取回 EOF/错误);0 - 不必发 int
|
||
* 限定条件:net_init() 已调用;任意任务上下文
|
||
* 函数说明:1. ESTABLISHED → 看 readable(net_poll 在 RECV_OK 置位、读空清零)
|
||
* 2. **非 ESTABLISHED 一律返回 1**:连接已消失时必须让上层真的 recv 一次
|
||
* 拿到 EOF/错误并自行复位;若把它门掉,"连接已不存在"会被永久藏住
|
||
* (推流侧 g_client 永不复位 → 再也不接受新客户端)
|
||
* 3. 描述符失效(net_get_sock 返回 NULL)同样返回 1 → 让 recv 报 BADF,
|
||
* 走调用方既有的错误分支重建,而不是静默卡死
|
||
* 4. ⚠ **不可作为唯一判据**:readable 只由 RECV_OK 中断置位,而
|
||
* net_reconcile_tick 的三类对账**不含**"芯片 RX 非空但 readable=0"
|
||
* → 事件未收到时本函数会恒返 0。调用方须保留**低频兜底 recv**
|
||
* (ui_net_sink 每 32 轮无条件收一次,最坏延迟 ≈320 ms)
|
||
*/
|
||
int net_can_read(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:TCP Client 发起连接
|
||
* 入口参数:sockfd - socket 描述符
|
||
* addr - 服务器地址
|
||
* addrlen - 地址长度
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已创建
|
||
* 函数说明:连接过程是异步的,需要调用 net_poll() 等待连接完成,
|
||
* 或使用 select() 等待可写事件
|
||
*/
|
||
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||
|
||
/*
|
||
* 函数功能:发送数据(TCP)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf - 数据缓冲区
|
||
* len - 数据长度
|
||
* flags - 通常为 0
|
||
* 返回值:实际写入字节数——**= len 为全部写入;< len 为短写,调用方必须检查**;
|
||
* 失败返回 -1(errno 已置位)
|
||
* 限定条件:TCP 连接已建立,指针非空
|
||
* 函数说明:1. 快路径:短暂自旋等待发送缓冲区空闲(预算 NET_SEND_SPIN_MS,默认 2ms),
|
||
* 拷贝数据后触发发送——健康链路下(实测 219us 量级)行为与旧版逐字节一致
|
||
* 2. 慢路径:自旋超预算后把请求**挂起登记**给 netTask,由
|
||
* net_send_pending_tick 在发送缓冲区空闲时续传(分片 NET_SEND_CHUNK_MAX),
|
||
* 调用方在任务通知上睡眠——**不再占用 netTask 执行者**(消除队头阻塞)
|
||
* 3. 短写语义:无论快路径超时还是挂起完成,只要存在未写完字节即按已发数返回,
|
||
* 不假装全部成功;调用方按短写重试剩余部分(见 BSD_Socket_API 使用指南 §3.5)
|
||
* 4. ⚠ 禁止在 IWDG required_mask 内任务做**无预算**的整块发送;挂起路径本身
|
||
* 受 NET_SEND_TIMEOUT_MS 无进展超时兜底,但仍建议调用方自带超时预算
|
||
*/
|
||
int net_send(int sockfd, const void *buf, int len, int flags);
|
||
|
||
/*
|
||
* 函数功能:接收数据(TCP,**默认无限阻塞**)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf - 接收缓冲区
|
||
* len - 缓冲区大小
|
||
* flags - 通常为 0;NET_MSG_DONTWAIT 单次强制非阻塞
|
||
* 返回值:实际接收字节数,0=对端关闭,-1=错误
|
||
* 限定条件:TCP 连接已建立
|
||
* 函数说明:1. 无数据时**无限等待**(无默认超时预算,对齐 POSIX/Python:模式归
|
||
* 使用者、超时归调用方);唤醒源 = 数据 / EOF / close / 网络重建
|
||
* (NET_ERR_CONNRESET)——会话死亡由对账①在 ~400ms 内判死兜底,
|
||
* 不存在"对端消失后永久挂死"的窗口
|
||
* 2. 模式属性:net_setblocking(fd, 0) 后本接口无数据立即返回
|
||
* NET_ERR_WOULDBLOCK;NET_MSG_DONTWAIT 仅单次覆盖该属性
|
||
* 3. ⚠ 文档契约(嵌入式特有):IWDG required_mask 内任务**禁止无限
|
||
* 阻塞 recv**——必须 net_select 超时或 net_recv_to 显式预算,
|
||
* 否则"对端连上不发数据"= IWDG 复位(超时归使用者对受监控任务是义务)
|
||
* 4. 超时首选 net_select(r,w,e,timeout_ms);net_recv_to 为显式预算便捷入口
|
||
*/
|
||
int net_recv(int sockfd, void *buf, int len, int flags);
|
||
|
||
/*
|
||
* 函数功能:接收数据(非阻塞具名入口,原 NET_MSG_DONTWAIT 路径转正)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf - 接收缓冲区
|
||
* len - 缓冲区大小
|
||
* 返回值:实际接收字节数;0 = 对端关闭(net 层已自动重监听);
|
||
* -1 = 错误(无数据 = NET_ERR_WOULDBLOCK,其余 errno 可查)
|
||
* 限定条件:非 netTask 上下文(netTask 内用 net_recv_sock + DONTWAIT)
|
||
* 函数说明:等价 net_recv(sockfd, buf, len, NET_MSG_DONTWAIT);
|
||
* 不改变 socket 的 blocking 属性(模式用 net_setblocking 设置)
|
||
*/
|
||
int net_recv_nb(int sockfd, void *buf, int len);
|
||
|
||
/*
|
||
* 函数功能:设置 Socket 阻塞/非阻塞**模式属性**(对齐 BSD O_NONBLOCK / Python
|
||
* setblocking,模式挂 socket 控制块属性)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* on - 1 = 阻塞(net_socket 默认);0 = 非阻塞
|
||
* 返回值:0 成功;-1 失败(描述符无效/未占用)
|
||
* 限定条件:socket 已创建
|
||
* 函数说明:1. 属性对 net_recv / net_recv_sock 生效:非阻塞模式下无数据立即
|
||
* 返回 NET_ERR_WOULDBLOCK(EOF 判定语义不变:CLOSED/session_dead
|
||
* 无数据仍返回 0 并触发自动重监听)
|
||
* 2. 直写控制块单字节(先例 net_set_event_cb),任意上下文可调;
|
||
* 最坏一次在途 recv 用旧模式,无撕裂风险
|
||
* 3. 与超时预算正交:模式是粘滞属性,单次预算用 net_recv_to/net_select
|
||
*/
|
||
int net_setblocking(int sockfd, int on);
|
||
|
||
/*
|
||
* 函数功能:接收数据(**带调用方指定超时**的阻塞版,用于分片有界读)
|
||
* 入口参数:sockfd - Socket 描述符
|
||
* buf/len - 接收缓冲与容量
|
||
* timeout_ms - 单次调用在 netTask 内的最长等待(毫秒,>0)
|
||
* 返回值:>0 实际字节数;0 = 对端关闭(EOF);-1 = 真错误(errno 可查);**-2 = 超时无数据**
|
||
* 限定条件:非 netTask 上下文;Socket 已连接
|
||
* 函数说明:1. **显式预算**便捷入口(等价 Python settimeout,
|
||
* 不再有隐藏默认值):net_recv 的无限阻塞 + 本接口的显式预算构成
|
||
* 超时语义的全部来源;超时首选仍是 net_select
|
||
* 2. 修复配套:lftpd 等"等对端下一行/下一块数据"的调用方
|
||
* 若无限阻塞 recv,会把 netTask(全部 socket 操作的唯一执行者)长期占住
|
||
* 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);
|
||
|
||
/*
|
||
* 函数功能:发送 UDP 数据报(**走消息队列**,任意任务可调用)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf - 数据缓冲区
|
||
* len - 数据长度(>0)
|
||
* flags - 目前不使用,传 0(与 net_send 同)
|
||
* dest_addr - 本包目的地址;NULL = 沿用本 Socket 当前 DesIP
|
||
* addrlen - 地址长度(NULL 目的时传 0 即可)
|
||
* 返回值:实际发送字节数 int > 0
|
||
* -1 失败,精确码经本任务错误码槽给出(net_get_errno()):
|
||
* NET_ERR_BADF / NET_ERR_INVAL / NET_ERR_TIMEDOUT / NET_ERR_BUSY
|
||
* 限定条件:socket 已创建(DGRAM 用法须先 net_bind 或 net_udp_set_peer 打开芯片侧
|
||
* Socket);net_init() 已执行;**任意任务上下文**(含 netTask 自身,
|
||
* netTask 内直接执行不入队——自投递给自身 = 死锁)
|
||
* 函数说明:1. 目的地址是**入参**,按值拷进 net_msg_t.addr 随消息进 netTask,
|
||
* 与 net_connect 传地址同一条通道;结果(已发字节数/错误码)
|
||
* 搭任务通知值回来(AGENTS「勿给 net_msg_t 加回传字段」)。
|
||
* 2. 带显式目的地址 = 芯片 DesIP 切到该 IP → 本 Socket 进入
|
||
* **UDP 客户端模式**(p_sock->udp_mode = NET_UDP_MODE_CLIENT):
|
||
* 此后芯片只收该 IP 的包且**不再添加 8 字节信息头**,
|
||
* net_recvfrom 相应地不剥头、源地址回填该固定对端。
|
||
* 要回服务器模式(任意源 + 带信息头)调 net_udp_set_peer(sockfd, NULL)。
|
||
* 3. dest_addr=NULL 时不改 DesIP:服务器模式下 DesIP=0xFFFFFFFF 即
|
||
* 向 255.255.255.255 广播(板级 UDP 广播测试的用法),模式不变。
|
||
* 4. 分块上限 NET_SEND_CHUNK_MAX(1KB 发送 FIFO,TRAP-NET-16),
|
||
* 门控 SENBUF_FREE(TRAP-NET-04);单块等待超 NET_SEND_SPIN_MS
|
||
* 登记挂起 send、由 net_send_pending_tick 续传 → **netTask 不被
|
||
* 一次大报发送占住**(与 TCP 发送同一套机制)。
|
||
* 5. 短写:返回值 < len 表示未全部交付(停滞预算 NET_SEND_TIMEOUT_MS
|
||
* 用尽),调用方须检查返回值——同 net_send 契约。
|
||
* 6. 手册 §9.2.4:UDP 一包最大 1472 字节;本层不做长度上限校验
|
||
* (超出只会分多块写、对端收不到完整包),调用方自负。
|
||
*/
|
||
int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||
const struct net_sockaddr *dest_addr, int addrlen);
|
||
|
||
/*
|
||
* 函数功能:接收 UDP 数据报(含源地址;**走消息队列**,任意任务可调用)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf - 接收缓冲区
|
||
* len - 缓冲区大小(>0)
|
||
* flags - 0 = 按 socket 的 blocking 属性等待;NET_MSG_DONTWAIT = 单次非阻塞
|
||
* src_addr - 输出:发送方地址(可为 NULL)
|
||
* addrlen - 输入输出:src_addr 结构容量/实际长度(可为 NULL)
|
||
* 返回值:实际接收字节数 int >= 0
|
||
* -1 失败,精确码经本任务错误码槽给出(net_get_errno()):
|
||
* NET_ERR_BADF / NET_ERR_INVAL / NET_ERR_WOULDBLOCK /
|
||
* NET_ERR_TIMEDOUT / NET_ERR_CONNRESET(close/重建取消)/ NET_ERR_BUSY
|
||
* 限定条件:socket 已创建且为 DGRAM;net_init() 已执行;**任意任务上下文**
|
||
* (netTask 内直接执行不入队;netTask 内的阻塞等待被登记守卫拒绝 →
|
||
* 须用 NET_MSG_DONTWAIT)
|
||
* 函数说明:1. 与 net_recv 同一条路径(入队 → netTask 串行执行芯片事务 →
|
||
* 结果搭通知值回来),**不再是**"仅限执行任务、自旋 net_poll"的
|
||
* 历史形态;非 netTask 调用不再回 NET_ERR_NOT_IN_NETTASK。
|
||
* 2. 一次调用 = 一个数据报:芯片缓冲内该包**全部读空**(服务器模式
|
||
* 手册要求一次性读出),载荷超出 len 的部分按 BSD 语义截断丢弃,
|
||
* 不会留下半包污染下一次解析。
|
||
* 3. 源地址按 udp_mode 取:服务器模式剥 8 字节信息头
|
||
* ([2-3] 源端口芯片小端、[4-7] 源 IP 线序字节 → 本层 s_addr 网络序
|
||
* 约定,见 net_inet_addr 注释,2026-10-24 定案同族);
|
||
* 客户端模式不剥头、源地址=本 Socket 固定对端。
|
||
* ⚠ 客户端模式若仍按服务器模式剥头,等于吃掉载荷前 8 字节
|
||
* (SNTP 应答 48 字节会前 8 字节丢失)——这是本字段存在的理由。
|
||
* 4. 阻塞语义与 net_recv 同构:无数据 + 阻塞 → **登记挂起、netTask
|
||
* 零占用返回**,数据到点断连由 net_udp_tick 按 1ms 节拍结束;
|
||
* 不再是自旋(旧形态会吃满 IWDG 预算并违反 netTask 契约)。
|
||
* 5. ⚠ IWDG required_mask 内任务禁止无限等待形态:用
|
||
* net_recvfrom_to() 显式预算或 net_select()(同 net_recv 契约)。
|
||
*/
|
||
int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||
struct net_sockaddr *src_addr, int *addrlen);
|
||
|
||
/*
|
||
* 函数功能:接收 UDP 数据报(**带调用方指定超时**,对应 net_recv_to 的 UDP 版)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* buf/len - 接收缓冲与容量
|
||
* flags - 目前不使用,传 0(超时由 timeout_ms 表达)
|
||
* timeout_ms - 本次等待预算(毫秒,>0)
|
||
* src_addr - 输出:发送方地址(可为 NULL)
|
||
* addrlen - 输入输出:src_addr 容量/实际长度(可为 NULL)
|
||
* 返回值:>0 实际字节数;-1 = 真错误(errno 可查);**-2 = 超时无数据**
|
||
* 限定条件:非 netTask 上下文(netTask 内须用 net_recvfrom + NET_MSG_DONTWAIT)
|
||
* 函数说明:1. 与 net_recv_to 同一条路径与同一套超时收口:挂起登记带 deadline,
|
||
* 到点由 net_udp_tick 以超时结束,对外统一 -2(不靠 errno 区分,
|
||
* 无跨任务 errno 竞态)。
|
||
* 2. 受 IWDG 监控的任务(含未来的 SNTP/对时任务)**必须**用本接口或
|
||
* net_select,不得用 net_recvfrom 的无限等待形态。
|
||
* 3. timeout_ms = 0 视为无效参数(无限等待请用 net_recvfrom)。
|
||
*/
|
||
int net_recvfrom_to(int sockfd, void *buf, int len, uint32_t timeout_ms,
|
||
struct net_sockaddr *src_addr, int *addrlen);
|
||
|
||
/*
|
||
* 函数功能:设置/查询 UDP Socket 的芯片模式(客户端 ↔ 服务器,见 net_types.h
|
||
* NET_UDP_MODE_* 与手册 §9.2.4)
|
||
* 入口参数:sockfd - socket 描述符(须为 DGRAM)
|
||
* peer - 非 NULL = 客户端模式:DesIP/DesPort 设为该对端,芯片只收
|
||
* 它的包且**不加** 8 字节信息头;
|
||
* NULL = 服务器模式:DesIP=0xFFFFFFFF、DesPort=0,收任意来源
|
||
* 且每个包带信息头(net_bind 的默认形态)
|
||
* 返回值:0 - 成功 int
|
||
* -1 - 失败(NET_ERR_BADF / NET_ERR_INVAL / NET_ERR_BUSY,errno 可查)
|
||
* 限定条件:socket 已创建且为 DGRAM 且已 net_bind(芯片侧 Socket 已打开);
|
||
* 任意任务上下文(走消息队列,netTask 内直接执行)
|
||
* 函数说明:1. 存在的理由:模式由"最近一次写 DesIP"决定,net_sendto 带目的地址
|
||
* 发一次就把芯片静默切到客户端模式。要给多个对端收发(TFTP 式
|
||
* "收到谁的包回给谁、然后继续听所有人")必须在每次带地址发送后
|
||
* 显式回服务器模式,否则回程包会被当成带头的包错解析。
|
||
* 2. 只改 DesIP/DesPort 两个寄存器,不重开 Socket(不丢接收缓冲内
|
||
* 已到的数据);本层 udp_mode 同步更新,recvfrom 剥头判定据此走。
|
||
* 3. 客户端 → 服务器切换后**先前**收到的包(无头)无法补上源地址,
|
||
* 模式切换时刻之后的包才按新模式解析——协议栈请"先切模式再等包"。
|
||
* 4. 切模式不改动 local_port,也不影响已登记的挂起 recv;挂起期间
|
||
* 切模式由 tick 在结算时读当前模式解析(同一包不会两解)。
|
||
*/
|
||
int net_udp_set_peer(int sockfd, const struct net_sockaddr_in *peer);
|
||
|
||
/*
|
||
* 函数功能:查询 UDP Socket 当前芯片模式
|
||
* 入口参数:sockfd - socket 描述符
|
||
* 返回值:NET_UDP_MODE_SERVER / NET_UDP_MODE_CLIENT uint8_t
|
||
* -1 - 描述符无效或非 DGRAM int
|
||
* 限定条件:任意上下文(纯 RAM 读,不发起芯片事务)
|
||
* 函数说明:诊断/单测/上层"要不要切回服务器模式"的判读入口
|
||
*/
|
||
int net_udp_get_mode(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:关闭 socket
|
||
* 入口参数:sockfd - socket 描述符
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已打开
|
||
* 函数说明:释放 Socket 控制块,TCP 先断开连接
|
||
*/
|
||
int net_close(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:主动拆掉当前 TCP 会话,**保留监听**
|
||
* 入口参数:sockfd - socket 描述符
|
||
* 返回值:0 成功(**监听型 fd 的“成功”= 拆除与重建已登记**,芯片未必已拆完,
|
||
* 见函数说明 2;含幂等:无活动会话),-1 失败
|
||
* 限定条件:非 netTask 上下文(经消息队列委托,同其它 net_* API)
|
||
* 函数说明:1. 适用场景=应用层放弃会话(对时 30s 预算耗尽、协议超时等):
|
||
* 单连接模型禁止对监听 fd net_close(连监听一起毁,AGENTS 约定),
|
||
* 而挂起但 TCP 仍活的客户端会永久占住单连接监听(PC 内核自动
|
||
* ACK keepalive,芯片僵尸判不死——《网络自愈架构设计》§5.2 E13 定案缺口)
|
||
* 2. 实现(2026-10-25 探针窗口心跳缺口修复起):auto_relisten fd = 登记 QUARANTINE 隔离
|
||
* 沉降 + REQ_DROP 重建请求,**登记即返**——“FIN 关闭 + 排渣 + 排空
|
||
* 事件 + 等 byte0=00H”(TRAP-NET-18 异常释放语义)与重建由
|
||
* net_listener_tick 按 30ms 节奏异步执行,端口恢复窗 ~0.4-1s 与被动
|
||
* 断连同型;**调用方不得按旧语义假设“返回即芯片已 CLOSED”**——返回
|
||
* 后 accept/recv 得 WOULDBLOCK 直至重建完成(time_sync 既有轮询天然
|
||
* 容忍)。旧同步形态曾使 netTask 占用 400-600ms、五任务心跳同窗
|
||
* 缺席声明 stall(《网络自愈架构设计》§4.6 记录,勿复活)。
|
||
* 非 auto_relisten(client fd)无监听可保,仍同步排渣(600ms 封顶)
|
||
* 3. 幂等:非 ESTABLISHED/CONNECTING 直接返 0,不动监听
|
||
*/
|
||
int net_drop_conn(int sockfd);
|
||
|
||
/*
|
||
* 事件回调 API
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:注册事件回调
|
||
* 入口参数:sockfd - socket 描述符
|
||
* cb - 回调函数
|
||
* arg - 用户参数
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已创建
|
||
* 函数说明:回调在 net_poll 上下文中触发
|
||
*/
|
||
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
|
||
|
||
/*
|
||
* 辅助函数
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:获取 **本任务** 最后一次 net_*() 调用失败时的精确错误码
|
||
* 入口参数:无
|
||
* 出口参数:无
|
||
* 返回值:错误码(NET_ERR_xxx);本任务尚无失败记录时为 NET_OK(0)
|
||
* 限定条件:无(任何上下文可调用,含中断——查询为纯本任务索引读)
|
||
* 函数说明:1. **按任务隔离**(2026-09-25):错误码存在每个任务自己的
|
||
* 槽位里,任务间互不干扰,不存在跨任务覆写竞态——旧实现的单一全局
|
||
* 变量会被 netTask/其他任务的 net 调用交错覆盖,调用方可能读到别人的码
|
||
* 2. 语义:本任务最后一次返回 -1 的 net_*() 调用所对应的精确码;
|
||
* 调用成功时**不清零**(与本 API 历史行为一致,保持向后兼容)
|
||
* 3. 任务句柄槽位用尽时回退到共享槽位(仅影响排障,不影响功能)
|
||
* 4. 超时类场景(net_recv_to)请直接用返回码 -2 判定,不要依赖本接口
|
||
*/
|
||
int net_get_errno(void);
|
||
|
||
/*
|
||
* 函数功能:查询 socket 当前状态(只读快照,可能滞后于 netTask)
|
||
* 返回值:状态值(net_sock_state_t);描述符无效/未占用 → -1
|
||
*/
|
||
int net_sock_state(int sockfd);
|
||
|
||
/* 手动自愈 API 退役(docs/网络/网络自愈架构设计.md §4.2):net_resync_listen / net_relisten 声明已删——
|
||
* 静默回收形态由对账⑤自动认领(2 轮去抖 + 1s 冷却,纪律"不发芯片命令"
|
||
* 原样保留在认领动作内);监听重建由 reconciler 形态③④(100ms 周期)/
|
||
* D10(30ms 重试)单一所有者。勿再引入"应用层手动自愈"入口。 */
|
||
|
||
/*
|
||
* 函数功能:将 IP 地址字符串转为网络字节序
|
||
* 入口参数:cp - 点分十进制字符串
|
||
* 返回值:网络字节序 IP,失败返回 0
|
||
* 限定条件:cp 指针非空
|
||
* 函数说明:不支持域名解析
|
||
*
|
||
* s_addr 的**唯一约定**(2026-10-24 定案:两套 IP 字节序约定统一为 POSIX 网络序;全仓只此一族,勿再引入第二套):
|
||
* 网络字节序整数 —— &s_addr 的第 0 个内存字节 == 点分第一段。
|
||
* 小端主机(STM32F407 与 PC 模拟器都是)上 "192.168.31.100" 的数值 = 0x641FA8C0。
|
||
* 与 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);
|
||
|
||
/*
|
||
* 函数功能:将网络字节序 IP 转为字符串
|
||
* 入口参数:addr - 网络字节序 IP
|
||
* buf - 输出缓冲区(至少 16 字节)
|
||
* 返回值:buf 指针
|
||
* 限定条件:buf 指针非空
|
||
*/
|
||
char *net_inet_ntoa(uint32_t addr, char *buf);
|
||
|
||
/*
|
||
* 函数功能:端口字节序转换(主机序 -> 网络序)
|
||
* 入口参数:hostshort - 主机序端口
|
||
* 返回值:网络序端口
|
||
* 限定条件:无
|
||
* 函数说明:小端 → 大端
|
||
*/
|
||
uint16_t net_htons(uint16_t hostshort);
|
||
|
||
/*
|
||
* 函数功能:端口字节序转换(网络序 -> 主机序)
|
||
* 入口参数:netshort - 网络序端口
|
||
* 返回值:主机序端口
|
||
* 限定条件:无
|
||
* 函数说明:大端 → 小端
|
||
*/
|
||
uint16_t net_ntohs(uint16_t netshort);
|
||
|
||
/*
|
||
* 函数功能:IP 地址字节序转换(主机序 -> 网络序)
|
||
* 入口参数:hostlong - 主机序 IP
|
||
* 返回值:网络序 IP
|
||
* 限定条件:无
|
||
* 函数说明:小端 → 大端
|
||
*/
|
||
uint32_t net_htonl(uint32_t hostlong);
|
||
|
||
/*
|
||
* 函数功能:IP 地址字节序转换(网络序 -> 主机序)
|
||
* 入口参数:netlong - 网络序 IP
|
||
* 返回值:主机序 IP
|
||
* 限定条件:无
|
||
* 函数说明:大端 → 小端
|
||
*/
|
||
uint32_t net_ntohl(uint32_t netlong);
|
||
|
||
#ifndef NET_NO_OS
|
||
/*
|
||
* 函数功能:处理消息队列中的请求(必须在 netTask 主循环中调用)
|
||
* 限定条件:net_init() 已调用
|
||
* 函数说明:处理其他任务通过 net_send/net_recv 等接口发送的请求,
|
||
* 在 netTask 上下文中串行化执行所有 CH395F 操作
|
||
*/
|
||
void net_process_messages(void);
|
||
#endif /* NET_NO_OS */
|
||
|
||
/*
|
||
* 函数功能:获取 Socket 控制块指针(内部使用)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* 返回值:Socket 控制块指针,失败返回 NULL
|
||
*/
|
||
net_sock_t *net_get_sock(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:直取 Socket 控制块数组元素,**不判 in_use**(net 层内部周期对账专用)
|
||
* 入口参数:sockfd - Socket 描述符 (0~7),调用方保证在范围内
|
||
* 返回值:控制块指针(永不为 NULL)
|
||
* 限定条件:netTask 上下文
|
||
* 函数说明:`net_get_sock()` 对未在用槽位返回 NULL,而周期对账必须看到 in_use==0 /
|
||
* state==CLOSED 的槽位(对账形态④ 认领孤儿监听正依赖 CLOSED 态)→ 单独提供。
|
||
* ⚠ 应用层请一律用 `net_get_sock()`;本函数仅供 net_events.c 的对账循环使用。
|
||
* 模拟器不实现(无调用者,链接期不需要)。
|
||
*/
|
||
net_sock_t *net_sock_raw(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:记录**本任务**最后一次失败的精确错误码(net 层内部通用工具)
|
||
* 入口参数:err - 错误码(NET_ERR_xxx,负值)
|
||
* 出口参数:无
|
||
* 返回值:err 原值(便于写成 `return net_set_errno(NET_ERR_XXX);`)
|
||
* 限定条件:无
|
||
* 函数说明:1. 只写本任务的槽位,其他任务读不到、也改不了 → 消除跨任务覆写竞态
|
||
* 2. 监听生命周期模块化:由 net_socket.c 的 static 提升为**模块间可见**,
|
||
* 供 net_listener.c 等同目录内部模块复用(定义仍在 net_socket.c)
|
||
*/
|
||
int net_set_errno(int err);
|
||
|
||
/* 「记本任务错误码 + 统一失败返回 -1」的紧凑写法(取代 `s_net_errno = X; return -1;`)
|
||
* 监听生命周期模块化:原定义在 net_socket.c,随 net_set_errno 一并提升到本头文件 */
|
||
#define NET_ERR_RETURN_1(err) (net_set_errno(err), -1)
|
||
|
||
/*
|
||
* 函数功能:获取 Socket 本地地址(IP + Port)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* addr - 输出:本地地址
|
||
* addrlen - 输入输出:地址结构体长度
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:socket 已创建或已绑定
|
||
*/
|
||
int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||
|
||
/*
|
||
* 函数功能:获取 Socket 对端地址(IP + Port)
|
||
* 入口参数:sockfd - socket 描述符
|
||
* addr - 输出:对端地址
|
||
* addrlen - 输入输出:地址结构体长度
|
||
* 返回值:0 成功,-1 失败(未连接返回 NOTCONN)
|
||
* 限定条件:socket 已连接(MCU 端读 CONNECT 事件缓存的对端,零 SPI;
|
||
* 单连接模型下监听 fd 转数据通道后同样有效)
|
||
*/
|
||
int net_getpeername(int sockfd, struct net_sockaddr *addr, int *addrlen);
|
||
|
||
#ifndef NET_NO_OS
|
||
/*
|
||
* 内部 API(需在 netTask 上下文中调用,绕过消息队列)
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:取下一个动态端口并推进游标(49152~65535 回绕,内部使用)
|
||
* 入口参数:无
|
||
* 返回值:分配到的端口(主机序) uint16_t
|
||
* 限定条件:单线程语义——TCP 绑定路径(调用方上下文)与 UDP 绑定执行体
|
||
* (netTask)都经此取号,簿记只住 net_socket.c 一处
|
||
* 函数说明:原逻辑内联在 net_bind 里;UDP 队列化后绑定动作挪进 netTask 执行,
|
||
* 两处都要用同一游标,故抽成函数(同一事实只在一处)。
|
||
* 不做"是否已被其他 Socket 占用"检查——与抽取前行为一致。
|
||
*/
|
||
uint16_t net_dynamic_port_next(void);
|
||
|
||
/*
|
||
* 函数功能:发送数据(内部版本,直接操作,不经过消息队列)
|
||
* 入口参数:p_sock - Socket 控制块指针
|
||
* buf - 数据缓冲区
|
||
* len - 数据长度
|
||
* 返回值:实际发送字节数,失败返回 -1
|
||
* 限定条件:必须在 netTask 上下文中调用
|
||
*/
|
||
int net_send_sock(net_sock_t *p_sock, const void *buf, int len);
|
||
|
||
/*
|
||
* 函数功能:接收数据(内部版本,直接操作,不经过消息队列)
|
||
* 入口参数:p_sock - Socket 控制块指针
|
||
* buf - 接收缓冲区
|
||
* len - 缓冲区大小
|
||
* flags - 通常为 0,可设置 NET_MSG_DONTWAIT
|
||
* 返回值:实际接收字节数,0=对端关闭,-1=错误
|
||
* 限定条件:必须在 netTask 上下文中调用
|
||
*/
|
||
int net_recv_sock(net_sock_t *p_sock, void *buf, int len, int flags);
|
||
|
||
/*
|
||
* 函数功能:关闭 socket(内部版本,直接操作,不经过消息队列)
|
||
* 入口参数:p_sock - Socket 控制块指针
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:必须在 netTask 上下文中调用
|
||
*/
|
||
int net_close_sock(net_sock_t *p_sock);
|
||
|
||
/*
|
||
* 函数功能:启动 TCP Server 监听(内部版本,直接操作,不经过消息队列)
|
||
* 入口参数:sockfd - Socket 描述符
|
||
* 返回值:0 成功,-1 失败
|
||
* 限定条件:必须在 netTask 上下文中调用
|
||
*/
|
||
int net_listen_locked(int sockfd);
|
||
|
||
/*
|
||
* 函数功能:判当前上下文是否本层执行任务(netTask / 硬件层的 testTask)
|
||
* 入口参数:无
|
||
* 返回值:1 - 是本层执行任务(或 net_init 前未捕获);0 - 明确不是 uint8_t
|
||
* 限定条件:net_init 之后判据才有效;任意上下文可读
|
||
* 函数说明:队列化接口用本判据决定"直接执行"还是"投递给 netTask"——执行任务
|
||
* 自己不能往自己的队列里投(要等自己回来泵,队列满即自等死锁);
|
||
* 挂起登记前也用它确认"完成动作有人做"。判据与留痕见定义处注释。
|
||
*/
|
||
uint8_t net_ctx_is_owner_task(void);
|
||
|
||
/*
|
||
* 函数功能:发送数据(内部锁定版本,TCP 与 UDP 共用同一份分块实现)
|
||
* 入口参数:p_sock - Socket 控制块指针
|
||
* buf - 数据缓冲区
|
||
* len - 数据长度
|
||
* caller - 挂起 send 的完成通知目标(执行任务自身传 NULL 即拒登记)
|
||
* 返回值:实际发送字节数(>= 0);NET_PENDING_REGISTERED = 已挂起;-1 = 错误
|
||
* 限定条件:必须在 netTask 上下文中调用
|
||
* 函数说明:UDP 队列化后 net_udp_sendto_exec 也走本函数——分块粒度
|
||
* (NET_SEND_CHUNK_MAX)、SENBUF_FREE 门控、末块不等、停滞超时、
|
||
* 挂起 send 表全部只有一份(TRAP-NET-16 的复发形态就是"两条路径
|
||
* 各写一套分块自旋",故不复制)。状态门按 type 区分:TCP 须
|
||
* ESTABLISHED,UDP 须 UDP_OPEN。
|
||
*/
|
||
int net_send_locked(net_sock_t *p_sock, const void *buf, int len, TaskHandle_t caller);
|
||
#endif /* NET_NO_OS */
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* NET_SOCKET_H */
|