/* * TCP平台接口:只负责同步非阻塞I/O、就绪等待和单调计时,不依赖104协议模块。 * 工程须链接且只链接一个实现;当前提供IEC104_Net_Windows.c。 * 不创建线程、不保存业务回调,也不决定协议故障、EOF排空或重连保留策略。 * * 职责边界:TcpServer决定何时接入、读写和关闭,Net负责执行一次平台操作。 * 典型生命周期:Init -> Listen -> Wait/Accept/Recv/Send -> Close各句柄 -> Cleanup。 * 调用方持有监听和客户端句柄;本层不会为其保存连接对象或业务状态。 * * 通用约定:native_error输出均允许NULL;成功时写0,失败时保留平台诊断码。 * 上层应按result调度,native_error只用于诊断,不应依赖某个平台的错误常量。 * 所有缓冲区均只在调用期间使用,函数返回后本层不再持有调用方的内存。 */ #ifndef IEC104_NET_H #define IEC104_NET_H #include #include #ifdef __cplusplus extern "C" { #endif /* TCP内部拥有的数值句柄;0可以是有效句柄。 * TcpServer可按其公开契约借给应用事件循环注册,应用不得接管I/O、关闭或修改句柄属性。 * 使用整数类型承载平台句柄,使公共头文件无需包含SOCKET等系统类型。 * 是否无效只能与IEC104_NET_INVALID_SOCKET比较,不能用if (!handle)判断。 */ typedef uintptr_t IEC104_NetSocket_t; #define IEC104_NET_INVALID_SOCKET ((IEC104_NetSocket_t)UINTPTR_MAX) /* 必须按枚举值判断:OK为0,正数不统一表示成功或有数据。 * WOULD_BLOCK表示当前没有进度,通常等待下一次就绪;RETRY表示本次操作可重试。 * RETRY_LATER仅用于接入资源暂缺,须由调用方暂停接入并安排定时重试。 * 重试次数、收发预算及超时期限由调用方限制,不能在后端无限循环。 */ typedef enum { IEC104_NET_ERROR = -1, /* 最终失败,native_error保存平台错误码。 */ IEC104_NET_OK = 0, /* 操作完成;Wait的就绪标志可为0,表示未报告socket就绪。 */ IEC104_NET_WOULD_BLOCK, /* 暂不可接受连接/读写,保留原有状态后续再试。 */ IEC104_NET_RETRY, /* 本次被中断或单个待接入客户端失效,可有界重试。 */ IEC104_NET_EOF, /* 仅Recv使用:对端发送方向有序关闭。 */ IEC104_NET_RETRY_LATER /* 仅Accept使用:资源暂缺,不能立即循环重试。 */ } IEC104_NetResult_t; /* 一次收发的完整结果;把状态、字节数和平台错误分开,避免把EOF当成暂不可读。 */ typedef struct { IEC104_NetResult_t result; /* 调度依据;读取transferred前先判断此字段。 */ size_t transferred; /* OK时为本次实际读写字节数,其余结果恒为0。 */ int native_error; /* 平台诊断码,OK/EOF为0;上层按result决定调度。 */ } IEC104_NetIoResult_t; /* Accept交付的对端地址副本,平台sockaddr和网络字节序不越过Net边界。 * 当前监听仅支持IPv4;address不包含端口,port使用主机字节序。 */ typedef struct { char address[16]; /* NUL结尾数字IPv4,最长15字符。 */ uint16_t port; /* 客户端源端口,并非本地监听端口。 */ } IEC104_NetPeer_t; /* Wait的关注位和就绪位使用同一组掩码,可以按位或组合。 * 就绪只表示可以尝试操作,最终状态仍由Accept/Recv/Send的返回值确定。 */ #define IEC104_NET_EVENT_ACCEPT 1U /* 监听句柄可尝试接入客户端。 */ #define IEC104_NET_EVENT_READ 2U /* 客户端可尝试接收,也可能读到EOF或错误。 */ #define IEC104_NET_EVENT_WRITE 4U /* 客户端可尝试发送,不保证整段数据一次写完。 */ /** * 功能:取得本次网络使用所需的平台初始化资源。 * 输出参数:native_error可为NULL;成功写0,失败写平台错误码。 * 返回值:OK表示初始化成功;ERROR表示失败,此时无需为本次调用Cleanup。 * 说明:在创建socket前调用;每次成功Init均须配对一次Cleanup。 * 重复调用并非幂等操作,不能把多次成功Init只配对一次Cleanup。 */ extern IEC104_NetResult_t IEC104_Net_Init(int *native_error); /** * 功能:释放一次成功Init取得的平台初始化资源。 * 说明:调用前先关闭本次持有的全部socket;本函数不逐一管理调用方的句柄。 * 无返回值,也不负责清空TcpServer中的连接状态。 */ extern void IEC104_Net_Cleanup(void); /** * 功能:取得平台对应的“参数无效”诊断码,不执行网络操作。 * 返回值:当前后端的参数错误码,用于上层自身参数校验失败时填写诊断信息。 * 说明:避免TcpServer为记录错误而包含Windows等平台的系统错误常量。 */ extern int IEC104_Net_Invalid_Argument_Error(void); /** * 功能:创建、绑定并启动一个非阻塞IPv4 TCP监听socket。 * 输入参数:bind_address为有效的NUL结尾数字IPv4字符串,不进行域名解析。 * port使用主机字节序;为0时由系统分配可用端口。 * 输出参数:listener、bound_port必填,分别接收新监听句柄和实际端口。 * bound_port同样使用主机字节序;native_error可为NULL。 * 各输出存储区不得重叠,也不得覆盖输入字符串。 * 返回值:OK时将新句柄的所有权交给调用方;ERROR时回收本次创建的socket, * 并将有效输出指针指向的listener/bound_port置为INVALID_SOCKET/0。 * 说明:只用于创建新句柄,不会关闭listener原来保存的句柄;先处理旧资源再调用。 * 失败不撤销此前成功的Init,调用方仍须按生命周期执行Cleanup。 */ extern IEC104_NetResult_t IEC104_Net_Listen( const char *bind_address, uint16_t port, IEC104_NetSocket_t *listener, uint16_t *bound_port, int *native_error); /** * 功能:从非阻塞监听socket接入至多一个客户端,不在内部循环accept。 * 输入参数:listener为Listen成功交付的监听句柄。 * 输出参数:client、peer必填且不得重叠,OK时交付非阻塞且启用TCP_NODELAY的客户端及其IPv4地址/源端口; * native_error可为NULL。 * 返回值:OK表示接入成功,调用方负责关闭客户端;WOULD_BLOCK表示暂无待接入连接; * RETRY表示本次被中断、待接入客户端失效、非阻塞/TCP_NODELAY设置或地址转换失败; * RETRY_LATER表示接入资源暂缺,调用方应暂停关注监听就绪并定时重试; * ERROR表示参数无效或其他失败。非OK时有效client输出为INVALID_SOCKET,peer保持原值。 * 说明:新客户端设置或地址转换失败时,先关闭它再返回RETRY(资源暂缺为RETRY_LATER), * 监听句柄仍由调用方持有,后端本身不等待。 * client只接收新句柄,不会自动关闭其中的旧句柄;不得覆盖仍在使用的连接。 * 是否接受额外客户端及重试多少次,由TcpServer的连接策略和预算决定。 */ extern IEC104_NetResult_t IEC104_Net_Accept( IEC104_NetSocket_t listener, IEC104_NetSocket_t *client, IEC104_NetPeer_t *peer, int *native_error); /** * 功能:对已接入的非阻塞客户端执行至多一次同步recv。 * 输入参数:socket_handle为有效客户端句柄;data非NULL,指向可写缓冲区; * capacity为缓冲区容量,必须大于0,当前Windows后端还要求不大于INT_MAX。 * 输出参数:OK时将transferred个字节写入data,不追加字符串结束符。 * 返回值:OK表示收到数据;EOF表示对端发送方向有序关闭;WOULD_BLOCK表示暂不可读; * RETRY表示本次操作被中断;ERROR表示参数或socket错误。 * 非OK时transferred为0;OK/EOF时native_error为0,其余状态保留诊断码。 * 说明:TCP是字节流,一次接收不对应一个完整104报文;拆帧由上层负责。 * EOF不会自动关闭句柄,调用方仍可排空待发送数据;函数返回后不再借用data。 * WOULD_BLOCK/RETRY不代表数据进度,不能据此重新计算或延长原超时期限。 */ extern IEC104_NetIoResult_t IEC104_Net_Recv( IEC104_NetSocket_t socket_handle, void *data, size_t capacity); /* 只读取得当前内核接收队列的字节数,不等待、不消费输入、不包含后来到达的字节。 * 用于给跨调度轮次的续收设定有限边界;不是完整APDU数,也不表示连接仍存活。 * available必填,仅OK时写入;失败返回ERROR并保留平台诊断,由上层结束连接。 */ extern IEC104_NetResult_t IEC104_Net_Pending_Input( IEC104_NetSocket_t socket_handle, uint32_t *available, int *native_error); /** * 功能:对已接入的非阻塞客户端执行至多一次同步send。 * 输入参数:socket_handle为有效客户端句柄;data非NULL,指向待发送数据; * length为待发送长度,必须大于0,当前Windows后端还要求不大于INT_MAX。 * 返回值:OK时transferred表示本次被本机网络栈接受的字节数,可能小于length或为0; * WOULD_BLOCK表示暂不可写;RETRY表示本次被中断;ERROR表示参数或socket错误。 * 非OK时transferred为0;此接口不会返回EOF,写入0字节仍属于OK。 * 说明:只按transferred推进发送位置,未写入的后缀由调用方保留并择机继续发送。 * 函数返回后不再借用data;OK不代表对端应用收到数据或完成104协议确认。 * WOULD_BLOCK/RETRY以及OK但写入0字节都不应被视为发送进度。 * 调用方须限制连续无进展的立即重试,并安排延时恢复;不能仅依赖新的可写边沿。 */ extern IEC104_NetIoResult_t IEC104_Net_Send( IEC104_NetSocket_t socket_handle, const void *data, size_t length); /** * 功能:等待本轮关注的监听或客户端事件;空集合只作有限定时等待,不执行I/O。 * 输入参数:interest为上述事件位的组合,允许为0,不允许包含未知位。 * 关注ACCEPT时listener须有效;关注READ/WRITE时client须有效; * 未被关注的句柄可以为INVALID_SOCKET。 * timeout_ms为本次等待时长,单位毫秒;为0时只查询,空集合直接返回。 * UINT32_MAX仍为有限时长;后端须避开系统无限等待哨兵,必要时提前返回。 * 输出参数:ready_events必填,每次先清零;native_error可为NULL。 * 返回值:OK时ready_events给出就绪事件的位组合,0表示未报告就绪(包括纯定时等待); * RETRY表示等待被中断,ERROR表示参数或等待失败,两者就绪位均为0。 * 说明:最多调用一次平台等待;RETRY交由调用方按剩余期限重新调度,后端不无限重试。 * 等待可能提前结束,是否到期由调用方按单调时钟重新判断。 * 就绪后实际I/O仍可能暂不可读写、部分发送或遇到EOF,必须检查后续操作结果。 */ extern IEC104_NetResult_t IEC104_Net_Wait( IEC104_NetSocket_t listener, IEC104_NetSocket_t client, uint32_t interest, uint32_t timeout_ms, uint32_t *ready_events, int *native_error); /** * 功能:关闭一个监听或客户端句柄,不调用Cleanup或业务回调。 * 输入参数:socket_handle为要关闭的句柄;INVALID_SOCKET视为已关闭。 * 输出参数:native_error可为NULL,失败时保留关闭操作的诊断码。 * 返回值:OK表示关闭成功或传入无效哨兵值;ERROR表示关闭操作失败。 * 说明:句柄按值传入,本函数无法修改调用方字段;调用方需维护自己的句柄状态。 * 成功关闭后应将保存的句柄置为INVALID_SOCKET,避免重复关闭已被系统复用的值。 */ extern IEC104_NetResult_t IEC104_Net_Close( IEC104_NetSocket_t socket_handle, int *native_error); /** * 功能:读取平台单调时钟,供连接超时和收发期限计算使用。 * 返回值:64位单调毫秒计数,不是UTC时间戳,也不用于显示日期;0及连续读取相等值有效。 * 说明:与日历时间及校时无关;同一会话的时间差和期限必须使用同一时钟来源。 * 有效运行期间不得倒退、复位或回绕。 * 若底层仅提供32位节拍,须通过回绕计数或等效机制扩展为64位, * 再按节拍频率换算为毫秒;不得仅作uint64_t强制转换。 * 扩展机制必须保证不漏记回绕,不能依赖本函数被频繁调用。 * 扩展计数的更新与读取须正确同步,取得高低位一致的快照, * 防止节拍中断或其他并发更新造成读值错误;这不构成从中断上下文调用本接口的保证。 * 本函数只读取时钟,不创建定时器,也不触发协议超时处理。 */ extern uint64_t IEC104_Net_Now_Ms(void); #ifdef __cplusplus } #endif #endif /* IEC104_NET_H */