# NET Socket FTP 支持改造方案 ## 背景 在 net_socket API 上移植 FTP Server(lftpd),需要支持 PASV 模式数据通道。现有 API 仅支持"一个监听 Socket 独占全部数据 Socket"的单 TCP Server 模型,改造后需支持**多监听者 + 动态 Socket 分配**。 ## Socket 需求量 | 用途 | Socket | 说明 | |------|--------|------| | 控制通道监听(端口 21) | Socket 0 | 多连接 TCP Server | | 控制通道数据 | Socket 1 | backlog=1,只接受 1 个 FTP 客户端 | | PASV 数据监听 + 传输 | Socket 2 | 动态分配,用后释放 | | 空闲 | Socket 3~7 | 备胎 | ## 改造项(7 项) ### A. `net_sock_t` 新增 `standalone_accept` 标志 - 位置:`net_types.h:net_sock_t` - 用途:区分多连接数据 Socket 和独立监听者(如 PASV) - 设 1:PASV 监听者 `handle_connect_event` → 原地转为 `ESTABLISHED` - 设 1:`handle_disconnect_event` → 释放(`CLOSED`),不恢复 `TCP_ACCEPT` ### B. `net_listen()` 按 backlog 分配 + 登记 data_socks[] - 循环从 `NET_TCP_SERVER_DATA_SOCK_START` 到 `backlog` 个 - 分配的数据 Socket 登记到 `p_sock->data_socks[]`,设 `data_sock_count` - `backlog == 0` 时:不分配数据 Socket,设 `standalone_accept=1` ### C. `net_bind()` 支持 port=0 自动分配 - `sin_port == 0` 时从 49152~65535 分配 - 静态变量 `s_dynamic_port` 递增 ### D. `handle_connect_event()` 支持独立监听 - `LISTENING + standalone_accept`:拷贝远程 IP/Port,状态转 `ESTABLISHED` - `LISTENING + !standalone_accept`:保持 LISTENING(现有行为) ### E. `handle_disconnect_event()` 支持独立释放 - `ESTABLISHED + standalone_accept`:设 `state = CLOSED, in_use = 0`(释放) - `ESTABLISHED + !standalone_accept`:恢复 `TCP_ACCEPT`(现有行为) - 释放时不清零整个控制块(正在 `net_recv` 中的任务仍需读取 state) ### F. `net_accept()` 支持单连接 + 修复多连接 - 先查 `data_socks[]`(修复现行 bug) - 再查 `standalone_accept` 监听者是否 `ESTABLISHED` → 返回自身 ### G. 新增 `net_getsockname()` - 返回 `local_port` + 本机 IP - 本机 IP 在 `net_init()` 时缓存(`s_local_ip`),避免 SPI 竞态 ## 消息队列序列化 ### 问题 `net_listen()`、`net_accept()` 直接调用 CH395F SPI,从非 netTask(如 FTP 任务)调用会与 `net_poll()` 冲突。 ### 方案 新增消息类型通过现有消息队列串行化: | 消息类型 | 用途 | 状态 | |---------|------|------| | `NET_MSG_LISTEN` | `net_listen()` 委托 netTask 执行 | 本次实现 | | `NET_MSG_ACCEPT` | `net_accept()` 委托 netTask 执行 | 本次实现 | `net_bind()` 暂不消息化(TCP 部分不碰 SPI,UDP 暂无需跨任务调用)。 ## 向后兼容 - 控制通道 `net_listen(sockfd=0, backlog=7)` 行为不变(仍配满 Socket 1~7) - `backlog < 7` 时才释放多余 Socket - `NET_MSG_LISTEN`/`NET_MSG_ACCEPT` 仅新增,不影响现有 `NET_MSG_SEND/RECV/CLOSE/CONNECT` - `net_sock_t` 新增字段 `standalone_accept` 默认 0,不影响现有使用 ## 实施顺序 1. 消息队列加 `NET_MSG_LISTEN`、`NET_MSG_ACCEPT` 2. `net_listen()` 消息化 + 按 backlog 分配 + data_socks 登记 3. `net_accept()` 消息化 + 单连接支持 4. `net_bind()` port=0 支持 5. `net_types.h` standalone_accept 字段 6. `handle_connect_event()` / `handle_disconnect_event()` 独立监听逻辑 7. `net_getsockname()`