diff --git a/tests/test_android_bridge.c b/tests/test_android_bridge.c index 79d2f4ba..4063382a 100644 --- a/tests/test_android_bridge.c +++ b/tests/test_android_bridge.c @@ -315,6 +315,10 @@ static int check_worker_requests(const char* directory) { REQUIRE(instance_lite_post(worker_payload_run, &payload, NULL, worker_payload_discard) == -1 && payload == -1); REQUIRE(!utun_bridge_clear_database(path)); char keys[1100]; snprintf(keys, sizeof(keys), "%s/keys.conf", path); REQUIRE(!test_unlink(keys)); + const char* folders[] = {"member_files/.uploads", "member_files", "dm_pending", "dm_media"}; + for (unsigned i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) { + snprintf(keys, sizeof(keys), "%s/%s", path, folders[i]); REQUIRE(!test_rmdir(keys)); + } REQUIRE(!test_rmdir(path)); printf("[PASS] worker requests: real worker read, nested call, stopped queue discard and waiter cancellation\n"); return 0; diff --git a/tools/chatgui-android/libutun_lite/instance_lite.c b/tools/chatgui-android/libutun_lite/instance_lite.c index 498a2a55..c8f1480a 100644 --- a/tools/chatgui-android/libutun_lite/instance_lite.c +++ b/tools/chatgui-android/libutun_lite/instance_lite.c @@ -7,7 +7,6 @@ * * UTUN выключен по умолчанию; [gui] utun_enabled=yes явно включает сервис при старте и рестарте. */ -#define _GNU_SOURCE 1 /* dladdr (Linux); no-op on Android/bionic */ #include "instance_lite.h" #include "utun_instance.h" #include "config_parser.h" @@ -42,9 +41,6 @@ #include #include #include -#include -#include -#include #include #include @@ -348,55 +344,6 @@ static void on_link_status_changed(struct ETCP_CONN* conn, struct ETCP_LINK* lin fire_local_sockets_event(); } -/* ── Crash handler ── */ - -static volatile int g_signal_caught = 0; -static volatile int g_signal_num = 0; - -struct crash_bt_state { void** frames; int count; int max; }; - -static _Unwind_Reason_Code crash_bt_cb(struct _Unwind_Context* ctx, void* arg) { - struct crash_bt_state* st = (struct crash_bt_state*)arg; - if (st->count < st->max) { - void* pc = (void*)_Unwind_GetIP(ctx); - if (pc) st->frames[st->count++] = pc; - return _URC_NO_REASON; - } - return _URC_END_OF_STACK; -} - -static void crash_signal_handler(int sig, siginfo_t* info, void* ctx) { - (void)ctx; - g_signal_caught = 1; g_signal_num = sig; - DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "CRASH signal=%d code=%d addr=%p thread still alive", sig, info->si_code, info->si_addr); - void* frames[64]; - struct crash_bt_state st = { frames, 0, 64 }; - _Unwind_Backtrace(crash_bt_cb, &st); - IL_LOGE("CRASH backtrace %d frames:", st.count); - for (int i = 0; i < st.count; i++) { - Dl_info dli; - if (dladdr(frames[i], &dli) && dli.dli_sname) { - IL_LOGE(" #%02d %p %s+%p (%s)", i, frames[i], dli.dli_sname, - (void*)((char*)frames[i] - (char*)dli.dli_saddr), - dli.dli_fname ? dli.dli_fname : "?"); - } else { - IL_LOGE(" #%02d %p (no symbol)", i, frames[i]); - } - } - signal(sig, SIG_DFL); - raise(sig); -} - -static void install_crash_handlers(void) { - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = crash_signal_handler; - sa.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &sa, NULL); - sigaction(SIGABRT, &sa, NULL); - sigaction(SIGBUS, &sa, NULL); -} - /* ── Thread function ── */ static void log_active_sockets(struct UTUN_INSTANCE* inst, const char* label); @@ -434,7 +381,6 @@ static void* instance_thread(void* arg) { if (!config) { IL_LOGE("parse_config_from_buf failed"); goto cleanup; } config->global.client_type = CLIENT_TYPE_MOBILE; /* Android — всегда мобильный узел (keepalive standby/normal) */ - install_crash_handlers(); if (ensure_keys(config)) { IL_LOGE("startup refused: Android identity is not saved"); free_config(config); @@ -799,8 +745,8 @@ static int request_restart(const char* new_config_text, int regenerate_keys) { return 0; } -void instance_lite_restart(const char* new_config_text) { - request_restart(new_config_text, 0); +int instance_lite_restart(const char* new_config_text) { + return request_restart(new_config_text, 0); } /* Принимает владение ненулевым task при любом результате. Все данные команды находятся в том же выделении @@ -932,74 +878,62 @@ static void update_sockets_trampoline(void* arg) { u_free(cfg_text); return; } + log_active_sockets(inst, "update OLD sockets"); struct utun_config* cfg = parse_config_from_buf(cfg_text, strlen(cfg_text), "android-update"); u_free(cfg_text); if (!cfg) { IL_LOGE("update_sockets: parse_config_from_buf failed"); return; } auto_socket_reload_config(inst, cfg); /* cfg владеет auto_socket: servers переносятся, остальное освобождается */ } -void instance_lite_update_sockets(const char* config_text) { - if (!config_text) return; - struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE); - struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE); - int running = __atomic_load_n(&g_running, __ATOMIC_ACQUIRE); - - /* Диагностика смены сети: какие сокеты/адреса были → какие будут (без полного рестарта). */ - log_active_sockets(inst, "update OLD sockets"); +int instance_lite_update_sockets(const char* config_text) { + if (!config_text) { IL_LOGE("update_sockets: config is NULL"); return -1; } log_config_servers(config_text, "update NEW config"); - - if (!ua || !inst || !running) { - IL_LOGE("update_sockets: instance not running (ua=%p inst=%p running=%d) — update dropped (no fallback restart)", - (void*)ua, (void*)inst, running); - return; - } char* copy = u_strdup(config_text); - if (!copy) { IL_LOGE("update_sockets: u_strdup failed"); return; } - uasync_post(ua, update_sockets_trampoline, copy); + if (!copy) { IL_LOGE("update_sockets: config allocation failed"); return -1; } + if (instance_lite_post(update_sockets_trampoline, copy, NULL, NULL)) { + IL_LOGE("update_sockets: core not ready, update rejected"); u_free(copy); return -1; + } + return 0; } /* ── Health check ping ── */ -static volatile int g_ping_id = 0; -static volatile int g_pong_id = 0; +static uint64_t g_ping_id; +static uint64_t g_pong_id; static void ping_trampoline(void* arg) { - (void)arg; - g_pong_id = g_ping_id; + __atomic_store_n(&g_pong_id, *(uint64_t*)arg, __ATOMIC_RELEASE); + u_free(arg); } void instance_lite_ping(void) { - struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE); - struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE); - if (!ua || !inst) return; - g_ping_id++; - uasync_post(ua, ping_trampoline, NULL); + if (!instance_lite_is_running()) return; + uint64_t* id = u_malloc(sizeof(*id)); + if (!id) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Android health ping allocation failed"); return; } + *id = __atomic_add_fetch(&g_ping_id, 1, __ATOMIC_ACQ_REL); + if (instance_lite_post(ping_trampoline, id, NULL, NULL)) u_free(id); } int instance_lite_is_responsive(void) { - struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE); - struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE); - if (!ua || !inst || !__atomic_load_n(&g_running, __ATOMIC_ACQUIRE)) return 0; - if (g_ping_id == 0) return 0; - return (g_pong_id == g_ping_id) ? 1 : 0; + uint64_t ping = __atomic_load_n(&g_ping_id, __ATOMIC_ACQUIRE); + return instance_lite_is_running() && ping && __atomic_load_n(&g_pong_id, __ATOMIC_ACQUIRE) == ping; +} + +static void collect_conn_list_run(void* unused) { + (void)unused; + chat_core_collect_conn_list_trampoline(instance_lite_get_instance()); } void instance_lite_collect_conn_list(void) { - struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE); - struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE); - if (!ua || !inst) return; - uasync_post(ua, chat_core_collect_conn_list_trampoline, inst); + if (instance_lite_post(collect_conn_list_run, NULL, NULL, NULL)) + DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Android connection list request rejected: core not ready"); } void instance_lite_collect_conn_metrics(uint64_t peer_node_id) { - struct UASYNC* ua = (struct UASYNC*)__atomic_load_n(&g_ua, __ATOMIC_ACQUIRE); - struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE); - if (!ua || !inst) return; struct chat_node_arg* arg = (struct chat_node_arg*)u_malloc(sizeof(struct chat_node_arg)); - if (!arg) return; - arg->inst = inst; + if (!arg) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Android connection metrics allocation failed"); return; } arg->node_id = peer_node_id; - uasync_post(ua, chat_core_collect_conn_metrics_trampoline, arg); + if (instance_lite_post(chat_core_collect_conn_metrics_trampoline, arg, &arg->inst, NULL)) u_free(arg); } int instance_lite_is_running(void) { diff --git a/tools/chatgui-android/libutun_lite/instance_lite.h b/tools/chatgui-android/libutun_lite/instance_lite.h index 318b8e24..83fdc882 100644 --- a/tools/chatgui-android/libutun_lite/instance_lite.h +++ b/tools/chatgui-android/libutun_lite/instance_lite.h @@ -110,12 +110,12 @@ int instance_lite_configure_radio(int64_t request_id, const int* values, instanc * При инициализации ставит запрос в очередь; при завершившемся worker делает join/start. * Обновление асинхронное; старые handles утрачивают силу. * Stop имеет приоритет перед ожидающим restart. Последний ещё не взятый worker запрос заменяет предыдущий. */ -void instance_lite_restart(const char* new_config_text); +int instance_lite_restart(const char* new_config_text); /* 0 — запрос принят, -1 — отказ с логом. */ /* Лёгкое обновление сокетов (auto_sockets=android): перечитывает [server] секции * из нового конфига и сверяет сокеты без полного рестарта. Posts to uasync thread. - * Если ядро не запущено — только логирует ошибку и дропает вызов. */ -void instance_lite_update_sockets(const char* config_text); + * 0 — копия принята worker, -1 — ошибка памяти/неготовое ядро с логом. */ +int instance_lite_update_sockets(const char* config_text); /* Поставить локальный ping в uasync (не сетевой). is_responsive=1 после исполнения последнего ping; * до первого ping/при остановке возвращает 0. Встроенного ожидания и проверки таймаута нет. */