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:
1 parent
96100663e7
commit
734851329f
11 files changed
+1147
-23
No files matched your search
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user