# 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()`
