Сохрани накопленные исправления аудио, async и диагностики
This commit is contained in:
1 parent
b1e3193899
commit
bdcf8b5634
59 files changed
+4611
-1441
No files matched your search
@@ -82,10 +82,13 @@ object TelecomCallManager {
|
||||
val tm = telecomManager() ?: return false
|
||||
val handle = phoneAccountHandle ?: return false
|
||||
val uri = Uri.fromParts("node", "0x%016x".format(peerNodeId), null)
|
||||
val extras = Bundle().apply {
|
||||
val callExtras = Bundle().apply {
|
||||
putLong(EXTRA_CALL_ID, callId)
|
||||
putLong(EXTRA_PEER_NODE_ID, peerNodeId)
|
||||
putString(EXTRA_DISPLAY_NAME, displayName)
|
||||
}
|
||||
val extras = Bundle().apply {
|
||||
putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras)
|
||||
putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, handle)
|
||||
}
|
||||
return try {
|
||||
|
||||
@@ -47,11 +47,17 @@ class UtunConnectionService : ConnectionService() {
|
||||
}
|
||||
|
||||
private fun parseRequest(request: ConnectionRequest?): Triple<Long, Long, String>? {
|
||||
val extras = request?.extras ?: return null
|
||||
val extras = request?.extras ?: run {
|
||||
LogManager.addLog("WARN", "UtunConnSvc", "connection request has no extras")
|
||||
return null
|
||||
}
|
||||
val callId = extras.getLong(TelecomCallManager.EXTRA_CALL_ID, 0L)
|
||||
val peer = extras.getLong(TelecomCallManager.EXTRA_PEER_NODE_ID, 0L)
|
||||
val name = extras.getString(TelecomCallManager.EXTRA_DISPLAY_NAME) ?: ""
|
||||
if (callId == 0L) return null
|
||||
if (callId == 0L) {
|
||||
LogManager.addLog("WARN", "UtunConnSvc", "connection request missing call ID; keys=${extras.keySet()}")
|
||||
return null
|
||||
}
|
||||
return Triple(callId, peer, name)
|
||||
}
|
||||
}
|
||||
@@ -98,14 +98,17 @@ static void bridge_log(int level, const char* fmt, ...) {
|
||||
}
|
||||
|
||||
static void bridge_debug_hook(int level, const char* category, const char* message) {
|
||||
/* DEBUG_*: ERROR=1..TRACE=5; bridge/Kotlin: TRACE=0..ERROR=4. */
|
||||
int bridge_level = level >= DEBUG_LEVEL_ERROR && level <= DEBUG_LEVEL_TRACE ? DEBUG_LEVEL_TRACE - level : BLEV_DEBUG;
|
||||
#ifdef __ANDROID__
|
||||
__android_log_print(blevel_to_android(level), LOG_TAG, "[%s] %s",
|
||||
__android_log_print(blevel_to_android(bridge_level), LOG_TAG, "[%s] %s",
|
||||
category ? category : "?", message ? message : "");
|
||||
#else
|
||||
fprintf(stderr, "[%s] %s\n", category ? category : "?", message ? message : "");
|
||||
#endif
|
||||
udp_log_write(message, (int)strlen(message));
|
||||
if (g_on_log) g_on_log(level, category, message);
|
||||
if (level == DEBUG_LEVEL_ERROR) udp_log_flush();
|
||||
if (g_on_log) g_on_log(bridge_level, category, message);
|
||||
}
|
||||
|
||||
static utun_config_string_fn g_cfg_string = NULL;
|
||||
@@ -1838,7 +1841,6 @@ 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_cancel_timer();
|
||||
utun_bridge_destroy();
|
||||
udp_log_stop();
|
||||
if (g_config_callback) { (*env)->DeleteGlobalRef(env, g_config_callback); g_config_callback = NULL; }
|
||||
|
||||
@@ -1,137 +1,177 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* Android UDP-лог: общий буфер под mutex; таймер принадлежит только uasync-потоку.
|
||||
* ULOG не проходит через debug hook, поэтому ошибки отправки не вызывают рекурсию. */
|
||||
#include "android_udp_log.h"
|
||||
#include "../libutun_lite/instance_lite.h"
|
||||
#include "../../../lib/u_async.h"
|
||||
#include "../../../lib/platform_compat.h"
|
||||
#include "../../../lib/socket_compat.h"
|
||||
#include "../../../lib/mem.h"
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define UDP_BUF_SIZE 65536
|
||||
#define UDP_BUF_SIZE 65507 /* Максимальный UDP payload для IPv4. */
|
||||
#define UDP_FLUSH_BYTES 16384
|
||||
#define UDP_FLUSH_TB 2000 /* 200ms in uasync timebase (0.1ms units) */
|
||||
#define UDP_FLUSH_TB 2000
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define ULOG(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "utun-udplog", fmt, ##__VA_ARGS__)
|
||||
#define ULOG(fmt, ...) __android_log_print(ANDROID_LOG_INFO, "utun-udplog", fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ULOG(fmt, ...) fprintf(stderr, "utun-udplog: " fmt "\n", ##__VA_ARGS__)
|
||||
#define ULOG(fmt, ...) fprintf(stderr, "utun-udplog: " fmt "\n", ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static int g_udp_fd = -1;
|
||||
static pthread_mutex_t g_udp_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct UASYNC* g_udp_ua;
|
||||
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 int g_udp_sent_first = 0;
|
||||
static int64_t g_udp_total_sent = 0;
|
||||
static int g_udp_send_errors = 0;
|
||||
|
||||
static void udp_reschedule_timer(void) {
|
||||
if (g_udp_stopping) return;
|
||||
if (g_udp_timer) 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 = (int)socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||
if (g_udp_fd < 0) { ULOG("socket() failed: %s (errno=%d)", strerror(errno), errno); return; }
|
||||
if (connect(g_udp_fd, (struct sockaddr*)&g_udp_addr, sizeof(g_udp_addr)) < 0) {
|
||||
ULOG("connect() to %s:%d failed: %s (errno=%d)",
|
||||
inet_ntoa(g_udp_addr.sin_addr), (int)ntohs(g_udp_addr.sin_port), strerror(errno), errno);
|
||||
close(g_udp_fd); g_udp_fd = -1; return;
|
||||
}
|
||||
ULOG("socket opened fd=%d -> %s:%d", g_udp_fd,
|
||||
inet_ntoa(g_udp_addr.sin_addr), (int)ntohs(g_udp_addr.sin_port));
|
||||
}
|
||||
static int g_udp_has_addr;
|
||||
static int g_udp_stopping;
|
||||
static char g_udp_buf[UDP_BUF_SIZE];
|
||||
static int g_udp_buf_len;
|
||||
static int g_udp_sent_first;
|
||||
static int64_t g_udp_total_sent;
|
||||
static unsigned g_udp_send_errors;
|
||||
/* Только uasync-поток читает и меняет handle. JNI и log hook его не трогают. */
|
||||
static void* g_udp_timer;
|
||||
|
||||
/* Вызывается под g_udp_mutex; все операции сокета неблокирующие. */
|
||||
static void udp_do_send(const char* data, int len) {
|
||||
if (g_udp_fd < 0) { udp_open_socket(); if (g_udp_fd < 0) return; }
|
||||
if (g_udp_fd < 0) {
|
||||
g_udp_fd = (int)socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||
if (g_udp_fd < 0) { ULOG("socket failed: %s (errno=%d)", strerror(errno), errno); return; }
|
||||
if (connect(g_udp_fd, (struct sockaddr*)&g_udp_addr, sizeof(g_udp_addr)) < 0) {
|
||||
ULOG("connect failed: %s (errno=%d)", strerror(errno), errno);
|
||||
close(g_udp_fd); g_udp_fd = -1; return;
|
||||
}
|
||||
}
|
||||
ssize_t sent = send(g_udp_fd, data, len, MSG_DONTWAIT);
|
||||
if (sent >= 0) {
|
||||
if (sent == len) {
|
||||
g_udp_total_sent += sent;
|
||||
if (!g_udp_sent_first) { ULOG("first send OK: %zd bytes, total=%lld", sent, (long long)g_udp_total_sent); g_udp_sent_first = 1; }
|
||||
if (!g_udp_sent_first) { ULOG("first send OK: %zd bytes", sent); g_udp_sent_first = 1; }
|
||||
return;
|
||||
}
|
||||
int send_errno = sent < 0 ? errno : 0;
|
||||
g_udp_send_errors++;
|
||||
if (g_udp_send_errors <= 3 || g_udp_send_errors % 100 == 0)
|
||||
ULOG("send() error #%d: %s (errno=%d)", g_udp_send_errors, strerror(errno), errno);
|
||||
if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH) {
|
||||
close(g_udp_fd);
|
||||
g_udp_fd = -1;
|
||||
ULOG("send error #%u: sent=%zd expected=%d error=%s (errno=%d)",
|
||||
g_udp_send_errors, sent, len, send_errno ? strerror(send_errno) : "short datagram", send_errno);
|
||||
if (send_errno == ECONNREFUSED || send_errno == ENETUNREACH || send_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;
|
||||
}
|
||||
static void udp_flush_locked(void) {
|
||||
if (!g_udp_buf_len) return;
|
||||
udp_do_send(g_udp_buf, g_udp_buf_len);
|
||||
g_udp_buf_len = 0;
|
||||
}
|
||||
|
||||
static void udp_update_timer(void* arg);
|
||||
|
||||
static void udp_flush_timer(void* arg) {
|
||||
g_udp_timer = NULL;
|
||||
/* перевзводим только если остались неотправленные данные */
|
||||
if (g_udp_buf_len > 0) udp_reschedule_timer();
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (g_udp_ua == arg && g_udp_has_addr && !g_udp_stopping) udp_flush_locked();
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
udp_update_timer(arg);
|
||||
}
|
||||
|
||||
/* Только uasync-поток: attach или posted-команда смены адреса. Mutex отпускаем
|
||||
* до операций с таймером: их DEBUG_ERROR может снова вызвать udp_log_write. */
|
||||
static void udp_update_timer(void* arg) {
|
||||
struct UASYNC* ua = arg;
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
int owns = g_udp_ua == ua;
|
||||
int enabled = g_udp_has_addr && !g_udp_stopping;
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
if (!owns) return;
|
||||
if (!enabled) {
|
||||
if (g_udp_timer) uasync_cancel_timeout(ua, g_udp_timer);
|
||||
g_udp_timer = NULL;
|
||||
} else if (!g_udp_timer) {
|
||||
g_udp_timer = uasync_set_timeout(ua, UDP_FLUSH_TB, ua, udp_flush_timer, "udp_log_flush");
|
||||
if (!g_udp_timer) ULOG("flush timer allocation failed ua=%p", (void*)ua);
|
||||
}
|
||||
}
|
||||
|
||||
void udp_log_attach(struct UASYNC* ua) {
|
||||
if (!ua) { ULOG("attach rejected: ua=NULL"); return; }
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (g_udp_ua) {
|
||||
ULOG("attach rejected: owner=%p requested=%p", (void*)g_udp_ua, (void*)ua);
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
return;
|
||||
}
|
||||
g_udp_ua = ua;
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
udp_update_timer(ua);
|
||||
ULOG("attached ua=%p: flush timer owned by core thread", (void*)ua);
|
||||
}
|
||||
|
||||
void udp_log_detach(struct UASYNC* ua) {
|
||||
if (!ua) return;
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (g_udp_ua != ua) { pthread_mutex_unlock(&g_udp_mutex); return; }
|
||||
g_udp_ua = NULL; /* После этого ни один producer не может post в старый ua. */
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
if (g_udp_timer) uasync_cancel_timeout(ua, g_udp_timer);
|
||||
g_udp_timer = NULL;
|
||||
ULOG("detached ua=%p: flush timer cancelled", (void*)ua);
|
||||
}
|
||||
|
||||
void udp_log_set_target(const char* ip, int port) {
|
||||
g_udp_buf_len = 0;
|
||||
g_udp_stopping = 0;
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (g_udp_has_addr) udp_flush_locked();
|
||||
if (g_udp_fd >= 0) { close(g_udp_fd); g_udp_fd = -1; }
|
||||
memset(&g_udp_addr, 0, sizeof(g_udp_addr));
|
||||
g_udp_addr.sin_family = AF_INET;
|
||||
g_udp_has_addr = ip && port > 0 && port <= 65535 && inet_pton(AF_INET, ip, &g_udp_addr.sin_addr) == 1;
|
||||
g_udp_addr.sin_port = htons((unsigned short)(g_udp_has_addr ? port : 0));
|
||||
g_udp_stopping = !g_udp_has_addr;
|
||||
g_udp_sent_first = 0;
|
||||
g_udp_total_sent = 0;
|
||||
g_udp_send_errors = 0;
|
||||
if (g_udp_fd >= 0) { close(g_udp_fd); g_udp_fd = -1; }
|
||||
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);
|
||||
ULOG("set target %s:%d -> has_addr=%d", ip, port, g_udp_has_addr);
|
||||
} else {
|
||||
g_udp_has_addr = 0;
|
||||
ULOG("set target disabled (ip=%s port=%d)", ip ? ip : "null", port);
|
||||
if (g_udp_ua) {
|
||||
/* Маленький u_malloc не логирует; при отказе используем только ULOG.
|
||||
* post_reserved тоже не вызывает debug hook. Detach ждёт этот mutex. */
|
||||
struct posted_task* task = u_malloc(sizeof(*task));
|
||||
if (task) {
|
||||
task->callback = udp_update_timer;
|
||||
task->arg = g_udp_ua;
|
||||
uasync_post_reserved(g_udp_ua, task);
|
||||
} else ULOG("target changed but timer update allocation failed");
|
||||
}
|
||||
ULOG("target %s:%d enabled=%d", ip ? ip : "(null)", port, g_udp_has_addr);
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
}
|
||||
|
||||
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;
|
||||
if (!data || len <= 0) return;
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (!g_udp_has_addr || g_udp_stopping) { pthread_mutex_unlock(&g_udp_mutex); return; }
|
||||
if (len > UDP_BUF_SIZE) {
|
||||
ULOG("log dropped: %d bytes exceeds UDP payload limit %d", len, UDP_BUF_SIZE);
|
||||
} else {
|
||||
udp_reschedule_timer(); /* взвести flush для частичных данных */
|
||||
if (len > UDP_BUF_SIZE - g_udp_buf_len) udp_flush_locked();
|
||||
memcpy(g_udp_buf + g_udp_buf_len, data, len);
|
||||
g_udp_buf_len += len;
|
||||
if (g_udp_buf_len >= UDP_FLUSH_BYTES) udp_flush_locked();
|
||||
}
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
}
|
||||
|
||||
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_flush(void) {
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
if (g_udp_has_addr) udp_flush_locked();
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
}
|
||||
|
||||
void udp_log_stop(void) {
|
||||
pthread_mutex_lock(&g_udp_mutex);
|
||||
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; }
|
||||
ULOG("stop: total_sent=%lld bytes, errors=%d", (long long)g_udp_total_sent, g_udp_send_errors);
|
||||
if (g_udp_has_addr) udp_flush_locked();
|
||||
ULOG("stop: total_sent=%lld bytes errors=%u", (long long)g_udp_total_sent, g_udp_send_errors);
|
||||
if (g_udp_fd >= 0) { close(g_udp_fd); g_udp_fd = -1; }
|
||||
g_udp_has_addr = 0;
|
||||
pthread_mutex_unlock(&g_udp_mutex);
|
||||
}
|
||||
@@ -11,22 +11,25 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Configure target. ua may be NULL (delayed init, will retry on write).
|
||||
* Call from ANY thread. Posts timer setup to uasync event loop. */
|
||||
struct UASYNC;
|
||||
|
||||
/* Только поток ядра: attach после create, detach перед каждым destroy/restart. */
|
||||
void udp_log_attach(struct UASYNC* ua);
|
||||
void udp_log_detach(struct UASYNC* ua);
|
||||
|
||||
/* Любой поток. Смена адреса передаёт управление таймером в поток ядра. */
|
||||
void udp_log_set_target(const char* ip, int port);
|
||||
|
||||
/* Write log line to buffer. Non-blocking send if threshold reached.
|
||||
* Thread-safe — call from any thread (bridge_debug_hook). */
|
||||
void udp_log_write(const char* data, int len);
|
||||
|
||||
/* Cancel flush timer (call before uasync_destroy, while ua is alive). */
|
||||
void udp_log_cancel_timer(void);
|
||||
/* Любой поток: ошибки отправляем немедленно, до возможной остановки ядра. */
|
||||
void udp_log_flush(void);
|
||||
|
||||
/* Flush buffer, close socket. Call after instance shutdown. */
|
||||
void udp_log_stop(void);
|
||||
|
||||
void udp_trampoline(void* arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -276,9 +276,8 @@ static void* instance_thread(void* arg) {
|
||||
if (!g_ua) { IL_LOGE("uasync_create failed"); free_config(config); __atomic_store_n(&g_thread_running, 0, __ATOMIC_RELEASE); pthread_detach(pthread_self()); return NULL; }
|
||||
standby_init(g_ua);
|
||||
|
||||
if (config->global.log_udp_ip[0] && config->global.log_udp_port > 0) {
|
||||
udp_log_set_target(config->global.log_udp_ip, config->global.log_udp_port);
|
||||
}
|
||||
udp_log_set_target(config->global.log_udp_ip, config->global.log_udp_port);
|
||||
udp_log_attach(g_ua);
|
||||
|
||||
IL_LOGI("[EVT_DIAG] thread: about to set chat_event handler, g_event_handler=%p", (void*)g_event_handler);
|
||||
ensure_keys(config);
|
||||
@@ -288,6 +287,7 @@ static void* instance_thread(void* arg) {
|
||||
if (!g_inst) {
|
||||
IL_LOGE("utun_instance_create_from_config failed");
|
||||
standby_deinit();
|
||||
udp_log_detach(g_ua);
|
||||
uasync_destroy(g_ua, 0);
|
||||
g_ua = NULL;
|
||||
u_report_unfreed_blocks();
|
||||
@@ -305,6 +305,7 @@ static void* instance_thread(void* arg) {
|
||||
utun_instance_destroy(g_inst);
|
||||
g_inst = NULL;
|
||||
standby_deinit();
|
||||
udp_log_detach(g_ua);
|
||||
uasync_destroy(g_ua, 0);
|
||||
g_ua = NULL;
|
||||
u_report_unfreed_blocks();
|
||||
@@ -362,6 +363,7 @@ static void* instance_thread(void* arg) {
|
||||
uasync_print_resources(g_ua, "AFTER_DESTROY");
|
||||
u_report_unfreed_blocks();
|
||||
standby_deinit();
|
||||
udp_log_detach(g_ua);
|
||||
uasync_destroy(g_ua, 0);
|
||||
my_ua = NULL;
|
||||
g_ua = uasync_create();
|
||||
@@ -378,6 +380,8 @@ static void* instance_thread(void* arg) {
|
||||
u_free(cfg);
|
||||
if (!config) { IL_LOGE("poll exit: parse_config failed"); break; }
|
||||
config->global.client_type = CLIENT_TYPE_MOBILE; /* Android — всегда мобильный узел */
|
||||
udp_log_set_target(config->global.log_udp_ip, config->global.log_udp_port);
|
||||
udp_log_attach(g_ua);
|
||||
|
||||
g_inst = utun_instance_create_from_config(g_ua, config);
|
||||
my_inst = g_inst;
|
||||
@@ -414,6 +418,7 @@ static void* instance_thread(void* arg) {
|
||||
}
|
||||
if (my_ua) {
|
||||
standby_deinit();
|
||||
udp_log_detach(my_ua);
|
||||
uasync_destroy(my_ua, 0);
|
||||
g_ua = NULL;
|
||||
my_ua = NULL;
|
||||
@@ -428,7 +433,7 @@ static void* instance_thread(void* arg) {
|
||||
IL_LOGI("cleanup (stale thread gen=%d vs %d): destroying own inst=%p ua=%p to avoid fd leak",
|
||||
my_gen, g_generation, (void*)my_inst, (void*)my_ua);
|
||||
if (my_inst) { utun_instance_destroy(my_inst); my_inst = NULL; }
|
||||
if (my_ua) { uasync_destroy(my_ua, 0); my_ua = NULL; }
|
||||
if (my_ua) { udp_log_detach(my_ua); uasync_destroy(my_ua, 0); my_ua = NULL; }
|
||||
}
|
||||
__atomic_store_n(&g_thread_running, 0, __ATOMIC_RELEASE);
|
||||
pthread_mutex_lock(&g_stop_mutex);
|
||||
|
||||
Reference in new issue
Block a user