Files

93 lines
3.0 KiB
C
Raw Permalink Normal View History

2026-09-08 10:35:16 +08:00
#include <c_TcpServer.h>
#include "c_SocketStream.h"
c_err_t c_TcpServer_Init(c_TcpServer_t* self, int family, uint16_t port, int backlog, c_Allocator_t* allocator) {
if (!self) return C_ERR_PARAM;
self->allocator = allocator ? *allocator : c_DefaultAllocator;
self->listen_sock = C_INVALID_SOCKET;
self->reactor = NULL;
self->is_running = C_FALSE;
/* 2. Instantiate the listening socket descriptor using the explicit parameter map */
self->listen_sock = socket(family, SOCK_STREAM, IPPROTO_IP);
if (self->listen_sock == C_INVALID_SOCKET) return C_ERR_FAIL;
/* 3. Enable SO_REUSEADDR to avoid socket bind crashes on rapid restarts */
c_Socket_SetReuseAddr(self->listen_sock, true);
/* 4. Configure dual-stack sockaddr union variants based on the address family */
c_SockAddr_t bind_addr;
if (c_SockAddr_Init(&bind_addr, family, 0, port)!=C_ERR_OK) {
c_TcpServer_Destroy(self);
return C_ERR_FAIL;
}
if (family == AF_INET6) {
/* Optional optimization: allow dual-stack IPv4 mapping on the IPv6 socket if supported */
c_Socket_SetIPV6Only(self->listen_sock, false);
}
/* 6. Bind the structural endpoint socket down to the network stack */
if (c_SocketUtil_BindWithSockAddr(self->listen_sock, &bind_addr) != C_ERR_OK) {
c_TcpServer_Destroy(self);
return C_ERR_FAIL;
}
/* 7. Switch the socket handle to listener mode with a generous backlog size */
if (listen(self->listen_sock, backlog) == C_SOCKET_ERROR) {
c_TcpServer_Destroy(self);
return C_ERR_FAIL;
}
self->is_running = C_TRUE;
return C_SUCCESS;
}
c_err_t c_TcpServer_SetReactor(c_TcpServer_t* self, c_TcpReactor_t* reactor) {
if (!self || !reactor) return C_ERR_PARAM;
self->reactor = reactor;
/* Automatically add our master listener socket to watch for read/inbound events */
return c_TcpReactor_Add(self->reactor, self->listen_sock, 1);
}
c_err_t c_TcpServer_Run(c_TcpServer_t* self, long timeout_ms, void* args) {
if (!self || !self->reactor || !self->is_running) return C_ERR_PARAM;
return c_TcpReactor_Poll(self->reactor, timeout_ms, self, args);
}
void c_TcpServer_Destroy(c_TcpServer_t* self) {
if (!self) return;
self->is_running = C_FALSE;
if (self->reactor) {
c_TcpReactor_Destroy(self->reactor);
self->reactor = NULL;
}
if (self->listen_sock != C_INVALID_SOCKET) {
c_Socket_Close(self->listen_sock);
}
}
const char* c_TcpServer_GetErrorString(int code) {
switch (code) {
case C_ERR_OK: {
return "OK";
}
case C_TCPSERVER_ERR_ON_ACCEPT: {
return "ACCEPT";
}
case C_TCPSERVER_ERR_ON_POLL: {
return "POLL";
}
case C_TCPSERVER_ERR_ON_POLLERR: {
return "POLLERR";
}
case C_TCPSERVER_ERR_ON_RECV: {
return "RECV";
}
default: {
return "UNKNOWN";
}
}
}