chatgui-android: auto_sockets=android — сокеты из конфига, лёгкое обновление без полного рестарта

- auto_sockets три-режимный: off/system/android; android берёт сокеты из [server] конфига
- auto_socket_reload_config: reconcile сокетов (remove→create) по имени+addr:port, сохранение портов
- etcp_create_server_socket вынесен из init_sockets; stcp_server_list_find_by_sock
- instance_lite_update_sockets + JNI nativeUpdateSockets + NativeLib.updateSockets
- NetworkChangeMonitor: updateSockets вместо restart; порты сохраняются при смене сети
This commit is contained in:
evgeny committed 2026-09-09 17:34:46 +03:00
1 parent c474c37284
commit 5b31a765c2
15 files changed
+266 -46

No files matched your search

@@ -333,6 +333,7 @@ class ConfigProvider(private val context: Context) {
appendLine("db_path=$dbDir")
appendLine("db_sync_enabled=1")
appendLine("chatserver_enabled=1")
appendLine("auto_sockets=android")
appendLine()
for (srv in servers) appendServerSection(this, srv, false)
for (srv in commented) appendServerSection(this, srv, true)
@@ -44,6 +44,11 @@ object NativeLib {
return nativeRestart(configText)
}
/** Лёгкое обновление сокетов (auto_sockets=android) без полного рестарта ядра */
fun updateSockets(configText: String): Boolean {
return nativeUpdateSockets(configText)
}
fun isReady(): Boolean = nativeIsRunning()
fun getMyNodeId(): Long = nativeGetMyNodeId()
@@ -156,6 +161,7 @@ object NativeLib {
private external fun nativeRequestInviteCandidates(channelId: String)
private external fun nativeRequestInviteLink(channelId: String, targetNodeId: Long)
private external fun nativeRestart(configText: String): Boolean
private external fun nativeUpdateSockets(configText: String): Boolean
private external fun nativePing()
private external fun nativeIsResponsive(): Boolean
private external fun nativeIsRunning(): Boolean
@@ -69,9 +69,7 @@ object NetworkChangeMonitor {
val nowStr = now.joinToString(", ") { (n, ip) -> "$n=$ip" }
LogManager.addLog("INFO", "NET", "network change: [$prevStr] -> [$nowStr]")
NativeLib.notifyNetworkActive()
val path = provider.getString("db.path") ?: ""
val port = provider.getInt("control.port")
NativeLib.restart(path, port, provider.buildConfigText())
NativeLib.updateSockets(provider.buildConfigText())
} finally {
restarting = false
}
@@ -1014,6 +1014,11 @@ void utun_bridge_restart(const char* config_text) {
bridge_log(BLEV_ERROR, "bridge restart: instance not ready after 5s");
}
void utun_bridge_update_sockets(const char* config_text) {
bridge_log(BLEV_INFO, "bridge update_sockets: posting to instance");
instance_lite_update_sockets(config_text);
}
void utun_bridge_ping(void) {
instance_lite_ping();
}
@@ -1519,6 +1524,17 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeRestart(
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeUpdateSockets(
JNIEnv* env, jobject thiz, jstring configText) {
(void)thiz;
if (!configText) return JNI_FALSE;
const char* cfg = (*env)->GetStringUTFChars(env, configText, NULL);
if (!cfg) return JNI_FALSE;
utun_bridge_update_sockets(cfg);
(*env)->ReleaseStringUTFChars(env, configText, cfg);
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeIsResponsive(
JNIEnv* env, jobject thiz) {
(void)env; (void)thiz;
@@ -70,6 +70,10 @@ uint64_t utun_bridge_get_my_node_id(void);
void utun_bridge_restart(const char* config_text);
/* ── Лёгкое обновление сокетов (auto_sockets=android) ── */
void utun_bridge_update_sockets(const char* config_text);
/* ── Health check ── */
void utun_bridge_ping(void);
@@ -24,6 +24,7 @@
#include "debug_config.h"
#include "transport_layer/etcp_connections.h"
#include "transport_layer/etcp.h"
#include "transport_layer/auto_socket.h"
#include "../jni_bridge/android_udp_log.h"
#include "../jni_bridge/android_jni_bridge.h"
#include "standby.h"
@@ -499,9 +500,9 @@ void instance_lite_stop(void) {
g_thread_exited = 0;
}
/* Логирует текущие активные сокеты (имя=ip:port(протокол)) — состояние ДО рестарта. */
/* Логирует текущие активные сокеты (имя=ip:port(протокол)) — состояние ДО изменения. */
static void log_active_sockets(struct UTUN_INSTANCE* inst, const char* label) {
if (!inst) { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "restart: %s: (no instance)", label); return; }
if (!inst) { DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "%s: (no instance)", label); return; }
char buf[768] = "";
int off = 0;
for (struct ETCP_SOCKET* s = inst->etcp_sockets; s; s = s->next) {
@@ -511,10 +512,10 @@ static void log_active_sockets(struct UTUN_INSTANCE* inst, const char* label) {
off += snprintf(buf + off, sizeof(buf) - (size_t)off, " %s=%s(%s)",
s->name, addr, s->is_tcp ? "TCP" : "UDP");
}
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "restart: %s:%s", label, buf[0] ? buf : " (none)");
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "%s:%s", label, buf[0] ? buf : " (none)");
}
/* Логирует [server:...]/addr= секции нового конфига — состояние ПОСЛЕ рестарта. */
/* Логирует [server:...]/addr= секции нового конфига — состояние ПОСЛЕ изменения. */
static void log_config_servers(const char* cfg, const char* label) {
char buf[768] = "";
int off = 0;
@@ -539,7 +540,7 @@ static void log_config_servers(const char* cfg, const char* label) {
while (*p && *p != '\n') p++;
if (*p == '\n') p++;
}
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "restart: %s:%s", label, buf[0] ? buf : " (none)");
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "%s:%s", label, buf[0] ? buf : " (none)");
}
void instance_lite_restart(const char* new_config_text) {
@@ -549,8 +550,8 @@ void instance_lite_restart(const char* new_config_text) {
int running = __atomic_load_n(&g_running, __ATOMIC_ACQUIRE);
/* Диагностика смены сети: какие сокеты/адреса были → какие будут */
log_active_sockets(inst, "OLD sockets");
log_config_servers(new_config_text, "NEW config");
log_active_sockets(inst, "restart OLD sockets");
log_config_servers(new_config_text, "restart NEW config");
if (!ua || !inst || !running) {
IL_LOGI("restart: instance dead, doing hard restart via stop+start");
@@ -568,6 +569,42 @@ void instance_lite_restart(const char* new_config_text) {
uasync_wakeup(ua);
}
/* ── Лёгкое обновление сокетов (auto_sockets=android) ── */
static void update_sockets_trampoline(void* arg) {
char* cfg_text = (char*)arg;
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)__atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
if (!inst) {
IL_LOGE("update_sockets: instance gone in trampoline — dropping update");
u_free(cfg_text);
return;
}
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");
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);
}
/* ── Health check ping ── */
static volatile int g_ping_id = 0;
@@ -45,6 +45,11 @@ void instance_lite_regenerate_keys(void);
* Posts to uasync thread — restart happens asynchronously. */
void instance_lite_restart(const char* new_config_text);
/* Лёгкое обновление сокетов (auto_sockets=android): перечитывает [server] секции
* из нового конфига и сверяет сокеты без полного рестарта. Posts to uasync thread.
* Если ядро не запущено — только логирует ошибку и дропает вызов. */
void instance_lite_update_sockets(const char* config_text);
/* Health check: posts a ping to uasync, returns responsiveness after delay */
void instance_lite_ping(void);
int instance_lite_is_responsive(void);