ui_net_sink 拆分为协议层与平台后端,新增 RemoDispBus 设计文档

This commit is contained in:
2026-09-11 21:25:02 +08:00
parent 47b2c1bb7b
commit e16bd882a6
20 changed files with 1600 additions and 408 deletions
+786
View File
@@ -0,0 +1,786 @@
/*
* 模块名称:Network Socket API (Winsock 模拟器后端)
* 模块功能:以 Windows Winsock2 实现 net_socket.h 的 BSD Socket 核心 API,
* 使 PC 模拟器与 MCU 端可共用同一份上层网络代码(ui_net_sink.c 等)
* 适用平台:Windows (Winsock2);构建时须定义 NET_NO_OS(剥离 FreeRTOS 相关接口)
* 作者:王建锋
* 创建日期:2026-09-10
* 修改记录:
* 2026-09-10 王建锋 创建初始版本(RemoDispBus 双端共用 net_* 后端)
*
* 设计要点:
* 1. fd 采用与 MCU 端一致的"控制块索引"模型(0 ~ NET_MAX_SOCKETS-1)
* 2. 所有 Socket 创建即置为非阻塞(ioctlsocket FIONBIO),使 net_recv /
* net_accept 的 DONTWAIT 语义与 MCU 端一致(无数据返回 -1 + NET_ERR_WOULDBLOCK)
* 3. 代次号在模拟器上恒为 0(无"网络重建"概念),net_get_generation 恒返回 0
* 4. net_get_sock 以 in_use 判活,供上层判断"监听 Socket 是否随客户端一同失效"
* 5. Winsock 句柄存放于并行数组 s_ws[],不侵入共享的 net_sock_t 结构体
*/
/*
* 注意:net_types.h(经 net_socket.h)必须先于 winsock2.h 包含。
* MSVC 的 C 编译器在 winsock2.h 定义 Windows 宏之后再解析本项目的地址结构体
* (struct net_in_addr / net_sockaddr_in)会报 C2143 / C2079;ARMCC 无此限制。
* 故此处先引入 net 类型,再引入 Winsock(net_socket.h 本身不依赖 Winsock)。
*/
#include "net_socket.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string.h>
#include <stdio.h>
/* WSA 版本号(MAKEWORD(2,2)) */
#define NET_SIM_WSA_VERSION 0x0202
/* 监听 backlog(单客户端) */
#define NET_SIM_BACKLOG 1
/* 控制块公开视图(in_use 判活,供 net_get_sock)与 Winsock 句柄并行数组 */
static net_sock_t s_socks[NET_MAX_SOCKETS];
static SOCKET s_ws[NET_MAX_SOCKETS];
static int s_net_errno = NET_OK; /* 最近一次操作错误码 */
static int s_generation = 0; /* 网络代次(模拟器恒为 0) */
/*
* 函数功能:确保 Winsock 已初始化(幂等)
* 入口参数:无
* 出口参数:无
* 返回值:0 - 就绪,-1 - WSAStartup 失败
* 限定条件:无
* 函数说明:任何 Socket 操作前先调用;已初始化则直接返回
*/
static int ensure_wsa(void)
{
static int s_done = 0;
if (s_done == 0) {
WSADATA wsa;
if (WSAStartup(NET_SIM_WSA_VERSION, &wsa) != 0) {
return -1;
}
s_done = 1;
}
return 0;
}
/*
* 函数功能:分配一个空闲 fd(控制块索引)
* 入口参数:无
* 出口参数:无
* 返回值:空闲索引(0 ~ NET_MAX_SOCKETS-1),-1 表示无空闲
* 限定条件:s_socks 已定义
* 函数说明:线性扫描,返回首个 in_use == 0 的控制块索引
*/
static int alloc_fd(void)
{
int i;
for (i = 0; i < NET_MAX_SOCKETS; i++) {
if (s_socks[i].in_use == 0) {
return i;
}
}
return -1;
}
/*
* 函数功能:net_sockaddr 拷贝为 Winsock sockaddr_in
* 入口参数:addr - 源地址(net_sockaddr,AF_INET 实为 net_sockaddr_in)
* out - 输出 Winsock 地址
* 出口参数:out - 填充
* 返回值:无
* 限定条件:两结构体布局一致(均 16 字节,字段偏移相同)
* 函数说明:字段偏移一致,按 sizeof 直接拷贝
*/
static void to_ws_addr(const struct net_sockaddr *addr, struct sockaddr_in *out)
{
memcpy(out, addr, sizeof(struct sockaddr_in));
}
/*
* 函数功能:Winsock sockaddr_in 拷贝为 net_sockaddr
* 入口参数:in - 源 Winsock 地址
* out - 输出 net_sockaddr
* 出口参数:out - 填充
* 返回值:无
* 限定条件:两结构体布局一致(均 16 字节,字段偏移相同)
* 函数说明:字段偏移一致,按 sizeof 直接拷贝
*/
static void from_ws_addr(const struct sockaddr_in *in, struct net_sockaddr *out)
{
memcpy(out, in, sizeof(struct sockaddr_in));
}
/*
* 函数功能:网络子系统初始化(模拟器:仅确保 Winsock 就绪)
* 入口参数:ip/mask/gateway/mac - 均忽略(模拟器无 CH395F 协议栈)
* 出口参数:无
* 返回值:0 - 成功,-1 - WSA 初始化失败
* 限定条件:无
* 函数说明:与 MCU 端 net_init 语义对齐,供上层统一调用
*/
int net_init(const char *ip, const char *mask, const char *gateway, const uint8_t *mac)
{
(void)ip;
(void)mask;
(void)gateway;
(void)mac;
if (ensure_wsa() != 0) {
s_net_errno = NET_ERR;
return -1;
}
s_net_errno = NET_OK;
return 0;
}
/*
* 函数功能:取网络代次号
* 入口参数:无
* 返回值:代次号(模拟器恒为 0)
* 限定条件:无
* 函数说明:模拟器无网络重建,代次恒 0,使上层代次自愈逻辑空转
*/
uint32_t net_get_generation(void)
{
return (uint32_t)s_generation;
}
/*
* 函数功能:递增网络代次号
* 入口参数:无
* 返回值:无
* 限定条件:无
* 函数说明:模拟器不会触发,保留接口以对齐 API
*/
void net_generation_inc(void)
{
s_generation++;
}
/*
* 函数功能:轮询所有 Socket 状态
* 入口参数:无
* 返回值:0(Winsock 非阻塞 I/O 直接反映事件,无需中断轮询)
* 限定条件:无
* 函数说明:模拟器无 CH395F 中断,空操作
*/
int net_poll(void)
{
return 0;
}
/*
* 函数功能:创建 socket
* 入口参数:domain - 地址族(仅 AF_INET)
* type - NET_SOCK_STREAM(TCP) 或 NET_SOCK_DGRAM(UDP)
* 出口参数:无
* 返回值:socket 描述符(0 ~ NET_MAX_SOCKETS-1),失败 -1
* 限定条件:Winsock 已就绪
* 函数说明:分配空闲控制块,创建 Winsock SOCKET 并置非阻塞
*/
int net_socket(int domain, int type)
{
int idx;
int is_udp;
SOCKET ws;
u_long nb = 1;
(void)domain;
if (ensure_wsa() != 0) {
s_net_errno = NET_ERR;
return -1;
}
idx = alloc_fd();
if (idx < 0) {
s_net_errno = NET_ERR;
return -1;
}
is_udp = (type == NET_SOCK_DGRAM);
ws = socket(AF_INET, is_udp ? SOCK_DGRAM : SOCK_STREAM,
is_udp ? IPPROTO_UDP : IPPROTO_TCP);
if (ws == INVALID_SOCKET) {
s_net_errno = NET_ERR;
return -1;
}
if (ioctlsocket(ws, FIONBIO, &nb) != 0) {
closesocket(ws);
s_net_errno = NET_ERR;
return -1;
}
memset(&s_socks[idx], 0, sizeof(net_sock_t));
s_socks[idx].in_use = 1;
s_socks[idx].type = (uint8_t)type;
s_socks[idx].state = NET_SOCK_STATE_CREATED;
s_socks[idx].ch395_sock = (uint8_t)idx;
s_ws[idx] = ws;
s_net_errno = NET_OK;
return idx;
}
/*
* 函数功能:绑定本地地址和端口
* 入口参数:sockfd - socket 描述符
* addr - 本地地址(net_sockaddr,AF_INET)
* addrlen - 地址结构体长度
* 出口参数:无
* 返回值:0 成功,-1 失败
* 限定条件:socket 已创建
* 函数说明:设置 SO_REUSEADDR 后 bind,便于断线后重监听复用端口
*/
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen)
{
struct sockaddr_in wsaddr;
int yes = 1;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (addr == NULL || addrlen < (int)sizeof(struct sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
setsockopt(s_ws[sockfd], SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes));
to_ws_addr(addr, &wsaddr);
if (bind(s_ws[sockfd], (struct sockaddr *)&wsaddr, sizeof(wsaddr)) == SOCKET_ERROR) {
s_net_errno = NET_ERR;
return -1;
}
s_socks[sockfd].state = NET_SOCK_STATE_BOUND;
s_net_errno = NET_OK;
return 0;
}
/*
* 函数功能:TCP Server 监听
* 入口参数:sockfd - socket 描述符
* 出口参数:无
* 返回值:0 成功,-1 失败
* 限定条件:socket 已绑定
* 函数说明:backlog 为 1(单客户端),监听 Socket 保持非阻塞
*/
int net_listen(int sockfd)
{
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (listen(s_ws[sockfd], NET_SIM_BACKLOG) == SOCKET_ERROR) {
s_net_errno = NET_ERR;
return -1;
}
s_socks[sockfd].state = NET_SOCK_STATE_LISTENING;
s_net_errno = NET_OK;
return 0;
}
/*
* 函数功能:TCP Server 接受连接
* 入口参数:sockfd - 监听 socket 描述符
* addr - 输出:客户端地址(可为 NULL)
* addrlen - 输入输出:地址长度(addr 非空时有效)
* 出口参数:addr/addrlen - 填充客户端地址
* 返回值:新 socket 描述符,失败 -1
* 限定条件:socket 正在监听
* 函数说明:非阻塞监听下无新连接时返回 -1 并置 NET_ERR_WOULDBLOCK;
* 与 MCU 端不同,Winsock 的 accept 返回独立于监听 Socket 的新 fd
*/
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen)
{
struct sockaddr_in wscli;
int wslen;
SOCKET cws;
int nidx;
u_long nb = 1;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
wslen = sizeof(wscli);
cws = accept(s_ws[sockfd], (addr != NULL) ? (struct sockaddr *)&wscli : NULL,
(addr != NULL) ? &wslen : NULL);
if (cws == INVALID_SOCKET) {
int err = WSAGetLastError();
s_net_errno = (err == WSAEWOULDBLOCK) ? NET_ERR_WOULDBLOCK : NET_ERR;
return -1;
}
if (addr != NULL && addrlen != NULL) {
from_ws_addr(&wscli, addr);
*addrlen = (int)sizeof(struct net_sockaddr_in);
}
nidx = alloc_fd();
if (nidx < 0) {
closesocket(cws);
s_net_errno = NET_ERR;
return -1;
}
ioctlsocket(cws, FIONBIO, &nb);
memset(&s_socks[nidx], 0, sizeof(net_sock_t));
s_socks[nidx].in_use = 1;
s_socks[nidx].type = (uint8_t)NET_SOCK_STREAM;
s_socks[nidx].state = NET_SOCK_STATE_ESTABLISHED;
s_socks[nidx].ch395_sock = (uint8_t)nidx;
s_ws[nidx] = cws;
s_net_errno = NET_OK;
return nidx;
}
/*
* 函数功能:TCP Client 发起连接
* 入口参数:sockfd - socket 描述符
* addr - 服务器地址
* addrlen - 地址长度
* 出口参数:无
* 返回值:0 成功(或已发起),-1 失败
* 限定条件:socket 已创建
* 函数说明:非阻塞 Socket 上连接未完成时返回 -1 + NET_ERR_WOULDBLOCK
*/
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen)
{
struct sockaddr_in wsaddr;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (addr == NULL || addrlen < (int)sizeof(struct sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
to_ws_addr(addr, &wsaddr);
if (connect(s_ws[sockfd], (struct sockaddr *)&wsaddr, sizeof(wsaddr)) == 0) {
s_socks[sockfd].state = NET_SOCK_STATE_ESTABLISHED;
s_net_errno = NET_OK;
return 0;
}
{
int err = WSAGetLastError();
s_net_errno = (err == WSAEWOULDBLOCK) ? NET_ERR_WOULDBLOCK : NET_ERR;
}
return -1;
}
/*
* 函数功能:发送数据(TCP)
* 入口参数:sockfd - socket 描述符
* buf - 数据缓冲区
* len - 数据长度
* flags - 通常为 0
* 出口参数:无
* 返回值:实际发送字节数,-1 错误;发送缓冲满时返回 0 + NET_ERR_WOULDBLOCK
* 限定条件:socket 已建立,buf 非空
* 函数说明:非阻塞单次发送(保持 UI 主循环不阻塞);协议帧小且对端主动
* 读取,实践中一次即发完
*/
int net_send(int sockfd, const void *buf, int len, int flags)
{
int r;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len < 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
r = send(s_ws[sockfd], (const char *)buf, len, flags);
if (r >= 0) {
s_socks[sockfd].send_bytes += (uint32_t)r;
s_net_errno = NET_OK;
return r;
}
{
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK) {
s_net_errno = NET_ERR_WOULDBLOCK;
return 0;
}
s_net_errno = NET_ERR;
}
return -1;
}
/*
* 函数功能:接收数据(TCP)
* 入口参数:sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
* flags - 通常为 0,可设 NET_MSG_DONTWAIT(Socket 本就非阻塞)
* 出口参数:buf - 填充接收数据
* 返回值:实际接收字节数;0 = 对端关闭;-1 = 无数据(NET_ERR_WOULDBLOCK)或错误
* 限定条件:socket 已建立
* 函数说明:与 MCU 端语义一致——>0 有数据,0 对端关闭,<0 且 errno 区分
* "暂无数据"与"真错误"
*/
int net_recv(int sockfd, void *buf, int len, int flags)
{
int r;
(void)flags;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len < 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
r = recv(s_ws[sockfd], (char *)buf, len, 0);
if (r > 0) {
s_socks[sockfd].recv_bytes += (uint32_t)r;
s_net_errno = NET_OK;
return r;
}
if (r == 0) {
s_net_errno = NET_OK;
return 0;
}
{
int err = WSAGetLastError();
s_net_errno = (err == WSAEWOULDBLOCK) ? NET_ERR_WOULDBLOCK : NET_ERR;
}
return -1;
}
/*
* 函数功能:发送 UDP 数据报(含目标地址)
* 入口参数:sockfd - socket 描述符
* buf - 数据缓冲区
* len - 数据长度
* flags - 通常为 0
* dest_addr - 目标地址
* addrlen - 地址长度
* 出口参数:无
* 返回值:实际发送字节数,-1 失败
* 限定条件:socket 已创建,buf/dest_addr 非空
*/
int net_sendto(int sockfd, const void *buf, int len, int flags,
const struct net_sockaddr *dest_addr, int addrlen)
{
struct sockaddr_in wsaddr;
int r;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len < 0 || dest_addr == NULL ||
addrlen < (int)sizeof(struct sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
to_ws_addr(dest_addr, &wsaddr);
r = sendto(s_ws[sockfd], (const char *)buf, len, flags,
(struct sockaddr *)&wsaddr, sizeof(wsaddr));
if (r >= 0) {
s_net_errno = NET_OK;
return r;
}
{
int err = WSAGetLastError();
s_net_errno = (err == WSAEWOULDBLOCK) ? NET_ERR_WOULDBLOCK : NET_ERR;
}
return -1;
}
/*
* 函数功能:接收 UDP 数据报(含源地址)
* 入口参数:sockfd - socket 描述符
* buf - 接收缓冲区
* len - 缓冲区大小
* flags - 通常为 0
* src_addr - 输出:发送方地址(可为 NULL)
* addrlen - 输入输出:源地址长度(可为 NULL)
* 出口参数:buf/src_addr/addrlen - 填充
* 返回值:实际接收字节数,-1 失败
* 限定条件:socket 已创建,buf 非空
*/
int net_recvfrom(int sockfd, void *buf, int len, int flags,
struct net_sockaddr *src_addr, int *addrlen)
{
struct sockaddr_in wsaddr;
int wslen;
int r;
(void)flags;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (buf == NULL || len < 0) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
wslen = sizeof(wsaddr);
r = recvfrom(s_ws[sockfd], (char *)buf, len, 0,
(struct sockaddr *)&wsaddr, &wslen);
if (r < 0) {
int err = WSAGetLastError();
s_net_errno = (err == WSAEWOULDBLOCK) ? NET_ERR_WOULDBLOCK : NET_ERR;
return -1;
}
if (src_addr != NULL && addrlen != NULL) {
from_ws_addr(&wsaddr, src_addr);
*addrlen = (int)sizeof(struct net_sockaddr_in);
}
s_net_errno = NET_OK;
return r;
}
/*
* 函数功能:关闭 socket
* 入口参数:sockfd - socket 描述符
* 出口参数:无
* 返回值:0 成功,-1 失败
* 限定条件:socket 已打开(in_use == 1)
* 函数说明:关闭 Winsock 句柄并释放控制块(in_use 清零,net_get_sock 转返回 NULL)
*/
int net_close(int sockfd)
{
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
closesocket(s_ws[sockfd]);
s_socks[sockfd].in_use = 0;
s_socks[sockfd].state = NET_SOCK_STATE_CLOSED;
s_ws[sockfd] = INVALID_SOCKET;
s_net_errno = NET_OK;
return 0;
}
/*
* 函数功能:注册事件回调
* 入口参数:sockfd - socket 描述符
* cb - 回调函数(NULL 取消注册)
* arg - 用户参数
* 出口参数:无
* 返回值:0 成功,-1 失败
* 限定条件:socket 已创建
* 函数说明:模拟器以非阻塞 I/O 直接感知事件,回调仅存储不主动触发
*/
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg)
{
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
s_socks[sockfd].event_cb = cb;
s_socks[sockfd].event_arg = arg;
s_net_errno = NET_OK;
return 0;
}
/*
* 函数功能:获取 socket 最后错误码
* 入口参数:无
* 返回值:最近一次 net_* 操作设置的错误码(NET_OK / NET_ERR_xxx)
* 限定条件:无
*/
int net_get_errno(void)
{
return s_net_errno;
}
/*
* 函数功能:将点分十进制 IP 字符串转为网络字节序 32 位地址
* 入口参数:cp - 点分十进制字符串(如 "192.168.1.100")
* 出口参数:无
* 返回值:网络字节序 IP(参数无效返回 0)
* 限定条件:无
* 函数说明:逐段解析后按 NET_HTONL 转网络字节序(与 MCU 端实现一致)
*/
uint32_t net_inet_addr(const char *cp)
{
uint32_t addr = 0;
int i;
if (cp == NULL) {
return 0;
}
for (i = 0; i < 4; i++) {
uint32_t val = 0;
while (*cp >= '0' && *cp <= '9') {
val = val * 10 + (uint32_t)(*cp - '0');
cp++;
}
addr |= (val << (i * 8));
if (*cp == '.') {
cp++;
}
}
return NET_HTONL(addr);
}
/*
* 函数功能:将网络字节序 32 位 IP 转为点分十进制字符串
* 入口参数:addr - 网络字节序 IP
* buf - 输出缓冲区(至少 16 字节)
* 出口参数:buf - 填充字符串
* 返回值:buf 指针(buf 为 NULL 时返回 NULL)
* 限定条件:buf 非空且长度足够
*/
char *net_inet_ntoa(uint32_t addr, char *buf)
{
uint32_t naddr = NET_NTOHL(addr);
if (buf == NULL) {
return NULL;
}
snprintf(buf, 16, "%lu.%lu.%lu.%lu",
(unsigned long)(naddr & 0xFF),
(unsigned long)((naddr >> 8) & 0xFF),
(unsigned long)((naddr >> 16) & 0xFF),
(unsigned long)((naddr >> 24) & 0xFF));
return buf;
}
/*
* 函数功能:端口字节序转换(主机序 -> 网络序)
* 入口参数:hostshort - 主机序端口
* 返回值:网络序端口
* 限定条件:无
*/
uint16_t net_htons(uint16_t hostshort)
{
return NET_HTONS(hostshort);
}
/*
* 函数功能:端口字节序转换(网络序 -> 主机序)
* 入口参数:netshort - 网络序端口
* 返回值:主机序端口
* 限定条件:无
*/
uint16_t net_ntohs(uint16_t netshort)
{
return NET_NTOHS(netshort);
}
/*
* 函数功能:IP 地址字节序转换(主机序 -> 网络序)
* 入口参数:hostlong - 主机序 IP
* 返回值:网络序 IP
* 限定条件:无
*/
uint32_t net_htonl(uint32_t hostlong)
{
return NET_HTONL(hostlong);
}
/*
* 函数功能:IP 地址字节序转换(网络序 -> 主机序)
* 入口参数:netlong - 网络序 IP
* 返回值:主机序 IP
* 限定条件:无
*/
uint32_t net_ntohl(uint32_t netlong)
{
return NET_NTOHL(netlong);
}
/*
* 函数功能:获取 Socket 控制块指针
* 入口参数:sockfd - socket 描述符
* 返回值:控制块指针;描述符越界或已释放(in_use == 0)时返回 NULL
* 限定条件:无
* 函数说明:上层据此判断"监听 Socket 是否随客户端一同失效"(单连接模型)
*/
net_sock_t *net_get_sock(int sockfd)
{
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
return NULL;
}
if (s_socks[sockfd].in_use == 0) {
return NULL;
}
return &s_socks[sockfd];
}
/*
* 函数功能:获取 Socket 本地地址(IP + Port)
* 入口参数:sockfd - socket 描述符
* addr - 输出:本地地址
* addrlen - 输入输出:地址结构体长度
* 出口参数:addr/addrlen - 填充
* 返回值:0 成功,-1 失败
* 限定条件:socket 已创建
* 函数说明:经 Winsock getsockname 读取实际绑定地址
*/
int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen)
{
struct sockaddr_in wsaddr;
int wslen;
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS || s_socks[sockfd].in_use == 0) {
s_net_errno = NET_ERR_BADF;
return -1;
}
if (addr == NULL || addrlen == NULL ||
*addrlen < (int)sizeof(struct net_sockaddr_in)) {
s_net_errno = NET_ERR_INVAL;
return -1;
}
wslen = sizeof(wsaddr);
if (getsockname(s_ws[sockfd], (struct sockaddr *)&wsaddr, &wslen) == SOCKET_ERROR) {
s_net_errno = NET_ERR;
return -1;
}
from_ws_addr(&wsaddr, addr);
*addrlen = (int)sizeof(struct net_sockaddr_in);
s_net_errno = NET_OK;
return 0;
}