/* * android_udp_log.c — non-blocking UDP log sender for Android * * Called ONLY from uasync worker thread (bridge_debug_hook). * No mutex needed. Flushes at 16KB threshold or via uasync timer. */ #include "android_udp_log.h" #include "../libutun_lite/instance_lite.h" #include "../../../lib/u_async.h" #include #include #include #include #include #include #include #define UDP_BUF_SIZE 65536 #define UDP_FLUSH_BYTES 16384 #define UDP_FLUSH_TB 2000 /* 200ms in uasync timebase (0.1ms units) */ static int g_udp_fd = -1; static struct sockaddr_in g_udp_addr; static int g_udp_has_addr = 0; static int g_udp_stopping = 0; static char g_udp_buf[UDP_BUF_SIZE]; static int g_udp_buf_len = 0; static void* g_udp_timer = NULL; static void udp_reschedule_timer(void) { if (g_udp_stopping) return; struct UASYNC* ua = instance_lite_get_uasync(); if (ua) g_udp_timer = uasync_set_timeout(ua, UDP_FLUSH_TB, NULL, udp_trampoline, "udp_log_flush"); } static void udp_open_socket(void) { if (g_udp_fd >= 0 || !g_udp_has_addr) return; g_udp_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); if (g_udp_fd < 0) return; if (connect(g_udp_fd, (struct sockaddr*)&g_udp_addr, sizeof(g_udp_addr)) < 0) { close(g_udp_fd); g_udp_fd = -1; return; } udp_reschedule_timer(); } static void udp_do_send(const char* data, int len) { if (g_udp_fd < 0) { udp_open_socket(); if (g_udp_fd < 0) return; } ssize_t sent = send(g_udp_fd, data, len, MSG_DONTWAIT); (void)sent; if (sent < 0 && (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH)) { close(g_udp_fd); g_udp_fd = -1; } } void udp_trampoline(void* arg) { (void)arg; if (g_udp_buf_len > 0) { udp_do_send(g_udp_buf, g_udp_buf_len); g_udp_buf_len = 0; } g_udp_timer = NULL; if (g_udp_fd >= 0) udp_reschedule_timer(); } void udp_log_set_target(const char* ip, int port) { g_udp_buf_len = 0; g_udp_stopping = 0; if (ip && port > 0) { memset(&g_udp_addr, 0, sizeof(g_udp_addr)); g_udp_addr.sin_family = AF_INET; g_udp_addr.sin_port = htons((unsigned short)port); g_udp_has_addr = (inet_pton(AF_INET, ip, &g_udp_addr.sin_addr) == 1); } else { g_udp_has_addr = 0; } } void udp_log_write(const char* data, int len) { if (!data || len <= 0 || !g_udp_has_addr) return; if (g_udp_fd < 0) udp_open_socket(); if (g_udp_buf_len + len > UDP_BUF_SIZE) { if (g_udp_buf_len > 0) { udp_do_send(g_udp_buf, g_udp_buf_len); g_udp_buf_len = 0; } if (len > UDP_BUF_SIZE) return; } memcpy(g_udp_buf + g_udp_buf_len, data, len); g_udp_buf_len += len; if (g_udp_buf_len >= UDP_FLUSH_BYTES) { udp_do_send(g_udp_buf, g_udp_buf_len); g_udp_buf_len = 0; } } void udp_log_cancel_timer(void) { g_udp_stopping = 1; struct UASYNC* ua = instance_lite_get_uasync(); if (ua && g_udp_timer) uasync_cancel_timeout(ua, g_udp_timer); g_udp_timer = NULL; } void udp_log_stop(void) { g_udp_stopping = 1; if (g_udp_buf_len > 0) { udp_do_send(g_udp_buf, g_udp_buf_len); g_udp_buf_len = 0; } if (g_udp_fd >= 0) { close(g_udp_fd); g_udp_fd = -1; } g_udp_has_addr = 0; }