Control: Add monitoring server with ETCP protocol support

- Implement control_server.c/h for monitoring and management
- Add Windows-compatible uasync_poll using select() instead of WSAPoll
- Fix Wintun adapter creation to open existing adapters first
- Add debug category for control server operations
- Update build files to include control server in compilation
- Add test_control_server to test suite
This commit is contained in:
jeka committed 2026-02-19 01:24:42 +03:00
1 parent 96100663e7
commit 734851329f
11 files changed
+1147 -23

No files matched your search

+1
View File
@@ -50,6 +50,7 @@ typedef uint64_t debug_category_t;
#define DEBUG_CATEGORY_NORMALIZER ((debug_category_t)1 << 11) // packet normalizer
#define DEBUG_CATEGORY_BGP ((debug_category_t)1 << 12) // BGP route exchange
#define DEBUG_CATEGORY_SOCKET ((debug_category_t)1 << 13) // Socket operations
#define DEBUG_CATEGORY_CONTROL ((debug_category_t)1 << 14) // Control/monitoring server
#define DEBUG_CATEGORY_ALL ((debug_category_t)0xFFFFFFFFFFFFFFFFULL)
/* Debug configuration structure */
+103 -15
View File
@@ -788,6 +788,107 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
return;
}
#ifdef _WIN32
// On Windows, use select() instead of WSAPoll to avoid issues with accepted sockets
fd_set read_fds, write_fds, except_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
SOCKET max_fd = 0;
// Add all active sockets to fd_sets
for (int i = 0; i < ua->sockets->count; i++) {
int idx = ua->sockets->active_indices[i];
struct socket_node* node = &ua->sockets->sockets[idx];
if (!node->active) continue;
SOCKET s;
if (node->type == SOCKET_NODE_TYPE_SOCK) {
s = node->sock;
} else {
s = (SOCKET)node->fd;
}
if (node->type == SOCKET_NODE_TYPE_SOCK) {
if (node->read_cbk_sock) FD_SET(s, &read_fds);
if (node->write_cbk_sock) FD_SET(s, &write_fds);
} else {
if (node->read_cbk) FD_SET(s, &read_fds);
if (node->write_cbk) FD_SET(s, &write_fds);
}
if (node->except_cbk) FD_SET(s, &except_fds);
if (s > max_fd) max_fd = s;
}
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
int ret = select((int)max_fd + 1, &read_fds, &write_fds, &except_fds, &tv);
if (ret < 0) {
int err = WSAGetLastError();
if (err != WSAEINTR) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "select failed: %d", err);
}
return;
}
if (ret > 0) {
for (int i = 0; i < ua->sockets->count; i++) {
int idx = ua->sockets->active_indices[i];
struct socket_node* node = &ua->sockets->sockets[idx];
if (!node->active) continue;
SOCKET s;
if (node->type == SOCKET_NODE_TYPE_SOCK) {
s = node->sock;
} else {
s = (SOCKET)node->fd;
}
int has_read = FD_ISSET(s, &read_fds);
int has_write = FD_ISSET(s, &write_fds);
int has_except = FD_ISSET(s, &except_fds);
if (!has_read && !has_write && !has_except) continue;
if (has_except) {
if (node->except_cbk) {
node->except_cbk(node->fd, node->user_data);
}
}
if (has_read) {
if (node->type == SOCKET_NODE_TYPE_SOCK) {
if (node->read_cbk_sock) {
node->read_cbk_sock(node->sock, node->user_data);
}
} else {
if (node->read_cbk) {
node->read_cbk(node->fd, node->user_data);
}
}
}
if (has_write) {
if (node->type == SOCKET_NODE_TYPE_SOCK) {
if (node->write_cbk_sock) {
node->write_cbk_sock(node->sock, node->user_data);
}
} else {
if (node->write_cbk) {
node->write_cbk(node->fd, node->user_data);
}
}
}
}
}
#else
// On non-Windows, use poll()
// Rebuild poll_fds if dirty or not allocated
if (ua->poll_fds_dirty || !ua->poll_fds) {
rebuild_poll_fds(ua);
@@ -798,21 +899,12 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
rebuild_poll_fds(ua);
}
/* Call poll with cached fds */
int ret = poll(ua->poll_fds, ua->poll_fds_count, timeout_ms);
if (ret < 0) {
#ifdef _WIN32
int err = WSAGetLastError();
if (err == WSAEINTR) {
return;
}
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "WSAPoll failed: %d", err);
#else
if (errno == EINTR) {
return;
}
perror("poll");
#endif
return;
}
@@ -832,12 +924,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
/* Socket event - lookup by fd */
struct socket_node* node = socket_array_get(ua->sockets, ua->poll_fds[i].fd);
if (!node) { // Try by socket_t (in case this is a socket)
socket_t lookup_sock;
#ifdef _WIN32
lookup_sock = (socket_t)(intptr_t)ua->poll_fds[i].fd;
#else
lookup_sock = ua->poll_fds[i].fd;
#endif
socket_t lookup_sock = ua->poll_fds[i].fd;
node = socket_array_get_by_sock(ua->sockets, lookup_sock);
}
if (!node) continue; // Socket may have been removed
@@ -884,6 +971,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
}
}
}
#endif
/* Process timeouts that may have expired during poll or socket processing */
process_timeouts(ua);