diff --git a/src/chat/chat_event.h b/src/chat/chat_event.h index ee5069a9..a6f0fec4 100644 --- a/src/chat/chat_event.h +++ b/src/chat/chat_event.h @@ -30,6 +30,8 @@ extern "C" { #define CHAT_EVT_DB_READY 9 /* data: none */ #define CHAT_EVT_STATUS_REFRESH 10 /* data: status text */ #define CHAT_EVT_KEYS_GENERATED 11 /* [pub_hex:64] */ +#define CHAT_EVT_SERVICE_STARTED 12 /* data: none */ +#define CHAT_EVT_SERVICE_STOPPED 13 /* data: none */ typedef void (*chat_event_handler_fn)(int type, const uint8_t* data, int len); diff --git a/tools/chatgui-android/AGENTS.md b/tools/chatgui-android/AGENTS.md index 42a33f57..0f6ed770 100644 --- a/tools/chatgui-android/AGENTS.md +++ b/tools/chatgui-android/AGENTS.md @@ -109,6 +109,24 @@ nc localhost 9999 > {"id":2,"cmd":"join","link":"utun://..."} ``` +## Логирование через logreceiver (только Android) + +Debug-сообщения с телефона дублируются через UDP на приёмник `tools/logreceiver/`. + +Запуск (всегда через скрипт, до старта utun): +```bash +tools/logreceiver/logreceiver_restart.sh +``` +Скрипт ротирует логи (история 10 запусков: `.log` → `.log.1` → … → `.log.10`), +убивает старый демон и запускает новый на `0.0.0.0:9999`, вывод в `logreceiver_output.log`. +При каждом запуске логи фиксируются в истории и начинается свежий лог. + +В конфиге Android: +```ini +log_udp_ip = +log_udp_port = 9999 +``` + ## Ключевые файлы для доработок ### C-слой diff --git a/tools/chatgui-android/jni_bridge/android_jni_bridge.c b/tools/chatgui-android/jni_bridge/android_jni_bridge.c index ffce966b..4ad2c74a 100644 --- a/tools/chatgui-android/jni_bridge/android_jni_bridge.c +++ b/tools/chatgui-android/jni_bridge/android_jni_bridge.c @@ -358,6 +358,7 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeStop( JNIEnv* env, jobject thiz) { (void)env; (void)thiz; utun_bridge_destroy(); + udp_log_stop(); } /* ── nativeInit (legacy, just saves callbacks) ── */ @@ -441,8 +442,9 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeSetEventCallback( JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeDestroy( JNIEnv* env, jobject thiz) { (void)thiz; - udp_log_stop(); + udp_log_cancel_timer(); utun_bridge_destroy(); + udp_log_stop(); if (g_config_callback) { (*env)->DeleteGlobalRef(env, g_config_callback); g_config_callback = NULL; } if (g_log_callback) { (*env)->DeleteGlobalRef(env, g_log_callback); g_log_callback = NULL; } if (g_event_callback) { (*env)->DeleteGlobalRef(env, g_event_callback); g_event_callback = NULL; } diff --git a/tools/chatgui-android/jni_bridge/android_udp_log.c b/tools/chatgui-android/jni_bridge/android_udp_log.c index 45a19aab..268ae664 100644 --- a/tools/chatgui-android/jni_bridge/android_udp_log.c +++ b/tools/chatgui-android/jni_bridge/android_udp_log.c @@ -22,11 +22,13 @@ 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"); } @@ -63,6 +65,7 @@ void udp_trampoline(void* arg) { 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; @@ -90,11 +93,16 @@ void udp_log_write(const char* data, int len) { } } -void udp_log_stop(void) { +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; - g_udp_buf_len = 0; } diff --git a/tools/chatgui-android/jni_bridge/android_udp_log.h b/tools/chatgui-android/jni_bridge/android_udp_log.h index 00b52e39..0e7e5951 100644 --- a/tools/chatgui-android/jni_bridge/android_udp_log.h +++ b/tools/chatgui-android/jni_bridge/android_udp_log.h @@ -19,7 +19,10 @@ void udp_log_set_target(const char* ip, int port); * Thread-safe — call from any thread (bridge_debug_hook). */ void udp_log_write(const char* data, int len); -/* Stop sending, close socket, cancel timer. Call from any thread. */ +/* Cancel flush timer (call before uasync_destroy, while ua is alive). */ +void udp_log_cancel_timer(void); + +/* Flush buffer, close socket. Call after instance shutdown. */ void udp_log_stop(void); void udp_trampoline(void* arg); diff --git a/tools/chatgui-android/libutun_lite/instance_lite.c b/tools/chatgui-android/libutun_lite/instance_lite.c index 27adcb81..c8c3a217 100644 --- a/tools/chatgui-android/libutun_lite/instance_lite.c +++ b/tools/chatgui-android/libutun_lite/instance_lite.c @@ -175,6 +175,7 @@ static void* instance_thread(void* arg) { IL_LOGE("utun_instance_create_from_config failed"); uasync_destroy(g_ua, 0); g_ua = NULL; + u_report_unfreed_blocks(); g_running = 0; return NULL; } @@ -207,6 +208,7 @@ static void* instance_thread(void* arg) { g_inst = NULL; uasync_destroy(g_ua, 0); g_ua = NULL; + u_report_unfreed_blocks(); g_running = 0; return NULL; } @@ -223,12 +225,28 @@ static void* instance_thread(void* arg) { } g_running = 1; + chat_event_post(CHAT_EVT_SERVICE_STARTED, NULL, 0); while (!g_stop) { uasync_poll(g_ua, 100); } - IL_LOGI("poll loop exit"); + IL_LOGI("poll loop exit, cleaning up"); + + if (g_inst) { + utun_instance_destroy(g_inst); + g_inst = NULL; + } + if (g_ua) { + uasync_destroy(g_ua, 0); + g_ua = NULL; + } + u_report_unfreed_blocks(); + g_running = 0; + chat_event_post(CHAT_EVT_SERVICE_STOPPED, NULL, 0); + g_event_handler = NULL; + pthread_detach(pthread_self()); + IL_LOGI("cleanup complete"); return NULL; } @@ -272,27 +290,10 @@ int instance_lite_start(const char* config_text) { } void instance_lite_stop(void) { - if (!g_running && !g_inst) return; + if (!g_inst && !g_running) return; IL_LOGI("stopping..."); - g_stop = 1; if (g_ua) uasync_wakeup(g_ua); - pthread_join(g_thread, NULL); - - if (g_inst) { - etcp_router_bind(g_inst, ETCP_RT_ID_CHAT_SYNC, NULL); - chat_sync_destroy(g_inst); - chat_core_destroy(g_inst); - utun_instance_destroy(g_inst); - g_inst = NULL; - } - if (g_ua) { - uasync_destroy(g_ua, 0); - g_ua = NULL; - } - g_running = 0; - g_event_handler = NULL; - IL_LOGI("stopped"); } int instance_lite_is_running(void) {