Browse Source

debug: реорганизация категорий — SYS(1), ETCP(4) расширен, CONNECTION(3) очищен; fix stcp_client.c sock_err до connect()

Категории:
- DEBUG_CATEGORY_SYS=1: u_async + ll_queue + memory + timing (было 4)
- DEBUG_CATEGORY_ETCP=4: ETCP + normalizer + BBR (было 3)
- DEBUG_CATEGORY_CONNECTION=3: только события статуса линка/подключения (INFO)
- DEBUG_CATEGORY_KEEPALIVE=21: только периодический мониторинг (DEBUG)
- Удалены: NORMALIZER, BBR, CONNECTIVITY
- Устаревшие DB_SYNC → CHAT_SYNC + MEMBER_SYNC (предыдущий коммит)

CONNECTION+INFO — только: Connection UP/DOWN, Link UP/down, Link initialized/added,
  NAT address init/changed, init server/client.
CONNECTION+DEBUG — retry, collision, reinit, socket register.
KEEPALIVE — init_timer SUPPRESSED, timer started, keepalive skipped.
REINIT — ETCP+INFO.
Connection status changed — GENERAL (пользовательский callback).
Dedup link_status: if(old_link_status) перед Link down.
Убран дублирующий Conn:%s из Link down, добавлен link_id в client added link.
Молчаливые ошибки: +DEBUG_ERROR в 15 местах (merkle_sync, member_sync, db_sync).

Fix: stcp_client.c — socket_get_error() вызывался ДО connect(), проверяя
застарелое errno вместо ошибки connect(). Неблокирующий connect() возвращает
-1+EINPROGRESS (норма), но сравнивался с мусором → ложный FAIL.
Все 4 STCP-теста исправлены (68/68 pass).
topo_upd
evgeny 2 months ago
parent
commit
be0e76c9a6
  1. 11
      lib/debug_config.c
  2. 31
      lib/debug_config.h
  3. 54
      lib/ll_queue.c
  4. 50
      lib/mem.c
  5. 16
      lib/memory_pool.c
  6. 64
      lib/u_async.c
  7. 46
      src/chat/chat_channel.c
  8. 18
      src/chat/chat_core.c
  9. 40
      src/chat/chat_msg.c
  10. 30
      src/chat/chat_profile.c
  11. 4
      src/chat/chat_setting.c
  12. 302
      src/chat/chat_sync.c
  13. 240
      src/chat/db_sync.c
  14. 65
      src/chat/member_sync.c
  15. 74
      src/chat/merkle_sync.c
  16. 22
      src/config_parser.c
  17. 2
      src/firewall.c
  18. 4
      src/ntp_time.c
  19. 10
      src/transport_layer/etcp.c
  20. 12
      src/transport_layer/etcp_bbr.c
  21. 49
      src/transport_layer/etcp_connections.c
  22. 74
      src/transport_layer/pkt_normalizer.c
  23. 5
      src/transport_layer/stcp_client.c
  24. 16
      src/utun.c
  25. 56
      src/utun_instance.c
  26. 10
      tests/simple_test.c
  27. 2
      tests/test_chat_sync_stress.c
  28. 4
      tests/test_config_debug.c
  29. 2
      tests/test_db_sync.c
  30. 20
      tests/test_debug_categories.c
  31. 2
      tests/test_etcp_dummynet.c
  32. 24
      tests/test_intensive_memory_pool.c
  33. 6
      tests/test_ll_queue.c
  34. 4
      tests/test_media_delivery_integration.c
  35. 20
      tests/test_memory_pool_and_config.c
  36. 16
      tests/test_tcp_io.c
  37. 34
      tests/test_u_async_comprehensive.c
  38. 4
      tools/chatgui-android/libutun_lite/instance_lite.c

11
lib/debug_config.c

@ -105,18 +105,14 @@ static const struct {
debug_category_t category;
} g_debug_categories[] = {
{"none", DEBUG_CATEGORY_NONE},
{"uasync", DEBUG_CATEGORY_UASYNC},
{"ll_queue", DEBUG_CATEGORY_LL_QUEUE},
{"sys", DEBUG_CATEGORY_SYS},
{"connection", DEBUG_CATEGORY_CONNECTION},
{"etcp", DEBUG_CATEGORY_ETCP},
{"crypto", DEBUG_CATEGORY_CRYPTO},
{"memory", DEBUG_CATEGORY_MEMORY},
{"timing", DEBUG_CATEGORY_TIMING},
{"config", DEBUG_CATEGORY_CONFIG},
{"tun", DEBUG_CATEGORY_TUN},
{"routing", DEBUG_CATEGORY_ROUTING},
{"timers", DEBUG_CATEGORY_TIMERS},
{"normalizer", DEBUG_CATEGORY_NORMALIZER},
{"bgp", DEBUG_CATEGORY_BGP},
{"socket", DEBUG_CATEGORY_SOCKET},
{"control", DEBUG_CATEGORY_CONTROL},
@ -127,10 +123,9 @@ static const struct {
{"nat", DEBUG_CATEGORY_NAT},
{"keepalive", DEBUG_CATEGORY_KEEPALIVE},
{"etcp_route", DEBUG_CATEGORY_ETCPROUTE},
{"bbr", DEBUG_CATEGORY_BBR},
{"etcp_dump", DEBUG_CATEGORY_ETCP_DUMP},
{"connectivity", DEBUG_CATEGORY_CONNECTIVITY},
{"db_sync", DEBUG_CATEGORY_DB_SYNC},
{"chat_sync", DEBUG_CATEGORY_CHAT_SYNC},
{"member_sync", DEBUG_CATEGORY_MEMBER_SYNC},
{"all", DEBUG_CATEGORY_ALL},
{NULL, DEBUG_CATEGORY_NONE}
};

31
lib/debug_config.h

@ -39,18 +39,18 @@ typedef enum {
typedef int debug_category_t;
#define DEBUG_CATEGORY_NONE 0
#define DEBUG_CATEGORY_UASYNC 1 // u_async module
#define DEBUG_CATEGORY_LL_QUEUE 2 // ll_queue module
#define DEBUG_CATEGORY_CONNECTION 3 // connection module
#define DEBUG_CATEGORY_ETCP 4 // etcp module
#define DEBUG_CATEGORY_CRYPTO 5 // crypto operations
#define DEBUG_CATEGORY_MEMORY 6 // memory management
#define DEBUG_CATEGORY_TIMING 7 // timing/performance
#define DEBUG_CATEGORY_CONFIG 8 // configuration parsing
#define DEBUG_CATEGORY_TUN 9 // TUN interface
#define DEBUG_CATEGORY_SYS 1 // System: u_async, ll_queue, memory, timing
// #define DEBUG_CATEGORY_LL_QUEUE 2 (merged into SYS)
#define DEBUG_CATEGORY_CONNECTION 3 // Connection: links, keepalive, status events
#define DEBUG_CATEGORY_ETCP 4 // ETCP: protocol, BBR, normalizer
#define DEBUG_CATEGORY_CRYPTO 5 // crypto operations
// #define DEBUG_CATEGORY_MEMORY 6 (merged into SYS)
// #define DEBUG_CATEGORY_TIMING 7 (merged into SYS)
#define DEBUG_CATEGORY_CONFIG 8 // configuration parsing
#define DEBUG_CATEGORY_TUN 9 // TUN interface
#define DEBUG_CATEGORY_ROUTING 10 // routing table
#define DEBUG_CATEGORY_TIMERS 11 // timer management
#define DEBUG_CATEGORY_NORMALIZER 12 // packet normalizer
// #define DEBUG_CATEGORY_NORMALIZER 12 (merged into ETCP)
#define DEBUG_CATEGORY_BGP 13 // BGP route exchange
#define DEBUG_CATEGORY_SOCKET 14 // Socket operations
#define DEBUG_CATEGORY_CONTROL 15 // Control/monitoring server
@ -59,13 +59,14 @@ typedef int debug_category_t;
#define DEBUG_CATEGORY_DEBUG 18 // Current debugging
#define DEBUG_CATEGORY_GENERAL 19 // Messages for user (common log)
#define DEBUG_CATEGORY_NAT 20 // EIM NAT module
#define DEBUG_CATEGORY_KEEPALIVE 21 // Link keepalive logic
#define DEBUG_CATEGORY_KEEPALIVE 21 // Keepalive periodic monitoring only
#define DEBUG_CATEGORY_ETCPROUTE 22 // ETCP routing
#define DEBUG_CATEGORY_BBR 23 // BBR congestion control
// #define DEBUG_CATEGORY_BBR 23 (merged into ETCP)
#define DEBUG_CATEGORY_ETCP_DUMP 24 // ETCP packet dump
#define DEBUG_CATEGORY_CONNECTIVITY 25 // Connection/handshake lifecycle
#define DEBUG_CATEGORY_DB_SYNC 26 // DB sync (chat, members, distributed tables)
#define DEBUG_CATEGORY_COUNT 27 // Total number of categories
// #define DEBUG_CATEGORY_CONNECTIVITY 25 (unused, removed)
#define DEBUG_CATEGORY_CHAT_SYNC 26 // Message DB sync (INIT_SYNC, PUSH, chain hash, recalc)
#define DEBUG_CATEGORY_MEMBER_SYNC 27 // Member + address + merkle sync
#define DEBUG_CATEGORY_COUNT 28 // Total number of categories
#define DEBUG_CATEGORY_ALL (-1) // special value for all categories
/* Debug configuration structure */

54
lib/ll_queue.c

@ -22,7 +22,7 @@ static inline void queue_check_thread(struct ll_queue* q) {
#ifdef _WIN32
DWORD current = GetCurrentThreadId();
if (q->owner_thread != current) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': thread mismatch! owner=%lu current=%lu",
q->name ? q->name : "unknown",
(unsigned long)q->owner_thread,
(unsigned long)current);
@ -32,7 +32,7 @@ static inline void queue_check_thread(struct ll_queue* q) {
#else
pthread_t current = pthread_self();
if (!pthread_equal(q->owner_thread, current)) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': thread mismatch! owner=%lu current=%lu",
q->name ? q->name : "unknown",
(unsigned long)q->owner_thread,
(unsigned long)current);
@ -99,7 +99,7 @@ struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, uint16_t index_o
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_new: created queue %p, hash_size=%zu", q, hash_size);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_new: created queue %p, hash_size=%zu", q, hash_size);
return q;
}
@ -124,7 +124,7 @@ struct ll_entry* ll_alloc_lldgram(uint16_t len) {
void queue_free(struct ll_queue* q) {
if (!q) return;
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_free: freeing queue %p, head=%p, tail=%p, count=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_free: freeing queue %p, head=%p, tail=%p, count=%d",
q, q->head, q->tail, q->count);
// ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно
@ -210,7 +210,7 @@ struct ll_entry* queue_entry_new(size_t data_size) {
entry->len = 0;
entry->pool = NULL; // Выделено через u_malloc
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new: created entry %p, size=%zu", entry, data_size);
// DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_entry_new: created entry %p, size=%zu", entry, data_size);
return entry;
}
@ -226,7 +226,7 @@ struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool) {
entry->len = 0;
entry->pool = pool; // Выделено из пула
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new_from_pool: created entry %p from pool %p", entry, pool);
// DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_entry_new_from_pool: created entry %p from pool %p", entry, pool);
return entry;
}
@ -265,7 +265,7 @@ static void add_to_hash(struct ll_queue* q, struct ll_entry* entry) {
if (!q || !entry) return;
if (q->hash_size == 0 || q->index_size == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] Empty hash_size=%d or index_size=%d",q->name, q->hash_size, q->index_size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] Empty hash_size=%d or index_size=%d",q->name, q->hash_size, q->index_size);
return;
}
@ -307,13 +307,13 @@ static void waiter_defer_cb(void* arg) {
struct queue_waiter_handle* h = (struct queue_waiter_handle*)arg;
h->call_soon_id = NULL;
if (h->defer_cb) h->defer_cb(h->defer_q, h->defer_arg);
else DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "waiter_defer_cb: NULL callback (stale?) q=%p", (void*)h->defer_q);
else DEBUG_ERROR(DEBUG_CATEGORY_SYS, "waiter_defer_cb: NULL callback (stale?) q=%p", (void*)h->defer_q);
}
static inline void queue_waiter_call(struct ll_queue* q, queue_threshold_callback_fn cb, void* arg,
struct queue_waiter_handle* h) {
if (q->waiter_defer) {
if (h->call_soon_id) { DEBUG_WARN(DEBUG_CATEGORY_LL_QUEUE, "queue_waiter_call: overwriting existing call_soon_id=%p", h->call_soon_id); uasync_call_soon_cancel(q->ua, h->call_soon_id); }
if (h->call_soon_id) { DEBUG_WARN(DEBUG_CATEGORY_SYS, "queue_waiter_call: overwriting existing call_soon_id=%p", h->call_soon_id); uasync_call_soon_cancel(q->ua, h->call_soon_id); }
h->defer_q = q; h->defer_cb = cb; h->defer_arg = arg;
h->call_soon_id = uasync_call_soon(q->ua, h, waiter_defer_cb);
} else {
@ -341,7 +341,7 @@ static void check_waiters(struct ll_queue* q) {
u_free(waiter);
if (cb) {
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "check_waiters: waking head waiter, count=%d<=%d, bytes=%zu<=%zu",
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "check_waiters: waking head waiter, count=%d<=%d, bytes=%zu<=%zu",
q->count, q->threshold_max_packets, q->total_bytes, q->threshold_max_bytes);
queue_waiter_call(q, cb, arg, h);
}
@ -354,13 +354,13 @@ int queue_data_put(struct ll_queue* q, struct ll_entry* entry) {
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put detected! entry=%p prev=%p next=%p len=%u",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] double put detected! entry=%p prev=%p next=%p len=%u",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next, entry->len);
abort();
}
if (q->hash_size > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] Put no-hash data to hash queue",q->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] Put no-hash data to hash queue",q->name);
queue_dgram_free(entry);
queue_entry_free(entry);
return -1;
@ -401,13 +401,13 @@ int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry) {
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_with_index detected! entry=%p prev=%p next=%p",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] double put_with_index detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->index_size == 0 || (size_t)q->index_offset + q->index_size > (size_t)entry->size) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
queue_dgram_free(entry);
queue_entry_free(entry);
return -1;
@ -450,13 +450,13 @@ int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry) {
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_first detected! entry=%p prev=%p next=%p",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] double put_first detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->hash_size > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] Put no-hash data to hash queue",q->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] Put no-hash data to hash queue",q->name);
queue_dgram_free(entry);
queue_entry_free(entry); // как было в оригинале
return -1;
@ -489,13 +489,13 @@ int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry)
#endif
if (entry->prev || entry->next || q->head == entry || q->tail == entry) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] double put_first_with_index detected! entry=%p prev=%p next=%p",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] double put_first_with_index detected! entry=%p prev=%p next=%p",
q->name, (void*)entry, (void*)entry->prev, (void*)entry->next);
abort();
}
if (q->index_size == 0 || (size_t)q->index_offset + q->index_size > (size_t)entry->size) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] invalid index: offset=%u size=%u (data_size=%u)",q->name, q->index_offset, q->index_size, entry->size);
queue_dgram_free(entry);
queue_entry_free(entry);
return -1;
@ -552,7 +552,7 @@ struct ll_entry* queue_data_get(struct ll_queue* q) {
remove_from_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_get: got entry %p (id=%u), count=%d", entry, entry->id, q->count);
// DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_data_get: got entry %p (id=%u), count=%d", entry, entry->id, q->count);
// Приостановить коллбэки для предотвращения рекурсии
q->callback_suspended = 1;
@ -582,7 +582,7 @@ int queue_check_consistency(struct ll_queue* q) {
if (!q) return -1;
if (q->count > 0 && !q->head) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count=%d but head is NULL!",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': count=%d but head is NULL!",
q->name ? q->name : "unknown", q->count);
return -1;
}
@ -594,7 +594,7 @@ int queue_check_consistency(struct ll_queue* q) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': CYCLE detected! entry=%p count=%d",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': CYCLE detected! entry=%p count=%d",
q->name ? q->name : "unknown", (void*)slow, q->count);
abort();
}
@ -610,7 +610,7 @@ int queue_check_consistency(struct ll_queue* q) {
actual_bytes += current->int_len;
if (current->next) {
if (current->next->prev != current) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': prev/next error at entry %p != %p entries: %d!=%d bytes: %zu!=%zu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': prev/next error at entry %p != %p entries: %d!=%d bytes: %zu!=%zu",
q->name ? q->name : "unknown", (void*)current, (void*)current->next->prev, actual_count, q->count, actual_bytes, q->total_bytes);
return -1;
}
@ -620,13 +620,13 @@ int queue_check_consistency(struct ll_queue* q) {
// Проверить хвост
if (q->tail && q->tail->next != NULL) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': tail error", q->name ? q->name : "unknown");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': tail error", q->name ? q->name : "unknown");
return -1; // Хвост должен иметь next == NULL
}
// Сравнить с сохранёнными значениями
if (actual_count != q->count || actual_bytes != q->total_bytes) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count error entries: %d!=%d or bytes: %zu!=%zu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Queue '%s': count error entries: %d!=%d or bytes: %zu!=%zu",
q->name ? q->name : "unknown", actual_count, q->count, actual_bytes, q->total_bytes);
return -1;
}
@ -678,7 +678,7 @@ int queue_waiter_wait(struct ll_queue* q, struct queue_waiter_handle* h,
struct queue_waiter* waiter = u_malloc(sizeof(struct queue_waiter));
if (!waiter) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] queue_waiter_wait: u_malloc failed", q->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] queue_waiter_wait: u_malloc failed", q->name);
return -1;
}
waiter->next = NULL;
@ -705,7 +705,7 @@ void queue_waiter_cancel(struct ll_queue* q, struct queue_waiter_handle* h) {
curr = curr->next;
}
if (!curr) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "[%s] queue_waiter_cancel: waiter not in list", q->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[%s] queue_waiter_cancel: waiter not in list", q->name);
h->internal = NULL;
return;
}
@ -780,7 +780,7 @@ int queue_remove_data(struct ll_queue* q, struct ll_entry* entry) {
remove_from_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_remove_data: removed entry %p (id=%u), count=%d", entry, entry->id, q->count);
// DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "queue_remove_data: removed entry %p (id=%u), count=%d", entry, entry->id, q->count);
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug
#endif

50
lib/mem.c

@ -75,7 +75,7 @@ static void hex_dump(const void* mem, size_t len) {
off += snprintf(line + off, sizeof(line) - off, " ");
}
}
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s", line);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s", line);
}
}
@ -91,30 +91,30 @@ void u_check(void* ptr, const char* text, const char* location) {
bool error = false;
for (size_t i = 0; i < BOUNDARY_CHECK_SIZE; i++) {
if (prefix_start[i] != PADDING_FILL) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: underflow prefix corrupted at %p, byte %zu (expected 0x%02X, got 0x%02X)", location, text, ptr, i, PADDING_FILL, prefix_start[i]);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: underflow prefix corrupted at %p, byte %zu (expected 0x%02X, got 0x%02X)", location, text, ptr, i, PADDING_FILL, prefix_start[i]);
error = true;
}
}
if (*pre_canary != CANARY) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: underflow canary corrupted at %p (expected 0x%X, got 0x%X)", location, text, ptr, CANARY, *pre_canary);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: underflow canary corrupted at %p (expected 0x%X, got 0x%X)", location, text, ptr, CANARY, *pre_canary);
error = true;
}
uint8_t* post_start = user + size + 4;
for (size_t i = 0; i < BOUNDARY_CHECK_SIZE; i++) {
if (post_start[i] != PADDING_FILL) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: overflow prefix corrupted at %p, byte %zu (expected 0x%02X, got 0x%02X)", location, text, ptr, i, PADDING_FILL, post_start[i]);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: overflow prefix corrupted at %p, byte %zu (expected 0x%02X, got 0x%02X)", location, text, ptr, i, PADDING_FILL, post_start[i]);
error = true;
}
}
uint32_t* post_canary = (uint32_t*)(user + size);
if (*post_canary != CANARY) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: overflow canary corrupted at %p (expected 0x%X, got 0x%X)", location, text, ptr, CANARY, *post_canary);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: overflow canary corrupted at %p (expected 0x%X, got 0x%X)", location, text, ptr, CANARY, *post_canary);
error = true;
}
if (error) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: Allocated at: %s", location, text, alloc_loc);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: Memory block size (user): %u bytes, total allocated: %u bytes", location, text, size, total);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s: %s: Full memory dump at base %p:", location, text, base);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Allocated at: %s", location, text, alloc_loc);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Memory block size (user): %u bytes, total allocated: %u bytes", location, text, size, total);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s: %s: Full memory dump at base %p:", location, text, base);
hex_dump(base, total);
exit(EXIT_FAILURE);
}
@ -188,21 +188,21 @@ void u_free_impl(void* ptr, const char* location) {
if (prev == NULL && allocated_head != base) {
UNLOCK();
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "========================================");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "DOUBLE FREE DETECTED");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "========================================");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Free attempt at: %s", location);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Pointer: %p", ptr);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Base: %p", (void*)base);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Allocated at: %s", alloc_loc);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "User size: %u bytes", size);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Total allocated: %u bytes", size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Active allocs: %zu", active_count);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "--- Metadata dump at %p (%u bytes) ---", (void*)base, (unsigned)(METADATA_SIZE + BOUNDARY_CHECK_SIZE + 8));
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "========================================");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "DOUBLE FREE DETECTED");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "========================================");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Free attempt at: %s", location);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Pointer: %p", ptr);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Base: %p", (void*)base);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Allocated at: %s", alloc_loc);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "User size: %u bytes", size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Total allocated: %u bytes", size + 12 + 2 * BOUNDARY_CHECK_SIZE + METADATA_SIZE);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Active allocs: %zu", active_count);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "--- Metadata dump at %p (%u bytes) ---", (void*)base, (unsigned)(METADATA_SIZE + BOUNDARY_CHECK_SIZE + 8));
hex_dump(base, METADATA_SIZE + BOUNDARY_CHECK_SIZE + 8);
if (size > 0 && size <= 1024 * 1024) {
uint32_t dump_size = (size > 256) ? 256 : size;
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "--- User data dump at %p (%u of %u bytes) ---", ptr, dump_size, size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "--- User data dump at %p (%u of %u bytes) ---", ptr, dump_size, size);
hex_dump(ptr, dump_size);
}
exit(EXIT_FAILURE);
@ -238,12 +238,12 @@ void u_report_unfreed_blocks(void) {
size_t alloc_count = allocations_count;
size_t free_count = frees_count;
UNLOCK();
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Memory stats: allocations=%zu, frees=%zu, current=%zu", alloc_count, free_count, count);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Memory stats: allocations=%zu, frees=%zu, current=%zu", alloc_count, free_count, count);
if (count == 0) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "No unfreed memory blocks.");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "No unfreed memory blocks.");
return;
}
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Unfreed memory blocks: %zu, allocations: %zu frees: %zu", count, allocations_count, frees_count);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Unfreed memory blocks: %zu, allocations: %zu frees: %zu", count, allocations_count, frees_count);
void* curr = head;
while (curr) {
char* alloc_loc = (char*)curr;
@ -251,8 +251,8 @@ void u_report_unfreed_blocks(void) {
uint32_t size = *(uint32_t*)(prefix_start + BOUNDARY_CHECK_SIZE + 4);
void* user_ptr = prefix_start + BOUNDARY_CHECK_SIZE + 8;
u_check(user_ptr, "unfreed_check", "u_report_unfreed_blocks");
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " - Allocated at: %s, size: %u bytes", alloc_loc, size);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " Full memory dump at %p:", user_ptr);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, " - Allocated at: %s, size: %u bytes", alloc_loc, size);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, " Full memory dump at %p:", user_ptr);
hex_dump(user_ptr, size);
curr = *(void**)((uint8_t*)curr + NEXT_OFFSET);
}

16
lib/memory_pool.c

@ -29,17 +29,17 @@ static void pool_check_and_clear_tags(struct memory_pool* pool, void* obj, const
uint8_t* counter = (uint8_t*)obj + POOL_COUNTER_OFF;
if (*canary != POOL_CANARY_VAL) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free BUFFER OVERFLOW pool=%p name=%s sz=%zu allocs=%zu reuse=%zu free=%d",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "pool_free BUFFER OVERFLOW pool=%p name=%s sz=%zu allocs=%zu reuse=%zu free=%d",
pool, pool->name ? pool->name : "?", pool->object_size, pool->allocations, pool->reuse_count, pool->free_count);
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, " obj=%p alloc=%s free=%s canary=0x%08x expected=0x%08x",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, " obj=%p alloc=%s free=%s canary=0x%08x expected=0x%08x",
obj, *loc ? *loc : "(null)", location, *canary, POOL_CANARY_VAL);
if (pool->object_size)
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_MEMORY, " user_data", obj, pool->object_size);
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_SYS, " user_data", obj, pool->object_size);
volatile int _halt = 1;
while (_halt) {}
}
if (*counter == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "pool_free DOUBLE FREE pool=%p name=%s sz=%zu allocs=%zu reuse=%zu alloc=%s free=%s",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "pool_free DOUBLE FREE pool=%p name=%s sz=%zu allocs=%zu reuse=%zu alloc=%s free=%s",
pool, pool->name ? pool->name : "?", pool->object_size, pool->allocations, pool->reuse_count,
*loc ? *loc : "(null)", location);
volatile int _halt = 1;
@ -84,12 +84,12 @@ void* memory_pool_alloc_impl(struct memory_pool* pool, const char* location) {
pool->reuse_count++;
memset(obj, 0, pool->object_size);
pool_init_tags(pool, obj, location);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_alloc reused: %s, remaining=%zu", location, pool->free_count);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "pool_alloc reused: %s, remaining=%zu", location, pool->free_count);
return obj;
}
pool->allocations++;
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_alloc: %s, total_allocs=%zu", location, pool->allocations);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "pool_alloc: %s, total_allocs=%zu", location, pool->allocations);
void* obj = u_calloc_impl(1, POOL_ALLOC_SIZE, location);
if (obj) pool_init_tags(pool, obj, location);
return obj;
@ -108,11 +108,11 @@ void memory_pool_free_impl(struct memory_pool* pool, void* obj, const char* loca
pool->free_head = obj;
pool->free_count++;
g_total_free++;
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_free returned: %s, free_count=%zu", location, pool->free_count);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "pool_free returned: %s, free_count=%zu", location, pool->free_count);
return;
}
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "pool_free direct: %s", location);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "pool_free direct: %s", location);
u_free_impl(obj, location);
}

64
lib/u_async.c

@ -454,7 +454,7 @@ static void process_timeouts(struct UASYNC* ua) {
}
if (node && node->callback) {
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "timer→immediate %s", node->name[0] ? node->name : "");
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "timer→immediate %s", node->name[0] ? node->name : "");
node->callback(node->arg);
}
@ -480,7 +480,7 @@ static void process_timeouts(struct UASYNC* ua) {
struct timeout_node* node = (struct timeout_node*)entry.data;
if (node && node->callback) {
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "timer→%s expired", node->name[0] ? node->name : "");
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "timer→%s expired", node->name[0] ? node->name : "");
node->callback(node->arg);
}
@ -937,7 +937,7 @@ static void process_epoll_events(struct UASYNC* ua, struct epoll_event* events,
struct socket_node* node = socket_array_get(ua->sockets, fd);
if (!node || !node->active) continue;
if (node->gen != ev_gen) { DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "EPOLL STALE fd=%d ev_gen=%u node_gen=%u — skipped", fd, ev_gen, node->gen); continue; }
if (node->gen != ev_gen) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "EPOLL STALE fd=%d ev_gen=%u node_gen=%u — skipped", fd, ev_gen, node->gen); continue; }
int local_fd = node->fd;
socket_t local_sock = node->sock;
int local_type = node->type;
@ -991,11 +991,11 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
uint64_t now_us_poll_entry = get_time_us();
if (ua->last_poll_exit_us && now_us_poll_entry - ua->last_poll_exit_us > 10000) {
DEBUG_WARN(DEBUG_CATEGORY_UASYNC, "Event loop stall: %lluus since end of last poll processing",
DEBUG_WARN(DEBUG_CATEGORY_SYS, "Event loop stall: %lluus since end of last poll processing",
(unsigned long long)(now_us_poll_entry - ua->last_poll_exit_us));
}
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "poll(%d sockets, %zu timers, timeout=%d.%dms)",
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "poll(%d sockets, %zu timers, timeout=%d.%dms)",
ua->sockets->count, ua->timeout_heap->size, timeout_tb >= 0 ? timeout_tb / 10000 : -1,
timeout_tb >= 0 ? (timeout_tb % 10000) / 10 : 0);
// Handle negative or zero timeout
@ -1142,7 +1142,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
if (ret < 0) {
int err = WSAGetLastError();
if (err != WSAEINTR) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "select failed: %d", err);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "select failed: %d", err);
}
return;
}
@ -1165,7 +1165,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
int has_except = FD_ISSET(s, &except_fds);
if (!has_read && !has_write && !has_except) continue;
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "select→fd=%d r=%d w=%d e=%d", (int)s, has_read, has_write, has_except);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "select→fd=%d r=%d w=%d e=%d", (int)s, has_read, has_write, has_except);
if (has_except) {
if (node->except_cbk) {
@ -1226,7 +1226,7 @@ void uasync_poll(struct UASYNC* ua, int timeout_tb) {
if (ret > 0) {
for (int i = 0; i < ua->poll_fds_count; i++) {
if (ua->poll_fds[i].revents == 0) continue;
DEBUG_DEBUG(DEBUG_CATEGORY_UASYNC, "poll→fd=%d rev=0x%x", ua->poll_fds[i].fd, ua->poll_fds[i].revents);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "poll→fd=%d rev=0x%x", ua->poll_fds[i].fd, ua->poll_fds[i].revents);
/* Handle wakeup fd separately */
if (wakeup_fd_present && i == 0) {
@ -1405,18 +1405,18 @@ struct UASYNC* uasync_create(void) {
ua->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (ua->epoll_fd >= 0) {
ua->use_epoll = 1;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Using epoll for socket monitoring");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Using epoll for socket monitoring");
// Add wakeup pipe to epoll
if (ua->wakeup_initialized) {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = -1; // -1 fd indicates wakeup
if (epoll_ctl(ua->epoll_fd, EPOLL_CTL_ADD, ua->wakeup_pipe[0], &ev) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_UASYNC, "Failed to add wakeup pipe to epoll: %s", strerror(errno));
DEBUG_WARN(DEBUG_CATEGORY_SYS, "Failed to add wakeup pipe to epoll: %s", strerror(errno));
}
}
} else {
DEBUG_WARN(DEBUG_CATEGORY_UASYNC, "Failed to create epoll fd, falling back to poll: %s", strerror(errno));
DEBUG_WARN(DEBUG_CATEGORY_SYS, "Failed to create epoll fd, falling back to poll: %s", strerror(errno));
}
#endif
@ -1427,7 +1427,7 @@ struct UASYNC* uasync_create(void) {
SOCKET r = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKET w = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r == INVALID_SOCKET || w == INVALID_SOCKET) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "Failed to create wakeup sockets");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create wakeup sockets");
u_free(ua);
return NULL;
}
@ -1442,7 +1442,7 @@ struct UASYNC* uasync_create(void) {
connect(w, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
closesocket(r);
closesocket(w);
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "Wakeup socket setup failed: %d", WSAGetLastError());
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Wakeup socket setup failed: %d", WSAGetLastError());
u_free(ua);
return NULL;
}
@ -1463,22 +1463,22 @@ struct UASYNC* uasync_create(void) {
#ifdef __linux__
ua->wakeup_pipe[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (ua->wakeup_pipe[0] < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "eventfd() failed: %s", strerror(errno));
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "eventfd() failed: %s", strerror(errno));
u_free(ua);
return NULL;
}
ua->wakeup_pipe[1] = ua->wakeup_pipe[0];
#else
if (pipe(ua->wakeup_pipe) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "pipe() failed: %s", strerror(errno));
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "pipe() failed: %s", strerror(errno));
u_free(ua);
return NULL;
}
if (fcntl(ua->wakeup_pipe[0], F_SETFL, O_NONBLOCK) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "fcntl(wakeup_pipe[0], O_NONBLOCK) failed: %s", strerror(errno));
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "fcntl(wakeup_pipe[0], O_NONBLOCK) failed: %s", strerror(errno));
}
if (fcntl(ua->wakeup_pipe[1], F_SETFL, O_NONBLOCK) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "fcntl(wakeup_pipe[1], O_NONBLOCK) failed: %s", strerror(errno));
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "fcntl(wakeup_pipe[1], O_NONBLOCK) failed: %s", strerror(errno));
}
#endif
ua->wakeup_initialized = 1;
@ -1489,7 +1489,7 @@ struct UASYNC* uasync_create(void) {
ev.events = EPOLLIN;
ev.data.fd = -1;
if (epoll_ctl(ua->epoll_fd, EPOLL_CTL_ADD, ua->wakeup_pipe[0], &ev) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_UASYNC, "Failed to add wakeup pipe to epoll: %s", strerror(errno));
DEBUG_WARN(DEBUG_CATEGORY_SYS, "Failed to add wakeup pipe to epoll: %s", strerror(errno));
}
}
#endif
@ -1508,15 +1508,15 @@ struct UASYNC* uasync_create(void) {
// Print all resources for debugging
void uasync_print_resources(struct UASYNC* ua, const char* prefix) {
if (!ua) {
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "%s: NULL uasync instance", prefix);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "%s: NULL uasync instance", prefix);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "%s: UASYNC Resource Report for %p", prefix, ua);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Timer Statistics: allocated=%zu, u_freed=%zu, active=%zd",
DEBUG_INFO(DEBUG_CATEGORY_SYS, "%s: UASYNC Resource Report for %p", prefix, ua);
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Timer Statistics: allocated=%zu, u_freed=%zu, active=%zd",
ua->timer_alloc_count, ua->timer_free_count,
(ssize_t)(ua->timer_alloc_count - ua->timer_free_count));
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Socket Statistics: allocated=%zu, u_freed=%zu, active=%zd",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Socket Statistics: allocated=%zu, u_freed=%zu, active=%zd",
ua->socket_alloc_count, ua->socket_free_count,
(ssize_t)(ua->socket_alloc_count - ua->socket_free_count));
@ -1533,36 +1533,36 @@ void uasync_print_resources(struct UASYNC* ua, const char* prefix) {
if (ua->timeout_heap->heap[i].deleted) {
deleted_timers++;
struct timeout_node* node = (struct timeout_node*)ua->timeout_heap->heap[i].data;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Timer DELETED: node=%p name='%s' exp=%llu remain=%lldms",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Timer DELETED: node=%p name='%s' exp=%llu remain=%lldms",
node, node ? node->name : "null", (unsigned long long)exp, (long long)remain);
} else {
active_timers++;
struct timeout_node* node = (struct timeout_node*)ua->timeout_heap->heap[i].data;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Timer ACTIVE: node=%p name='%s' exp=%llu remain=%lldms",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Timer ACTIVE: node=%p name='%s' exp=%llu remain=%lldms",
node, node ? node->name : "null", (unsigned long long)exp, (long long)remain);
}
}
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Active timers in heap: %zu, deleted: %zu, total: %zu",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Active timers in heap: %zu, deleted: %zu, total: %zu",
active_timers, deleted_timers, ua->timeout_heap->size);
}
// Показать активные сокеты
if (ua->sockets) {
int active_sockets = 0;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Socket array capacity: %d, active: %d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Socket array capacity: %d, active: %d",
ua->sockets->capacity, ua->sockets->count);
for (int i = 0; i < ua->sockets->capacity; i++) {
if (ua->sockets->sockets[i].active) {
active_sockets++;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Socket: fd=%d, active=%d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Socket: fd=%d, active=%d",
ua->sockets->sockets[i].fd,
ua->sockets->sockets[i].active);
}
}
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, " Total active sockets: %d", active_sockets);
DEBUG_INFO(DEBUG_CATEGORY_SYS, " Total active sockets: %d", active_sockets);
}
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "%s: End of resource report", prefix);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "%s: End of resource report", prefix);
}
// Modified function in u_async.c: uasync_destroy
@ -1589,7 +1589,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
// Check for potential memory leaks
if (ua->timer_alloc_count != ua->timer_free_count || ua->socket_alloc_count != ua->socket_free_count) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Memory leaks detected before cleanup: timers %zu/%zu, sockets %zu/%zu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Memory leaks detected before cleanup: timers %zu/%zu, sockets %zu/%zu",
ua->timer_alloc_count, ua->timer_free_count, ua->socket_alloc_count, ua->socket_free_count);
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "Timer leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->timer_alloc_count, ua->timer_free_count,
@ -1657,7 +1657,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
u_freed_count++;
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "Freed %d socket nodes in destroy", u_freed_count);
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "Freed %d socket nodes in destroy", u_freed_count);
socket_array_destroy(ua->sockets);
}
@ -1684,7 +1684,7 @@ void uasync_destroy(struct UASYNC* ua, int close_fds) {
// Final leak check
if (ua->timer_alloc_count != ua->timer_free_count || ua->socket_alloc_count != ua->socket_free_count) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Memory leaks detected after cleanup: timers %zu/%zu, sockets %zu/%zu",
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Memory leaks detected after cleanup: timers %zu/%zu, sockets %zu/%zu",
ua->timer_alloc_count, ua->timer_free_count, ua->socket_alloc_count, ua->socket_free_count);
DEBUG_ERROR(DEBUG_CATEGORY_TIMERS, "FINAL Timer leak: allocated=%zu, u_freed=%zu, diff=%zd",
ua->timer_alloc_count, ua->timer_free_count,

46
src/chat/chat_channel.c

@ -69,7 +69,7 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) {
buf[pos++] = (uint8_t)(port >> 8); buf[pos++] = (uint8_t)(port & 0xFF);
count++;
uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] collect_my_addrs UDP sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] collect_my_addrs UDP sock=%d %d.%d.%d.%d:%d",
CC_ID, s->sock_id, ip[0], ip[1], ip[2], ip[3], port);
} else if (sa && sa->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
@ -79,7 +79,7 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) {
uint16_t port = ntohs(sin6->sin6_port);
buf[pos++] = (uint8_t)(port >> 8); buf[pos++] = (uint8_t)(port & 0xFF);
count++;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] collect_my_addrs UDP v6 sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] collect_my_addrs UDP v6 sock=%d port=%d",
CC_ID, s->sock_id, port);
}
s = s->next;
@ -97,7 +97,7 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) {
buf[pos++] = (uint8_t)(port >> 8); buf[pos++] = (uint8_t)(port & 0xFF);
count++;
uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] collect_my_addrs TCP sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] collect_my_addrs TCP sock=%d %d.%d.%d.%d:%d",
CC_ID, ts->sock_id, ip[0], ip[1], ip[2], ip[3], port);
} else if (addr && addr->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
@ -107,7 +107,7 @@ static int collect_my_addrs(uint8_t* buf, int max_buf_sz) {
uint16_t port = ntohs(sin6->sin6_port);
buf[pos++] = (uint8_t)(port >> 8); buf[pos++] = (uint8_t)(port & 0xFF);
count++;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] collect_my_addrs TCP v6 sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] collect_my_addrs TCP v6 sock=%d port=%d",
CC_ID, ts->sock_id, port);
}
ts = ts->next; }
@ -134,10 +134,10 @@ void chat_core_ensure_channel_ready(const char* ch_id) {
if (si) {
si_register(si, ch_id);
db_sync_set_insert_cb(si, on_msg_inserted, u_strdup(ch_id));
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: channel ready ch=%s tbl=%s hash=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: channel ready ch=%s tbl=%s hash=0x%016llx",
CC_ID, ch_id, tbl_msg, (unsigned long long)ch_hash);
} else {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: db_sync_instance_add failed for ch=%s",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: db_sync_instance_add failed for ch=%s",
CC_ID, ch_id);
}
}
@ -146,13 +146,13 @@ void chat_core_ensure_channel_ready(const char* ch_id) {
void chat_core_create_channel(struct chat_channel_create* req) {
if (!g_cc.initialized) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: create_channel NOT INITIALIZED ch=%s",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: create_channel NOT INITIALIZED ch=%s",
CC_ID, req ? req->channel_id : "(null)");
return;
}
if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: create_channel req=NULL", CC_ID); return; }
if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: create_channel req=NULL", CC_ID); return; }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: create_channel BEGIN ch=%s name=%s",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: create_channel BEGIN ch=%s name=%s",
CC_ID, req->channel_id, req->name);
int rc = topo_node_sqlite_channel_put(g_cc.db,
@ -162,10 +162,10 @@ void chat_core_create_channel(struct chat_channel_create* req) {
req->signature);
if (rc != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: channel_put FAILED ch=%s rc=%d",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: channel_put FAILED ch=%s rc=%d",
CC_ID, req->channel_id, rc);
} else {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: channel_put OK ch=%s name=%s owner=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: channel_put OK ch=%s name=%s owner=0x%016llx",
CC_ID, req->channel_id, req->name, (unsigned long long)req->owner_node_id);
chat_core_ensure_channel_ready(req->channel_id);
@ -191,7 +191,7 @@ void chat_core_create_channel(struct chat_channel_create* req) {
g_cc.inst->my_keys.public_key, g_cc.inst->my_ed25519_pubkey,
join_sig, join_ts, NULL, 0, juser3, my_addrs, my_addr_cnt, NULL, NULL, 0);
if (mrc != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync_put(self) FAILED ch=%s rc=%d",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: member_sync_put(self) FAILED ch=%s rc=%d",
CC_ID, req->channel_id, mrc);
}
chat_core_sync_my_addresses();
@ -202,7 +202,7 @@ void chat_core_create_channel(struct chat_channel_create* req) {
}
void chat_core_create_channel_trampoline(void* arg) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "chat_core: TRAMPOLINE invoked arg=%p", arg);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "chat_core: TRAMPOLINE invoked arg=%p", arg);
struct chat_channel_create* req = (struct chat_channel_create*)arg;
chat_core_create_channel(req);
u_free(req);
@ -215,10 +215,10 @@ void chat_core_create_channel_auto_trampoline(void* arg) {
void chat_core_create_channel_auto(const char* name) {
if (!g_cc.initialized || !name) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: create_channel_auto — not initialized or NULL name", CC_ID);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: create_channel_auto — not initialized or NULL name", CC_ID);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: create_channel_auto BEGIN name=%s", CC_ID, name);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: create_channel_auto BEGIN name=%s", CC_ID, name);
uint8_t x25519_pub[32] = {0}, x25519_priv[32] = {0};
{ EVP_PKEY* pkey = NULL; EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
@ -270,31 +270,31 @@ void chat_core_create_channel_auto(const char* name) {
/* ─── управление подключением к каналу (выбор в GUI) ─── */
void chat_core_connect_channel(const char* ch_id) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel called ch_id=%s initialized=%d", CC_ID, ch_id ? ch_id : "(null)", g_cc.initialized);
if (!g_cc.initialized || !ch_id || !ch_id[0]) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel — skip (not ready)", CC_ID); return; }
if (!g_cc.inst->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel — no topo_groups", CC_ID); return; }
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel called ch_id=%s initialized=%d", CC_ID, ch_id ? ch_id : "(null)", g_cc.initialized);
if (!g_cc.initialized || !ch_id || !ch_id[0]) { DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel — skip (not ready)", CC_ID); return; }
if (!g_cc.inst->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel — no topo_groups", CC_ID); return; }
uint64_t gid = strtoull(ch_id, NULL, 10);
if (gid == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel — invalid ch_id=%s", CC_ID, ch_id); return; }
if (gid == 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel — invalid ch_id=%s", CC_ID, ch_id); return; }
chat_core_ensure_channel_ready(ch_id);
struct TOPO_GROUP* group = topo_groups_find(g_cc.inst->topo_groups, gid);
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel — group not found ch=%s gid=%016llx total_groups=%d", CC_ID, ch_id, (unsigned long long)gid, queue_entry_count(g_cc.inst->topo_groups->group_list)); return; }
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel — group not found ch=%s gid=%016llx total_groups=%d", CC_ID, ch_id, (unsigned long long)gid, queue_entry_count(g_cc.inst->topo_groups->group_list)); return; }
if (group->connect) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel — already in progress ch=%s active=%d",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel — already in progress ch=%s active=%d",
CC_ID, ch_id, topo_group_connect_active_count(group));
return;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel ch=%s gid=%016llx group_type=%d — starting connect_init", CC_ID, ch_id, (unsigned long long)gid, group->group_type);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel ch=%s gid=%016llx group_type=%d — starting connect_init", CC_ID, ch_id, (unsigned long long)gid, group->group_type);
topo_group_connect_init(group);
}
void chat_core_connect_channel_trampoline(void* arg) {
char* ch_id = (char*)arg;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: connect_channel_trampoline ch_id=%s", CC_ID, ch_id ? ch_id : "(null)");
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "%s: connect_channel_trampoline ch_id=%s", CC_ID, ch_id ? ch_id : "(null)");
if (!ch_id) return;
chat_core_connect_channel(ch_id);
u_free(ch_id);

18
src/chat/chat_core.c

@ -56,7 +56,7 @@ int db_exec(const char* sql) {
char* err = NULL;
int rc = sqlite3_exec(g_cc.db, sql, NULL, NULL, &err);
if (rc != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: sql error: %s", CC_ID, err);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: sql error: %s", CC_ID, err);
sqlite3_free(err);
}
return rc;
@ -82,7 +82,7 @@ void si_register(struct DB_SYNC_INSTANCE* si, const char* ch_id) {
g_cc.si_count++;
uint32_t msg_cnt = db_sync_count(si);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: si_register ch=%s mc=%u", CC_ID, ch_id, msg_cnt);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: si_register ch=%s mc=%u", CC_ID, ch_id, msg_cnt);
}
/* ─── жизненный цикл ─── */
@ -94,12 +94,12 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) {
if (inst->topo_sqlite_db) {
g_cc.db = inst->topo_sqlite_db; g_cc.shared_db = 1;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: using shared SQLite db=%p", CC_ID, (void*)g_cc.db);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: using shared SQLite db=%p", CC_ID, (void*)g_cc.db);
} else {
int rc = sqlite3_open_v2(db_path, &g_cc.db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL);
if (rc != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cannot open DB %s: %s",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: cannot open DB %s: %s",
CC_ID, db_path, sqlite3_errmsg(g_cc.db));
sqlite3_close(g_cc.db); g_cc.db = NULL; return -1;
}
@ -173,7 +173,7 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) {
char sql[1024]; snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO ui_state(key,value) VALUES('media_base','%s')", mbase);
sqlite3_exec(g_cc.db, sql, NULL, NULL, NULL);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: media_base=%s", CC_ID, mbase);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: media_base=%s", CC_ID, mbase);
}
/* seed stub accounts if empty */
@ -182,7 +182,7 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) {
if (sqlite3_prepare_v2(g_cc.db, "SELECT COUNT(*) FROM accounts",
-1, &cnt_st, NULL) == SQLITE_OK) {
if (sqlite3_step(cnt_st) == SQLITE_ROW && sqlite3_column_int(cnt_st, 0) == 0) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: seeding 5 stub accounts", CC_ID);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: seeding 5 stub accounts", CC_ID);
struct { int64_t id; const char* name; const char* letter; const char* color; } accs[] = {
{1, "Alice", "A", "#4A90E2"}, {2, "Bob", "B", "#7ED321"},
{3, "Carol", "C", "#F5A623"}, {4, "Dave", "D", "#9013FE"},
@ -218,11 +218,11 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) {
if (ch && ch[0]) { chat_core_ensure_channel_ready(ch); loaded++; }
}
sqlite3_finalize(stmt);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: loaded %d channels from DB", CC_ID, loaded);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: loaded %d channels from DB", CC_ID, loaded);
}
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: initialized, db=%s node_id=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: initialized, db=%s node_id=0x%016llx",
CC_ID, db_path, (unsigned long long)g_cc.my_node_id);
{ uint8_t nid[8]; memcpy(nid, &g_cc.my_node_id, 8); chat_event_post(CHAT_EVT_MY_NODE_ID, nid, 8); }
@ -243,7 +243,7 @@ void chat_core_destroy(struct UTUN_INSTANCE* inst) {
if (g_cc.db && !g_cc.shared_db) { sqlite3_close(g_cc.db); }
g_cc.db = NULL; g_cc.inst = NULL;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: destroyed", CC_ID);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: destroyed", CC_ID);
}
sqlite3* chat_core_get_db(void) { return g_cc.db; }

40
src/chat/chat_msg.c

@ -36,14 +36,14 @@ static int msg_get_prev_chain_hash(const char* tbl, uint8_t out[32]) {
}
void chat_core_submit_message(struct chat_msg_submit* req) {
if (!g_cc.initialized) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: submit before init", CC_ID); return; }
if (!g_cc.initialized) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: submit before init", CC_ID); return; }
if (!req) return;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: SUBMIT ch=%s ct=%s len=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: SUBMIT ch=%s ct=%s len=%u",
CC_ID, req->channel_id, req->content_type, req->data_len);
struct DB_SYNC_INSTANCE* si = si_find(req->channel_id);
if (!si) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: no db_sync instance for ch=%s", CC_ID, req->channel_id); return; }
if (!si) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: no db_sync instance for ch=%s", CC_ID, req->channel_id); return; }
char json[4096];
snprintf(json, sizeof(json),
@ -57,13 +57,13 @@ void chat_core_submit_message(struct chat_msg_submit* req) {
size_t jl = strlen(json); memcpy(sig_msg + soff, json, jl); soff += jl;
uint8_t sig[64];
if (sc_ed25519_sign(g_cc.inst->my_ed25519_privkey, sig_msg, soff, sig) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: Ed25519 sign failed", CC_ID);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: Ed25519 sign failed", CC_ID);
return;
}
int ret = db_sync_insert_signed(si, json, strlen(json), sig, 64, ts, NULL);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: db_sync_insert_signed failed ret=%d", CC_ID, ret);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: db_sync_insert_signed failed ret=%d", CC_ID, ret);
return;
}
}
@ -93,7 +93,7 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
struct media_submit_ctx* mctx = (struct media_submit_ctx*)arg;
if (err || !result) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: media registration failed ch=%s err=%d",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: media registration failed ch=%s err=%d",
CC_ID, mctx->channel_id, err);
u_free(mctx);
return;
@ -101,7 +101,7 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
struct DB_SYNC_INSTANCE* si = si_find(mctx->channel_id);
if (!si) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: no db_sync instance for ch=%s", CC_ID, mctx->channel_id);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: no db_sync instance for ch=%s", CC_ID, mctx->channel_id);
u_free(mctx);
return;
}
@ -113,7 +113,7 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
size_t extra = 128 + 32 + 64 + pairs_len + 256;
size_t fdcap = base_len + extra;
char* full_data = u_malloc(fdcap);
if (!full_data) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: data alloc fail", CC_ID); u_free(mctx); return; }
if (!full_data) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: data alloc fail", CC_ID); u_free(mctx); return; }
size_t off = 0;
if (base_len > 0) {
@ -139,7 +139,7 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
size_t json_cap = full_data_len + 256;
char* json = u_malloc(json_cap);
if (!json) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: json alloc fail", CC_ID); u_free(full_data); u_free(mctx); return; }
if (!json) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: json alloc fail", CC_ID); u_free(full_data); u_free(mctx); return; }
snprintf(json, json_cap,
"{\"n\":%llu,\"ch\":\"%s\",\"ct\":\"%s\",\"d\":\"%.*s\"}",
(unsigned long long)g_cc.my_node_id, mctx->channel_id,
@ -148,20 +148,20 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
uint64_t ts = db_sync_next_timestamp(si);
size_t sig_msg_len = 8 + strlen(json);
uint8_t* sig_msg = u_malloc(sig_msg_len);
if (!sig_msg) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: sig_msg alloc fail", CC_ID); u_free(json); u_free(full_data); u_free(mctx); return; }
if (!sig_msg) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: sig_msg alloc fail", CC_ID); u_free(json); u_free(full_data); u_free(mctx); return; }
memcpy(sig_msg, &ts, 8);
memcpy(sig_msg + 8, json, sig_msg_len - 8);
uint8_t json_sig[64];
if (sc_ed25519_sign(g_cc.inst->my_ed25519_privkey, sig_msg, sig_msg_len, json_sig) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: Ed25519 sign JSON failed", CC_ID);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: Ed25519 sign JSON failed", CC_ID);
u_free(sig_msg); u_free(json); u_free(full_data); u_free(mctx); return;
}
int ret = db_sync_insert_signed(si, json, strlen(json), json_sig, 64, ts, NULL);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: media insert failed ret=%d", CC_ID, ret);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: media insert failed ret=%d", CC_ID, ret);
} else {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: media message inserted ch=%s ts=%llu",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: media message inserted ch=%s ts=%llu",
CC_ID, mctx->channel_id, (unsigned long long)ts);
const char* base = strrchr(mctx->media_dest, '/');
const char* filename = base ? base + 1 : mctx->media_dest;
@ -173,15 +173,15 @@ static void on_media_registered(void* arg, int err, const struct media_index_res
}
static void chat_core_submit_media_message(struct chat_msg_submit* req) {
if (!g_cc.initialized) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: media submit before init", CC_ID); return; }
if (!g_cc.initialized) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: media submit before init", CC_ID); return; }
if (!req || req->media_src[0] == '\0') return;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: MEDIA SUBMIT ch=%s ct=%s src=%s dst=%s copy=%d",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: MEDIA SUBMIT ch=%s ct=%s src=%s dst=%s copy=%d",
CC_ID, req->channel_id, req->content_type,
req->media_src, req->media_dest, req->media_copy);
if (!g_cc.inst->media_async) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: media_async not initialized", CC_ID);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: media_async not initialized", CC_ID);
return;
}
@ -232,7 +232,7 @@ int chat_core_update_local_attrs(const char* ch_id, uint64_t ts,
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(g_cc.db, sql, -1, &stmt, NULL) != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: update local_attrs prep fail: %s", CC_ID, sqlite3_errmsg(g_cc.db));
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: update local_attrs prep fail: %s", CC_ID, sqlite3_errmsg(g_cc.db));
return -1;
}
sqlite3_bind_text(stmt, 1, local_attrs_json, -1, SQLITE_STATIC);
@ -241,10 +241,10 @@ int chat_core_update_local_attrs(const char* ch_id, uint64_t ts,
int rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: update local_attrs step fail rc=%d", CC_ID, rc);
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: update local_attrs step fail rc=%d", CC_ID, rc);
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: local_attrs updated ch=%s ts=%llu", CC_ID, ch_id, (unsigned long long)ts);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: local_attrs updated ch=%s ts=%llu", CC_ID, ch_id, (unsigned long long)ts);
return 0;
}
@ -539,7 +539,7 @@ static void md_auto_download(struct UTUN_INSTANCE* inst,
if (!*p) return; p++;
long long fsize = strtoll(p, (char**)&p, 10);
if (max_size > 0 && fsize > (long long)max_size) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: media too large (%lld > %llu bytes), skip auto-download",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: media too large (%lld > %llu bytes), skip auto-download",
CC_ID, fsize, (unsigned long long)max_size);
return;
}

30
src/chat/chat_profile.c

@ -69,10 +69,10 @@ void chat_core_update_my_name(const char* name) {
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", name);
int r1 = topo_node_sqlite_member_put(g_cc.db, ch, myid, new_sig, join_ts, NULL, 0,
g_cc.inst->my_keys.public_key, g_cc.inst->my_ed25519_pubkey, juser, NULL, NULL, NULL, 0);
if (r1 != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r1);
if (r1 != 0) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: member_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r1);
int r2 = member_sync_put(g_cc.inst, ch, myid, g_cc.inst->my_keys.public_key,
g_cc.inst->my_ed25519_pubkey, new_sig, join_ts, NULL, 0, juser, NULL, 0, NULL, NULL, 0);
if (r2 != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r2);
if (r2 != 0) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: member_sync_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r2);
uint8_t evt[65]; uint8_t cl = (uint8_t)strlen(ch);
evt[0] = cl; memcpy(evt + 1, ch, cl);
chat_event_post(CHAT_EVT_MEMBERS_CHANGED, evt, 1 + cl);
@ -92,7 +92,7 @@ void chat_core_update_my_name_trampoline(void* arg) {
void chat_core_sync_my_addresses(void) {
if (!g_cc.initialized || !g_cc.db || !g_cc.inst) return;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] sync_my_addresses START my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] sync_my_addresses START my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
sqlite3_stmt* del = NULL;
sqlite3_prepare_v2(g_cc.db, "DELETE FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &del, NULL);
@ -100,7 +100,7 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int64(del, 1, (sqlite3_int64)g_cc.my_node_id);
sqlite3_step(del);
int deleted = sqlite3_changes(g_cc.db);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] DELETE addr_type=0 for my_node=0x%016llx: %d rows deleted", CC_ID, (unsigned long long)g_cc.my_node_id, deleted);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] DELETE addr_type=0 for my_node=0x%016llx: %d rows deleted", CC_ID, (unsigned long long)g_cc.my_node_id, deleted);
sqlite3_finalize(del);
}
@ -109,7 +109,7 @@ void chat_core_sync_my_addresses(void) {
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,1,?,?,0,?)", -1, &ins, NULL);
if (!ins) {
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] FAIL prepare INSERT stmt my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] FAIL prepare INSERT stmt my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
return;
}
@ -120,7 +120,7 @@ void chat_core_sync_my_addresses(void) {
int sock_family = sock->local_addr.ss_family ? sock->local_addr.ss_family : 0;
struct sockaddr_storage* sa = (sock->interface_addr.ss_family == sock_family) ? &sock->interface_addr : NULL;
if (!sa) sa = sock->local_addr.ss_family ? &sock->local_addr : NULL;
if (!sa) { DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] socket %d — no address for family=%d", CC_ID, sock_count, sock_family); sock = sock->next; continue; }
if (!sa) { DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] socket %d — no address for family=%d", CC_ID, sock_count, sock_family); sock = sock->next; continue; }
if (sa->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
@ -131,7 +131,7 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(ins, 5, (int)sock->sock_id);
sqlite3_step(ins); sqlite3_reset(ins);
uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, ip[0], ip[1], ip[2], ip[3], (int)ntohs(sin->sin_port));
written++;
} else if (sa->ss_family == AF_INET6) {
@ -142,7 +142,7 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(ins, 4, (int)ntohs(sin6->sin6_port));
sqlite3_bind_int(ins, 5, (int)sock->sock_id);
sqlite3_step(ins); sqlite3_reset(ins);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT v6 my_node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT v6 my_node=0x%016llx sock=%d port=%d",
CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, (int)ntohs(sin6->sin6_port));
written++;
}
@ -171,7 +171,7 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(tcp_ins, 5, (int)ts->sock_id);
sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins);
uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT TCP my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
CC_ID, (unsigned long long)g_cc.my_node_id, ts->sock_id, ip[0], ip[1], ip[2], ip[3], (int)ntohs(sin->sin_port));
tcp_written++;
} else if (addr->ss_family == AF_INET6) {
@ -183,24 +183,24 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(tcp_ins, 4, (int)ntohs(sin6->sin6_port));
sqlite3_bind_int(tcp_ins, 5, (int)ts->sock_id);
sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT TCP v6 my_node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP v6 my_node=0x%016llx sock=%d port=%d",
CC_ID, (unsigned long long)g_cc.my_node_id, ts->sock_id, (int)ntohs(sin6->sin6_port));
tcp_written++;
}
ts = ts->next; }
sqlite3_finalize(tcp_ins);
if (tcp_written > 0)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] TCP DONE: %d addresses written, my_node=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] TCP DONE: %d addresses written, my_node=0x%016llx",
CC_ID, tcp_written, (unsigned long long)g_cc.my_node_id);
}
}
if (sock_count == 0 && tcp_written == 0)
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] no sockets found — NO addresses written!", CC_ID);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] no sockets found — NO addresses written!", CC_ID);
else if (written == 0 && tcp_written == 0)
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] %d sockets found but 0 addresses written", CC_ID, sock_count);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] %d sockets found but 0 addresses written", CC_ID, sock_count);
else
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] DONE: %d UDP + %d TCP = %d total, my_node=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] DONE: %d UDP + %d TCP = %d total, my_node=0x%016llx",
CC_ID, written, tcp_written, written + tcp_written, (unsigned long long)g_cc.my_node_id);
sqlite3_stmt* chk = NULL;
@ -208,7 +208,7 @@ void chat_core_sync_my_addresses(void) {
if (chk) {
sqlite3_bind_int64(chk, 1, (sqlite3_int64)g_cc.my_node_id);
int cnt = sqlite3_step(chk) == SQLITE_ROW ? sqlite3_column_int(chk, 0) : -1;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] VERIFY: total addr_type=0 rows for my_node=0x%016llx = %d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] VERIFY: total addr_type=0 rows for my_node=0x%016llx = %d",
CC_ID, (unsigned long long)g_cc.my_node_id, cnt);
sqlite3_finalize(chk);
}

4
src/chat/chat_setting.c

@ -8,8 +8,8 @@
#include "chat_setting.h"
#include "../../lib/debug_config.h"
#ifdef DEBUG_CATEGORY_DB_SYNC
#define CS_ID DEBUG_CATEGORY_DB_SYNC
#ifdef DEBUG_CATEGORY_CHAT_SYNC
#define CS_ID DEBUG_CATEGORY_CHAT_SYNC
#else
#define CS_ID DEBUG_CATEGORY_GENERAL
#endif

302
src/chat/chat_sync.c

@ -99,26 +99,26 @@ static struct ETCP_CONN* cs_find_conn_for_node(struct UTUN_INSTANCE* inst, uint6
static int cs_send(struct chat_sync* cs, const char* ch_id, uint64_t dst,
const uint8_t* payload, size_t len) {
if (len < 1) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send len<1", CS_ID); return -1; }
if (len < 1) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cs_send len<1", CS_ID); return -1; }
uint8_t ch_len = (uint8_t)strlen(ch_id);
if (ch_len > 63) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send ch_len=%u > 63", CS_ID, ch_len); return -1; }
if (ch_len > 63) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cs_send ch_len=%u > 63", CS_ID, ch_len); return -1; }
size_t total = 1 + 1 + ch_len + len;
uint8_t* buf = u_malloc(total);
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send alloc(%zu) failed", CS_ID, total); return -1; }
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cs_send alloc(%zu) failed", CS_ID, total); return -1; }
uint8_t* p = buf;
*p++ = ETCP_RT_ID_CHAT_SYNC;
*p++ = ch_len;
memcpy(p, ch_id, ch_len); p += ch_len;
memcpy(p, payload, len);
struct ll_entry* entry = queue_entry_new(0);
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send queue_entry_new failed", CS_ID); u_free(buf); return -1; }
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cs_send queue_entry_new failed", CS_ID); u_free(buf); return -1; }
entry->dgram = buf; entry->len = total;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: SEND %s to=%016llx ch=%s len=%zu",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: SEND %s to=%016llx ch=%s len=%zu",
CS_ID, cs_msg_name(payload[0]), (unsigned long long)dst, ch_id, len);
struct ETCP_CONN* conn = cs_find_conn_for_node(cs->inst, dst);
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: no conn for node %016llx", CS_ID, (unsigned long long)dst); u_free(buf); queue_entry_free(entry); return -1; }
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: no conn for node %016llx", CS_ID, (unsigned long long)dst); u_free(buf); queue_entry_free(entry); return -1; }
int rc = etcp_send(conn, entry);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "%s: etcp_send rc=%d id=0x%02x to=%016llx conn=%s", CS_ID, rc, payload[0], (unsigned long long)dst, conn->log_name);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: etcp_send rc=%d id=0x%02x to=%016llx conn=%s", CS_ID, rc, payload[0], (unsigned long long)dst, conn->log_name);
return rc;
}
@ -158,7 +158,7 @@ static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* in
static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!entry || entry->len < 4) {
if (entry) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: recv short entry len=%zu conn=%s", CS_ID, entry->len, conn ? conn->log_name : "?");
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: recv short entry len=%zu conn=%s", CS_ID, entry->len, conn ? conn->log_name : "?");
if (entry->dgram) u_free(entry->dgram); queue_entry_free(entry);
}
return;
@ -174,22 +174,22 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
char ch_id[64]; memcpy(ch_id, d + 2, ch_len); ch_id[ch_len] = '\0';
uint8_t type = d[2 + ch_len];
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: recv %s(%02x) from=%016llx ch=%s len=%zu",
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: recv %s(%02x) from=%016llx ch=%s len=%zu",
CS_ID, cs_msg_name(type), type, (unsigned long long)peer, ch_id, dlen);
const uint8_t* pl = d + 3 + ch_len;
size_t plen = dlen - 3 - ch_len;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: RECV %s from=%016llx ch=%s len=%zu",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: RECV %s from=%016llx ch=%s len=%zu",
CS_ID, cs_msg_name(type), (unsigned long long)peer, ch_id, plen);
switch (type) {
case CS_MSG_CHANNEL_INFO_REQ: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → handle INFO_REQ", CS_ID); cs_handle_channel_info_req(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_INFO_RESP:DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → handle INFO_RESP", CS_ID); cs_handle_channel_info_resp(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_JOIN: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → handle JOIN", CS_ID); cs_handle_channel_join(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_WELCOME: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → handle WELCOME", CS_ID); cs_handle_welcome(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_PEER_UPSERT: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → handle PEER_UPSERT", CS_ID); cs_handle_peer_upsert(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_INFO_REQ: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle INFO_REQ", CS_ID); cs_handle_channel_info_req(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_INFO_RESP:DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle INFO_RESP", CS_ID); cs_handle_channel_info_resp(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_JOIN: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN", CS_ID); cs_handle_channel_join(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_WELCOME: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle WELCOME", CS_ID); cs_handle_welcome(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_PEER_UPSERT: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle PEER_UPSERT", CS_ID); cs_handle_peer_upsert(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_ERROR: {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: RECV ERROR from=%016llx ch=%s", CS_ID, (unsigned long long)peer, ch_id);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: RECV ERROR from=%016llx ch=%s", CS_ID, (unsigned long long)peer, ch_id);
if (g_cs->info_req_timer) { uasync_cancel_timeout(g_cs->inst->ua, g_cs->info_req_timer); g_cs->info_req_timer = NULL; }
uint8_t err[20]; memcpy(err, &peer, 8); int r = -1; memcpy(err + 8, &r, 4);
memcpy(err + 12, &g_cs->pending_invite_ch_id, 8); chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20);
@ -198,7 +198,7 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
}
case CS_MSG_PEER_REMOVE: cs_handle_peer_remove(g_cs, peer, ch_id, pl, plen); break;
case CS_MSG_CHANNEL_INVITE: cs_handle_channel_invite(g_cs, peer, ch_id, pl, plen); break;
default: DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: UNKNOWN msg type=%02x from=%016llx", CS_ID, type, (unsigned long long)peer); break;
default: DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: UNKNOWN msg type=%02x from=%016llx", CS_ID, type, (unsigned long long)peer); break;
}
u_free(entry->dgram); queue_entry_free(entry);
}
@ -209,7 +209,7 @@ static void cs_info_req_timeout_cb(void* arg) {
struct chat_sync* cs = (struct chat_sync*)arg;
if (!cs || !cs->initialized) return;
cs->info_req_timer = NULL;
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_REQ timeout peer=%016llx ch=%llu",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_REQ timeout peer=%016llx ch=%llu",
CS_ID, (unsigned long long)cs->pending_invite_node_id,
(unsigned long long)cs->pending_invite_ch_id);
uint8_t err[20]; memcpy(err, &cs->pending_invite_node_id, 8);
@ -225,7 +225,7 @@ static void cs_join_timeout_cb(void* arg) {
if (!cs || !cs->initialized) return;
cs->join_timer = NULL;
uint64_t peer = cs->pending_invite_node_id;
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_JOIN timeout peer=%016llx ch=%llu",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_JOIN timeout peer=%016llx ch=%llu",
CS_ID, (unsigned long long)peer, (unsigned long long)cs->pending_invite_ch_id);
uint8_t err[20]; memcpy(err, &peer, 8);
int r = CONN_EVENT_TIMEOUT; memcpy(err + 8, &r, 4);
@ -241,7 +241,7 @@ static void cs_invite_send_timeout_cb(void* arg) {
if (!cs || !cs->initialized) return;
cs->invite_send_timer = NULL;
uint64_t peer = cs->pending_invite_node_id;
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE timeout — joiner did not respond peer=%016llx ch=%llu",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE timeout — joiner did not respond peer=%016llx ch=%llu",
CS_ID, (unsigned long long)peer, (unsigned long long)cs->pending_invite_ch_id);
uint8_t err[20]; memcpy(err, &peer, 8);
int r = CONN_EVENT_TIMEOUT; memcpy(err + 8, &r, 4);
@ -257,8 +257,8 @@ static void cs_invite_send_timeout_cb(void* arg) {
static struct ETCP_CONN* cs_find_conn_for_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
if (conn && conn->initialized && conn->links_up) return conn;
if (!inst->connections) { DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn connections=NULL", CS_ID); return NULL; }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn node=%016llx NOT FOUND (head=%p count=%d)",
if (!inst->connections) { DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn connections=NULL", CS_ID); return NULL; }
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn node=%016llx NOT FOUND (head=%p count=%d)",
CS_ID, (unsigned long long)node_id, (void*)inst->connections->head, queue_entry_count(inst->connections));
return NULL;
}
@ -275,7 +275,7 @@ static struct ETCP_CONN* cs_find_conn_by_pubkey(struct UTUN_INSTANCE* inst,
if (conn && conn->initialized && conn->links_up
&& memcmp(conn->crypto_ctx.peer_public_key, pubkey_bin, 32) == 0) {
*out_node_id = conn->peer_node_id;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn_by_pubkey MATCH conn=%s peer=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn_by_pubkey MATCH conn=%s peer=0x%016llx",
CS_ID, conn->log_name, (unsigned long long)conn->peer_node_id);
return conn;
}
@ -287,10 +287,10 @@ static struct ETCP_CONN* cs_find_conn_by_pubkey(struct UTUN_INSTANCE* inst,
/* ── helper: check if peer has active ETCP link ── */
static int cs_is_peer_online(struct UTUN_INSTANCE* inst, uint64_t peer_id) {
if (!inst->connections) { DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: is_online peer=0x%016llx CONNS=NULL", CS_ID, (unsigned long long)peer_id); return 0; }
if (!inst->connections) { DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: is_online peer=0x%016llx CONNS=NULL", CS_ID, (unsigned long long)peer_id); return 0; }
struct ETCP_CONN* conn = instance_find_conn(inst, peer_id);
if (conn) return conn->initialized && conn->links_up;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: is_online peer=0x%016llx NOT FOUND", CS_ID, (unsigned long long)peer_id);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: is_online peer=0x%016llx NOT FOUND", CS_ID, (unsigned long long)peer_id);
return 0;
}
@ -305,7 +305,7 @@ static void cs_post_channel_online(struct chat_sync* cs, const char* ch_id) {
for (int j = 0; j < ch->peer_count; j++) {
int p_on = cs_is_peer_online(cs->inst, ch->peer_ids[j]);
if (p_on) online++;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: PEERS_ONLINE peer[%d]=0x%016llx online=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEERS_ONLINE peer[%d]=0x%016llx online=%d",
CS_ID, j, (unsigned long long)ch->peer_ids[j], p_on);
}
}
@ -315,7 +315,7 @@ static void cs_post_channel_online(struct chat_sync* cs, const char* ch_id) {
memcpy(evt + 1, ch_id, cl);
uint16_t oc = (uint16_t)online; memcpy(evt + 1 + cl, &oc, 2);
chat_event_post(CHAT_EVT_CHANNEL_PEERS_ONLINE, evt, 1 + (int)cl + 2);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: PEERS_ONLINE ch=%.*s total_online=%d", CS_ID, (int)cl, ch_id, online);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEERS_ONLINE ch=%.*s total_online=%d", CS_ID, (int)cl, ch_id, online);
}
/* ── Throttled sync (не чаще CS_SYNC_INTERVAL_MS) ── */
@ -327,7 +327,7 @@ static void cs_flush_sync(struct chat_sync* cs) {
for (int j = 0; j < ch->peer_count; j++) {
uint64_t pid = ch->peer_ids[j];
if (pid == myid || !cs_is_peer_online(cs->inst, pid)) continue;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: flush_sync start for peer=%016llx ch=%s",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: flush_sync start for peer=%016llx ch=%s",
CS_ID, (unsigned long long)pid, ch->channel_id);
member_sync_start(cs->inst, pid, ch->channel_id, NULL, NULL);
}
@ -339,7 +339,7 @@ static void cs_sync_timer_cb(void* arg) {
if (!cs || !cs->initialized) return;
cs->sync_timer = NULL;
cs->sync_scheduled = 0;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: sync timer fire", CS_ID);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sync timer fire", CS_ID);
cs_flush_sync(cs);
}
@ -348,14 +348,14 @@ static void cs_schedule_sync(struct chat_sync* cs) {
cs->sync_scheduled = 1;
cs->sync_timer = uasync_set_timeout(cs->inst->ua,
CS_SYNC_INTERVAL_MS * 10, cs, cs_sync_timer_cb, "cs_sync");
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: sync scheduled in %ums", CS_ID, CS_SYNC_INTERVAL_MS);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sync scheduled in %ums", CS_ID, CS_SYNC_INTERVAL_MS);
}
/* ── Unified peer status change (локальная БД + GUI + push_update + schedule_sync) ── */
static void cs_on_remote_status_changed(uint64_t peer, int online) {
if (!g_cs) return;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: remote status changed peer=%016llx online=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: remote status changed peer=%016llx online=%d",
CS_ID, (unsigned long long)peer, online);
for (int i = 0; i < g_cs->channel_count; i++) {
for (int j = 0; j < g_cs->channels[i].peer_count; j++) {
@ -397,7 +397,7 @@ static void cs_on_peer_status_changed(uint64_t peer, int online) {
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: peer_status_changed peer=0x%016llx online=%d channels=%d found=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: peer_status_changed peer=0x%016llx online=%d channels=%d found=%d",
CS_ID, (unsigned long long)peer, online, g_cs->channel_count, found_in_channel);
/* 4. Запланировать member_sync_start (throttled) */
@ -407,7 +407,7 @@ static void cs_on_peer_status_changed(uint64_t peer, int online) {
static void _on_member_sync_done(uint64_t peer, const char* ns, int result, void* arg) {
struct channel_cache* ch = (struct channel_cache*)arg;
if (result == MT_OK && ch) ch->synced = CS_SYNC_DONE;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync %s ns=%s peer=%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_sync %s ns=%s peer=%016llx",
CS_ID, result == MT_OK ? "OK" : "FAIL", ns, (unsigned long long)peer);
}
@ -418,18 +418,18 @@ struct invite_sync_arg {
static void _on_invite_sync_done(uint64_t peer, const char* ns, int result, void* arg) {
struct invite_sync_arg* sa = (struct invite_sync_arg*)arg;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync %s ns=%s peer=%016llx sa=%p node=0x%016llx ch=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_sync %s ns=%s peer=%016llx sa=%p node=0x%016llx ch=%s",
CS_ID, result == MT_OK ? "OK" : "FAIL", ns,
(unsigned long long)peer, (void*)sa, sa ? (unsigned long long)sa->node_id : 0, sa ? sa->ch_id : "(null)");
if (result == MT_OK && sa && g_cs) {
if (sa->node_id == 0 || sa->ch_id[0] == '\0') {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync CORRUPTED sa=%p node_id=0x%016llx ch_id='%s' — skip, will free",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_sync CORRUPTED sa=%p node_id=0x%016llx ch_id='%s' — skip, will free",
CS_ID, (void*)sa, (unsigned long long)sa->node_id, sa->ch_id);
} else {
cs_post_channel_online(g_cs, sa->ch_id);
uint8_t one = 1;
merkle_sync_push_update(g_cs->inst, sa->ch_id, sa->node_id, 0x01, &one, 1);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync push_update node=0x%016llx online=1 ch=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_sync push_update node=0x%016llx online=1 ch=%s",
CS_ID, (unsigned long long)sa->node_id, sa->ch_id);
}
}
@ -450,7 +450,7 @@ static void cs_start_channel_join(struct chat_sync* cs, uint64_t peer) {
cs_send(cs, ch_id_str, peer, req, 2 + (plen > 127 ? 127 : (int)plen));
cs->info_req_timer = uasync_set_timeout(cs->inst->ua,
CS_INFO_REQ_TIMEOUT_MS * 10, cs, cs_info_req_timeout_cb, "cs_info_req");
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: sent CHANNEL_INFO_REQ ch=%llu peer=0x%016llx pass_len=%zu",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sent CHANNEL_INFO_REQ ch=%llu peer=0x%016llx pass_len=%zu",
CS_ID, (unsigned long long)cs->pending_invite_ch_id, (unsigned long long)peer, plen);
}
@ -461,14 +461,14 @@ static void cs_on_conn_up(struct ETCP_CONN* conn, int event, void* arg) { (void)
if (!conn || !g_cs) return;
uint64_t peer = conn->peer_node_id;
if (peer == 0 || peer == g_cs->inst->node_id) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: conn_up peer=%016llx init=%d links=%d", CS_ID, (unsigned long long)peer, conn->initialized, conn->links_up);
if (!conn->initialized) { DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: conn_up SKIP — not initialized peer=%016llx", CS_ID, (unsigned long long)peer); return; }
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: conn_up peer=%016llx init=%d links=%d", CS_ID, (unsigned long long)peer, conn->initialized, conn->links_up);
if (!conn->initialized) { DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: conn_up SKIP — not initialized peer=%016llx", CS_ID, (unsigned long long)peer); return; }
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: conn_up peer=%016llx pending_invite=%llu links_up=%d", CS_ID, (unsigned long long)peer, (unsigned long long)g_cs->pending_invite_ch_id, conn->links_up);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: conn_up peer=%016llx pending_invite=%llu links_up=%d", CS_ID, (unsigned long long)peer, (unsigned long long)g_cs->pending_invite_ch_id, conn->links_up);
if (g_cs->pending_invite_ch_id != 0) {
if (g_cs->pending_invite_node_id != 0 && g_cs->pending_invite_node_id != peer)
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: invite node_id MISMATCH: invite=0x%016llx ETCP_peer=0x%016llx — invite is STALE!",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite node_id MISMATCH: invite=0x%016llx ETCP_peer=0x%016llx — invite is STALE!",
CS_ID, (unsigned long long)g_cs->pending_invite_node_id, (unsigned long long)peer);
g_cs->pending_invite_node_id = peer;
if (g_cs->pending_invite_is_inviter) {
@ -497,13 +497,13 @@ static void cs_on_conn_down(struct ETCP_CONN* conn, int event, void* arg) { (voi
(void)arg;
if (!conn || !g_cs) return;
uint64_t peer = conn->peer_node_id;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: conn_down peer=%016llx", CS_ID, (unsigned long long)peer);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: conn_down peer=%016llx", CS_ID, (unsigned long long)peer);
cs_on_peer_status_changed(peer, 0);
cs_cancel_proto_timers(g_cs);
if (g_cs->pending_invite_node_id == peer) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: conn down while waiting invite resp peer=%016llx, timers cancelled, state kept for retry on reconnect",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: conn down while waiting invite resp peer=%016llx, timers cancelled, state kept for retry on reconnect",
CS_ID, (unsigned long long)peer);
/* invite state survives connection flaps: only timeout or explicit protocol end clears it */
}
@ -532,7 +532,7 @@ static void cs_on_conn_status(struct ETCP_CONN* conn, int status, void* arg) {
static void cs_on_new_conn(struct ETCP_CONN* conn, void* arg) {
(void)arg;
if (!conn) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: new_conn conn=%p", CS_ID, (void*)conn);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: new_conn conn=%p", CS_ID, (void*)conn);
etcp_conn_add_cbk(conn, cs_on_conn_up, NULL, ETCP_CBK_EVENT_UP);
etcp_conn_add_cbk(conn, cs_on_conn_down, NULL, ETCP_CBK_EVENT_DOWN);
}
@ -599,7 +599,7 @@ static void refresh_timer_cb(void* arg) {
int chat_sync_init(struct UTUN_INSTANCE* inst) {
if (!inst) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: init", CS_ID);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: init", CS_ID);
struct chat_sync* cs = u_calloc(1, sizeof(*cs));
if (!cs) return -1;
cs->inst = inst;
@ -619,14 +619,14 @@ int chat_sync_init(struct UTUN_INSTANCE* inst) {
member_sync_init(inst);
member_sync_set_node_updated_cb(cs_on_remote_status_changed);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: initialized", CS_ID);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: initialized", CS_ID);
return 0;
}
void chat_sync_destroy(struct UTUN_INSTANCE* inst) {
struct chat_sync* cs = g_cs;
if (!cs || !inst) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: destroy", CS_ID);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: destroy", CS_ID);
if (cs->sync_timer) { uasync_cancel_timeout(inst->ua, cs->sync_timer); cs->sync_timer = NULL; }
if (cs->invite_send_timer) { uasync_cancel_timeout(inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; }
if (cs->sync_scheduled) { cs->sync_scheduled = 0; cs_flush_sync(cs); }
@ -767,7 +767,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
}
struct chat_invite* inv = u_calloc(1, sizeof(struct chat_invite));
if (!inv) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite calloc failed", CS_ID); return; }
if (!inv) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: connect_from_invite calloc failed", CS_ID); return; }
inv->channel_id = channel_id;
inv->node_id = node_id;
@ -775,7 +775,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
size_t addrs_sz = addrs_data_len > 0 ? (size_t)addrs_data_len : (size_t)addr_count * 9;
inv->addrs_data = u_malloc(addrs_sz);
if (!inv->addrs_data) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite malloc(%zu) failed", CS_ID, addrs_sz); u_free(inv); return; }
if (!inv->addrs_data) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: connect_from_invite malloc(%zu) failed", CS_ID, addrs_sz); u_free(inv); return; }
memcpy(inv->addrs_data, addrs_data, addrs_sz);
inv->addr_count = addr_count;
@ -794,7 +794,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
(long long)channel_id, (long long)node_id, addr_count, password ? "yes" : "no");
#endif
#ifndef __ANDROID__
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite start ch=%llu node=0x%016llx pubkey=%016llx... addrs=%d pass=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite start ch=%llu node=0x%016llx pubkey=%016llx... addrs=%d pass=%s",
CS_ID, channel_id, node_id, *(const uint64_t*)pubkey_bin, addr_count, password && password[0] ? "yes" : "no");
#endif
@ -807,20 +807,20 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
/* ─── chat_sync_join_channel: join channel via already-connected peer ─── */
void chat_sync_join_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id) {
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: inst=NULL", CS_ID); return; }
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: ch_id NULL/empty", CS_ID); return; }
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel: inst=NULL", CS_ID); return; }
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel: ch_id NULL/empty", CS_ID); return; }
uint64_t channel_id = strtoull(ch_id, NULL, 10);
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel invalid ch_id='%s'", CS_ID, ch_id); return; }
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel invalid ch_id='%s'", CS_ID, ch_id); return; }
struct ETCP_CONN* conn = instance_find_conn(inst, target_node_id);
if (!conn || !conn->links_up || !conn->initialized) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel no active conn to 0x%016llx for ch=%s",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel no active conn to 0x%016llx for ch=%s",
CS_ID, (unsigned long long)target_node_id, ch_id);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel ch=%s peer=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel ch=%s peer=0x%016llx",
CS_ID, ch_id, (unsigned long long)target_node_id);
g_cs->pending_invite_ch_id = channel_id;
@ -834,7 +834,7 @@ void chat_sync_join_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint6
static int cs_ed25519_sign(const uint8_t* privkey, const uint8_t* msg, size_t msg_len,
uint8_t* sig_out) {
EVP_PKEY* pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, privkey, SC_PRIVKEY_SIZE);
if (!pkey) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: EVP_PKEY_new failed", CS_ID); return -1; }
if (!pkey) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: EVP_PKEY_new failed", CS_ID); return -1; }
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
if (!mdctx) { EVP_PKEY_free(pkey); return -1; }
int ok = (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) == 1)
@ -847,7 +847,7 @@ static int cs_ed25519_sign(const uint8_t* privkey, const uint8_t* msg, size_t ms
static int cs_ed25519_verify(const uint8_t* pubkey, const uint8_t* msg, size_t msg_len,
const uint8_t* sig) {
EVP_PKEY* pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, pubkey, SC_PUBKEY_SIZE);
if (!pkey) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: EVP_PKEY_new pub failed", CS_ID); return -1; }
if (!pkey) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: EVP_PKEY_new pub failed", CS_ID); return -1; }
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
if (!mdctx) { EVP_PKEY_free(pkey); return -1; }
int rc = EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey)
@ -876,7 +876,7 @@ static int _get_node_name(sqlite3* db, uint64_t node_id, char* out, size_t sz) {
if (!db || !out || !sz) return -1;
sqlite3_stmt* st = NULL;
sqlite3_prepare_v2(db, "SELECT name FROM nodes WHERE node_id=?", -1, &st, NULL);
if (!st) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: _get_node_name prepare failed node=0x%016llx", CS_ID, (unsigned long long)node_id); return -1; }
if (!st) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: _get_node_name prepare failed node=0x%016llx", CS_ID, (unsigned long long)node_id); return -1; }
sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id);
int rc = -1;
if (sqlite3_step(st) == SQLITE_ROW) {
@ -892,7 +892,7 @@ static int _get_node_name(sqlite3* db, uint64_t node_id, char* out, size_t sz) {
static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: INFO_REQ ch=%s from=%016llx len=%zu", CS_ID, ch_id, (unsigned long long)peer, len);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: INFO_REQ ch=%s from=%016llx len=%zu", CS_ID, ch_id, (unsigned long long)peer, len);
/* joiner responded to our CHANNEL_INVITE — cancel invite send timer */
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; }
@ -912,7 +912,7 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
struct global_config *gcfg = &cs->inst->config->global;
if (gcfg->chatserver_enabled && gcfg->chatserver_join_password[0]) {
if (strcmp(req_password, gcfg->chatserver_join_password) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_REQ wrong password ch=%s from=%016llx (got '%s', expected '%s')",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_REQ wrong password ch=%s from=%016llx (got '%s', expected '%s')",
CS_ID, ch_id, (unsigned long long)peer, req_password, gcfg->chatserver_join_password);
uint8_t err[2] = { CS_MSG_ERROR, 0x01 }; /* 0x01 = wrong password */
cs_send(cs, ch_id, peer, err, 2);
@ -924,13 +924,13 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
char name[128]; uint64_t owner; uint8_t x25519[32], ed_pub[32], ch_sig[64];
if (topo_node_sqlite_channel_get(cs->inst->topo_sqlite_db,
ch_id, name, (int)sizeof(name), &owner, x25519, ed_pub, ch_sig) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_REQ unknown ch=%s from=%016llx", CS_ID, ch_id, (unsigned long long)peer);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_REQ unknown ch=%s from=%016llx", CS_ID, ch_id, (unsigned long long)peer);
uint8_t err[1] = { CS_MSG_ERROR }; cs_send(cs, ch_id, peer, err, 1);
return;
}
uint64_t myid = cs->inst->node_id;
if (memcmp(cs->inst->my_keys.public_key, x25519, 32) != 0)
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP pubkey MISMATCH: my=%016llx ch=%016llx — channel was created with DIFFERENT keys!",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP pubkey MISMATCH: my=%016llx ch=%016llx — channel was created with DIFFERENT keys!",
CS_ID, *(const uint64_t*)cs->inst->my_keys.public_key, *(const uint64_t*)x25519);
/* load or create join_sig */
uint8_t my_join_sig[64] = {0}; uint64_t my_join_ts = 0;
@ -945,7 +945,7 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
my_join_ts = (uint64_t)ntp_time_get_seconds(cs->inst);
memcpy(join_msg + mlen, &my_join_ts, 8); mlen += 8;
cs_ed25519_sign(cs->inst->my_ed25519_privkey, join_msg, mlen, my_join_sig);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP created NEW join_sig: myid=%016llx ts=%llu",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP created NEW join_sig: myid=%016llx ts=%llu",
CS_ID, (unsigned long long)myid, (unsigned long long)my_join_ts);
}
}
@ -989,11 +989,11 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: INFO_RESP ch=%s from=%016llx len=%zu", CS_ID, ch_id, (unsigned long long)peer, len);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: INFO_RESP ch=%s from=%016llx len=%zu", CS_ID, ch_id, (unsigned long long)peer, len);
if (cs->info_req_timer) { uasync_cancel_timeout(cs->inst->ua, cs->info_req_timer); cs->info_req_timer = NULL; }
if (len < 1) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
if (len < 1) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
uint8_t nl = pl[0];
if (1 + nl + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP truncated len=%zu", CS_ID, len); return; }
if (1 + nl + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP truncated len=%zu", CS_ID, len); return; }
const uint8_t* p = pl + 1;
char name[128]; memcpy(name, p, nl); name[nl] = '\0'; p += nl;
uint64_t owner; memcpy(&owner, p, 8); p += 8;
@ -1003,7 +1003,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
uint8_t inv_flags = *p++;
const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0;
if (inv_flags & PEERS_FLAG_HAS_JOIN) {
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP truncated at inviter_join_sig peer=%016llx", CS_ID, (unsigned long long)peer); return; }
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP truncated at inviter_join_sig peer=%016llx", CS_ID, (unsigned long long)peer); return; }
inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8;
}
const uint8_t* inviter_update_sig = p; p += 64; uint64_t inviter_update_ts;
@ -1012,7 +1012,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
char inv_userinfo[128] = "";
if (p + inv_userinfo_len <= pl + len) { memcpy(inv_userinfo, p, inv_userinfo_len); inv_userinfo[inv_userinfo_len] = '\0'; }
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP from peer=%016llx owner=%016llx ch_x25519=%016llx ch_ed=%016llx name=%s",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP from peer=%016llx owner=%016llx ch_x25519=%016llx ch_ed=%016llx name=%s",
CS_ID, (unsigned long long)peer, (unsigned long long)owner,
*(const uint64_t*)x25519, *(const uint64_t*)ed_pub, name);
@ -1024,7 +1024,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
memcpy(vmsg + vlen, x25519, 32); vlen += 32;
memcpy(vmsg + vlen, ed_pub, 32); vlen += 32;
if (cs_ed25519_verify(ed_pub, vmsg, vlen, ch_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP invalid ch_sig ch=%s", CS_ID, ch_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP invalid ch_sig ch=%s", CS_ID, ch_id);
return;
}
@ -1032,13 +1032,13 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
topo_node_sqlite_channel_put(cs->inst->topo_sqlite_db,
ch_id, name, owner, x25519, NULL, ed_pub, NULL, ch_sig);
chat_core_ensure_channel_ready(ch_id);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: channel ready for sync ch=%s, db_sync will pick up via periodic check or active conn",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: channel ready for sync ch=%s, db_sync will pick up via periodic check or active conn",
CS_ID, ch_id);
/* verify inviter's join_sig AND save node info using ETCP-authenticated keys */
{ struct ETCP_CONN* inv_conn = cs_find_conn_for_node(cs->inst, peer);
if (!inv_conn) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP no ETCP conn for inviter peer=%016llx", CS_ID, (unsigned long long)peer);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP no ETCP conn for inviter peer=%016llx", CS_ID, (unsigned long long)peer);
return;
}
const uint8_t* inv_x25519 = inv_conn->crypto_ctx.peer_public_key;
@ -1050,12 +1050,12 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
{ const char* nm = inv_userinfo[0] ? inv_userinfo : "";
size_t nl2 = strlen(nm); memcpy(ivmsg + ilen, nm, nl2 + 1); ilen += nl2 + 1; }
if (cs_ed25519_verify(inv_ed, ivmsg, ilen, inviter_update_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP invalid inviter_update_sig peer=%016llx ts=%llu",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INFO_RESP invalid inviter_update_sig peer=%016llx ts=%llu",
CS_ID, (unsigned long long)peer, (unsigned long long)inviter_update_ts);
}
sqlite3* vdb = cs->inst->topo_sqlite_db;
/* save inviter's address from ETCP connection */
{ DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INFO_RESP save inviter peer=%016llx", CS_ID, (unsigned long long)peer);
{ DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP save inviter peer=%016llx", CS_ID, (unsigned long long)peer);
struct ETCP_LINK* lk = inv_conn->links;
int lk_count = 0, lk_written = 0;
while (lk) { lk_count++;
@ -1072,19 +1072,19 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
sqlite3_bind_int(as, 4, (int)lk->conn->sock_id);
sqlite3_step(as); sqlite3_finalize(as);
lk_written++;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INFO_RESP INSERT peer=%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP INSERT peer=%016llx sock=%d %d.%d.%d.%d:%d",
CS_ID, (unsigned long long)peer, (int)lk->conn->sock_id, ip[0], ip[1], ip[2], ip[3], port);
}
} else if (lk->initialized) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INFO_RESP SKIP non-IPv4 link for peer=%016llx", CS_ID, (unsigned long long)peer);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP SKIP non-IPv4 link for peer=%016llx", CS_ID, (unsigned long long)peer);
}
lk = lk->next;
}
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INFO_RESP DONE peer=%016llx: %d links, %d written",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP DONE peer=%016llx: %d links, %d written",
CS_ID, (unsigned long long)peer, lk_count, lk_written);
}
int rc = topo_node_sqlite_member_put(vdb, ch_id, peer, inviter_join_sig, inviter_join_ts, inviter_update_sig, inviter_update_ts, inv_x25519, inv_ed, inv_userinfo, inviter_join_sig, NULL, NULL, 0);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(inviter) FAILED ch=%s peer=%016llx rc=%d", CS_ID, ch_id, (unsigned long long)peer, rc);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put(inviter) FAILED ch=%s peer=%016llx rc=%d", CS_ID, ch_id, (unsigned long long)peer, rc);
char inv_name[128]; json_flat_get(inv_userinfo, "name", inv_name, sizeof(inv_name));
topo_node_sqlite_node_update_verified(vdb, peer, inv_name, inv_x25519, inv_ed, inviter_join_ts, ntp_time_get_seconds(cs->inst));
}
@ -1159,10 +1159,10 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
if (len < 8 + 32 + 32 + 64 + 8 + 1 + 1) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_JOIN too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
if (len < 8 + 32 + 32 + 64 + 8 + 1 + 1) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_JOIN too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
const uint8_t* p = pl;
uint64_t node_id; memcpy(&node_id, p, 8); p += 8;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN ch=%s node=%016llx from=%016llx", CS_ID, ch_id, (unsigned long long)node_id, (unsigned long long)peer);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN ch=%s node=%016llx from=%016llx", CS_ID, ch_id, (unsigned long long)node_id, (unsigned long long)peer);
const uint8_t* x25519 = p; p += 32;
const uint8_t* ed_pub = p; p += 32;
const uint8_t* join_sig = p; p += 64;
@ -1176,7 +1176,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
uint8_t ch_x25519[32], ch_ed25519[32];
if (topo_node_sqlite_channel_get(cs->inst->topo_sqlite_db, ch_id,
NULL, 0, NULL, ch_x25519, ch_ed25519, NULL) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN channel not in DB ch=%s", CS_ID, ch_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN channel not in DB ch=%s", CS_ID, ch_id);
return;
}
uint8_t vmsg[256]; size_t vlen = 0;
@ -1186,7 +1186,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
memcpy(vmsg + vlen, x25519, 32); vlen += 32;
memcpy(vmsg + vlen, &join_ts, 8); vlen += 8;
if (cs_ed25519_verify(ed_pub, vmsg, vlen, join_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx ts=%llu)", CS_ID,
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx ts=%llu)", CS_ID,
(unsigned long long)node_id, ch_id,
(unsigned long long)node_id, *(const uint64_t*)x25519, *(const uint64_t*)ed_pub, (unsigned long long)join_ts);
return;
@ -1194,19 +1194,19 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
sqlite3* db = cs->inst->topo_sqlite_db;
int rc = topo_node_sqlite_member_put(db, ch_id, node_id, join_sig, join_ts, NULL, 0, x25519, ed_pub, joiner_userinfo, NULL, NULL, NULL, 0);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(joiner) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put(joiner) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
{ char j_name[128]; json_flat_get(joiner_userinfo, "name", j_name, sizeof(j_name));
topo_node_sqlite_node_update_verified(db, node_id, j_name, x25519, ed_pub, join_ts, ntp_time_get_seconds(cs->inst)); }
/* save/update node addresses */
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] JOIN save addrs node=0x%016llx addr_cnt=%d", CS_ID, (unsigned long long)node_id, addr_cnt);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] JOIN save addrs node=0x%016llx addr_cnt=%d", CS_ID, (unsigned long long)node_id, addr_cnt);
for (uint8_t i = 0; i < addr_cnt && p + 2 <= pl + len; i++) {
uint8_t fm = *p++;
uint8_t sid = *p++;
uint8_t proto = *p++;
int ip_len = (fm == 4) ? 4 : 16;
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN addr truncated node=0x%016llx fm=%u i=%u", CS_ID, (unsigned long long)node_id, fm, i); break; }
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN addr truncated node=0x%016llx fm=%u i=%u", CS_ID, (unsigned long long)node_id, fm, i); break; }
const uint8_t* ip = p; p += ip_len;
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2;
@ -1223,10 +1223,10 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
sqlite3_step(stmt); sqlite3_finalize(stmt);
}
if (fm == 4)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] JOIN INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] JOIN INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
CS_ID, (unsigned long long)node_id, sid, ip[0], ip[1], ip[2], ip[3], port);
else
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] JOIN INSERT v6 node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] JOIN INSERT v6 node=0x%016llx sock=%d port=%d",
CS_ID, (unsigned long long)node_id, sid, port);
}
@ -1270,17 +1270,17 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
{ uint8_t evt[65]; uint8_t cl=(uint8_t)strlen(ch_id); evt[0]=cl; memcpy(evt+1,ch_id,cl);
chat_event_post(CHAT_EVT_MEMBERS_CHANGED, evt, 1+cl); }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN calling cs_post_channel_online ch=%s", CS_ID, ch_id);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN calling cs_post_channel_online ch=%s", CS_ID, ch_id);
cs_post_channel_online(cs, ch_id);
/* initiate member sync with the joiner (server side) */
struct invite_sync_arg* sa = u_malloc(sizeof(struct invite_sync_arg));
if (sa) { sa->node_id = node_id;
strncpy(sa->ch_id, ch_id, sizeof(sa->ch_id) - 1); sa->ch_id[sizeof(sa->ch_id) - 1] = '\0';
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN alloc sa=%p node=0x%016llx ch=%s", CS_ID, (void*)sa, (unsigned long long)sa->node_id, sa->ch_id);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN alloc sa=%p node=0x%016llx ch=%s", CS_ID, (void*)sa, (unsigned long long)sa->node_id, sa->ch_id);
member_sync_start(cs->inst, node_id, ch_id, _on_invite_sync_done, sa); }
else member_sync_start(cs->inst, node_id, ch_id, NULL, NULL);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN starting member_sync with joiner node=0x%016llx ch=%s done_cb=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN starting member_sync with joiner node=0x%016llx ch=%s done_cb=%s",
CS_ID, (unsigned long long)node_id, ch_id, sa ? "yes" : "no");
/* if we're the inviter — joiner joined successfully, notify GUI */
@ -1289,14 +1289,14 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
uint8_t evt[20]; memcpy(evt, &node_id, 8); int r = 0; memcpy(evt + 8, &r, 4);
memcpy(evt + 12, &ch_id_num, 8);
chat_event_post(CHAT_EVT_CONNECT_RESULT, evt, 20);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN posted CHAT_EVT_CONNECT_RESULT to GUI node=0x%016llx ch=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN posted CHAT_EVT_CONNECT_RESULT to GUI node=0x%016llx ch=%s",
CS_ID, (unsigned long long)node_id, ch_id);
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0;
cs->pending_invite_is_inviter = 0;
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; }
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN accepted node=0x%016llx ch=%s addrs=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN accepted node=0x%016llx ch=%s addrs=%d",
CS_ID, (unsigned long long)node_id, ch_id, addr_cnt);
}
@ -1306,21 +1306,21 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
if (cs->join_timer) { uasync_cancel_timeout(cs->inst->ua, cs->join_timer); cs->join_timer = NULL; }
(void)peer;
if (len < 2) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
if (len < 2) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer); return; }
sqlite3* db = cs->inst->topo_sqlite_db;
const uint8_t* p = pl;
uint16_t pc; memcpy(&pc, p, 2); p += 2;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME ch=%s from=%016llx peers=%u", CS_ID, ch_id, (unsigned long long)peer, pc);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME ch=%s from=%016llx peers=%u", CS_ID, ch_id, (unsigned long long)peer, pc);
for (uint16_t i = 0; i < pc; i++) {
if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME peer[%u] truncated at %td len=%zu", CS_ID, i, p - pl, len); break; } /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */
if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME peer[%u] truncated at %td len=%zu", CS_ID, i, p - pl, len); break; } /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */
uint64_t node_id; memcpy(&node_id, p, 8); p += 8;
const uint8_t* x25519 = p; p += 32;
const uint8_t* ed_pub = p; p += 32;
uint8_t flags = *p++;
const uint8_t* join_sig = NULL; uint64_t join_ts = 0;
if (flags & PEERS_FLAG_HAS_JOIN) {
if (p + 64 + 8 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME join_sig truncated node=0x%016llx i=%u", CS_ID, (unsigned long long)node_id, i); break; }
if (p + 64 + 8 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME join_sig truncated node=0x%016llx i=%u", CS_ID, (unsigned long long)node_id, i); break; }
join_sig = p; p += 64;
memcpy(&join_ts, p, 8); p += 8;
}
@ -1341,7 +1341,7 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
uint8_t ch_x2[32], ch_ed2[32];
if (topo_node_sqlite_channel_get(db, ch_id,
NULL, 0, NULL, ch_x2, ch_ed2, NULL) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME channel not in DB ch=%s", CS_ID, ch_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME channel not in DB ch=%s", CS_ID, ch_id);
continue;
}
uint8_t vmsg[256]; size_t vlen = 0;
@ -1356,7 +1356,7 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
if (ver) {
if (EVP_DigestVerifyInit(ver, NULL, NULL, NULL, pkey) != 1
|| EVP_DigestVerify(ver, join_sig, 64, vmsg, vlen) != 1) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME invalid join_sig node=0x%016llx — skipping", CS_ID, (unsigned long long)node_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME invalid join_sig node=0x%016llx — skipping", CS_ID, (unsigned long long)node_id);
EVP_MD_CTX_free(ver); EVP_PKEY_free(pkey);
continue;
}
@ -1367,20 +1367,20 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
}
int rc = topo_node_sqlite_member_put(db, ch_id, node_id, join_sig, join_ts, NULL, 0, x25519, ed_pub, peer_userinfo, NULL, NULL, NULL, 0);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(welcome) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put(welcome) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
{ char pn[256]; json_flat_get(peer_userinfo, "name", pn, sizeof(pn));
topo_node_sqlite_node_update_verified(db, node_id, pn, x25519, ed_pub, join_ts, ntp_time_get_seconds(cs->inst)); }
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] WELCOME save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac);
for (uint8_t j = 0; j < ac; j++) {
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] header truncated node=0x%016llx", CS_ID, j, (unsigned long long)node_id); break; }
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME addr[%u] header truncated node=0x%016llx", CS_ID, j, (unsigned long long)node_id); break; }
uint8_t fm = *p++;
uint8_t sid = *p++;
uint8_t proto = *p++;
int ip_len = (fm == 4) ? 4 : 16;
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, j, (unsigned long long)node_id, fm); break; }
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, j, (unsigned long long)node_id, fm); break; }
const uint8_t* ip = p; p += ip_len;
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2;
@ -1397,10 +1397,10 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
sqlite3_step(stmt2); sqlite3_finalize(stmt2);
}
if (fm == 4)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] WELCOME INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
CS_ID, (unsigned long long)node_id, sid, ip[0], ip[1], ip[2], ip[3], port);
else
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME INSERT v6 node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] WELCOME INSERT v6 node=0x%016llx sock=%d port=%d",
CS_ID, (unsigned long long)node_id, sid, port);
}
member_sync_cancel(g_cs->inst, node_id, ch_id);
@ -1416,9 +1416,9 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
const char* my_name = cs->inst->name[0] ? cs->inst->name : "";
int src = topo_node_sqlite_member_put(db, ch_id, myid, NULL, 0, NULL, 0, my_x25, my_ed, my_name, NULL, NULL, NULL, 0);
if (src != 0)
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(self) FAILED in WELCOME ch=%s rc=%d", CS_ID, ch_id, src);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put(self) FAILED in WELCOME ch=%s rc=%d", CS_ID, ch_id, src);
else
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME added self to peers ch=%s node=0x%016llx", CS_ID, ch_id, (unsigned long long)myid);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME added self to peers ch=%s node=0x%016llx", CS_ID, ch_id, (unsigned long long)myid);
}
uint8_t evt[65]; uint8_t ch_id_len = (uint8_t)strlen(ch_id);
@ -1427,17 +1427,17 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
chat_event_post(CHAT_EVT_MEMBERS_CHANGED, evt, 1 + ch_id_len);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME calling cs_post_channel_online ch=%s", CS_ID, ch_id);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME calling cs_post_channel_online ch=%s", CS_ID, ch_id);
cs_post_channel_online(cs, ch_id);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME processed ch=%s peers=%d — message sync triggered via db_sync (active conn or peer_check timer every 5s)",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME processed ch=%s peers=%d — message sync triggered via db_sync (active conn or peer_check timer every 5s)",
CS_ID, ch_id, pc);
if (cs->pending_invite_ch_id != 0) {
uint64_t ch_id_num = strtoull(ch_id, NULL, 10);
uint8_t cevt[20]; memcpy(cevt, &peer, 8); int r = 0; memcpy(cevt + 8, &r, 4); memcpy(cevt + 12, &ch_id_num, 8);
chat_event_post(CHAT_EVT_CONNECT_RESULT, cevt, 20);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME invite success ch=%s peer=%016llx — posted CHAT_EVT_CONNECT_RESULT",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: WELCOME invite success ch=%s peer=%016llx — posted CHAT_EVT_CONNECT_RESULT",
CS_ID, ch_id, (unsigned long long)peer);
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0; if (cs->join_timer) { uasync_cancel_timeout(cs->inst->ua, cs->join_timer); cs->join_timer = NULL; }
}
@ -1447,7 +1447,7 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
if (len < 8 + 32 + 32 + 64 + 8 + 1 + 1 + 1) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT too short len=%zu", CS_ID, len); return; }
if (len < 8 + 32 + 32 + 64 + 8 + 1 + 1 + 1) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT too short len=%zu", CS_ID, len); return; }
const uint8_t* p = pl;
uint64_t node_id; memcpy(&node_id, p, 8); p += 8;
const uint8_t* x25519 = p; p += 32;
@ -1463,7 +1463,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
uint8_t ch_x3[32], ch_ed3[32];
if (topo_node_sqlite_channel_get(cs->inst->topo_sqlite_db, ch_id,
NULL, 0, NULL, ch_x3, ch_ed3, NULL) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT channel not in DB ch=%s", CS_ID, ch_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT channel not in DB ch=%s", CS_ID, ch_id);
return;
}
uint8_t vmsg[256]; size_t vlen = 0;
@ -1473,7 +1473,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
memcpy(vmsg + vlen, x25519, 32); vlen += 32;
memcpy(vmsg + vlen, &join_ts, 8); vlen += 8;
if (cs_ed25519_verify(ed_pub, vmsg, vlen, join_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT invalid sig node=0x%016llx", CS_ID,
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT invalid sig node=0x%016llx", CS_ID,
(unsigned long long)node_id);
return;
}
@ -1481,19 +1481,19 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
sqlite3* db = cs->inst->topo_sqlite_db;
int rc = topo_node_sqlite_member_put(db, ch_id, node_id, join_sig, join_ts, NULL, 0, x25519, ed_pub, peer_userinfo, NULL, NULL, NULL, 0);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(peer_upsert) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
if (rc != 0) DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put(peer_upsert) FAILED ch=%s node=0x%016llx rc=%d", CS_ID, ch_id, (unsigned long long)node_id, rc);
{ char pn2[128]; json_flat_get(peer_userinfo, "name", pn2, sizeof(pn2));
topo_node_sqlite_node_update_verified(db, node_id, pn2, x25519, ed_pub, join_ts, ntp_time_get_seconds(cs->inst)); }
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] PEER_UPSERT save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] PEER_UPSERT save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac);
for (uint8_t i = 0; i < ac; i++) {
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] header truncated node=0x%016llx", CS_ID, i, (unsigned long long)node_id); break; }
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT addr[%u] header truncated node=0x%016llx", CS_ID, i, (unsigned long long)node_id); break; }
uint8_t fm = *p++;
uint8_t sid = *p++;
uint8_t proto = *p++;
int ip_len = (fm == 4) ? 4 : 16;
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, i, (unsigned long long)node_id, fm); break; }
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, i, (unsigned long long)node_id, fm); break; }
const uint8_t* ip = p; p += ip_len;
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2;
@ -1511,10 +1511,10 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
sqlite3_step(stmt); sqlite3_finalize(stmt);
}
if (fm == 4)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] PEER_UPSERT INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] PEER_UPSERT INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d",
CS_ID, (unsigned long long)node_id, sid, ip[0], ip[1], ip[2], ip[3], port);
else
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] PEER_UPSERT INSERT v6 node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] PEER_UPSERT INSERT v6 node=0x%016llx sock=%d port=%d",
CS_ID, (unsigned long long)node_id, sid, port);
}
@ -1525,7 +1525,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
/* propagate to others (except sender and the subject node) */
cs_propagate(cs, ch_id, peer, pl, len);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT node=0x%016llx ch=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_UPSERT node=0x%016llx ch=%s",
CS_ID, (unsigned long long)node_id, ch_id);
}
@ -1533,7 +1533,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
static void cs_handle_peer_remove(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
if (len < 8) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_REMOVE too short len=%zu", CS_ID, len); return; }
if (len < 8) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_REMOVE too short len=%zu", CS_ID, len); return; }
uint64_t node_id; memcpy(&node_id, pl, 8);
sqlite3* db = cs->inst->topo_sqlite_db;
@ -1544,7 +1544,7 @@ static void cs_handle_peer_remove(struct chat_sync* cs, uint64_t peer,
cs_propagate(cs, ch_id, peer, pl, len);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_REMOVE node=0x%016llx ch=%s",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEER_REMOVE node=0x%016llx ch=%s",
CS_ID, (unsigned long long)node_id, ch_id);
}
@ -1552,16 +1552,16 @@ static void cs_handle_peer_remove(struct chat_sync* cs, uint64_t peer,
static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
const char* ch_id, const uint8_t* pl, size_t len) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE ch=%s from=%016llx len=%zu",
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE ch=%s from=%016llx len=%zu",
CS_ID, ch_id, (unsigned long long)peer, len);
if (len < 1 + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE too short len=%zu peer=%016llx", CS_ID, len, (unsigned long long)peer);
return;
}
/* Same payload format as CHANNEL_INFO_RESP */
const uint8_t* p = pl;
uint8_t nl = *p++;
if (1 + nl + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1 > (int)len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE truncated", CS_ID); return; }
if (1 + nl + 8 + 32 + 32 + 64 + 1 + 64 + 8 + 1 > (int)len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE truncated", CS_ID); return; }
char name[128]; memcpy(name, p, nl); name[nl] = '\0'; p += nl;
uint64_t owner; memcpy(&owner, p, 8); p += 8;
const uint8_t* x25519 = p; p += 32;
@ -1570,7 +1570,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
uint8_t inv_flags = *p++;
const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0;
if (inv_flags & PEERS_FLAG_HAS_JOIN) {
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE truncated at join_sig/ts from=%016llx", CS_ID, (unsigned long long)peer); return; }
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE truncated at join_sig/ts from=%016llx", CS_ID, (unsigned long long)peer); return; }
inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; }
/* skip inviter_update_sig/ts/userinfo for now — verify channel sig only */
p += 64; uint64_t inviter_update_ts; memcpy(&inviter_update_ts, p, 8); p += 8;
@ -1584,7 +1584,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
memcpy(vmsg + vlen, x25519, 32); vlen += 32;
memcpy(vmsg + vlen, ed_pub, 32); vlen += 32;
if (cs_ed25519_verify(ed_pub, vmsg, vlen, ch_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE invalid ch_sig ch=%s from=%016llx", CS_ID, ch_id, (unsigned long long)peer);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE invalid ch_sig ch=%s from=%016llx", CS_ID, ch_id, (unsigned long long)peer);
return;
}
@ -1594,17 +1594,17 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
struct global_config *gcfg = &cs->inst->config->global;
policy = gcfg->chatserver_enabled ? 0 : chat_setting_get_int("join_policy", 1);
}
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE policy=%d (chatserver=%d) ch=%s from=%016llx",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE policy=%d (chatserver=%d) ch=%s from=%016llx",
CS_ID, policy, cs->inst->config->global.chatserver_enabled, ch_id, (unsigned long long)peer);
if (policy == 2) { /* deny */
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE denied (policy=deny) ch=%s from=%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE denied (policy=deny) ch=%s from=%016llx",
CS_ID, ch_id, (unsigned long long)peer);
return;
}
if (policy == 0) { /* autojoin */
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE autojoin ch=%s from=%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE autojoin ch=%s from=%016llx",
CS_ID, ch_id, (unsigned long long)peer);
/* Save channel and start join handshake */
topo_node_sqlite_channel_put(cs->inst->topo_sqlite_db,
@ -1637,7 +1637,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
evt[epos++] = (uint8_t)inv_name_len;
if (inv_name_len) { memcpy(evt + epos, inv_name, inv_name_len); epos += inv_name_len; }
chat_event_post(CHAT_EVT_INVITE_RECEIVED, evt, epos);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE ask posted to GUI ch=%s name=%s from=%016llx (%s)",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE ask posted to GUI ch=%s name=%s from=%016llx (%s)",
CS_ID, ch_id, name, (unsigned long long)peer, inv_name);
}
}
@ -1681,7 +1681,7 @@ static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* in
uint8_t il = (uint8_t)strlen(juser);
buf[boff++] = il; memcpy(buf + boff, juser, il); boff += il;
int rc = cs_send(cs, ch_id, target_node_id, buf, boff);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s rc=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s rc=%d",
CS_ID, (unsigned long long)target_node_id, ch_id, rc);
return rc;
}
@ -1689,20 +1689,20 @@ static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* in
/* ─── chat_sync_invite_to_channel: пригласить узел в наш канал ─── */
void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id) {
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: inst=NULL", CS_ID); return; }
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: ch_id NULL/empty", CS_ID); return; }
if (target_node_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: target_node_id=0", CS_ID); return; }
if (target_node_id == inst->node_id) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: self-invite rejected self=0x%016llx", CS_ID, (unsigned long long)inst->node_id); return; }
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: inst=NULL", CS_ID); return; }
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: ch_id NULL/empty", CS_ID); return; }
if (target_node_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: target_node_id=0", CS_ID); return; }
if (target_node_id == inst->node_id) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: self-invite rejected self=0x%016llx", CS_ID, (unsigned long long)inst->node_id); return; }
uint64_t channel_id = strtoull(ch_id, NULL, 10);
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel invalid ch_id='%s'", CS_ID, ch_id); return; }
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel invalid ch_id='%s'", CS_ID, ch_id); return; }
/* Get channel data from DB */
char ch_name[128]; uint64_t owner; uint8_t ch_x25519[32], ch_ed[32], ch_sig[64];
if (topo_node_sqlite_channel_get(inst->topo_sqlite_db,
ch_id, ch_name, (int)sizeof(ch_name), &owner, ch_x25519, ch_ed, ch_sig) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel channel not found: %s", CS_ID, ch_id);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel channel not found: %s", CS_ID, ch_id);
return;
}
@ -1716,7 +1716,7 @@ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id,
struct TOPO_GROUP_NODE* nq = topo_node_find_by_id(g, target_node_id);
if (nq && nq->handle) {
/* Already have a handle — connection in progress or established */
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel — existing handle for node 0x%016llx, waiting for conn_up",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel — existing handle for node 0x%016llx, waiting for conn_up",
CS_ID, (unsigned long long)target_node_id);
g_cs->pending_invite_ch_id = channel_id;
g_cs->pending_invite_node_id = target_node_id;
@ -1730,12 +1730,12 @@ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id,
/* Addresses loaded from node_addresses in DB by conn_mgr */
int r = conn_mgr_open_invite(inst, channel_id, ni, target_node_id, NULL, NULL, NULL);
if (r < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel conn_mgr_open_invite failed rc=%d", CS_ID, r);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel conn_mgr_open_invite failed rc=%d", CS_ID, r);
}
u_free(ni);
}
} else {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel — no topo_groups, cannot connect", CS_ID);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel — no topo_groups, cannot connect", CS_ID);
return;
}
/* Mark pending: after conn_up, we send CHANNEL_INVITE.
@ -1776,7 +1776,7 @@ static void cs_invite_trampoline(void* arg) {
uint64_t target_node_id = w->target_node_id;
if (channel_id == 0 || target_node_id == 0 || target_node_id == inst->node_id) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid params ch=%llu target=0x%016llx",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs invalid params ch=%llu target=0x%016llx",
CS_ID, (unsigned long long)channel_id, (unsigned long long)target_node_id);
u_free(w); return;
}
@ -1802,7 +1802,7 @@ static void cs_invite_trampoline(void* arg) {
/* Not connected — build TOPO_NODE with addresses and connect */
if (!inst->topo_groups) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs — no topo_groups, cannot connect", CS_ID);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs — no topo_groups, cannot connect", CS_ID);
u_free(w); return;
}
@ -1832,7 +1832,7 @@ static void cs_invite_trampoline(void* arg) {
}
if (!ni->v4_addrs && !ni->v6_addrs) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs no valid addrs for node=0x%016llx",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs no valid addrs for node=0x%016llx",
CS_ID, (unsigned long long)target_node_id);
u_free(ni); u_free(w); return;
}
@ -1843,7 +1843,7 @@ static void cs_invite_trampoline(void* arg) {
int r = conn_mgr_open_invite(inst, channel_id, ni, target_node_id, cs_invite_conn_cb, NULL, NULL);
if (r < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs conn_mgr_open_invite failed rc=%d", CS_ID, r);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs conn_mgr_open_invite failed rc=%d", CS_ID, r);
g_cs->pending_invite_node_id = 0; g_cs->pending_invite_ch_id = 0;
g_cs->pending_invite_is_inviter = 0;
}
@ -1860,12 +1860,12 @@ void chat_sync_invite_to_channel_with_addrs(
int addrs_data_len)
{
if (!g_cs || !inst || !ch_id || !ch_id[0] || !pubkey_bin || !addrs_data || addr_count <= 0 || addrs_data_len <= 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid args", CS_ID);
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs invalid args", CS_ID);
return;
}
uint64_t channel_id = strtoull(ch_id, NULL, 10);
if (channel_id == 0 || target_node_id == 0 || target_node_id == inst->node_id) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid params ch=%s target=0x%016llx",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs invalid params ch=%s target=0x%016llx",
CS_ID, ch_id, (unsigned long long)target_node_id);
return;
}
@ -1880,7 +1880,7 @@ void chat_sync_invite_to_channel_with_addrs(
memcpy(w->addrs_data, addrs_data, (size_t)addrs_data_len);
uasync_post(inst->ua, cs_invite_trampoline, w);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs posted to uasync ch=%s target=0x%016llx addrs=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs posted to uasync ch=%s target=0x%016llx addrs=%d",
CS_ID, ch_id, (unsigned long long)target_node_id, addr_count);
}
@ -1890,11 +1890,11 @@ void chat_sync_accept_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, ui
if (!g_cs || !inst) return;
char ch_id[64]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)channel_id);
if (channel_id == 0 || inviter_node_id == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: accept_invite invalid params ch=%llu node=%016llx",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite invalid params ch=%llu node=%016llx",
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: accept_invite ch=%llu inviter=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: accept_invite ch=%llu inviter=0x%016llx",
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
chat_core_ensure_channel_ready(ch_id);
chat_sync_join_channel(inst, ch_id, inviter_node_id);
@ -1903,7 +1903,7 @@ void chat_sync_accept_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, ui
void chat_sync_deny_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t inviter_node_id) {
(void)inst;
if (!g_cs) return;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: deny_invite ch=%llu inviter=0x%016llx",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: deny_invite ch=%llu inviter=0x%016llx",
CS_ID, (unsigned long long)channel_id, (unsigned long long)inviter_node_id);
/* silently ignore — no response needed */
}

240
src/chat/db_sync.c

@ -148,34 +148,34 @@ static int si_prep(struct DB_SYNC_INSTANCE* si, sqlite3_stmt** stmt, const char*
// Открывает SQLite БД, включает WAL, mmap и прочие оптимизации для высокой производительности
static int db_sqlite_open(struct DB_SYNC* db, const char* path)
{
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "path=%s", path);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "path=%s", path);
int rc = sqlite3_open(path, &db->db);
if (rc != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_sync: sqlite3_open(%s): %s", path, sqlite3_errmsg(db->db));
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: sqlite3_open(%s): %s", path, sqlite3_errmsg(db->db));
sqlite3_close(db->db);
db->db = NULL;
return -1;
}
char* err = NULL;
rc = sqlite3_exec(db->db, "PRAGMA journal_mode=WAL", NULL, NULL, &err);
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_sync: WAL pragma: %s", err); sqlite3_free(err); }
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: WAL pragma: %s", err); sqlite3_free(err); }
sqlite3_exec(db->db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL);
sqlite3_exec(db->db, "PRAGMA wal_autocheckpoint=10000", NULL, NULL, NULL);
sqlite3_exec(db->db, "PRAGMA cache_size=-32768", NULL, NULL, NULL);
sqlite3_exec(db->db, "PRAGMA mmap_size=134217728", NULL, NULL, NULL);
sqlite3_exec(db->db, "PRAGMA temp_store=MEMORY", NULL, NULL, NULL);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: SQLite opened at %s", path);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: SQLite opened at %s", path);
return 0;
}
// Закрывает SQLite БД (только свою, shared не трогает)
static void db_sqlite_close(struct DB_SYNC* db)
{
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "");
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "");
if (!db->db || db->shared_db) return;
sqlite3_close(db->db);
db->db = NULL;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: SQLite closed");
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: SQLite closed");
}
// ============================================================
@ -227,7 +227,7 @@ static struct DB_SYNC_INSTANCE* db_instance_find(struct DB_SYNC* db, uint64_t ha
// Выделяет новый слот инстанса в массиве, расширяя его при необходимости
static struct DB_SYNC_INSTANCE* db_instance_alloc(struct DB_SYNC* db)
{
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "count=%d cap=%d", db->instance_count, db->instance_capacity);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "count=%d cap=%d", db->instance_count, db->instance_capacity);
if (db->instance_count >= db->instance_capacity) {
int nc = db->instance_capacity ? db->instance_capacity * 2 : 4;
struct DB_SYNC_INSTANCE* np = u_realloc(db->instances, nc * sizeof(*db->instances));
@ -318,13 +318,13 @@ static int db_chain_hash_at(struct DB_SYNC_INSTANCE* si, uint32_t pos, uint8_t o
" ORDER BY timestamp, author_signature"
" LIMIT 1 OFFSET ?") != SQLITE_OK)
{
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "chain_hash_at prepare: %s", sqlite3_errmsg(SI_DB(si)));
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "chain_hash_at prepare: %s", sqlite3_errmsg(SI_DB(si)));
return -1;
}
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)pos);
if (sqlite3_step(stmt) != SQLITE_ROW) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "chain_hash_at no row pos=%u tbl=%s", pos, SI_TBL(si)); sqlite3_finalize(stmt); return -1; }
if (sqlite3_step(stmt) != SQLITE_ROW) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "chain_hash_at no row pos=%u tbl=%s", pos, SI_TBL(si)); sqlite3_finalize(stmt); return -1; }
const void* b = sqlite3_column_blob(stmt, 0);
if (!b || sqlite3_column_bytes(stmt, 0) < 32) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "chain_hash_at blob too small pos=%u tbl=%s", pos, SI_TBL(si)); sqlite3_finalize(stmt); return -1; }
if (!b || sqlite3_column_bytes(stmt, 0) < 32) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "chain_hash_at blob too small pos=%u tbl=%s", pos, SI_TBL(si)); sqlite3_finalize(stmt); return -1; }
memcpy(out, b, 32);
sqlite3_finalize(stmt);
return 0;
@ -354,7 +354,7 @@ static int db_prev_chain_hash(struct DB_SYNC_INSTANCE* si, uint64_t ts, const ui
" WHERE timestamp<?1 OR (timestamp=?1 AND author_signature<?2)"
" ORDER BY timestamp DESC, author_signature DESC"
" LIMIT 1") != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_prev_chain_hash prep: %s", sqlite3_errmsg(SI_DB(si)));
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_prev_chain_hash prep: %s", sqlite3_errmsg(SI_DB(si)));
return -1; }
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ts);
sqlite3_bind_blob(stmt, 2, author_sig, DB_SIG_SIZE, SQLITE_STATIC);
@ -416,20 +416,20 @@ static void db_recalc_tick(void* arg)
uint32_t batch = (total - si->recalc.pos > 50) ? 50 : total - si->recalc.pos;
int rc = sqlite3_exec(db, "BEGIN IMMEDIATE", NULL, NULL, NULL);
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "recalc BEGIN: %s", sqlite3_errmsg(db)); return; }
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "recalc BEGIN: %s", sqlite3_errmsg(db)); return; }
sqlite3_stmt* sel, *upd;
if (si_prep(si, &sel,
"SELECT id,timestamp,node_id,author_signature FROM \"%s\""
" ORDER BY timestamp, author_signature"
" LIMIT -1 OFFSET ?") != SQLITE_OK)
{ DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "recalc SELECT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return; }
{ DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "recalc SELECT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return; }
sqlite3_bind_int64(sel, 1, (sqlite3_int64)si->recalc.pos);
if (si_prep(si, &upd,
"UPDATE \"%s\" SET chain_hash=?"
" WHERE timestamp=? AND author_signature=?") != SQLITE_OK)
{ DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "recalc UPDATE prep: %s", sqlite3_errmsg(db)); sqlite3_finalize(sel); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return; }
{ DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "recalc UPDATE prep: %s", sqlite3_errmsg(db)); sqlite3_finalize(sel); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return; }
uint8_t ch[32]; uint32_t processed = 0;
while (sqlite3_step(sel) == SQLITE_ROW && processed < batch) {
@ -452,15 +452,15 @@ static void db_recalc_tick(void* arg)
sqlite3_finalize(sel);
rc = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
if (rc != SQLITE_OK) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "recalc COMMIT: %s", sqlite3_errmsg(db));
if (rc != SQLITE_OK) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "recalc COMMIT: %s", sqlite3_errmsg(db));
si->recalc.pos += processed;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "recalc tick tbl=%s pos=%u batch=%u/%u total=%u",
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "recalc tick tbl=%s pos=%u batch=%u/%u total=%u",
SI_TBL(si), si->recalc.pos - processed, processed, batch, total);
if (si->recalc.pos >= total) {
si->recalc.timer = NULL;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "recalc complete tbl=%s pos=%u(total)", SI_TBL(si), si->recalc.pos);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "recalc complete tbl=%s pos=%u(total)", SI_TBL(si), si->recalc.pos);
} else {
si->recalc.timer = uasync_set_timeout(si->db_sync->inst->ua, 100, si, db_recalc_tick, "db_recalc");
}
@ -514,11 +514,11 @@ static void si_dump_table(struct DB_SYNC_INSTANCE* si, const char* tag)
snprintf(buf, sizeof(buf), "[%2u] id=%-2llu ts=%-10llu auth=%04llX ch8=%016llX",
total, (unsigned long long)id, (unsigned long long)ts,
(unsigned long long)(auth >> 16), ch8);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, " %s %s", tag, buf);
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, " %s %s", tag, buf);
total++;
}
sqlite3_finalize(stmt);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, " %s: table=%s mc=%u", tag, SI_TBL(si), mc);
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, " %s: table=%s mc=%u", tag, SI_TBL(si), mc);
}
// Проверяет Ed25519 подпись автора: verify(pubkey, ts[8] || json, sig). Возвращает 0 если подпись верна
@ -529,7 +529,7 @@ static int db_verify_author_sig(struct DB_SYNC_INSTANCE* si,
{
uint8_t pubkey[32];
if (db_get_ed25519_pubkey(si->db_sync, author_node_id, pubkey) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC,
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC,
"cannot get Ed25519 pubkey for author=%016llx — discarding",
(unsigned long long)author_node_id);
return -1;
@ -538,7 +538,7 @@ static int db_verify_author_sig(struct DB_SYNC_INSTANCE* si,
memcpy(msg + off, &ts, 8); off += 8;
if (jlen > 0) { memcpy(msg + off, json, jlen); off += jlen; }
if (sc_ed25519_verify(pubkey, msg, off, sig) != SC_OK) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC,
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC,
"author_sig VERIFY FAIL author=%016llx ed_pubkey=%016llx... msg_len=%zu sig=%016llx... — discarding as forgery",
(unsigned long long)author_node_id, *(uint64_t*)pubkey, off, *(uint64_t*)sig);
return -1;
@ -553,7 +553,7 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
const uint8_t* author_sig,
const char* local_attrs)
{
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "id=%llu ts=%llu author=%N len=%zu", (unsigned long long)id, (unsigned long long)ts, (unsigned long long)author_node_id, jlen);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "id=%llu ts=%llu author=%N len=%zu", (unsigned long long)id, (unsigned long long)ts, (unsigned long long)author_node_id, jlen);
sqlite3* db = SI_DB(si);
sqlite3_stmt* stmt;
int rc;
@ -573,16 +573,16 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
}
rc = sqlite3_exec(db, "BEGIN IMMEDIATE", NULL, NULL, NULL);
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "insert BEGIN: %s", sqlite3_errmsg(db)); return -1; }
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "insert BEGIN: %s", sqlite3_errmsg(db)); return -1; }
// Check if record already exists by (timestamp, author_signature)
if (si_prep(si, &stmt, "SELECT 1 FROM \"%s\" WHERE timestamp=? AND author_signature=?") != SQLITE_OK)
{ DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_record_insert SELECT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
{ DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_record_insert SELECT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ts);
sqlite3_bind_blob(stmt, 2, author_sig, DB_SIG_SIZE, SQLITE_STATIC);
int exists = (sqlite3_step(stmt) == SQLITE_ROW);
sqlite3_finalize(stmt);
if (exists) { DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ already exists, skip"); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return 1; }
if (exists) { DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ already exists, skip"); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return 1; }
// Compute chain hash
uint8_t prev_ch[32];
@ -596,7 +596,7 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
" (timestamp,node_id,id,chain_hash,flags,data,"
" author_signature,local_attrs,delivered_peers,delivery_chain)"
" VALUES (?,?,?,?,0,?,?,?,0,'')") != SQLITE_OK)
{ DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_record_insert INSERT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
{ DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_record_insert INSERT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ts);
sqlite3_bind_int64(stmt, 2, (sqlite3_int64)author_node_id);
sqlite3_bind_int64(stmt, 3, (sqlite3_int64)id);
@ -608,11 +608,11 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
else sqlite3_bind_text(stmt, 7, "", -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "INSERT: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
if (rc != SQLITE_DONE) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "INSERT: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
si->next_id = id + 1;
rc = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "insert COMMIT: %s", sqlite3_errmsg(db)); return -1; }
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "insert COMMIT: %s", sqlite3_errmsg(db)); return -1; }
uint32_t ins_pos = si_find_pos(si, ts, author_sig);
db_sync_schedule_recalc(si, ins_pos);
@ -650,7 +650,7 @@ static int db_record_insert_cascade(struct DB_SYNC_INSTANCE* si,
}
}
if (push_count > 0)
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:ME--] → PUSH: id=%llu => %d peers",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:ME--] → PUSH: id=%llu => %d peers",
SI_SHRT(si), (unsigned long long)rid, push_count);
return 0;
}
@ -663,9 +663,9 @@ static int db_record_insert_cascade(struct DB_SYNC_INSTANCE* si,
static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id, uint64_t hash, const uint8_t* payload, size_t plen)
{
struct ll_entry* entry = queue_entry_new(0);
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "queue_entry_new"); return -1; }
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "queue_entry_new"); return -1; }
uint8_t* buf = u_malloc(plen + 9);
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "db_sync_send_hash: u_malloc(%zu) failed for dst=%016llx", plen + 9, (unsigned long long)node_id); queue_entry_free(entry); return -1; }
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_sync_send_hash: u_malloc(%zu) failed for dst=%016llx", plen + 9, (unsigned long long)node_id); queue_entry_free(entry); return -1; }
buf[0] = ETCP_RT_ID_DB_SYNC;
uint64_t hb = htobe64(hash);
memcpy(buf + 1, &hb, 8);
@ -675,14 +675,14 @@ static int db_sync_send_hash(struct DB_SYNC* db, uint64_t node_id, uint64_t hash
struct ETCP_CONN* conn = instance_find_conn(db->inst, node_id);
if (!conn || !conn->links_up) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "sync: send DROP — no direct conn to %04llX (hash=%016llx, type=%02x, conn=%p lu=%d)",
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "sync: send DROP — no direct conn to %04llX (hash=%016llx, type=%02x, conn=%p lu=%d)",
(unsigned long long)(node_id >> 16), hash, plen > 0 ? payload[0] : 0,
(void*)conn, conn ? conn->links_up : -1);
queue_entry_free(entry);
return -1;
}
int ret = etcp_send(conn, entry);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync: send OK → etcp_send ret=%d conn=%s l_up=%d init=%d q=%p",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: send OK → etcp_send ret=%d conn=%s l_up=%d init=%d q=%p",
ret, conn->log_name, conn->links_up, conn->initialized, (void*)conn->send_input_q);
return ret;
}
@ -758,12 +758,12 @@ static void db_handle_error(struct DB_SYNC_INSTANCE* si, uint64_t src, const uin
if (len < 1 || !si) return;
const char* what = (p[0] == DB_ERR_NOT_FOUND) ? "NOT_FOUND" :
(p[0] == DB_ERR_DISABLED) ? "DISABLED" : "UNKNOWN";
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC,
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC,
"sync [%s:%04llX] ← ERROR: code=%u (%s) — peer rejected our sync",
SI_SHRT(si), (unsigned long long)(src >> 16), p[0], what);
struct SI_PEER* sp = si_peer_find(si, src);
if (sp) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← ERROR: reset sync_state 2→0, synced_pos stays at %u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← ERROR: reset sync_state 2→0, synced_pos stays at %u",
SI_SHRT(si), (unsigned long long)(src >> 16), sp->synced_pos);
sp->sync_state = 0;
}
@ -773,7 +773,7 @@ static void db_handle_error(struct DB_SYNC_INSTANCE* si, uint64_t src, const uin
// с разреженными хешами (интервалы: 1,1,1,2,2,4,4,4,4,4,4,4,4,4,4,4) и флагом has_tail
static void db_handle_init_sync(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 4) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "INIT_SYNC too short %zu from %016llx", len, (unsigned long long)src); return; }
if (len < 4) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "INIT_SYNC too short %zu from %016llx", len, (unsigned long long)src); return; }
db_sync_flush_recalc(si);
uint32_t pc = *(uint32_t*)p;
uint32_t mc = db_count(si);
@ -785,7 +785,7 @@ static void db_handle_init_sync(struct DB_SYNC_INSTANCE* si, uint64_t src, const
static const uint16_t iv[16] = {1, 1, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
uint32_t accum = 0; int sparse_cnt = 0;
for (int i = 0; i < 16; i++) { if (tp < accum + iv[i]) break; accum += iv[i]; sparse_cnt++; }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_SYNC: peer=%u my=%u → tp=%u ch8=%016llX has_tail=%u sparse=%d",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_SYNC: peer=%u my=%u → tp=%u ch8=%016llX has_tail=%u sparse=%d",
SI_SHRT(si), (unsigned long long)(src >> 16), pc, mc, tp, my_ch8_at_tp, has_tail, sparse_cnt);
uint8_t resp[4096];
@ -817,7 +817,7 @@ static void db_handle_init_sync(struct DB_SYNC_INSTANCE* si, uint64_t src, const
struct SI_PEER* sp = si_peer_add(si, src);
if (sp && sp->sync_state == 0) { sp->sync_state = 1; sp->sync_start_tb = get_time_tb(); }
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] → INIT_RESP: sent %u bytes to peer=%016llx ret=%d flow=%u,%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] → INIT_RESP: sent %u bytes to peer=%016llx ret=%d flow=%u,%u",
SI_SHRT(si), (unsigned long long)(src >> 16), off, (unsigned long long)src, sret,
resp[0], resp[1]);
}
@ -826,7 +826,7 @@ static void db_handle_init_sync(struct DB_SYNC_INSTANCE* si, uint64_t src, const
// отправляет наши данные начиная с неё и запрашивает данные пира с той же позиции
static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 14) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "INIT_RESP too short %zu from %016llx", len, (unsigned long long)src); return; }
if (len < 14) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "INIT_RESP too short %zu from %016llx", len, (unsigned long long)src); return; }
db_sync_flush_recalc(si);
uint32_t tp = *(uint32_t*)p;
uint64_t peer_ch8; memcpy(&peer_ch8, p + 4, 8);
@ -837,7 +837,7 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
uint64_t my_ch8 = 0;
uint32_t mc = db_count(si);
if (mc > 0 && tp < mc) db_chain_hash8_at(si, tp, &my_ch8);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_RESP: tp=%u my=%u my_ch8=%016llX peer_ch8=%016llX has_tail=%u sc=%d",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_RESP: tp=%u my=%u my_ch8=%016llX peer_ch8=%016llX has_tail=%u sc=%d",
SI_SHRT(si), (unsigned long long)(src >> 16), tp, mc, my_ch8, peer_ch8, has_tail, sc);
struct SI_PEER* sp = si_peer_find(si, src);
@ -852,7 +852,7 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
if (si_send_data_batch(si, src, sent, b, vp, want) <= 0) break;
sent += b;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_RESP: peer empty → sent %u/%u records, awaiting response",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_RESP: peer empty → sent %u/%u records, awaiting response",
SI_SHRT(si), (unsigned long long)(src >> 16), sent, mc);
return;
}
@ -865,7 +865,7 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
memcpy(sd + 1, &mc, 4); memcpy(sd + 5, &my_ch8, 8);
db_sync_send(si, src, sd, 13);
si_fire_sync_done(si, src);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_RESP: MATCH+no_tail ss→2 → SYNC_DONE tp=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_RESP: MATCH+no_tail ss→2 → SYNC_DONE tp=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), tp);
return;
}
@ -875,7 +875,7 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
uint32_t scnt = mc - rfrom; if (scnt > DB_SEND_DATA_MAX) scnt = DB_SEND_DATA_MAX;
if (scnt > 0) si_send_data_batch(si, src, rfrom, scnt, vp, rfrom);
else si_send_data_batch(si, src, rfrom, 0, vp, rfrom);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_RESP: MATCH+tail → SEND_DATA from=%u want=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_RESP: MATCH+tail → SEND_DATA from=%u want=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), rfrom, rfrom);
return;
}
@ -890,14 +890,14 @@ static void db_handle_init_resp(struct DB_SYNC_INSTANCE* si, uint64_t src, const
} else if (pos < fm) fm = pos;
}
uint32_t vp = fm > 0 ? fm - 1 : (uint32_t)-1; if (sp) sp->verified_pos = vp;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← INIT_RESP: MISMATCH fm=%u vp=%u mc=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← INIT_RESP: MISMATCH fm=%u vp=%u mc=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), fm, vp, mc);
// Send our records from fm, request peer's from fm
uint32_t scnt = mc - fm; if (scnt > DB_SEND_DATA_MAX) scnt = DB_SEND_DATA_MAX;
if (scnt > 0) si_send_data_batch(si, src, fm, scnt, vp, fm);
else si_send_data_batch(si, src, fm, 0, vp, fm);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] → SEND_DATA from=%u vp=%u cnt=%u want=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] → SEND_DATA from=%u vp=%u cnt=%u want=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), fm, vp, scnt, fm);
}
@ -924,7 +924,7 @@ static int si_send_data_batch(struct DB_SYNC_INSTANCE* si, uint64_t dst, uint32_
if (si_prep(si, &stmt,
"SELECT id,timestamp,node_id,data,author_signature"
" FROM \"%s\" ORDER BY timestamp, author_signature"
" LIMIT ? OFFSET ?") != SQLITE_OK) return -1;
" LIMIT ? OFFSET ?") != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] SEND_DATA: si_prep failed tbl=%s", SI_SHRT(si), (unsigned long long)(dst >> 16), SI_TBL(si)); return -1; }
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)count);
sqlite3_bind_int64(stmt, 2, (sqlite3_int64)from);
int bad_del = 0;
@ -960,13 +960,13 @@ static int si_send_data_batch(struct DB_SYNC_INSTANCE* si, uint64_t dst, uint32_
}
sqlite3_finalize(stmt);
if (rc == 0 && bad_del == 0)
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] SEND_DATA: 0 records from=%u count=%u",
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] SEND_DATA: 0 records from=%u count=%u",
SI_SHRT(si), (unsigned long long)(dst >> 16), from, count);
}
*rcp = rc;
db_sync_send(si, dst, buf, off);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] → SEND_DATA: %u recs from=%u want=%u vp=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] → SEND_DATA: %u recs from=%u want=%u vp=%u",
SI_SHRT(si), (unsigned long long)(dst >> 16), rc, from, want_from, vp);
return (int)rc;
}
@ -980,20 +980,20 @@ static int si_parse_record(const uint8_t** pp, const uint8_t* end,
uint32_t* rdlen, const uint8_t** rdata,
const uint8_t** rsig, int* rsiglen)
{
if (*pp + 28 > end) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "si_parse_record: truncated header, need 28 have %td", end - *pp); return -1; }
if (*pp + 28 > end) { DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "si_parse_record: truncated header, need 28 have %td", end - *pp); return -1; }
*rid = *(uint64_t*)*pp; *pp += 8;
*rts = *(uint64_t*)*pp; *pp += 8;
*rauthor = *(uint64_t*)*pp; *pp += 8;
*rdlen = *(uint32_t*)*pp; *pp += 4;
if (*pp + *rdlen > end) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "si_parse_record: data overrun dlen=%u have=%td", *rdlen, end - *pp); return -1; }
if (*pp + *rdlen > end) { DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "si_parse_record: data overrun dlen=%u have=%td", *rdlen, end - *pp); return -1; }
*rdata = (*rdlen > 0) ? *pp : NULL;
*pp += *rdlen;
if (*pp + 1 > end) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "si_parse_record: sig_len overrun"); return -1; }
if (*pp + 1 > end) { DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "si_parse_record: sig_len overrun"); return -1; }
*rsiglen = (int)(*(*pp)++);
if (*rsiglen > 0) {
if (*pp + *rsiglen > end) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "si_parse_record: sig data overrun slen=%d have=%td", *rsiglen, end - *pp); return -1; }
if (*pp + *rsiglen > end) { DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "si_parse_record: sig data overrun slen=%d have=%td", *rsiglen, end - *pp); return -1; }
*rsig = *pp;
*pp += *rsiglen;
} else {
@ -1007,7 +1007,7 @@ static int si_parse_record(const uint8_t** pp, const uint8_t* end,
// корректирует synced_pos, при want_from шлёт встречные данные
static void db_handle_send_data(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 14) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SEND_DATA: truncated len=%zu (need >=14)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
if (len < 14) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← SEND_DATA: truncated len=%zu (need >=14)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
db_sync_flush_recalc(si);
uint32_t from = *(uint32_t*)p;
uint16_t count = *(uint16_t*)(p + 4);
@ -1038,7 +1038,7 @@ static void db_handle_send_data(struct DB_SYNC_INSTANCE* si, uint64_t src, const
char extra[32] = ""; if (duplicates) snprintf(extra, sizeof(extra), " (%u dup)", duplicates);
if (bad_sigs) { size_t el = strlen(extra); snprintf(extra+el, sizeof(extra)-el, "%s%u bad", extra[0]?", ":" (", bad_sigs); }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← DATA: from=%u cnt=%u vp=%u want=%u → ins=%u%s mc=%u sp=%u→%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← DATA: from=%u cnt=%u vp=%u want=%u → ins=%u%s mc=%u sp=%u→%u",
SI_SHRT(si), (unsigned long long)(src >> 16), from, count, vp, want_from, received, extra, db_count(si),
old_spos, sp ? sp->synced_pos : 0);
@ -1051,7 +1051,7 @@ static void db_handle_send_data(struct DB_SYNC_INSTANCE* si, uint64_t src, const
} else {
si_send_data_batch(si, src, want_from, 0, vp, DB_WANT_FROM_NONE);
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← DATA: responded with %u recs from=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← DATA: responded with %u recs from=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), want_from < mc ? (mc - want_from > DB_SEND_DATA_MAX ? DB_SEND_DATA_MAX : mc - want_from) : 0, want_from);
}
@ -1064,7 +1064,7 @@ static void db_handle_send_data(struct DB_SYNC_INSTANCE* si, uint64_t src, const
db_sync_send(si, src, sd, 13);
sp->sync_state = 2; sp->sync_start_tb = 0;
si_fire_sync_done(si, src);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← DATA: exchange complete, → SYNC_DONE mc=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← DATA: exchange complete, → SYNC_DONE mc=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), mc);
}
@ -1073,7 +1073,7 @@ static void db_handle_send_data(struct DB_SYNC_INSTANCE* si, uint64_t src, const
// Обрабатывает SYNC_DONE: финальная сверка хешей. mc==pc → sync завершён, mc<pc → запрашиваем хвост, mc>pc → отправляем хвост
static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 12) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "SYNC_DONE too short %zu from %016llx", len, (unsigned long long)src); return; }
if (len < 12) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "SYNC_DONE too short %zu from %016llx", len, (unsigned long long)src); return; }
db_sync_flush_recalc(si);
uint32_t pc = *(uint32_t*)p;
uint64_t pch8; memcpy(&pch8, p + 4, 8);
@ -1084,7 +1084,7 @@ static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const
if (mc == pc && mch8 == pch8) {
if (sp) { sp->synced_pos = mc > 0 ? mc - 1 : 0; sp->sync_state = 2; sp->sync_start_tb = 0; }
si_fire_sync_done(si, src);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SYNC_DONE: matched ✓ mc=%u ss→2",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← SYNC_DONE: matched ✓ mc=%u ss→2",
SI_SHRT(si), (unsigned long long)(src >> 16), mc);
} else if (mc < pc) {
// Request tail
@ -1094,7 +1094,7 @@ static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const
memcpy(req + 7, &vp_send, 4); memcpy(req + 11, &mc, 4);
db_sync_send(si, src, req, 15);
if (sp) sp->sync_state = 1;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u < pc=%u → request tail from=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u < pc=%u → request tail from=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), mc, pc, mc);
} else if (mc > pc) {
// mc > pc: send tail
@ -1102,13 +1102,13 @@ static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const
uint32_t scnt = mc - pc; if (scnt > DB_SEND_DATA_MAX) scnt = DB_SEND_DATA_MAX;
si_send_data_batch(si, src, pc, scnt, pc > 0 ? pc - 1 : (uint32_t)-1, DB_WANT_FROM_NONE);
if (sp) sp->sync_state = 1;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u > pc=%u → send tail from=%u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u > pc=%u → send tail from=%u",
SI_SHRT(si), (unsigned long long)(src >> 16), mc, pc, pc);
} else {
// mc == pc but chain hash differs — accept as converged
if (sp) { sp->synced_pos = mc > 0 ? mc - 1 : 0; sp->sync_state = 2; sp->sync_start_tb = 0; }
si_fire_sync_done(si, src);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u == pc=%u (hash !match) → accept as converged",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← SYNC_DONE: mc=%u == pc=%u (hash !match) → accept as converged",
SI_SHRT(si), (unsigned long long)(src >> 16), mc, pc);
}
}
@ -1116,10 +1116,10 @@ static void db_handle_sync_done(struct DB_SYNC_INSTANCE* si, uint64_t src, const
// Обрабатывает ACK_PUSH: помечает запись флагом DB_REC_FLAG_WAS_SENT и обновляет delivery_chain
static void db_handle_ack_push(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 16) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← PUSH ACK: truncated len=%zu (need >=16)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
if (len < 16) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← PUSH ACK: truncated len=%zu (need >=16)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
uint64_t ts = *(uint64_t*)p;
uint64_t author = *(uint64_t*)(p + 8);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "from=%016llx ts=%llu author=%016llx", (unsigned long long)src, (unsigned long long)ts, (unsigned long long)author);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "from=%016llx ts=%llu author=%016llx", (unsigned long long)src, (unsigned long long)ts, (unsigned long long)author);
sqlite3_stmt* stmt;
if (si_prep(si, &stmt,
@ -1134,7 +1134,7 @@ static void db_handle_ack_push(struct DB_SYNC_INSTANCE* si, uint64_t src, const
int changed = sqlite3_changes(SI_DB(si));
sqlite3_finalize(stmt);
if (changed > 0)
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← PUSH ACK: ts=%llu — delivery confirmed by peer",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← PUSH ACK: ts=%llu — delivery confirmed by peer",
SI_SHRT(si), (unsigned long long)(src >> 16), (unsigned long long)ts);
}
si_delivery_update(si, ts, author, src);
@ -1144,14 +1144,14 @@ static void db_handle_ack_push(struct DB_SYNC_INSTANCE* si, uint64_t src, const
// если запись вставлена не в конец (в середину)
static void db_handle_push(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint8_t* p, size_t len)
{
if (len < 30) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← PUSH: truncated len=%zu (need >=30)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
if (len < 30) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← PUSH: truncated len=%zu (need >=30)", SI_SHRT(si), (unsigned long long)(src >> 16), len); return; }
const uint8_t* ptr = p;
uint64_t rid, rts, rauthor;
uint32_t rdlen;
const uint8_t* rdata, *rsig;
int rsiglen;
if (si_parse_record(&ptr, p + len, &rid, &rts, &rauthor, &rdlen, &rdata, &rsig, &rsiglen) != 0) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "from=%016llx id=%llu author=%016llx ts=%llu len=%u", (unsigned long long)src, (unsigned long long)rid, (unsigned long long)rauthor, (unsigned long long)rts, rdlen);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "from=%016llx id=%llu author=%016llx ts=%llu len=%u", (unsigned long long)src, (unsigned long long)rid, (unsigned long long)rauthor, (unsigned long long)rts, rdlen);
int ret = db_record_insert_cascade(si, rid, rts, rauthor, (const char*)rdata, rdlen, rsig, src, NULL);
if (ret == 0) {
@ -1166,14 +1166,14 @@ static void db_handle_push(struct DB_SYNC_INSTANCE* si, uint64_t src, const uint
memcpy(ack + 1, &rts, 8);
memcpy(ack + 9, &rauthor, 8);
db_sync_send(si, src, ack, 17);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← PUSH: msg id=%llu author=%016llX ts=%llu → inserted at pos=%u (of %u total)",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← PUSH: msg id=%llu author=%016llX ts=%llu → inserted at pos=%u (of %u total)",
SI_SHRT(si), (unsigned long long)(src >> 16),
(unsigned long long)rid, (unsigned long long)rauthor, (unsigned long long)rts, ins_pos, total);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:%04llX] ← PUSH: msg id=%llu author=%016llX ts=%llu → inserted at pos=%u (of %u total)",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:%04llX] ← PUSH: msg id=%llu author=%016llX ts=%llu → inserted at pos=%u (of %u total)",
SI_SHRT(si), (unsigned long long)(src >> 16),
(unsigned long long)rid, (unsigned long long)rauthor, (unsigned long long)rts, ins_pos, total);
if (adj_count > 0 && ins_pos < total - 1) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync [%s:----] PUSH: inserted at pos=%u NOT at tail → reset synced_pos of %d peers from ≥%u back to %u",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync [%s:----] PUSH: inserted at pos=%u NOT at tail → reset synced_pos of %d peers from ≥%u back to %u",
SI_SHRT(si), ins_pos, adj_count, ins_pos, ins_pos > 0 ? ins_pos - 1 : 0);
}
}
@ -1196,7 +1196,7 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
uint8_t type = entry->dgram[9];
const uint8_t* payload = entry->dgram + 10;
size_t plen = entry->len - 10;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "recv type=%02x from=%016llx hash=%016llx len=%zu", type, (unsigned long long)src, (unsigned long long)hash, plen);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "recv type=%02x from=%016llx hash=%016llx len=%zu", type, (unsigned long long)src, (unsigned long long)hash, plen);
struct DB_SYNC_INSTANCE* si = db_instance_find(db, hash);
if (!si) {
@ -1213,17 +1213,17 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
if (h == hash) {
si = db_sync_instance_add(db->inst, tbl, hash, 1);
if (si) { si_peer_add(si, src); }
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "lazy-register: tbl=%s ch=%s hash=%016llx", tbl, ch_id, (unsigned long long)hash);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "lazy-register: tbl=%s ch=%s hash=%016llx", tbl, ch_id, (unsigned long long)hash);
break;
}
}
sqlite3_finalize(st);
}
if (!si) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC,
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC,
"recv msg type=0x%02x from %016llx hash=%016llx — instance NOT FOUND; sending DB_ERR_NOT_FOUND",
type, (unsigned long long)src, (unsigned long long)hash);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ instance not found for hash=%016llx", (unsigned long long)hash);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ instance not found for hash=%016llx", (unsigned long long)hash);
uint8_t err[2]; err[0] = DB_MSG_ERROR; err[1] = DB_ERR_NOT_FOUND;
db_sync_send_hash(db, src, hash, err, 2);
queue_dgram_free(entry); queue_entry_free(entry); return;
@ -1236,16 +1236,16 @@ static void db_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
}
switch (type) {
case DB_MSG_INIT_SYNC: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle INIT_SYNC"); db_handle_init_sync(si, src, payload, plen); break;
case DB_MSG_INIT_RESP: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle INIT_RESP"); db_handle_init_resp(si, src, payload, plen); break;
case DB_MSG_SEND_DATA: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle SEND_DATA"); db_handle_send_data(si, src, payload, plen); break;
case DB_MSG_PUSH: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle PUSH"); db_handle_push(si, src, payload, plen); break;
case DB_MSG_ACK_PUSH: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle ACK_PUSH"); db_handle_ack_push(si, src, payload, plen); break;
case DB_MSG_REQUEST_SYNC: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle REQUEST_SYNC"); db_handle_request_sync(si, src, payload, plen); break;
case DB_MSG_SYNC_DONE: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle SYNC_DONE"); db_handle_sync_done(si, src, payload, plen); break;
case DB_MSG_ERROR: DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "→ handle ERROR"); db_handle_error(si, src, payload, plen); break;
case DB_MSG_INIT_SYNC: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle INIT_SYNC"); db_handle_init_sync(si, src, payload, plen); break;
case DB_MSG_INIT_RESP: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle INIT_RESP"); db_handle_init_resp(si, src, payload, plen); break;
case DB_MSG_SEND_DATA: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle SEND_DATA"); db_handle_send_data(si, src, payload, plen); break;
case DB_MSG_PUSH: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle PUSH"); db_handle_push(si, src, payload, plen); break;
case DB_MSG_ACK_PUSH: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle ACK_PUSH"); db_handle_ack_push(si, src, payload, plen); break;
case DB_MSG_REQUEST_SYNC: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle REQUEST_SYNC"); db_handle_request_sync(si, src, payload, plen); break;
case DB_MSG_SYNC_DONE: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle SYNC_DONE"); db_handle_sync_done(si, src, payload, plen); break;
case DB_MSG_ERROR: DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "→ handle ERROR"); db_handle_error(si, src, payload, plen); break;
default:
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "sync: unknown msg type 0x%02x from %04llX (hash=%016llx) — dropped",
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "sync: unknown msg type 0x%02x from %04llX (hash=%016llx) — dropped",
type, (unsigned long long)(src >> 16), hash);
break;
}
@ -1275,7 +1275,7 @@ static void db_sync_on_conn_up(struct ETCP_CONN* conn, void* arg)
if (!db->enabled) return;
uint64_t pid = conn->peer_node_id;
if (pid == 0 || pid == db->inst->node_id) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "peer=%016llx init=%d links=%d", (unsigned long long)pid, conn->initialized, conn->links_up);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "peer=%016llx init=%d links=%d", (unsigned long long)pid, conn->initialized, conn->links_up);
db->last_connected_tb = get_time_tb();
int synced = 0;
@ -1294,7 +1294,7 @@ static void db_sync_on_conn_up(struct ETCP_CONN* conn, void* arg)
if (tbl_list[0]) { size_t tl = strlen(tbl_list); snprintf(tbl_list + tl, sizeof(tbl_list) - tl, ",%s", SI_SHRT(si)); }
else snprintf(tbl_list, sizeof(tbl_list), "%s", SI_SHRT(si));
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync: CONN UP peer=%04llX → %d tables: [%s] — initiating sync for %d",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: CONN UP peer=%04llX → %d tables: [%s] — initiating sync for %d",
(unsigned long long)(pid >> 16), db->instance_count, synced > 0 ? tbl_list : "none", synced);
}
@ -1307,7 +1307,7 @@ static void db_sync_on_conn_down(struct ETCP_CONN* conn, void* arg)
if (!db->enabled) return;
uint64_t pid = conn->peer_node_id;
if (pid == 0) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "peer=%016llx", (unsigned long long)pid);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "peer=%016llx", (unsigned long long)pid);
for (int i = 0; i < db->instance_count; i++) {
struct SI_PEER* p = si_peer_find(&db->instances[i], pid);
@ -1322,7 +1322,7 @@ static void db_sync_on_conn_down(struct ETCP_CONN* conn, void* arg)
}
cd_done:
if (!any) db->last_connected_tb = 0;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync: CONN DOWN peer=%04llX → reset sync state for %d tables",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: CONN DOWN peer=%04llX → reset sync state for %d tables",
(unsigned long long)(pid >> 16), db->instance_count);
}
@ -1336,7 +1336,7 @@ static void db_sync_initiate_sync(struct DB_SYNC_INSTANCE* si, uint64_t pid)
uint32_t mc = db_count(si);
uint64_t my_id = si->db_sync->inst->node_id;
struct SI_PEER* p = si_peer_find(si, pid);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "pid=%016llx my=%u tbl=%s", (unsigned long long)pid, mc, SI_TBL(si));
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "pid=%016llx my=%u tbl=%s", (unsigned long long)pid, mc, SI_TBL(si));
if (is_master(my_id, pid)) {
if (p) { p->sync_start_tb = get_time_tb(); p->sync_state = 1; }
@ -1355,7 +1355,7 @@ static void db_sync_initiate_sync(struct DB_SYNC_INSTANCE* si, uint64_t pid)
static void db_verify_chain(struct DB_SYNC_INSTANCE* si)
{
uint32_t mc = db_count(si);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "tbl=%s mc=%u", SI_TBL(si), mc);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s mc=%u", SI_TBL(si), mc);
if (mc == 0) return;
uint8_t prev_ch[32]; memset(prev_ch, 0, 32);
@ -1385,7 +1385,7 @@ static void db_verify_chain(struct DB_SYNC_INSTANCE* si)
sqlite3_finalize(stmt);
if (bad_pos >= 0) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "chain_hash mismatch at pos %d/%u in %s, recalculating",
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "chain_hash mismatch at pos %d/%u in %s, recalculating",
bad_pos, mc, SI_TBL(si));
db_sync_schedule_recalc(si, (uint32_t)bad_pos);
}
@ -1405,8 +1405,10 @@ int db_sync_chain_verify(struct DB_SYNC_INSTANCE* si)
sqlite3_stmt* stmt;
if (si_prep(si, &stmt,
"SELECT id,timestamp,node_id,author_signature,chain_hash FROM \"%s\""
" ORDER BY timestamp, author_signature") != SQLITE_OK)
" ORDER BY timestamp, author_signature") != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "verify_chain_hash: si_prep failed tbl=%s", SI_TBL(si));
return -1;
}
for (uint32_t pos = 0; sqlite3_step(stmt) == SQLITE_ROW; pos++) {
uint64_t rid = (uint64_t)sqlite3_column_int64(stmt, 0);
uint64_t rts = (uint64_t)sqlite3_column_int64(stmt, 1);
@ -1463,7 +1465,7 @@ static void db_sync_peer_check_cb(void* arg)
{
struct DB_SYNC* db = (struct DB_SYNC*)arg;
if (!db || !db->enabled) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "instances=%d", db->instance_count);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "instances=%d", db->instance_count);
struct TOPO_GROUP* g = topo_groups_get_default(db->inst->topo_groups);
if (!g) {
@ -1507,7 +1509,7 @@ static void db_sync_peer_check_cb(void* arg)
"%s%s:%04llX[sp=%u]", tl ? "," : "",
SI_SHRT(si), (unsigned long long)(best->node_id >> 16), min_pos); }
} else {
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "peer_check skip peer=%016llx — no Ed25519 pubkey yet", (unsigned long long)best->node_id);
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "peer_check skip peer=%016llx — no Ed25519 pubkey yet", (unsigned long long)best->node_id);
best = NULL; total_skipped++;
}
}
@ -1523,7 +1525,7 @@ static void db_sync_peer_check_cb(void* arg)
for (int j = 0; j < si->peer_count; j++) {
struct SI_PEER* p = &si->peers[j];
if (p->sync_state == 1 && p->sync_start_tb > 0 && now - p->sync_start_tb > to_tb) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC,
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC,
"sync [%s:%04llX] TIMEOUT: no response for %llu ms, sync_state 1→0 (synced_pos was %u)",
SI_SHRT(si), (unsigned long long)(p->node_id >> 16),
(unsigned long long)((now - p->sync_start_tb) / 10), p->synced_pos);
@ -1538,7 +1540,7 @@ static void db_sync_peer_check_cb(void* arg)
}
if (total_synced > 0) {
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "sync: PEER CHECK → %d tables, launched sync for %d: %s",
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "sync: PEER CHECK → %d tables, launched sync for %d: %s",
db->instance_count, total_synced, launched_list);
}
@ -1550,7 +1552,7 @@ static void db_sync_peer_check_cb(void* arg)
static void db_sync_instance_ttl_cb(void* arg)
{
struct DB_SYNC_INSTANCE* si = (struct DB_SYNC_INSTANCE*)arg;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "tbl=%s enabled=%d", SI_TBL(si), si->enabled);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s enabled=%d", SI_TBL(si), si->enabled);
uint64_t interval = DB_SYNC_TTL_INTERVAL * 10000u;
if (!si || !si->enabled || !si->db_sync || !si->db_sync->db) {
@ -1578,7 +1580,7 @@ static void db_sync_instance_ttl_cb(void* arg)
int d = sqlite3_changes(SI_DB(si));
sqlite3_finalize(stmt);
if (d > 0) DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "TTL cleanup deleted %d unsent records (tbl=%s)", d, SI_TBL(si));
if (d > 0) DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "TTL cleanup deleted %d unsent records (tbl=%s)", d, SI_TBL(si));
si->ttl_timer = uasync_set_timeout(si->db_sync->inst->ua, interval, si, db_sync_instance_ttl_cb, "db_sync_ttl");
}
@ -1590,16 +1592,16 @@ static void db_sync_instance_ttl_cb(void* arg)
// Инициализирует модуль db_sync: открывает БД, регистрирует ETCP-биндинг, запускает таймер проверки пиров
int db_sync_init(struct UTUN_INSTANCE* inst)
{
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "NULL instance"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "inst=%p enabled=%d", (void*)inst, inst->config->global.db_sync_enabled);
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "NULL instance"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "inst=%p enabled=%d", (void*)inst, inst->config->global.db_sync_enabled);
struct DB_SYNC* db = u_calloc(1, sizeof(struct DB_SYNC));
if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "u_calloc failed"); return -1; }
if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "u_calloc failed"); return -1; }
db->inst = inst;
db->last_connected_tb = 0;
if (!inst->config->global.db_sync_enabled) {
db->enabled = 0; inst->db_sync = db;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: disabled by config");
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: disabled by config");
return 0;
}
@ -1609,13 +1611,13 @@ int db_sync_init(struct UTUN_INSTANCE* inst)
const char* dp = inst->config->global.db_path;
if (inst->topo_sqlite_db) {
db->db = inst->topo_sqlite_db; db->shared_db = 1;
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: using shared SQLite db=%p", (void*)db->db);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: using shared SQLite db=%p", (void*)db->db);
} else {
char sp[512];
if (dp[0]) snprintf(sp, sizeof(sp), "%s/chats.db", dp);
else snprintf(sp, sizeof(sp), "/tmp/utun_db_sync");
if (db_sqlite_open(db, sp) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "SQLite open failed, sync disabled");
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "SQLite open failed, sync disabled");
db->enabled = 0;
}
}
@ -1627,7 +1629,7 @@ int db_sync_init(struct UTUN_INSTANCE* inst)
db->peer_check_timer = uasync_set_timeout(inst->ua, DB_SYNC_PEER_CHECK_INTERVAL * 10000u,
db, db_sync_peer_check_cb, "db_sync_peer");
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: initialized (enabled=%d)", db->enabled);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: initialized (enabled=%d)", db->enabled);
return 0;
}
@ -1635,7 +1637,7 @@ int db_sync_init(struct UTUN_INSTANCE* inst)
void db_sync_destroy(struct UTUN_INSTANCE* inst)
{
if (!inst || !inst->db_sync) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "inst=%p instances=%d", (void*)inst, inst->db_sync->instance_count);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "inst=%p instances=%d", (void*)inst, inst->db_sync->instance_count);
struct DB_SYNC* db = inst->db_sync;
inst->db_sync = NULL;
@ -1657,19 +1659,19 @@ void db_sync_destroy(struct UTUN_INSTANCE* inst)
db_sqlite_close(db);
if (db->instances) u_free(db->instances);
u_free(db);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "db_sync: destroyed");
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "db_sync: destroyed");
}
// Создаёт SQLite-таблицу для синхронизации, регистрирует пиров, запускает первичную синхронизацию и TTL-таймер
struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const char* table_name, uint64_t hash, int auto_sync)
{
if (!inst || !inst->db_sync || !table_name || !table_name[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "instance_add invalid args"); return NULL; }
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "table=%s hash=%016llx", table_name, (unsigned long long)hash);
if (!inst || !inst->db_sync || !table_name || !table_name[0]) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "instance_add invalid args"); return NULL; }
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "table=%s hash=%016llx", table_name, (unsigned long long)hash);
struct DB_SYNC* db = inst->db_sync;
if (!db->enabled || !db->db) return NULL;
struct DB_SYNC_INSTANCE* si = db_instance_find(db, hash);
if (si) { DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "instance already exists hash=%016llx", (unsigned long long)hash); return si; }
if (si) { DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance already exists hash=%016llx", (unsigned long long)hash); return si; }
si = db_instance_alloc(db);
if (!si) return NULL;
@ -1694,13 +1696,13 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
" PRIMARY KEY (timestamp, author_signature))",
si->table_name);
int rc = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "CREATE TABLE %s: %s", si->table_name, sqlite3_errmsg(db->db)); si->enabled = 0; return si; }
if (rc != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "CREATE TABLE %s: %s", si->table_name, sqlite3_errmsg(db->db)); si->enabled = 0; return si; }
snprintf(sql, sizeof(sql),
"CREATE INDEX IF NOT EXISTS \"idx_%s_ttl\""
" ON \"%s\" (node_id, timestamp)",
si->table_name, si->table_name);
rc = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
if (rc != SQLITE_OK) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "CREATE INDEX %s: %s", si->table_name, sqlite3_errmsg(db->db));
if (rc != SQLITE_OK) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "CREATE INDEX %s: %s", si->table_name, sqlite3_errmsg(db->db));
}
// Get next id
@ -1716,7 +1718,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
db_verify_chain(si);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "instance_add: tbl=%s mc=%u next_id=%llu hash=%016llx", SI_TBL(si), db_count(si), (unsigned long long)si->next_id, (unsigned long long)si->hash);
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "instance_add: tbl=%s mc=%u next_id=%llu hash=%016llx", SI_TBL(si), db_count(si), (unsigned long long)si->next_id, (unsigned long long)si->hash);
si->ttl_timer = uasync_set_timeout(inst->ua, DB_SYNC_TTL_INTERVAL * 10000u, si, db_sync_instance_ttl_cb, "db_sync_ttl");
@ -1729,14 +1731,14 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
if (pid != 0 && pid != inst->node_id && ce->conn->links_up > 0) {
peers_found++;
struct SI_PEER* p = si_peer_add(si, pid);
if (!p) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "si_peer_add failed for %N in %s", (unsigned long long)pid, SI_TBL(si)); continue; }
if (!p) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "si_peer_add failed for %N in %s", (unsigned long long)pid, SI_TBL(si)); continue; }
if (p->sync_state == 0 && auto_sync) { p->sync_state = 1; db_sync_initiate_sync(si, pid); peers_synced++; }
}
entry = entry->next;
}
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC,
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC,
"instance added table=%s tbl=%s hash=%016llx next_id=%llu peers_found=%d peers_synced=%d mc=%u",
table_name, si->table_name, (unsigned long long)hash,
(unsigned long long)si->next_id, peers_found, peers_synced, db_count(si));
@ -1747,7 +1749,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si)
{
if (!si) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
struct DB_SYNC* db = si->db_sync;
struct UTUN_INSTANCE* inst = db->inst;
@ -1762,7 +1764,7 @@ void db_sync_instance_remove(struct DB_SYNC_INSTANCE* si)
(db->instance_count - idx - 1) * sizeof(*db->instances));
db->instance_count--;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "instance removed tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "instance removed tbl=%s hash=%016llx", si->table_name, (unsigned long long)si->hash);
}
// Вставляет подписанную запись: проверяет подпись, вставляет в БД, рассылает PUSH всем синхронизированным пирам
@ -1770,9 +1772,9 @@ int db_sync_insert_signed(struct DB_SYNC_INSTANCE* si, const char* json_data, si
const uint8_t* sig, size_t sig_len, uint64_t ts,
const char* local_attrs)
{
if (!si || !si->enabled || !json_data || len == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "insert invalid args"); return -1; }
if (!sig || sig_len != DB_SIG_SIZE) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "insert_signed: signature required (64 bytes Ed25519)"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "tbl=%s id=%llu ts=%llu len=%zu", SI_TBL(si), (unsigned long long)si->next_id, (unsigned long long)ts, len);
if (!si || !si->enabled || !json_data || len == 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "insert invalid args"); return -1; }
if (!sig || sig_len != DB_SIG_SIZE) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "insert_signed: signature required (64 bytes Ed25519)"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s id=%llu ts=%llu len=%zu", SI_TBL(si), (unsigned long long)si->next_id, (unsigned long long)ts, len);
uint64_t id = si->next_id;
uint64_t author_node_id = si->db_sync->inst->node_id;
@ -1824,7 +1826,7 @@ int db_sync_select(struct DB_SYNC_INSTANCE* si, uint32_t offset, uint32_t limit,
db_sync_select_cb cb, void* arg)
{
if (!si || !si->enabled || !cb) return 0;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "tbl=%s off=%u lim=%u", SI_TBL(si), offset, limit);
DEBUG_TRACE(DEBUG_CATEGORY_CHAT_SYNC, "tbl=%s off=%u lim=%u", SI_TBL(si), offset, limit);
sqlite3_stmt* stmt;
if (si_prep(si, &stmt,

65
src/chat/member_sync.c

@ -96,9 +96,9 @@ static void _compute_member_hash(uint64_t node_id, const uint8_t* x25519,
static int _member_update_bucket_hash(void* ctx, const char* ns, uint8_t level,
uint64_t prefix64, EVP_MD_CTX* sha_ctx) {
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)ctx;
sqlite3* db = _db(inst); if (!db) return -1;
sqlite3* db = _db(inst); if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bucket_hash — db is NULL", MS_ID); return -1; }
if (level == 0) return 0;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: bucket_hash ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix64);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bucket_hash ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix64);
char peers_tbl[128]; _peers_table(ns, peers_tbl, sizeof(peers_tbl));
int mask_shift = 64 - (int)level * 5;
@ -112,7 +112,7 @@ static int _member_update_bucket_hash(void* ctx, const char* ns, uint8_t level,
peers_tbl, (long long)mask, (long long)prefix64);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bucket_hash prepare failed ns=%s", MS_ID, ns); return -1; }
int count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
@ -166,9 +166,9 @@ static int _member_get_items(void* ctx, const char* ns, uint8_t level,
uint64_t prefix, uint8_t prefix_bytes,
uint8_t* buf, size_t* len) {
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)ctx;
sqlite3* db = _db(inst); if (!db || !buf || !len) return -1;
sqlite3* db = _db(inst); if (!db || !buf || !len) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: get_items — invalid args db=%p buf=%p len=%p", MS_ID, (void*)db, (void*)buf, (void*)len); return -1; }
if (level == 0) { *len = 0; return 0; }
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: get_items ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: get_items ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix);
char peers_tbl[128]; _peers_table(ns, peers_tbl, sizeof(peers_tbl));
int mask_shift = 64 - (int)level * 5;
@ -182,7 +182,7 @@ static int _member_get_items(void* ctx, const char* ns, uint8_t level,
peers_tbl, (long long)mask, (long long)prefix);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: get_items prepare failed ns=%s", MS_ID, ns); return -1; }
size_t off = 0;
if (off + 2 > *len) { sqlite3_finalize(stmt); return -2; }
@ -259,7 +259,7 @@ static int _member_get_items(void* ctx, const char* ns, uint8_t level,
}
sqlite3_finalize(stmt);
*len = off;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: get_items ns=%s L%d/P%016llx mask=%016llx count=%u off=%zu",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: get_items ns=%s L%d/P%016llx mask=%016llx count=%u off=%zu",
MS_ID, ns, level, (unsigned long long)prefix, (unsigned long long)mask, *cnt, off);
return 0;
}
@ -294,10 +294,10 @@ void member_sync_remove_props_cbk(node_props_changed_fn fn, void* arg) {
static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
const uint8_t* data, size_t len) {
struct UTUN_INSTANCE* inst = (struct UTUN_INSTANCE*)ctx;
if (len < 2) return -1;
if (len < 2) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_items — len=%zu < 2", MS_ID, len); return -1; }
uint16_t count; memcpy(&count, data, 2);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: apply_items ns=%s count=%u from=%016llx", MS_ID, ns, count, (unsigned long long)from_peer);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: apply_items ns=%s count=%u from=%016llx", MS_ID, ns, count, (unsigned long long)from_peer);
const uint8_t* mp = data + 2; size_t mrem = len - 2;
sqlite3* db = _db(inst);
@ -348,7 +348,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
int ok = (EVP_DigestVerifyInit(ver, NULL, NULL, NULL, pkey) == 1)
&& (EVP_DigestVerify(ver, usig, 64, vmsg, vlen) == 1);
if (!ok)
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync invalid update_sig node=0x%016llx ns=%s", MS_ID,
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_sync invalid update_sig node=0x%016llx ns=%s", MS_ID,
(unsigned long long)nid, ns);
EVP_MD_CTX_free(ver);
}
@ -376,7 +376,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
int ok = (EVP_DigestVerifyInit(vctx, NULL, NULL, NULL, pkey) == 1)
&& (EVP_DigestVerify(vctx, atsig, 64, amsg, aoff) == 1);
if (!ok) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync invalid adm_tags_sig node=0x%016llx ns=%s tags=%s",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_sync invalid adm_tags_sig node=0x%016llx ns=%s tags=%s",
MS_ID, (unsigned long long)nid, ns, atags);
adm_ver = -1; /* skip this record */
}
@ -385,7 +385,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
EVP_PKEY_free(pkey);
}
} else {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: cannot verify adm_tags_sig — no channel key for ns=%s", MS_ID, ns);
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cannot verify adm_tags_sig — no channel key for ns=%s", MS_ID, ns);
adm_ver = -1;
}
/* check version is strictly greater than local */
@ -401,7 +401,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
int local_ver = 0; const char* lv = strstr(local_tags, "ver=");
if (lv) local_ver = atoi(lv + 4);
if (adm_ver <= local_ver) {
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: stale adm_tags node=0x%016llx ns=%s ver=%d <= local=%d — skipping",
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: stale adm_tags node=0x%016llx ns=%s ver=%d <= local=%d — skipping",
MS_ID, (unsigned long long)nid, ns, adm_ver, local_ver);
adm_ver = -1;
}
@ -416,7 +416,7 @@ static int _member_apply_items(void* ctx, const char* ns, uint64_t from_peer,
nid != inst->node_id ? addrs : NULL,
nid != inst->node_id ? (int)ac : 0,
atags[0] ? atags : NULL, atsig, adm_storage);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync recv ns=%s nid=0x%016llx ac=%d adm_ver=%d storage=%d", MS_ID, ns, (unsigned long long)nid, ac, adm_ver, adm_storage);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync recv ns=%s nid=0x%016llx ac=%d adm_ver=%d storage=%d", MS_ID, ns, (unsigned long long)nid, ac, adm_ver, adm_storage);
/* fire node_props_changed callbacks */
{ struct ms_props_cbk* pc = g_props_cbks;
if (pc) {
@ -470,7 +470,7 @@ static void _rebuild_all_trees(struct UTUN_INSTANCE* inst) {
while (sqlite3_step(ns) == SQLITE_ROW) {
uint64_t nid = (uint64_t)sqlite3_column_int64(ns, 0);
merkle_sync_recompute_path(inst, ch_id, nid);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: rebuild tree ns=%s nid=%016llx", MS_ID, ch_id, (unsigned long long)nid);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: rebuild tree ns=%s nid=%016llx", MS_ID, ch_id, (unsigned long long)nid);
}
sqlite3_finalize(ns);
}
@ -479,12 +479,11 @@ static void _rebuild_all_trees(struct UTUN_INSTANCE* inst) {
}
int member_sync_init(struct UTUN_INSTANCE* inst) {
if (!inst) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: init", MS_ID);
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: init — inst is NULL", MS_ID); return -1; }
int rc = merkle_sync_init(inst, 0x31, &g_member_ops, inst);
if (rc != 0) return rc;
_rebuild_all_trees(inst);
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: initialized, merkle_rc=%d", MS_ID, rc);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: initialized, merkle_rc=%d", MS_ID, rc);
return 0;
}
@ -510,29 +509,29 @@ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id,
const char* userinfo,
const uint8_t* addrs_data, int addr_count,
const char* adm_tags, const uint8_t* adm_tags_sig, int storage) {
if (!inst || !ch_id) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: put ch=%s nid=%016llx userinfo=%s ac=%d adm_tags=%s storage=%d", MS_ID, ch_id, (unsigned long long)member_id, userinfo ? userinfo : "", addr_count, adm_tags ? adm_tags : "", storage);
sqlite3* db = _db(inst); if (!db) return -1;
if (!inst || !ch_id) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: put — inst=%p ch_id=%s", MS_ID, (void*)inst, ch_id ? ch_id : "(null)"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: put ch=%s nid=%016llx userinfo=%s ac=%d adm_tags=%s storage=%d", MS_ID, ch_id, (unsigned long long)member_id, userinfo ? userinfo : "", addr_count, adm_tags ? adm_tags : "", storage);
sqlite3* db = _db(inst); if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: put — db is NULL ch=%s", MS_ID, ch_id); return -1; }
int rc = topo_node_sqlite_member_put(db, ch_id, member_id,
join_sig, join_ts, update_sig, update_ts,
x25519, ed25519, userinfo, NULL,
adm_tags, adm_tags_sig, storage);
if (rc != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put FAILED ch=%s id=0x%016llx userinfo=%s rc=%d",
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_put FAILED ch=%s id=0x%016llx userinfo=%s rc=%d",
MS_ID, ch_id, (unsigned long long)member_id, userinfo ? userinfo : "", rc);
return -1;
}
if (addrs_data && addr_count > 0) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addr_count=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addr_count=%d",
MS_ID, (unsigned long long)member_id, ch_id, addr_count);
sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
sqlite3_stmt* ds = NULL;
sqlite3_prepare_v2(db, "DELETE FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &ds, NULL);
if (ds) { sqlite3_bind_int64(ds, 1, (sqlite3_int64)member_id); sqlite3_step(ds);
int deleted = sqlite3_changes(db);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put DELETE addr_type=0 node=0x%016llx: %d rows deleted",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put DELETE addr_type=0 node=0x%016llx: %d rows deleted",
MS_ID, (unsigned long long)member_id, deleted);
sqlite3_finalize(ds); }
@ -559,24 +558,24 @@ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id,
sqlite3_step(as); sqlite3_reset(as);
if (fam == 4) {
const uint8_t* ip = p - 6; /* p advanced by ip_sz(4) + port(2) - back to start of ip */
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put INSERT node=0x%016llx proto=%d sock=%d %d.%d.%d.%d:%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put INSERT node=0x%016llx proto=%d sock=%d %d.%d.%d.%d:%d",
MS_ID, (unsigned long long)member_id, proto, sid, ip[0], ip[1], ip[2], ip[3], port);
} else {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put INSERT v6 node=0x%016llx sock=%d port=%d",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put INSERT v6 node=0x%016llx sock=%d port=%d",
MS_ID, (unsigned long long)member_id, sid, port);
}
written++;
}
sqlite3_finalize(as);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put DONE node=0x%016llx: %d addrs written",
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put DONE node=0x%016llx: %d addrs written",
MS_ID, (unsigned long long)member_id, written);
}
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
} else {
if (!addrs_data)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addrs_data=NULL — NO addresses (skipping)", MS_ID, (unsigned long long)member_id, ch_id);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addrs_data=NULL — NO addresses (skipping)", MS_ID, (unsigned long long)member_id, ch_id);
else
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addr_count=%d — empty, NO DELETE (skipping)", MS_ID, (unsigned long long)member_id, ch_id, addr_count);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put node=0x%016llx ch=%s addr_count=%d — empty, NO DELETE (skipping)", MS_ID, (unsigned long long)member_id, ch_id, addr_count);
}
merkle_sync_recompute_path(inst, ch_id, member_id);
@ -584,9 +583,9 @@ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id,
}
int member_sync_del(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t member_id) {
if (!inst || !ch_id) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: del ch=%s nid=%016llx", MS_ID, ch_id, (unsigned long long)member_id);
sqlite3* db = _db(inst); if (!db) return -1;
if (!inst || !ch_id) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: del — inst=%p ch_id=%s", MS_ID, (void*)inst, ch_id ? ch_id : "(null)"); return -1; }
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: del ch=%s nid=%016llx", MS_ID, ch_id, (unsigned long long)member_id);
sqlite3* db = _db(inst); if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: del — db is NULL ch=%s", MS_ID, ch_id); return -1; }
topo_node_sqlite_member_del(db, ch_id, member_id);
merkle_sync_recompute_path(inst, ch_id, member_id);
return 0;
@ -611,7 +610,7 @@ void member_sync_set_node_updated_cb(member_sync_node_updated_fn cb) {
void member_sync_set_online(struct UTUN_INSTANCE* inst, uint64_t node_id, int online) {
if (!inst) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: set_online nid=%016llx online=%d", MS_ID, (unsigned long long)node_id, online);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: set_online nid=%016llx online=%d", MS_ID, (unsigned long long)node_id, online);
sqlite3* db = _db(inst); if (!db) return;
topo_node_sqlite_node_set_online(db, node_id, online);
}

74
src/chat/merkle_sync.c

@ -97,16 +97,16 @@ static void _ensure_table(struct merkle_sync* ms) {
static int _recompute_bucket(struct merkle_sync* ms, const char* ns,
uint8_t level, uint64_t prefix64) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix64);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: ns=%s L%d/P%016llx", MS_ID, ns, level, (unsigned long long)prefix64);
sqlite3* db = _db(ms->inst); if (!db) return -1;
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
int count = ms->ops->update_bucket_hash(ms->data_ctx, ns, level, prefix64, ctx);
if (count < 0) { DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → error", MS_ID); EVP_MD_CTX_free(ctx); return -1; }
if (count < 0) { DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → error", MS_ID); EVP_MD_CTX_free(ctx); return -1; }
if (count == 0) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → empty, deleted", MS_ID);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → empty, deleted", MS_ID);
EVP_MD_CTX_free(ctx);
sqlite3_stmt* ds = NULL;
sqlite3_prepare_v2(db,
@ -120,7 +120,7 @@ static int _recompute_bucket(struct merkle_sync* ms, const char* ns,
uint8_t hash[MT_HASH_SIZE];
EVP_DigestFinal_ex(ctx, hash, NULL);
EVP_MD_CTX_free(ctx);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: → saved, count=%d", MS_ID, count);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → saved, count=%d", MS_ID, count);
sqlite3_stmt* is = NULL;
sqlite3_prepare_v2(db,
@ -139,8 +139,8 @@ static int _recompute_bucket(struct merkle_sync* ms, const char* ns,
void merkle_sync_recompute_path(struct UTUN_INSTANCE* inst, const char* ns, uint64_t key) {
struct merkle_sync* ms = inst->msync;
if (!ms || !ms->initialized) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: recompute_path called but msync not initialized", MS_ID); return; }
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: ns=%s key=%016llx", MS_ID, ns, (unsigned long long)key);
if (!ms || !ms->initialized) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: recompute_path called but msync not initialized", MS_ID); return; }
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: ns=%s key=%016llx", MS_ID, ns, (unsigned long long)key);
for (uint8_t level = 1; level <= MT_MAX_LEVEL; level++)
_recompute_bucket(ms, ns, level, merkle_sync_level_prefix(key, level));
}
@ -174,7 +174,7 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns,
*bitmap = 0;
if (level >= MT_MAX_LEVEL) return 0;
sqlite3* db = _db(ms->inst); if (!db) return -1;
sqlite3* db = _db(ms->inst); if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: _get_level_hashes — db is NULL", MS_ID); return -1; }
int next_shift = 64 - ((int)level + 1) * 5; if (next_shift < 0) next_shift = 0;
@ -187,7 +187,7 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns,
" WHERE namespace=? AND level=? AND prefix64>=? AND prefix64<=?"
" ORDER BY prefix64";
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK || !stmt) {
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: _get_level_hashes SQL error ns=%s L%d — %s", MS_ID, ns, level, sqlite3_errmsg(db));
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: _get_level_hashes SQL error ns=%s L%d — %s", MS_ID, ns, level, sqlite3_errmsg(db));
return -1;
}
sqlite3_bind_text(stmt, 1, ns, -1, SQLITE_STATIC);
@ -206,7 +206,7 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns,
memcpy(hashes[bucket], h, MT_HASH_SIZE);
}
sqlite3_finalize(stmt);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: _get_level_hashes ns=%s L%d/P%016llx bitmap=%08x",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: _get_level_hashes ns=%s L%d/P%016llx bitmap=%08x",
MS_ID, ns, level, (unsigned long long)prefix, *bitmap);
return 0;
}
@ -214,10 +214,10 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns,
/* ── Send helpers ── */
static struct ETCP_CONN* ms_find_conn_for_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
if (!inst->connections) { DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn — inst->connections is NULL", MS_ID); return NULL; }
if (!inst->connections) { DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn — inst->connections is NULL", MS_ID); return NULL; }
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
if (!conn) { DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn — node=%016llx NOT FOUND", MS_ID, (unsigned long long)node_id); return NULL; }
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: find_conn — node=%016llx found=%d initialized=%d links_up=%d",
if (!conn) { DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn — node=%016llx NOT FOUND", MS_ID, (unsigned long long)node_id); return NULL; }
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: find_conn — node=%016llx found=%d initialized=%d links_up=%d",
MS_ID, (unsigned long long)node_id, 1, conn->initialized, conn->links_up);
if (conn->initialized && conn->links_up) return conn;
return NULL;
@ -234,10 +234,10 @@ static int _send_msg(struct merkle_sync* ms, uint64_t peer,
if (!entry) { u_free(buf); return -1; }
entry->dgram = buf; entry->len = 1 + len;
struct ETCP_CONN* conn = ms_find_conn_for_node(ms->inst, peer);
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: no conn for node %016llx", MS_ID, (unsigned long long)peer); u_free(buf); queue_entry_free(entry); return -1; }
if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: no conn for node %016llx", MS_ID, (unsigned long long)peer); u_free(buf); queue_entry_free(entry); return -1; }
int r = etcp_send(conn, entry);
if (r != 0) { u_free(buf); queue_entry_free(entry); }
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: send OK peer=%016llx len=%zu rc=%d", MS_ID, (unsigned long long)peer, len, r);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: send OK peer=%016llx len=%zu rc=%d", MS_ID, (unsigned long long)peer, len, r);
return r;
}
@ -261,7 +261,7 @@ static int _send_broadcast_data(struct merkle_sync* ms, uint64_t peer, const cha
static int _send_hashes(struct merkle_sync* ms, uint64_t peer, const char* ns,
uint8_t level, uint64_t prefix, uint8_t prefix_bytes, int is_data) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: send_hashes peer=%016llx ns=%s L%d P%016llx is_data=%d", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, is_data);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: send_hashes peer=%016llx ns=%s L%d P%016llx is_data=%d", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, is_data);
uint8_t ch_len = (uint8_t)strlen(ns);
size_t max_sz = 1 + 1 + ch_len + 1 + 1 + prefix_bytes + 1 + 4 + MT_BUCKETS * MT_HASH_SIZE + 2 + 65536;
uint8_t* buf = u_malloc(max_sz);
@ -285,7 +285,7 @@ static int _send_hashes(struct merkle_sync* ms, uint64_t peer, const char* ns,
} else {
uint32_t bitmap; uint8_t hashes[MT_BUCKETS][MT_HASH_SIZE];
_get_level_hashes(ms, ns, level, prefix, prefix_bytes, &bitmap, hashes);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: send_hashes peer=%016llx ns=%s level=%d prefix=%016llx bitmap=%08x", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, bitmap);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: send_hashes peer=%016llx ns=%s level=%d prefix=%016llx bitmap=%08x", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, bitmap);
memcpy(p, &bitmap, 4); p += 4;
for (int i = 0; i < MT_BUCKETS; i++)
if (bitmap & (1u << i)) { memcpy(p, hashes[i], MT_HASH_SIZE); p += MT_HASH_SIZE; }
@ -297,7 +297,7 @@ static int _send_hashes(struct merkle_sync* ms, uint64_t peer, const char* ns,
static int _send_batch(struct merkle_sync* ms, uint64_t peer, const char* ns,
struct bucket_entry* buckets, int count) {
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: send_batch peer=%016llx ns=%s count=%d", MS_ID, (unsigned long long)peer, ns, count);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: send_batch peer=%016llx ns=%s count=%d", MS_ID, (unsigned long long)peer, ns, count);
uint8_t ch_len = (uint8_t)strlen(ns);
size_t max_sz = 1 + 1 + ch_len + 1 + (size_t)count * (1 + 1 + 8 + 1 + 4 + MT_BUCKETS * MT_HASH_SIZE + 65536);
uint8_t* buf = u_malloc(max_sz);
@ -362,11 +362,11 @@ static int _find_pending(struct ms_session* s, uint8_t level, uint64_t prefix) {
}
static void _session_done(struct ms_session* s, int result) {
if (s->sess_state == SESS_SYNCED) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: session ALREADY DONE peer=%016llx ns=%s", MS_ID, (unsigned long long)s->peer, s->ns); return; }
if (s->sess_state == SESS_SYNCED) { DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: session ALREADY DONE peer=%016llx ns=%s", MS_ID, (unsigned long long)s->peer, s->ns); return; }
merkle_sync_done_cb cb = s->done_cb; void* arg = s->cb_arg;
s->done_cb = NULL; s->cb_arg = NULL;
if (result == MT_OK) { s->sess_state = SESS_SYNCED; DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: session SYNCED peer=%016llx ns=%s", MS_ID, (unsigned long long)s->peer, s->ns); }
else { s->sess_state = SESS_SYNCING; DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: session FAILED peer=%016llx ns=%s result=%d", MS_ID, (unsigned long long)s->peer, s->ns, result); }
if (result == MT_OK) { s->sess_state = SESS_SYNCED; DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: session SYNCED peer=%016llx ns=%s", MS_ID, (unsigned long long)s->peer, s->ns); }
else { s->sess_state = SESS_SYNCING; DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: session FAILED peer=%016llx ns=%s result=%d", MS_ID, (unsigned long long)s->peer, s->ns, result); }
if (cb) cb(s->peer, s->ns, result, arg);
}
@ -380,7 +380,7 @@ static void _handle_hashes(struct merkle_sync* ms, uint64_t peer, const char* ns
uint8_t is_data = pl[2 + pb];
const uint8_t* payload = pl + 3 + pb;
size_t paylen = plen - 3 - pb;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: handle_hashes peer=%016llx ns=%s L%d/P%016llx is_data=%d", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, is_data);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: handle_hashes peer=%016llx ns=%s L%d/P%016llx is_data=%d", MS_ID, (unsigned long long)peer, ns, level, (unsigned long long)prefix, is_data);
struct ms_session* s = _session_find(ms, peer, ns);
@ -421,7 +421,7 @@ static void _handle_hashes(struct merkle_sync* ms, uint64_t peer, const char* ns
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: handle_hashes peer=%016llx ns=%s level=%d remote_bm=%08x local_bm=%08x differs=%08x is_data=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: handle_hashes peer=%016llx ns=%s level=%d remote_bm=%08x local_bm=%08x differs=%08x is_data=%d",
MS_ID, (unsigned long long)peer, ns, level, remote_bm, local_bm, differs, is_data);
if (differs == 0 && level == 0) {
@ -490,7 +490,7 @@ static void _handle_request(struct merkle_sync* ms, uint64_t peer, const char* n
const uint8_t* pl, size_t plen) {
if (plen < 1) return;
uint8_t count = pl[0]; const uint8_t* bp = pl + 1; size_t off = 0;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: handle_request peer=%016llx ns=%s count=%d", MS_ID, (unsigned long long)peer, ns, count);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: handle_request peer=%016llx ns=%s count=%d", MS_ID, (unsigned long long)peer, ns, count);
struct bucket_entry buckets[32]; int bc = 0;
for (uint8_t i = 0; i < count && bc < 32; i++) {
@ -510,7 +510,7 @@ static void _handle_batch(struct merkle_sync* ms, uint64_t peer, const char* ns,
const uint8_t* pl, size_t plen) {
if (plen < 1) return;
uint8_t count = pl[0]; const uint8_t* bp = pl + 1; size_t rem = plen - 1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: handle_batch peer=%016llx ns=%s count=%d len=%zu", MS_ID, (unsigned long long)peer, ns, count, plen - 1);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: handle_batch peer=%016llx ns=%s count=%d len=%zu", MS_ID, (unsigned long long)peer, ns, count, plen - 1);
for (uint8_t i = 0; i < count && rem >= 3; i++) {
uint8_t lvl = bp[0]; uint8_t pb_i = bp[1]; rem -= 2; bp += 2;
@ -576,7 +576,7 @@ static void _recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (dlen < (size_t)(2 + ch_len + 1)) { u_free(entry->dgram); queue_entry_free(entry); return; }
char ns[64]; memcpy(ns, d + 2, ch_len); ns[ch_len] = '\0';
uint8_t type = d[2 + ch_len];
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: recv type=%02x from=%016llx ns=%s len=%zu", MS_ID, type, (unsigned long long)peer, ns, dlen);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: recv type=%02x from=%016llx ns=%s len=%zu", MS_ID, type, (unsigned long long)peer, ns, dlen);
const uint8_t* pl = d + 3 + ch_len;
size_t plen = dlen - 3 - ch_len;
@ -588,7 +588,7 @@ static void _recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (plen >= 9 && ms->ops->apply_update) {
uint64_t key; memcpy(&key, pl, 8);
uint8_t utype = pl[8];
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: recv ITEM_UPDATE key=%016llx type=%02x from=%016llx ns=%s",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: recv ITEM_UPDATE key=%016llx type=%02x from=%016llx ns=%s",
MS_ID, (unsigned long long)key, utype, (unsigned long long)peer, ns);
ms->ops->apply_update(ms->data_ctx, ns, key, utype, pl + 9, plen - 9);
}
@ -604,7 +604,7 @@ void merkle_sync_push_update(struct UTUN_INSTANCE* inst, const char* ns,
uint64_t key, uint8_t type, const uint8_t* data, size_t len) {
struct merkle_sync* ms = inst ? inst->msync : NULL;
if (!ms || !ms->initialized || !ns || !data) return;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: push_update ns=%s key=%016llx type=%02x len=%zu",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: push_update ns=%s key=%016llx type=%02x len=%zu",
MS_ID, ns, (unsigned long long)key, type, len);
uint8_t ch_len = (uint8_t)strlen(ns);
@ -631,7 +631,7 @@ void merkle_sync_push_update(struct UTUN_INSTANCE* inst, const char* ns,
struct ETCP_CONN* conn = ms_find_conn_for_node(inst, s->peer);
if (!conn) { u_free(dcopy); queue_entry_free(entry); continue; }
int r = etcp_send(conn, entry);
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: push_update sent type=%02x to=%016llx rc=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: push_update sent type=%02x to=%016llx rc=%d",
MS_ID, type, (unsigned long long)s->peer, r);
if (r != 0) { u_free(dcopy); queue_entry_free(entry); }
}
@ -644,7 +644,7 @@ void merkle_sync_broadcast(struct UTUN_INSTANCE* inst, const char* ns,
uint64_t from_peer, const uint8_t* data, size_t len) {
struct merkle_sync* ms = inst ? inst->msync : NULL;
if (!ms || !ms->initialized || !ns || !data || len < 2) return;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: broadcast ns=%s from=%016llx len=%zu",
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: broadcast ns=%s from=%016llx len=%zu",
MS_ID, ns, (unsigned long long)from_peer, len);
for (struct ms_session* s = ms->sessions; s; s = s->next) {
if (s->sess_state != SESS_SYNCED || s->peer == from_peer || strcmp(s->ns, ns) != 0) continue;
@ -657,7 +657,7 @@ void merkle_sync_broadcast(struct UTUN_INSTANCE* inst, const char* ns,
int merkle_sync_bg_check(struct UTUN_INSTANCE* inst, const char* ns) {
struct merkle_sync* ms = inst ? inst->msync : NULL;
if (!ms || !ms->initialized) return -1;
sqlite3* db = _db(inst); if (!db || !ns) return -1;
sqlite3* db = _db(inst); if (!db || !ns) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bg_check — db or ns is NULL db=%p ns=%s", MS_ID, (void*)db, ns ? ns : "(null)"); return -1; }
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db,
@ -666,7 +666,7 @@ int merkle_sync_bg_check(struct UTUN_INSTANCE* inst, const char* ns) {
sqlite3_bind_text(stmt, 1, ns, -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 2, MT_MAX_LEVEL);
if (sqlite3_step(stmt) != SQLITE_ROW) { sqlite3_finalize(stmt); return -1; }
if (sqlite3_step(stmt) != SQLITE_ROW) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bg_check — no hash row for ns=%s", MS_ID, ns); sqlite3_finalize(stmt); return -1; }
uint64_t pref = (uint64_t)sqlite3_column_int64(stmt, 0);
sqlite3_finalize(stmt);
@ -697,7 +697,7 @@ static void _bg_timer_cb(void* arg) {
if (!ch_id) continue;
int rc = merkle_sync_bg_check(ms->inst, ch_id);
if (rc < 0) continue;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: bg_check ns=%s → %s", MS_ID, ch_id, rc == 0 ? "consistent" : "RECALCULATED");
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: bg_check ns=%s → %s", MS_ID, ch_id, rc == 0 ? "consistent" : "RECALCULATED");
break;
}
sqlite3_finalize(cs);
@ -711,7 +711,7 @@ static void _bg_timer_cb(void* arg) {
int merkle_sync_init(struct UTUN_INSTANCE* inst, uint8_t svc_id,
const struct merkle_sync_data_ops* ops, void* data_ctx) {
if (!inst || !ops) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: init svc=%02x", MS_ID, svc_id);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: init svc=%02x", MS_ID, svc_id);
struct merkle_sync* ms = u_calloc(1, sizeof(*ms));
if (!ms) return -1;
ms->inst = inst; ms->svc_id = svc_id; ms->ops = ops; ms->data_ctx = data_ctx;
@ -725,7 +725,7 @@ int merkle_sync_init(struct UTUN_INSTANCE* inst, uint8_t svc_id,
ms->bg_timer = uasync_set_timeout(inst->ua, (uint32_t)(MS_BG_INTERVAL_MS * 10),
ms, _bg_timer_cb, "ms_bg");
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: initialized svc=%02x", MS_ID, svc_id);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: initialized svc=%02x", MS_ID, svc_id);
return 0;
}
@ -755,7 +755,7 @@ int merkle_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
_ensure_table(ms);
struct ms_session* s = _session_find(ms, peer, ns);
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: start peer=%016llx ns=%s new=%d", MS_ID, (unsigned long long)peer, ns, s ? 0 : 1);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: start peer=%016llx ns=%s new=%d", MS_ID, (unsigned long long)peer, ns, s ? 0 : 1);
if (!s) {
s = u_calloc(1, sizeof(*s));
if (!s) return -1;
@ -765,7 +765,7 @@ int merkle_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
ms->sessions = s;
} else {
s->pending_count = 0;
DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: start OVERWRITE peer=%016llx ns=%s", MS_ID, (unsigned long long)peer, ns);
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: start OVERWRITE peer=%016llx ns=%s", MS_ID, (unsigned long long)peer, ns);
}
s->sess_state = SESS_SYNCING;
s->done_cb = done_cb; s->cb_arg = arg;
@ -777,7 +777,7 @@ int merkle_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer,
void merkle_sync_cancel(struct UTUN_INSTANCE* inst, uint64_t peer, const char* ns) {
struct merkle_sync* ms = inst ? inst->msync : NULL;
if (!ms || !ns) return;
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: cancel peer=%016llx ns=%s", MS_ID, (unsigned long long)peer, ns);
DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: cancel peer=%016llx ns=%s", MS_ID, (unsigned long long)peer, ns);
struct ms_session** p = &ms->sessions;
while (*p) {
struct ms_session* s = *p;

22
src/config_parser.c

@ -182,7 +182,7 @@ static uint32_t get_netif_index(const char *ifname) {
static struct CFG_CLIENT_LINK* create_client_link(struct CFG_SERVER* local_srv, const char *remote_addr) {
struct CFG_CLIENT_LINK *link = u_calloc(1, sizeof(struct CFG_CLIENT_LINK));
if (!link) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_client_link: failed to allocate memory for client link");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "create_client_link: failed to allocate memory for client link");
return NULL;
}
@ -208,7 +208,7 @@ static void free_cfg_client_links(struct CFG_CLIENT_LINK *links) {
static struct CFG_ROUTE_ENTRY* create_route_entry(const char *subnet_str) {
struct CFG_ROUTE_ENTRY *entry = u_calloc(1, sizeof(struct CFG_ROUTE_ENTRY));
if (!entry) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_route_entry: failed to allocate memory for route entry");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "create_route_entry: failed to allocate memory for route entry");
return NULL;
}
@ -276,7 +276,7 @@ static int parse_firewall_rule(const char *rule_str, struct global_config *globa
struct CFG_FIREWALL_RULE *new_rules = u_realloc(global->firewall_rules,
new_cap * sizeof(struct CFG_FIREWALL_RULE));
if (!new_rules) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to realloc firewall rules");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to realloc firewall rules");
return -1;
}
global->firewall_rules = new_rules;
@ -322,7 +322,7 @@ static int parse_control_allow(const char *rule_str, struct global_config *globa
struct CFG_CONTROL_ALLOW *new_allows = u_realloc(global->control_allows,
new_cap * sizeof(struct CFG_CONTROL_ALLOW));
if (!new_allows) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to realloc control allows");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to realloc control allows");
return -1;
}
global->control_allows = new_allows;
@ -827,7 +827,7 @@ static section_type_t parse_section_header(const char *line, char *name, size_t
static struct utun_config* parse_config_internal(FILE *fp, const char *filename) {
struct utun_config *cfg = u_calloc(1, sizeof(struct utun_config));
if (!cfg) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate memory for config structure");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate memory for config structure");
return NULL;
}
@ -894,7 +894,7 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
if (cur_section == SECTION_SERVER) {
cur_server = u_calloc(1, sizeof(struct CFG_SERVER));
if (!cur_server) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate memory for server %s", name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate memory for server %s", name);
goto error;
}
strcpy(cur_server->name, name);
@ -902,14 +902,14 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
} else if (cur_section == SECTION_CLIENT) {
cur_client = u_calloc(1, sizeof(struct CFG_CLIENT));
if (!cur_client) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate memory for client %s", name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate memory for client %s", name);
goto error;
}
strcpy(cur_client->name, name);
} else if (cur_section == SECTION_NETWORK) {
cur_network = u_calloc(1, sizeof(struct CFG_NETWORK));
if (!cur_network) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate memory for network %s", name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate memory for network %s", name);
goto error;
}
strcpy(cur_network->name, name);
@ -980,7 +980,7 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
} else if (strcmp(key, "key") == 0) {
struct CFG_ALLOWED_KEY *new_key = u_calloc(1, sizeof(struct CFG_ALLOWED_KEY));
if (!new_key) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate allowed key");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate allowed key");
} else if (strlen(value) != SC_PUBKEY_SIZE * 2) {
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid key length %zu, expected %d", filename, line_num, strlen(value), SC_PUBKEY_SIZE * 2);
u_free(new_key);
@ -1031,7 +1031,7 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
cfg->global.ntp_servers = ns;
cfg->global.ntp_server_count++;
} else {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "%s:%d: Failed to allocate NTP server entry", filename, line_num);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "%s:%d: Failed to allocate NTP server entry", filename, line_num);
}
} else if (strcmp(key, "interval") == 0) {
cfg->global.ntp_resync_interval = atoi(value);
@ -1115,7 +1115,7 @@ static int blr_get_line(blr_t *blr, char *line, size_t maxlen) {
struct utun_config* parse_config_from_buf(const char *buf, size_t len, const char *filename) {
struct utun_config *cfg = u_calloc(1, sizeof(struct utun_config));
if (!cfg) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate memory for config structure"); return NULL; }
if (!cfg) { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate memory for config structure"); return NULL; }
cfg->global.name[0] = '\0';
cfg->global.keepalive_timeout = 2000;
cfg->global.keepalive_interval = 200;

2
src/firewall.c

@ -32,7 +32,7 @@ int fw_load_rules(struct firewall_ctx *ctx, const struct global_config *cfg) {
if (cfg->firewall_rule_count > 0) {
ctx->rules = u_calloc(cfg->firewall_rule_count, sizeof(struct CFG_FIREWALL_RULE));
if (!ctx->rules) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "failed to allocate rules");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "failed to allocate rules");
return -1;
}
memcpy(ctx->rules, cfg->firewall_rules,

4
src/ntp_time.c

@ -256,7 +256,7 @@ int ntp_time_init(struct UTUN_INSTANCE* instance) {
if (g->ntp_server_count > 0) {
ntp->servers = u_malloc(g->ntp_server_count * sizeof(char*));
if (!ntp->servers) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "NTP: failed to allocate servers array");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "NTP: failed to allocate servers array");
ntp->server_count = 0;
return -1;
}
@ -265,7 +265,7 @@ int ntp_time_init(struct UTUN_INSTANCE* instance) {
while (ns && i < g->ntp_server_count) {
ntp->servers[i] = u_strdup(ns->name);
if (!ntp->servers[i]) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "NTP: failed to duplicate server name");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "NTP: failed to duplicate server name");
while (--i >= 0) u_free(ntp->servers[i]);
u_free(ntp->servers);
ntp->servers = NULL;

10
src/transport_layer/etcp.c

@ -306,7 +306,7 @@ void etcp_cbk_fire(struct ETCP_CONN* conn, int event) {
}
static void etcp_on_up(struct ETCP_CONN* etcp) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection UP (links_up=%d initialized=%d)", etcp->log_name, etcp->links_up, etcp->initialized);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Connection UP (links_up=%d initialized=%d)", etcp->log_name, etcp->links_up, etcp->initialized);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "CRYPTO_ON_UP_BEFORE: log=%s seskey=%02x%02x%02x%02x peer_pub=%02x%02x%02x%02x",
etcp->log_name,
etcp->crypto_ctx.session_key[0], etcp->crypto_ctx.session_key[1],
@ -324,7 +324,7 @@ static void etcp_on_up(struct ETCP_CONN* etcp) {
}
static void etcp_on_down(struct ETCP_CONN* etcp) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection DOWN (links_up=%d)", etcp->log_name, etcp->links_up);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Connection DOWN (links_up=%d)", etcp->log_name, etcp->links_up);
etcp_cbk_fire(etcp, ETCP_CBK_EVENT_DOWN);
etcp_fire_conn_status(etcp, ETCP_CONN_STATUS_DOWN);
}
@ -995,7 +995,7 @@ static void etcp_link_ready_callback(struct ETCP_CONN* etcp) {
}
if (etcp->links_up==0) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] etcp_link_ready_callback: links_up 0→1, calling etcp_on_up (initialized=%d tx_state=%d)", etcp->log_name, etcp->initialized, etcp->tx_state);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] etcp_link_ready_callback: links_up 0→1, calling etcp_on_up (initialized=%d tx_state=%d)", etcp->log_name, etcp->initialized, etcp->tx_state);
etcp->links_up=1;
etcp_on_up(etcp);
} else DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] etcp_link_ready_callback: links_up=%d already up", etcp->log_name, etcp->links_up);
@ -1401,7 +1401,7 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d
link->delivered_bytes += rs.delivered;
link->last_ack_time_tb = now_tb;
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] BBR in: seq=%u del=%u iv=%uus rtt=%uus pri=%u tx_infl=%u cur=%u/%u lost=%d app=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] BBR in: seq=%u del=%u iv=%uus rtt=%uus pri=%u tx_infl=%u cur=%u/%u lost=%d app=%d",
link->local_link_id, seq, rs.delivered, rs.interval_us, rs.rtt_us,
rs.prior_delivered, rs.tx_in_flight, link->inflight_bytes, link->inflight_lim_bytes,
rs.lost, rs.is_app_limited);
@ -1417,7 +1417,7 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d
link->bandwidth = (uint32_t)((uint64_t)new_pacing * 8 / 1000);
link->bbr_loss_since_ack = 0;
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] BBR out: cwnd %u→%u pace %u→%u bw=%uK mode=%d cyc=%d infl=%u/%u",
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] BBR out: cwnd %u→%u pace %u→%u bw=%uK mode=%d cyc=%d infl=%u/%u",
link->local_link_id, old_cwnd, new_cwnd, old_pacing, new_pacing,
link->bandwidth, link->bbr->mode, link->bbr->cycle_idx, link->inflight_bytes, new_cwnd);

12
src/transport_layer/etcp_bbr.c

@ -328,13 +328,13 @@ static void bbr_exit_probe_rtt(struct bbr* bbr)
{
bbr_reset_lower_bounds(bbr);
if (bbr->full_bw_reached) {
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d exit probe_rtt → PROBE_BW",
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d exit probe_rtt → PROBE_BW",
bbr->link_id, bbr->mode, BBR_PROBE_BW);
bbr->mode = BBR_PROBE_BW;
bbr_start_bw_probe_down(bbr);
bbr_start_bw_probe_cruise(bbr);
} else {
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d exit probe_rtt → STARTUP",
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d exit probe_rtt → STARTUP",
bbr->link_id, bbr->mode, BBR_STARTUP);
bbr->mode = BBR_STARTUP;
}
@ -541,13 +541,13 @@ static void bbr_check_drain(struct bbr* bbr, const struct bbr_rate_sample* rs,
{
(void)rs; (void)sample_bw;
if (bbr->mode == BBR_STARTUP && bbr->full_bw_reached) {
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d STARTUP→DRAIN", bbr->link_id, bbr->mode, BBR_DRAIN);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d STARTUP→DRAIN", bbr->link_id, bbr->mode, BBR_DRAIN);
bbr->mode = BBR_DRAIN;
bbr_reset_congestion_signals(bbr);
}
if (bbr->mode == BBR_DRAIN &&
inflight_packets <= bbr_inflight(bbr, bbr_max_bw(bbr), BBR_UNIT, mss)) {
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d DRAIN→PROBE_BW infl_pkt=%u", bbr->link_id, bbr->mode, BBR_PROBE_BW, inflight_packets);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d DRAIN→PROBE_BW infl_pkt=%u", bbr->link_id, bbr->mode, BBR_PROBE_BW, inflight_packets);
bbr->mode = BBR_PROBE_BW;
bbr_start_bw_probe_down(bbr);
}
@ -591,7 +591,7 @@ static void bbr_update_min_rtt(struct bbr* bbr, const struct bbr_rate_sample* rs
if (BBR_PROBE_RTT_MS > 0 && probe_rtt_expired &&
!bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) {
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d →PROBE_RTT cwnd=%u infl_pkt=%u",
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d →PROBE_RTT cwnd=%u infl_pkt=%u",
bbr->link_id, bbr->mode, BBR_PROBE_RTT, *cwnd, inflight_packets);
bbr->mode = BBR_PROBE_RTT;
bbr_save_cwnd(bbr, *cwnd);
@ -619,7 +619,7 @@ static void bbr_update_min_rtt(struct bbr* bbr, const struct bbr_rate_sample* rs
static void bbr_reset_startup_mode(struct bbr* bbr)
{
DEBUG_DEBUG(DEBUG_CATEGORY_BBR, "[L%u] mode %d→%d →STARTUP (reset)", bbr->link_id, bbr->mode, BBR_STARTUP);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] mode %d→%d →STARTUP (reset)", bbr->link_id, bbr->mode, BBR_STARTUP);
bbr->mode = BBR_STARTUP;
}

49
src/transport_layer/etcp_connections.c

@ -196,9 +196,9 @@ static void etcp_link_init_timer_cbk(void* arg) {
}
link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk, "link_init");
if (link->link_state == 3 && link->initialized) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d", link->etcp->log_name, link->link_state, link->initialized, link->link_status, link->recv_keepalive, link->remote_keepalive, link->etcp->links_up); return; }
if (link->etcp->links_up > 0) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] init_timer: SUPPRESSED (links_up=%d > 0)", link->etcp->log_name, link->etcp->links_up); return; }
if (link->etcp->fin_wait) { DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] init_timer: SUPPRESSED (fin_wait)", link->etcp->log_name); return; }
if (link->link_state == 3 && link->initialized) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d", link->etcp->log_name, link->link_state, link->initialized, link->link_status, link->recv_keepalive, link->remote_keepalive, link->etcp->links_up); return; }
if (link->etcp->links_up > 0) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED (links_up=%d > 0)", link->etcp->log_name, link->etcp->links_up); return; }
if (link->etcp->fin_wait) { DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] init_timer: SUPPRESSED (fin_wait)", link->etcp->log_name); return; }
if (link->etcp->got_initial_pkt == 0) etcp_link_send_init(link,1,0);
else etcp_link_send_init(link,0,0);
}
@ -308,7 +308,7 @@ static void keepalive_timer_cb(void* arg) {
// Check if all links are down and start recovery if needed (client only)
if (link->is_server == 0 && etcp_all_links_down(link->etcp)) {
DEBUG_WARN(DEBUG_CATEGORY_KEEPALIVE, "[%s] All links are down, starting recovery", link->etcp->log_name);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] All links are down, starting recovery", link->etcp->log_name);
etcp_link_enter_reinit(link);// keepalive timr после reinit не нужен
return;
}
@ -332,8 +332,9 @@ static void keepalive_timer_cb(void* arg) {
link->link_status = 0;
etcp_fire_link_status_cbk(link, link->link_state, old_link_status);
etcp_on_link_down(link->etcp);
DEBUG_INFO(DEBUG_CATEGORY_KEEPALIVE, "[%s] Conn:%s Link down: link_id=%d state=%d init=%d ka=%d remote_ka=%d tmo: %llu>%llu els=%llums", link->etcp->log_name, link->conn?link->conn->name:"???", link->local_link_id, link->link_state, link->initialized, link->recv_keepalive, link->remote_keepalive, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10));
DEBUG_WARN(DEBUG_CATEGORY_KEEPALIVE, "[%s] Link %p (local_id=%d) recv status changed to DOWN - no packets for %llu ms", link->etcp->log_name, link, link->local_link_id, (unsigned long long)(elapsed/10));
if (old_link_status) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link down: link_id=%d state=%d init=%d ka=%d remote_ka=%d tmo: %llu>%llu els=%llums", link->etcp->log_name, link->local_link_id, link->link_state, link->initialized, link->recv_keepalive, link->remote_keepalive, (unsigned long long)timeout_units, (unsigned long long)elapsed, (unsigned long long)(elapsed/10));
}
}
}
@ -502,7 +503,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S
struct ETCP_SOCKET* e_sock = u_calloc(1, sizeof(struct ETCP_SOCKET));
if (!e_sock) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate connection");
return NULL;
}
e_sock->fd = SOCKET_INVALID; // Initialize to invalid socket
@ -729,7 +730,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S
u_free(e_sock);
return NULL;
}
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Registered ETCP socket with uasync");
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Registered ETCP socket with uasync");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP] Socket %p registered and active", e_sock);
return e_sock;
}
@ -1788,7 +1789,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
}
if (link)
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "INIT packet on existing link from=%s log=%s link_state=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "INIT packet on existing link from=%s log=%s link_state=%d",
sockaddr_storage_to_str(&addr).str,
link->etcp ? link->etcp->log_name : "null", link->link_state);
@ -1836,7 +1837,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct conn_queue_entry* ce = (struct conn_queue_entry*)ol->etcp->conn_queue_entry->data;
if (ce->peer_node_id == 0) {
conn = ol->etcp;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] reusing unindexed outbound conn (q_key=0, peer=0x%016llx) for incoming INIT from %s",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] reusing unindexed outbound conn (q_key=0, peer=0x%016llx) for incoming INIT from %s",
conn->log_name, (unsigned long long)peer_id, sockaddr_storage_to_str(&addr).str);
}
}
@ -1880,7 +1881,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
}
if (conn->fin_wait) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] received INIT during fin_wait, clearing", conn->log_name);
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] received INIT during fin_wait, clearing", conn->log_name);
conn->fin_wait = 0;
if (conn->fin_wait_clear_cb) { conn->fin_wait_clear_cb(conn, conn->fin_wait_clear_arg); conn->fin_wait_clear_cb = NULL; conn->fin_wait_clear_arg = NULL; }
}
@ -1902,7 +1903,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
errorcode = 67;
goto ec_fr;
}
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] found existing outbound link by addr for incoming INIT, reusing link=%p",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] found existing outbound link by addr for incoming INIT, reusing link=%p",
conn->log_name, existing_link);
} else if (existing_link) {
struct ETCP_CONN* old_conn = existing_link->etcp;
@ -1948,7 +1949,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// ── Collision handling ──
if (req->collision) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
conn->log_name, (unsigned long long)peer_id);
conn->session_id = session_id;
etcp_conn_reinit(conn);
@ -1960,13 +1961,13 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
int yielding = 0;
if (ml) {
if (conn->instance->node_id < peer_id) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
conn->log_name, (unsigned long long)conn->instance->node_id, (unsigned long long)peer_id);
memory_pool_free(e_sock->instance->pkt_pool, pkt);
etcp_link_send_init(ml, 0, 1);
return;
}
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: peer smaller, yielding master, processing as slave",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: peer smaller, yielding master, processing as slave",
conn->log_name);
yielding = 1;
if (ml->init_timer) { uasync_cancel_timeout(conn->instance->ua, ml->init_timer); ml->init_timer = NULL; }
@ -1999,7 +2000,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// ── Collision handling ──
if (req->collision) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] INIT collision=1 from peer=%016llx — remote is master, becoming slave",
conn->log_name, (unsigned long long)peer_id);
conn->session_id = session_id;
etcp_conn_reinit(conn);
@ -2009,7 +2010,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct ETCP_LINK* ml = conn->links;
while (ml) { if (ml->is_server == 0) break; ml = ml->next; }
if (ml && conn->instance->node_id < peer_id) {
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] COLLISION: we=master node_id=%016llx < peer=%016llx — sending collision INIT",
conn->log_name, (unsigned long long)conn->instance->node_id, (unsigned long long)peer_id);
memory_pool_free(e_sock->instance->pkt_pool, pkt);
etcp_link_send_init(ml, 0, 1);
@ -2021,7 +2022,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
conn->session_id = session_id;
if (sess_changed || conn->got_initial_pkt) {
send_reset = 1;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] REINIT new link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d",
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] REINIT new link: code=0x%02x sess=%08x→%08x got_init=%d initialized=%d links_up=%d",
conn->log_name, code, conn->session_id, session_id, conn->got_initial_pkt, conn->initialized, conn->links_up);
etcp_conn_reinit(conn);
} }
@ -2058,7 +2059,7 @@ process_decrypted:
/* restore recv_keepalive BEFORE computing link_status = remote && local */
if (link->recv_keepalive != 1) {
link->recv_keepalive = 1;
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "[%s] Link %d recv_keepalive restored to 1 (was 0) link_status=%d remote_ka=%d state=%d init=%d links_up=%d",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d recv_keepalive restored to 1 (was 0) link_status=%d remote_ka=%d state=%d init=%d links_up=%d",
link->etcp->log_name, link->local_link_id, link->link_status, link->remote_keepalive, link->link_state, link->initialized, link->etcp->links_up);
}
@ -2067,7 +2068,7 @@ process_decrypted:
if (link->link_status != was_up)
etcp_fire_link_status_cbk(link, link->link_state, was_up);
if (link->link_status && !was_up && link->initialized) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "[%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d → calling loadbalancer_link_ready", link->etcp->log_name, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d → calling loadbalancer_link_ready", link->etcp->log_name, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_state, link->initialized);
loadbalancer_link_ready(link);
}
@ -2311,11 +2312,11 @@ int init_connections(struct UTUN_INSTANCE* instance) {
break;
}
conn = node_conn_direct_get_conn(handle);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "client %s ncd handle=%p conn=%p %s sock=%s",
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "client %s ncd handle=%p conn=%p %s sock=%s",
client->name, handle, conn, r == NCD_NEW ? "NEW" : "REUSED", sock->name);
} else {
etcp_link_new(conn, sock, &cl->remote_addr, 0);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "client %s added link sock=%s", client->name, sock->name);
struct ETCP_LINK* link = etcp_link_new(conn, sock, &cl->remote_addr, 0);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "client %s added link link_id=%d sock=%s", client->name, link ? link->local_link_id : -1, sock->name);
}
}
@ -2324,7 +2325,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
if (ch) { ch->node_id = node_id; strncpy(ch->name, client->name, MAX_CONN_NAME_LEN - 1);
ch->handle = handle; ch->next = instance->config_conn_handles;
instance->config_conn_handles = ch;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "client %s saved handle to config_conn_handles", client->name); }
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "client %s saved handle to config_conn_handles", client->name); }
}
client = client->next;

74
src/transport_layer/pkt_normalizer.c

@ -21,16 +21,16 @@ static void pn_send_to_etcp(struct PKTNORM* pn);
// Initialization
struct PKTNORM* pn_init(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!etcp) return NULL;
if (etcp->mtu<200) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "ETCP MTU error=%d", etcp->mtu);
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ETCP MTU error=%d", etcp->mtu);
}
struct PKTNORM* pn = u_calloc(1, sizeof(struct PKTNORM));
if (!pn) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "calloc failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "calloc failed");
return NULL;
}
@ -42,14 +42,14 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) {
pn->frag_size = etcp->mtu - ACK_REZERV - UDP_HDR_SIZE - UDP_SC_HDR_SIZE;
int min_frag = UDP_HDR_SIZE + UDP_SC_HDR_SIZE + ACK_REZERV;
if (etcp->mtu < min_frag || pn->frag_size > etcp->mtu) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "MTU %d too small (min %d)", etcp->mtu, min_frag);
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "MTU %d too small (min %d)", etcp->mtu, min_frag);
pn->frag_size = etcp->mtu;
}
pn->tx_wait_time = 10;
pn->input = queue_new(pn->ua, 0, 0, 0, "pn_input"); // No hash needed
if (!pn->input) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "queue_new(input) failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "queue_new(input) failed");
pn_deinit(pn);
return NULL;
}
@ -58,7 +58,7 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) {
pn->output = queue_new(pn->ua, 0, 0, 0, "pn_output"); // No hash needed
if (!pn->output) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "queue_new(output) failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "queue_new(output) failed");
pn_deinit(pn);
return NULL;
}
@ -78,7 +78,7 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) {
// Deinitialization
void pn_deinit(struct PKTNORM* pn) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pn) return;
// Unregister from routing module
@ -136,7 +136,7 @@ void pn_deinit(struct PKTNORM* pn) {
// Reset unpacker state
void pn_unpacker_reset_state(struct PKTNORM* pn) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pn) return;
// Reset recvpart
@ -149,7 +149,7 @@ void pn_unpacker_reset_state(struct PKTNORM* pn) {
// Reset packer and unpacker state (for reconnection)
void pn_reset(struct PKTNORM* pn) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pn) return;
// Cancel flush timer
@ -183,13 +183,13 @@ void pn_reset(struct PKTNORM* pn) {
// Send data to packer (copies and adds to input queue or pending, triggering callback) используется только в юниттесте
void pn_packer_send(struct PKTNORM* pn, uint8_t* data, uint16_t len) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pn || !data || len == 0) return;
struct ll_entry* entry = ll_alloc_lldgram(len);
if (!entry) {
pn->alloc_errors++;
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "ll_alloc_lldgram failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ll_alloc_lldgram failed");
return;
}
memcpy(entry->dgram, data, len);
@ -202,34 +202,34 @@ void pn_packer_send(struct PKTNORM* pn, uint8_t* data, uint16_t len) {
pn->flush_timer = NULL;
}
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "PUT to input");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "PUT to input");
int ret = queue_data_put(pn->input, entry);
pn->in_total_pkts++;
pn->in_total_bytes += len;
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "PUT to input end");
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "queue_data_put returned %d, input count=%d", ret, queue_entry_count(pn->input));
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "PUT to input end");
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "queue_data_put returned %d, input count=%d", ret, queue_entry_count(pn->input));
}
// Internal: Packer callback
static void packer_cb(struct ll_queue* q, void* arg) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
struct PKTNORM* pn = (struct PKTNORM*)arg;
if (!pn) return;
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "input_q->pn: waiting etcp input threshold");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "input_q->pn: waiting etcp input threshold");
queue_waiter_wait(pn->etcp->input_queue, &pn->input_waiter_handle, etcp_input_ready_cb, pn);
}
// Helper to send block to ETCP as ETCP_FRAGMENT
static void pn_send_to_etcp(struct PKTNORM* pn) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pn || !pn->data || pn->data_ptr == 0) return;
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "pn_send_to_etcp");
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "pn_send_to_etcp");
// Allocate ETCP_FRAGMENT from io_pool
struct ETCP_FRAGMENT* frag = (struct ETCP_FRAGMENT*)queue_entry_new_from_pool(pn->etcp->io_pool);
if (!frag) {// drop data
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "send to etcp alloc error");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "send to etcp alloc error");
pn->alloc_errors++;
pn->data_ptr = 0;
return;
@ -242,7 +242,7 @@ static void pn_send_to_etcp(struct PKTNORM* pn) {
frag->ll.dgram_pool = pn->etcp->instance->data_pool;
frag->ll.memlen = pn->etcp->instance->data_pool->object_size;
DEBUG_DEBUG(DEBUG_CATEGORY_NORMALIZER, "pn->etcp: size=%d memlen=%d frag_size=%d", frag->ll.len, frag->ll.memlen, pn->frag_size);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "pn->etcp: size=%d memlen=%d frag_size=%d", frag->ll.len, frag->ll.memlen, pn->frag_size);
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP)) log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP, "NORM->ETCP", pn->data, frag->ll.len);
queue_data_put(pn->etcp->input_queue, (struct ll_entry*)frag);
@ -253,7 +253,7 @@ static void pn_send_to_etcp(struct PKTNORM* pn) {
// Internal: Renew sndpart buffer
static void pn_buf_renew(struct PKTNORM* pn) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (pn->data) {
int remain = pn->data_size - pn->data_ptr;
if (remain < 3) pn_send_to_etcp(pn);
@ -262,14 +262,14 @@ static void pn_buf_renew(struct PKTNORM* pn) {
pn->data = memory_pool_alloc(pn->etcp->instance->data_pool);
if (!pn->data) {
pn->alloc_errors++;
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "memory_pool_alloc failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "memory_pool_alloc failed");
return;
}
int size=pn->etcp->instance->data_pool->object_size;
if (size>pn->frag_size) size=pn->frag_size;
pn->data_size = size;
pn->data_ptr=0;
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "new bufer size=%d bytes",size);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "new bufer size=%d bytes",size);
}
}
@ -279,11 +279,11 @@ static void etcp_input_ready_cb(struct ll_queue* q, void* arg) {
if (!pn || !pn->etcp) return;
// if (pn->etcp->initialized==0) return;// начинаем обработку очередей только когда готов etcp
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "before get");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "before get");
struct ll_entry* in_dgram = queue_data_get(pn->input);
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "after get");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "after get");
if (!in_dgram) {
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "Q EMPTY");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Q EMPTY");
queue_resume_callback(pn->input);
return;
}
@ -291,7 +291,7 @@ static void etcp_input_ready_cb(struct ll_queue* q, void* arg) {
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP)) log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP, "->NORM", in_dgram->dgram, in_dgram->len);
pn_buf_renew(pn);
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "new pkt hdrpos=%d",pn->data_ptr);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "new pkt hdrpos=%d",pn->data_ptr);
if (!pn->data) goto exit; // Allocation failed
pn->data[pn->data_ptr++] = in_dgram->len & 0xFF;
pn->data[pn->data_ptr++] = (in_dgram->len >> 8) & 0xFF;
@ -301,7 +301,7 @@ static void etcp_input_ready_cb(struct ll_queue* q, void* arg) {
int remain = pn->data_size - pn->data_ptr;
int avail = in_dgram->len - in_ptr;
if (avail < remain) remain = avail;
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "copy %d bytes (in_ptr=%d, out_ptr=%d)",remain, in_ptr, pn->data_ptr);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "copy %d bytes (in_ptr=%d, out_ptr=%d)",remain, in_ptr, pn->data_ptr);
memcpy(pn->data + pn->data_ptr, in_dgram->dgram + in_ptr, remain);
pn->data_ptr += remain;
in_ptr += remain;
@ -329,7 +329,7 @@ exit:
// Internal: Flush callback on timeout
static void pn_flush_cb(void* arg) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
struct PKTNORM* pn = (struct PKTNORM*)arg;
if (!pn) return;
@ -340,7 +340,7 @@ static void pn_flush_cb(void* arg) {
// Internal: Unpacker callback (assembles fragments into original packets)
static void pn_unpacker_cb(struct ll_queue* q, void* arg) {
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "");
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
struct PKTNORM* pn = (struct PKTNORM*)arg;
if (!pn) return;
@ -354,7 +354,7 @@ static void pn_unpacker_cb(struct ll_queue* q, void* arg) {
uint16_t ptr = 0;
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP)) log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP, "ETCP->NORM", payload, len);
DEBUG_DEBUG(DEBUG_CATEGORY_NORMALIZER, "unpacking fragment len=%d", len);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "unpacking fragment len=%d", len);
while (ptr < len) {
if (!pn->recvpart) {
@ -362,18 +362,18 @@ static void pn_unpacker_cb(struct ll_queue* q, void* arg) {
if (len - ptr < 2) {
pn->logic_errors++;
// Incomplete header, reset
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "reset state");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "reset state");
// pn_unpacker_reset_state(pn);
etcp_conn_reinit(pn->etcp);
break;
}
uint16_t part_size = payload[ptr] | (payload[ptr + 1] << 8);
// DEBUG_INFO(DEBUG_CATEGORY_NORMALIZER, "new fragment pkt_len=%d (at %d)", part_size, ptr);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "new fragment pkt_len=%d (at %d)", part_size, ptr);
ptr += 2;
if (part_size<1 || part_size>16384) {
pn->logic_errors++;
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "PART_SIZE ERROR!!! %d", part_size);
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "PART_SIZE ERROR!!! %d", part_size);
etcp_conn_reinit(pn->etcp);
break;
}
@ -381,7 +381,7 @@ static void pn_unpacker_cb(struct ll_queue* q, void* arg) {
pn->recvpart = ll_alloc_lldgram(part_size);
if (!pn->recvpart) {
pn->alloc_errors++;
DEBUG_ERROR(DEBUG_CATEGORY_NORMALIZER, "ll_alloc_lldgram failed");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ll_alloc_lldgram failed");
break;
}
pn->recvpart->len = 0;
@ -390,14 +390,14 @@ static void pn_unpacker_cb(struct ll_queue* q, void* arg) {
uint16_t rem = pn->recvpart->memlen - pn->recvpart->len;// осталось собрать байт
uint16_t avail = len - ptr;// доступно байт сейчас
uint16_t cp = (rem < avail) ? rem : avail;
DEBUG_DEBUG(DEBUG_CATEGORY_NORMALIZER, "copy: remain=%d avail=%d in_ptr=%d out_ptr=%d", rem, avail, ptr, pn->recvpart->len);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "copy: remain=%d avail=%d in_ptr=%d out_ptr=%d", rem, avail, ptr, pn->recvpart->len);
memcpy(pn->recvpart->dgram + pn->recvpart->len, payload + ptr, cp);
pn->recvpart->len += cp;
ptr += cp;
if (pn->recvpart->len == pn->recvpart->memlen) {
uint32_t recv_len = pn->recvpart->len;
DEBUG_DEBUG(DEBUG_CATEGORY_NORMALIZER, "unpacked dgram (size=%d)", recv_len);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "unpacked dgram (size=%d)", recv_len);
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP)) log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_DUMP, "NORM->", pn->recvpart->dgram, recv_len);
queue_data_put(pn->output, pn->recvpart);
pn->out_total_pkts++;

5
src/transport_layer/stcp_client.c

@ -275,8 +275,9 @@ struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uin
c->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (c->sock == SOCKET_INVALID) { freeaddrinfo(res); u_free(cli); return NULL; }
socket_set_nonblocking(c->sock);
{ int sock_err = socket_get_error();
if (connect(c->sock, res->ai_addr, res->ai_addrlen) < 0 && sock_err != EINPROGRESS && sock_err != ERR_WOULDBLOCK) {
if (connect(c->sock, res->ai_addr, res->ai_addrlen) < 0) {
int sock_err = socket_get_error();
if (sock_err != EINPROGRESS && sock_err != ERR_WOULDBLOCK) {
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "stcp_client connect to %s:%u failed err=%d(%s)", addr, port, sock_err, socket_strerror(sock_err));
socket_close_wrapper(c->sock); freeaddrinfo(res); u_free(cli); return NULL;
}

16
src/utun.c

@ -278,16 +278,16 @@ int main(int argc, char *argv[]) {
debug_config_init();
// debug_set_level(DEBUG_LEVEL_TRACE);
debug_set_level(DEBUG_LEVEL_ERROR);
// debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_UASYNC & ~DEBUG_CATEGORY_TIMERS & ~DEBUG_CATEGORY_CRYPTO & ~DEBUG_CATEGORY_ETCP & ~DEBUG_CATEGORY_CONNECTION); // Enable all except uasync
// debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_UASYNC & ~DEBUG_CATEGORY_TIMERS);//
// debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_SYS & ~DEBUG_CATEGORY_TIMERS & ~DEBUG_CATEGORY_CRYPTO & ~DEBUG_CATEGORY_ETCP & ~DEBUG_CATEGORY_CONNECTION); // Enable all except uasync
// debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_SYS & ~DEBUG_CATEGORY_TIMERS);//
debug_enable_function_name(1);
if (args.debug_config) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Apply debug CLI args");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Apply debug CLI args");
debug_parse_config(args.debug_config);
}
else {
DEBUG_DEBUG(DEBUG_CATEGORY_MEMORY, "No debug CLI args - set all");
DEBUG_DEBUG(DEBUG_CATEGORY_SYS, "No debug CLI args - set all");
}
// Enable file logging (default: utun.log, truncate on start)
@ -320,7 +320,7 @@ int main(int argc, char *argv[]) {
struct UASYNC* ua = uasync_create();
main_ua=ua;
if (!ua) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create uasync instance");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create uasync instance");
return 1;
}
@ -341,7 +341,7 @@ int main(int argc, char *argv[]) {
// Create and initialize instance
struct UTUN_INSTANCE *instance = utun_instance_create(ua, args.config_file);
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create UTUN instance");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create UTUN instance");
return 1;
}
@ -353,7 +353,7 @@ int main(int argc, char *argv[]) {
// Initialize all components (TUN, routing, connections)
if (utun_instance_init(instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize instance");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to initialize instance");
utun_instance_destroy(instance);
return 1;
}
@ -382,7 +382,7 @@ int main(int argc, char *argv[]) {
return 1;
}
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Run mainloop");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Run mainloop");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Run mainloop");
while (instance && instance->running) {

56
src/utun_instance.c

@ -98,7 +98,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
// Set my keys
if (sc_init_local_keys(&instance->my_keys, config->global.my_public_key_hex, config->global.my_private_key_hex) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to initialize local keys");
return -1;
}
@ -145,7 +145,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
while (net) {
struct ll_entry *entry = queue_entry_new(sizeof(struct NETWORK_ENTRY));
if (!entry) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate network entry for %s", net->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate network entry for %s", net->name);
net = net->next;
continue;
}
@ -171,7 +171,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
// Create routing module
if (routing_create(instance) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create routing module");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create routing module");
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing module created");
@ -366,7 +366,7 @@ struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct
// Allocate instance
struct UTUN_INSTANCE *instance = u_calloc(1, sizeof(struct UTUN_INSTANCE));
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate UTUN_INSTANCE");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate UTUN_INSTANCE");
return NULL;
}
instance->etcp_connect_timeout_tb = 20000;
@ -399,7 +399,7 @@ struct UTUN_INSTANCE* utun_instance_create_from_str(struct UASYNC* ua, const cha
void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
if (!instance) return;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Starting cleanup for instance %p", instance);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Starting cleanup for instance %p", instance);
// Диагностика ресурсов ДО cleanup
utun_instance_diagnose_leaks(instance, "BEFORE_CLEANUP");
@ -442,16 +442,16 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
// Cleanup conn_mgr BEFORE sockets (unbinds from etcp_router, closes NCD handles while conns alive)
// Cleanup ETCP sockets and connections FIRST (before destroying uasync)
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections");
struct ETCP_SOCKET* sock = instance->etcp_sockets;
while (sock) {
struct ETCP_SOCKET* next = sock->next;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Removing socket %p, fd=%d", sock, sock->fd);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Removing socket %p, fd=%d", sock, sock->fd);
etcp_socket_remove(sock); // Полный cleanup сокета
sock = next;
}
instance->etcp_sockets = NULL;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP sockets cleanup complete");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] ETCP sockets cleanup complete");
// Cleanup chat before db_sync (chat releases db_sync instances)
chat_sync_destroy(instance);
@ -471,7 +471,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
}
}
queue_free(instance->connections); instance->connections = NULL;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] ETCP connections cleanup complete");
// Cleanup TCP connections (stcp_links)
if (instance->tcp_connections) {
@ -484,7 +484,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
}
}
queue_free(instance->tcp_connections); instance->tcp_connections = NULL;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] TCP connections cleanup complete");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] TCP connections cleanup complete");
// Cleanup TCP sockets
while (instance->tcp_sockets) tcp_socket_remove(instance->tcp_sockets);
@ -573,28 +573,28 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
// Cleanup config
if (instance->config) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing configuration");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Freeing configuration");
free_config(instance->config);
instance->config = NULL;
}
// Cleanup packet pool (ensure no leak if stop wasn't called)
if (instance->pkt_pool) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying packet pool");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Destroying packet pool");
memory_pool_destroy(instance->pkt_pool);
instance->pkt_pool = NULL;
}
// Cleanup packet pool (ensure no leak if stop wasn't called)
if (instance->ack_pool) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying ack pool");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Destroying ack pool");
memory_pool_destroy(instance->ack_pool);
instance->ack_pool = NULL;
}
// Cleanup data pool
if (instance->data_pool) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Destroying data pool");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Destroying data pool");
memory_pool_destroy(instance->data_pool);
instance->data_pool = NULL;
}
@ -611,7 +611,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
}
// Free the instance memory
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Freeing instance memory");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Freeing instance memory");
// Cleanup nodeinfo callback chain
while (instance->nodeinfo_cbks) {
@ -620,7 +620,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
}
u_free(instance);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Instance destroyed completely");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Instance destroyed completely");
}
// Stop instance
@ -738,7 +738,7 @@ int utun_instance_init(struct UTUN_INSTANCE *instance) {
// Диагностическая функция для анализа утечек
void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *phase) {
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "[DIAGNOSE] NULL instance for phase: %s", phase);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "[DIAGNOSE] NULL instance for phase: %s", phase);
return;
}
@ -768,33 +768,33 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
}
}
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[LEAK DIAGNOSIS] Phase: %s", phase);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Instance: %p, Node ID: %llu, UA: %p, Running: %d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[LEAK DIAGNOSIS] Phase: %s", phase);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Instance: %p, Node ID: %llu, UA: %p, Running: %d",
instance, (unsigned long long)instance->node_id, instance->ua, instance->running);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "STRUCTURE COUNTS - ETCP Sockets: %d, ETCP Connections: %d, ETCP Links: %d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, "STRUCTURE COUNTS - ETCP Sockets: %d, ETCP Connections: %d, ETCP Links: %d",
report.etcp_sockets_count, report.etcp_connections_count, report.etcp_links_count);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "RESOURCE STATUS - Memory Pool: %s, TUN: %s, TUN FD: %d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, "RESOURCE STATUS - Memory Pool: %s, TUN: %s, TUN FD: %d",
instance->pkt_pool ? "ALLOCATED" : "NULL",
instance->tun ? instance->tun->ifname : "NULL",
instance->tun ? instance->tun->fd : -1);
if (instance->pkt_pool) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "POTENTIAL LEAK: Memory Pool not freed");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "POTENTIAL LEAK: Memory Pool not freed");
}
if (instance->tun) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "POTENTIAL LEAK: TUN interface not closed");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "POTENTIAL LEAK: TUN interface not closed");
}
if (report.etcp_sockets_count > 0) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "POTENTIAL LEAK: %d ETCP sockets still allocated", report.etcp_sockets_count);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "POTENTIAL LEAK: %d ETCP sockets still allocated", report.etcp_sockets_count);
}
if (report.etcp_connections_count > 0) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "POTENTIAL LEAK: %d ETCP connections still allocated", report.etcp_connections_count);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "POTENTIAL LEAK: %d ETCP connections still allocated", report.etcp_connections_count);
}
if (report.etcp_links_count > 0) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "POTENTIAL LEAK: %d ETCP links still allocated", report.etcp_links_count);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "POTENTIAL LEAK: %d ETCP links still allocated", report.etcp_links_count);
}
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[LEAK DIAGNOSIS] Recommendations: pkt_pool=%d, tun=%d, sockets=%d, connections=%d",
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[LEAK DIAGNOSIS] Recommendations: pkt_pool=%d, tun=%d, sockets=%d, connections=%d",
instance->pkt_pool ? 1 : 0,
instance->tun ? 1 : 0,
report.etcp_sockets_count,
@ -945,7 +945,7 @@ struct UTUN_INSTANCE *utun_instance_reload(struct UTUN_INSTANCE *instance, struc
while (net) {
struct ll_entry *new_entry = queue_entry_new(sizeof(struct NETWORK_ENTRY));
if (!new_entry) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate network entry for reload: %s", net->name);
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to allocate network entry for reload: %s", net->name);
net = net->next;
continue;
}

10
tests/simple_test.c

@ -18,22 +18,22 @@ int main() {
uasync_t* ua = uasync_create();
if (!ua) return 1;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== Simple Corruption Test ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Simple Corruption Test ===");
// Create just one socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Created socket with fd=%d", sock);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Created socket with fd=%d", sock);
void* id = uasync_add_socket(ua, sock, test_callback, NULL, NULL, NULL);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Added socket: fd=%d, id=%p", sock, id);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Added socket: fd=%d, id=%p", sock, id);
// Check if fd is still correct (internal struct socket_node not exposed)
// struct socket_node* node = (struct socket_node*)id;
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Node fd after add: %d", sock);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Node fd after add: %d", sock);
// Try to remove immediately (no polling)
int result = uasync_remove_socket(ua, id);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Remove result: %d", result);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Remove result: %d", result);
close(sock);
uasync_destroy(ua, 0);

2
tests/test_chat_sync_stress.c

@ -135,7 +135,7 @@ int main(void) {
debug_config_init();
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_TRACE);
debug_set_category_level(DEBUG_CATEGORY_DB_SYNC, DEBUG_LEVEL_TRACE);
debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_TRACE);
debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_TRACE);
if (create_temp_configs() != 0) { fprintf(stderr, "FAIL: config creation\n"); return 1; }

4
tests/test_config_debug.c

@ -113,8 +113,8 @@ int main() {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "ERROR от ETCP (должен выводиться)");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "INFO от ETCP (должен выводиться - уровень debug)");
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "DEBUG от ETCP (должен выводиться - уровень debug)");
DEBUG_INFO(DEBUG_CATEGORY_LL_QUEUE, "INFO от LL_QUEUE (должен выводиться)");
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "INFO от MEMORY (должен выводиться)");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "INFO от LL_QUEUE (должен выводиться)");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "INFO от MEMORY (должен выводиться)");
DEBUG_INFO(DEBUG_CATEGORY_TRAFFIC, "INFO от TRAFFIC (должен выводиться)");
DEBUG_DEBUG(DEBUG_CATEGORY_TRAFFIC, "DEBUG от TRAFFIC (должен выводиться - уровень debug)");
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "INFO от CONNECTION (НЕ должен выводиться - категория не включена)");

2
tests/test_db_sync.c

@ -185,7 +185,7 @@ static void remove_si(struct DB_SYNC_INSTANCE** psi) {
int main(void) {
printf("=== test_db_sync ===\n");
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR);
debug_set_category_level(DEBUG_CATEGORY_DB_SYNC, DEBUG_LEVEL_DEBUG);
debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG);
if (create_temp_configs() != 0) { cleanup_temp_configs(); return 1; }
utun_instance_set_tun_init_enabled(0);

20
tests/test_debug_categories.c

@ -52,13 +52,13 @@ int main(int argc, char *argv[]) {
debug_categories |= DEBUG_CATEGORY_ETCP;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "✅ Включена категория ETCP");
} else if (strcmp(argv[i], "--debug-queue") == 0) {
debug_enable_category(DEBUG_CATEGORY_LL_QUEUE);
debug_categories |= DEBUG_CATEGORY_LL_QUEUE;
DEBUG_INFO(DEBUG_CATEGORY_LL_QUEUE, "✅ Включена категория LL_QUEUE");
debug_enable_category(DEBUG_CATEGORY_SYS);
debug_categories |= DEBUG_CATEGORY_SYS;
DEBUG_INFO(DEBUG_CATEGORY_SYS, "✅ Включена категория LL_QUEUE");
} else if (strcmp(argv[i], "--debug-memory") == 0) {
debug_enable_category(DEBUG_CATEGORY_MEMORY);
debug_categories |= DEBUG_CATEGORY_MEMORY;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "✅ Включена категория MEMORY");
debug_enable_category(DEBUG_CATEGORY_SYS);
debug_categories |= DEBUG_CATEGORY_SYS;
DEBUG_INFO(DEBUG_CATEGORY_SYS, "✅ Включена категория MEMORY");
} else if (strcmp(argv[i], "--debug-all") == 0) {
debug_set_categories(DEBUG_CATEGORY_ALL);
debug_categories = DEBUG_CATEGORY_ALL;
@ -88,8 +88,8 @@ int main(int argc, char *argv[]) {
// Сообщения от разных категорий
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Сообщение от ETCP категории");
DEBUG_INFO(DEBUG_CATEGORY_LL_QUEUE, "Сообщение от LL_QUEUE категории");
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Сообщение от MEMORY категории");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Сообщение от LL_QUEUE категории");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Сообщение от MEMORY категории");
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Сообщение от CONNECTION категории");
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "Сообщение от CRYPTO категории");
@ -98,8 +98,8 @@ int main(int argc, char *argv[]) {
char cat_buf[256];
int cat_pos = snprintf(cat_buf, sizeof(cat_buf), "Активные категории: ");
if (debug_categories & DEBUG_CATEGORY_ETCP) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "ETCP ");
if (debug_categories & DEBUG_CATEGORY_LL_QUEUE) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "LL_QUEUE ");
if (debug_categories & DEBUG_CATEGORY_MEMORY) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "MEMORY ");
if (debug_categories & DEBUG_CATEGORY_SYS) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "LL_QUEUE ");
if (debug_categories & DEBUG_CATEGORY_SYS) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "MEMORY ");
if (debug_categories & DEBUG_CATEGORY_CONNECTION) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "CONNECTION ");
if (debug_categories & DEBUG_CATEGORY_CRYPTO) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "CRYPTO ");
if (debug_categories == DEBUG_CATEGORY_ALL) cat_pos += snprintf(cat_buf + cat_pos, sizeof(cat_buf) - cat_pos, "ALL ");

2
tests/test_etcp_dummynet.c

@ -181,7 +181,7 @@ int main(void) {
srand((unsigned)time(NULL));
debug_config_init();
// debug_set_level(DEBUG_LEVEL_WARN);
debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_UASYNC & ~DEBUG_CATEGORY_TIMERS & ~DEBUG_CATEGORY_CRYPTO); // Enable all except uasync
debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_SYS & ~DEBUG_CATEGORY_TIMERS & ~DEBUG_CATEGORY_CRYPTO); // Enable all except uasync
socket_platform_init();
crc32_init();

24
tests/test_intensive_memory_pool.c

@ -106,33 +106,33 @@ int main() {
debug_set_level(DEBUG_LEVEL_TRACE);
debug_set_categories(DEBUG_CATEGORY_ALL);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "=== Интенсивный тест пулов памяти ===");
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Тестируется производительность с пулами vs без пулов");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Интенсивный тест пулов памяти ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Тестируется производительность с пулами vs без пулов");
const int iterations = 1000;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Запуск теста без пулов памяти...");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Запуск теста без пулов памяти...");
double time_without = test_without_pools(iterations);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Время без пулов: %.3f сек", time_without);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Waiter callbacks: %d", waiter_callback_count);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Время без пулов: %.3f сек", time_without);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Waiter callbacks: %d", waiter_callback_count);
waiter_callback_count = 0;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Запуск теста с пулами памяти...");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Запуск теста с пулами памяти...");
double time_with = test_with_pools(iterations);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Время с пулами: %.3f сек", time_with);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Waiter callbacks: %d", waiter_callback_count);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Время с пулами: %.3f сек", time_with);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Waiter callbacks: %d", waiter_callback_count);
if (time_with > 0 && time_without > 0) {
double speedup = time_without / time_with;
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Результат: пулы памяти дали %.2fx ускорение", speedup);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Результат: пулы памяти дали %.2fx ускорение", speedup);
if (time_with < time_without) {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "✅ Пулы памяти эффективны!");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "✅ Пулы памяти эффективны!");
} else {
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "⚠️ Пулы памяти не дали преимущества в этом тесте");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "⚠️ Пулы памяти не дали преимущества в этом тесте");
}
} else {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "❌ Ошибка в тесте с пулами");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "❌ Ошибка в тесте с пулами");
}
return 0;

6
tests/test_ll_queue.c

@ -15,8 +15,8 @@
#include "../lib/debug_config.h"
#include "../lib/memory_pool.h"
#ifndef DEBUG_CATEGORY_LL_QUEUE
#define DEBUG_CATEGORY_LL_QUEUE 1
#ifndef DEBUG_CATEGORY_SYS
#define DEBUG_CATEGORY_SYS 1
#endif
static struct {
@ -413,7 +413,7 @@ static void test_stress(void) {
int main(void) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_DEBUG);
debug_set_categories(DEBUG_CATEGORY_LL_QUEUE);
debug_set_categories(DEBUG_CATEGORY_SYS);
double t0 = now_ms();

4
tests/test_media_delivery_integration.c

@ -239,8 +239,8 @@ int main(void) {
debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_TIMERS, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_SOCKET, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_LL_QUEUE, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_UASYNC, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_TRACE);
debug_set_category_level(DEBUG_CATEGORY_GENERAL, DEBUG_LEVEL_TRACE);
debug_enable_file_output("/tmp/mdl_integration.log", 1);

20
tests/test_memory_pool_and_config.c

@ -26,21 +26,21 @@ int main() {
debug_set_level(DEBUG_LEVEL_TRACE);
debug_set_categories(DEBUG_CATEGORY_ALL);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "=== Memory Pool and Config File Test ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Memory Pool and Config File Test ===");
// Test 1: Memory pool optimization
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Test 1: Memory pool optimization...");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Test 1: Memory pool optimization...");
uasync_t* ua = uasync_create();
if (!ua) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create uasync");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create uasync");
return 1;
}
// Create queue with memory pools enabled
struct ll_queue* queue = queue_new(ua, 0, 0, 0,"q1");
if (!queue) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create queue with pools");
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Failed to create queue with pools");
uasync_destroy(ua, 0);
return 1;
}
@ -72,7 +72,7 @@ int main() {
queue_free(queue);
uasync_destroy(ua, 0);
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "Memory pool test: PASS");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Memory pool test: PASS");
// Test 2: Configuration file support
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Test 2: Configuration file support...");
@ -95,11 +95,11 @@ int main() {
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Configuration parsed successfully");
// Test that configuration was applied
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_LL_QUEUE)) {
DEBUG_INFO(DEBUG_CATEGORY_LL_QUEUE, "LL_QUEUE debug level correctly set");
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_SYS)) {
DEBUG_INFO(DEBUG_CATEGORY_SYS, "LL_QUEUE debug level correctly set");
}
if (debug_should_output(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_UASYNC)) {
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "UASYNC info level correctly set");
if (debug_should_output(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_SYS)) {
DEBUG_INFO(DEBUG_CATEGORY_SYS, "UASYNC info level correctly set");
}
if (!debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_ETCP)) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "ETCP correctly limited to error level");
@ -118,6 +118,6 @@ int main() {
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Configuration file test: PASS");
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "=== All tests completed successfully ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== All tests completed successfully ===");
return 0;
}

16
tests/test_tcp_io.c

@ -18,9 +18,9 @@ static int tests_run = 0;
static int tests_passed = 0;
static int tests_failed = 0;
#define TEST_START(name) do { DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "TEST: %s... ", name); tests_run++; } while(0)
#define TEST_PASS() do { DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "PASS"); tests_passed++; } while(0)
#define TEST_FAIL(msg) do { DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "FAIL: %s", msg); tests_failed++; return; } while(0)
#define TEST_START(name) do { DEBUG_INFO(DEBUG_CATEGORY_SYS, "TEST: %s... ", name); tests_run++; } while(0)
#define TEST_PASS() do { DEBUG_INFO(DEBUG_CATEGORY_SYS, "PASS"); tests_passed++; } while(0)
#define TEST_FAIL(msg) do { DEBUG_ERROR(DEBUG_CATEGORY_SYS, "FAIL: %s", msg); tests_failed++; return; } while(0)
#define ASSERT_TRUE(cond, msg) do { if (!(cond)) TEST_FAIL(msg); } while(0)
#define ASSERT_EQ(a, b, msg) do { if ((a) != (b)) TEST_FAIL(msg); } while(0)
@ -545,7 +545,7 @@ int main(void) {
debug_set_level(DEBUG_LEVEL_INFO);
debug_set_categories(DEBUG_CATEGORY_ALL);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== tcp_io Unit Tests ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== tcp_io Unit Tests ===");
test_basic_send_recv();
test_partial_write();
@ -559,10 +559,10 @@ int main(void) {
test_double_push_close();
test_fin_before_close();
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== Test Statistics ===");
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests run: %d", tests_run);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests passed: %d", tests_passed);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests failed: %d", tests_failed);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Test Statistics ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests run: %d", tests_run);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests passed: %d", tests_passed);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests failed: %d", tests_failed);
return (tests_failed > 0) ? 1 : 0;
#endif

34
tests/test_u_async_comprehensive.c

@ -37,17 +37,17 @@ static struct {
/* Test result tracking */
#define TEST_START(name) do { \
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "TEST: %s... ", name); \
DEBUG_INFO(DEBUG_CATEGORY_SYS, "TEST: %s... ", name); \
test_stats.tests_run++; \
} while(0)
#define TEST_PASS() do { \
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "PASS"); \
DEBUG_INFO(DEBUG_CATEGORY_SYS, "PASS"); \
test_stats.tests_passed++; \
} while(0)
#define TEST_FAIL(msg) do { \
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, "FAIL: %s", msg); \
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "FAIL: %s", msg); \
test_stats.tests_failed++; \
} while(0)
@ -68,7 +68,7 @@ static struct {
#define ASSERT_EQ(a, b, msg) do { \
if ((a) != (b)) { \
TEST_FAIL(msg); \
DEBUG_ERROR(DEBUG_CATEGORY_UASYNC, " Expected: %ld, Got: %ld", (long)(b), (long)(a)); \
DEBUG_ERROR(DEBUG_CATEGORY_SYS, " Expected: %ld, Got: %ld", (long)(b), (long)(a)); \
return; \
} \
} while(0)
@ -638,8 +638,8 @@ int main(void) {
debug_set_level(DEBUG_LEVEL_INFO);
debug_set_categories(DEBUG_CATEGORY_ALL);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== lib Comprehensive Unit Tests ===");
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Testing race conditions, memory management, and error handling");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== lib Comprehensive Unit Tests ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Testing race conditions, memory management, and error handling");
/* Run all tests */
test_basic_timers();
@ -653,19 +653,19 @@ int main(void) {
test_socket_flags_toggle();
/* Print statistics */
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== Test Statistics ===");
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests run: %d", test_stats.tests_run);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests passed: %d", test_stats.tests_passed);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Tests failed: %d", test_stats.tests_failed);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Timer callbacks: %d", test_stats.timer_callbacks);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Timer cancellations: %d", test_stats.timer_cancellations);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Immediate timeouts: %d", test_stats.immediate_timeouts);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Socket events: %d", test_stats.socket_events);
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "Race condition errors: %d", test_stats.race_condition_errors);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Test Statistics ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests run: %d", test_stats.tests_run);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests passed: %d", test_stats.tests_passed);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Tests failed: %d", test_stats.tests_failed);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Timer callbacks: %d", test_stats.timer_callbacks);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Timer cancellations: %d", test_stats.timer_cancellations);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Immediate timeouts: %d", test_stats.immediate_timeouts);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Socket events: %d", test_stats.socket_events);
DEBUG_INFO(DEBUG_CATEGORY_SYS, "Race condition errors: %d", test_stats.race_condition_errors);
/* Memory leak detection */
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "=== Memory Leak Detection ===");
DEBUG_INFO(DEBUG_CATEGORY_UASYNC, "No memory leaks detected during testing");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "=== Memory Leak Detection ===");
DEBUG_INFO(DEBUG_CATEGORY_SYS, "No memory leaks detected during testing");
return (test_stats.tests_failed > 0) ? 1 : 0;
}

4
tools/chatgui-android/libutun_lite/instance_lite.c

@ -369,8 +369,8 @@ int instance_lite_start(const char* config_text) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_UASYNC, DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_MEMORY, DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_SYS, DEBUG_LEVEL_INFO);
debug_enable_function_name(0);
cfg_get_val(config_text, "db_path", g_db_path, sizeof(g_db_path));

Loading…
Cancel
Save