- Remove is_dm column from channels table (dm detection by member count)
- Rename member name column to userinfo — extensible json_flat format
- Add json_flat.c/h library for compact JSON serialization
- Fix join_sig message format: use ch_x25519+ch_ed25519 instead of channel_id string
- Remove name from join_msg body (now in userinfo via json_flat)
- Update chat_core, chat_sync, member_sync, db_manager to new format
- Add topo_strategy.txt — архитектурные заметки по топологии
- chat_conn_mgr.c/h: new connection manager (1 per instance, global in g_cc)
- cm_rotation() — single rotation method: random addr pick, INIT, retry
- 10 parallel slots per node (CM_MAX_PARALLEL), evict worst RTT on excess
- DEAD slot reuse before close — close only when replacement ready
- per-connection DOWN callback via etcp_conn_add_down_cbk
- background ping cycle: random node→random addr RTT measurement
- chat_core.c: added g_cc.conn_mgr field, init/destroy/getter
- chat_sync.c: migrate to new API, add_node() at WELCOME/JOIN/PEER_UPSERT
- Removed old ca_state/ca_ctx/ca_* single-flight code
- Sound files loaded from filesystem (sound_dir in INI config, absolute or relative)
- Per-event enable/disable + volume stored in DB (ui_state table)
- SoundManager: setEvent(), effective volume = master * per-event
- SoundSettingsPage UI: 4 event rows (checkbox + slider)
- chat_core_save_ui_state() for async DB writes via uasync thread
- DbManager::getUiStateInt() for reading settings from GUI thread
- Default sounds copied to sounds/ dir next to DB, config entries written
INSERT OR REPLACE deletes the old row and inserts a new one,
resetting unspecified columns (online, update_ts) to DEFAULT 0.
This was wiping online=1 set by cs_on_peer_status_changed/member_sync_set_online.
Replaced 5 INSERT OR REPLACE INTO nodes with INSERT INTO ... ON CONFLICT
DO UPDATE SET — only updates the specified columns, preserving online status.
Files:
- chat_core.c:638 (invite flow)
- chat_sync.c:1045 (CHANNEL_INFO_RESP), 1193 (JOIN), 1449 (PEER_UPSERT)
- topo_node_sqlite.c:121 (BGP node_put)
- chat_core_sync_my_addresses: DELETE + INSERT с подсчётом строк, CHECK verify
- chat_core_connect_from_invite: DELETE + INSERT с IP:port
- member_sync_put: DELETE + INSERT с IP:port, warn если addrs_data=NULL
- cs_handle_channel_info_resp: адрес инвайтера из ETCP link
- cs_handle_channel_join: адреса джойнера
- cs_handle_peer_upsert: адреса пира
- cs_handle_welcome: адреса из WELCOME
Все логи с префиксом [ADDR_SYNC] в DEBUG_CATEGORY_DEBUG
- utun_node.cpp: open topo_sqlite_db with FULLMUTEX + all PRAGMAs (WAL, FK, NORMAL sync, checkpoint)
- db_sync.c: reuse inst->topo_sqlite_db if available (shared_db flag)
- chat_core.c: reuse inst->topo_sqlite_db if available (shared_db flag)
- db_sync_destroy/chat_core_destroy: skip close on shared handle
- Only topo_groups_destroy closes the shared handle
- Fallback: each module opens own connection if topo_sqlite_db is NULL
ready_cbks/etcp_conn_set_ready_cbk/add_ready/remove_ready → init_cbks/..._init_cbk
ca_ready_cb → ca_init_cb
cm_direct_ready_cb → cm_direct_init_cb
cm_reverse_ready_cb → cm_reverse_init_cb
ntp_node_on_conn_ready → ntp_node_on_conn_init
connect_ready_cb → connect_init_cb
init accurately describes when conn->initialized=1, before keepalives establish UP.
Also fire etcp_fire_conn_status INIT at this point instead of create time.
- chat_core.c: dump node_addresses total, per-node counts, nodes lookup before addr query
- topo_group.c: log db path, rc, and db pointer after sqlite3_open
- topo_group.c: open {db_path}/chats.db instead of {db_path} — was opening a directory
- chat_core.c: remove inst->topo_sqlite_db = g_cc.db — keep topo_sqlite_db as separate
uTun-only connection without FULLMUTEX, avoiding contention with GUI reads
- chat_core.c: add DEBUG_INFO before each synchronous cb(FAIL) — pinpoints exact failure reason
- chat_sync.c: add log in ac_fill when ca_state=NULL after chat_core_connect_auto call
- db_sync: rename column author→node_id, open chats.db instead of sync file,
db_sync_instance_add takes table_name directly
- chat_core: remove CREATE TABLE msg_ch_*, remove on_db_sync_insert (74 lines),
remove fallback INSERT in submit_message, add minimal on_msg_inserted
for GUI notification only
- db_manager: update getMessages for new schema (parse JSON from data column),
fix ORDER BY to use author_signature instead of datahash,
update syncCursorNext to parse JSON
- si_register simplified: db_count from same table, no more msg vs sync gap
- chat_core_has_conn: search all connections (pending+ready) by peer_node_id
- chat_core_connect_from_invite: skip chat_core_connect_auto if already connected
- ca_timeout_cb: close timed-out connection to free socket link slot
+ cancel remaining timers + ca_cleanup on all-failed
- chat_core_sync_my_addresses(): remove private IP filter (192.168, 10.x, etc.)
so LAN addresses are stored for direct connections
- topo_node_sqlite_channel_peers_all(): include peers without addresses
in WELCOME message (was skipped entirely, causing empty peer list)
- chat_core_create_channel(): pass real local addresses to member_sync_put()
instead of NULL,0
- chat_core_init(): log number of channels loaded from DB on startup
- topo_sqlite_db moved from TOPO_GROUPS to UTUN_INSTANCE (direct access)
- topo_groups_set_sqlite_db() removed
- chatgui: chat_sync_connect_node → chat_core_connect_auto (direct ETCP, no conn_mgr)
- chatgui: chat_core_connect_from_invite saves to SQLite → auto connect (no BGP)
- chatgui: removed _on_node_updated BGP callback from member_sync
- chatgui: removed conn_mgr_get_status from status dump
- chatgui: removed all conn_mgr.h and topo_group.h includes
- chatgui: CONN_MGR_ERR_* constants → CC_* in chat_core.h
- removed unused cc_parallel_* code, conn_state_str/conn_type_str helpers
- db_sync_on_conn_up: per-instance synced/skipped counters
- db_sync_peer_check_cb: summary INFO of check results
- db_sync_instance_add: peers_found + peers_synced counts
- db_handle_init_sync/initiate_sync: enhanced with tbl name
- db_handle_init_resp: tp + my_mc in sync complete/dh match
- db_handle_send_data: range + SYNC_DONE details; stop reason when mc>pk
- db_handle_sync_done: both counts + datahashes in mismatch; dh in confirm
- db_sync_recv_cb: INFO when instance NOT FOUND (timing race)
- cs_handle_channel_info_resp: sync readiness after channel ready
- cs_handle_welcome: note about db_sync peer_check timer
- on_db_sync_insert: counter (#1-3 then every 10) with ch/n/ts/dh/ct
- chat_core.c: CREATE TABLE IF NOT EXISTS peers_* in ensure_channel_ready
- utun_node.cpp: GUI_ERROR redirected to debug log file via guiDebugFile()
- etcp_connections.c: reuse unindexed outbound conn (peer_node_id==0)
on cross-connect INIT to avoid 'Can not insert link to socket'
- utun_instance.h: add chat_connections queue (indexed by node_id, 8 bytes)
- chat_sync.c: queue_new in init, queue_free in destroy, queue_find_data_by_index in cs_find_conn_for_node
- chat_sync.c: remove from queue in cs_on_conn_down
- chat_core.c: add to queue in connect_from_invite and connect_auto
- chat_core.c: remove from queue in cc_parallel_cleanup and ca_cleanup
- db_sync.c: replace linear conn search with queue_find_data_by_index (db_sync_send_hash)
- Replace db_sync_stub.c with real src/db_sync.c in libutun
- Remove message sync protocol from chat_sync (INIT_SYNC/INIT_RESP/SEND_DATA/PUSH/ACK_PUSH/SYNC_DONE)
- Keep chat_sync auxiliary: join protocol, peer management, auto-connect
- Remove chat_core_insert_record, cursor_*, mark_sent/ttl_delete stubs
- chat_core on_db_sync_insert now only does SQLite INSERT + GUI notify
- Move db_sync_init() from instance_init_common to utun_instance_init for config override timing
- Force db_sync_enabled=1 in utun_node.cpp
- db_sync handles all P2P message sync via service 0x20
Replace etcp_router_bind/etcp_route_send/etcp_router_unbind with
direct etcp_bind/etcp_send/etcp_unbind + find-conn-by-node_id helpers.
Same approach as db_sync (0x20). Service IDs unchanged (0x30, 0x31).
ca_ready_cb and cc_parallel_ready_cb called etcp_connection_close
synchronously on non-selected connections from within the ready_cbk
callback chain. This corrupts senders_list in topo_group, causing
UAF in topo_group_start_link_nat_check.
Now uses uasync_call_soon (zero-delay timer) to defer the close
to the next event loop iteration, after the callback chain completes
and callbacks_running flag is reset.
- Added struct ca_ctx** ctxs to ca_state (parallel array)
- ca_cleanup now frees all ctxs[i] and the ctxs array
- ca_ready_cb: removed u_free(ctx), added etcp_conn_remove_ready_cbk before cleanup
- ca_timeout_cb: removed u_free(ctx) — ctx lives until ca_cleanup
- All error paths set ctxs[i]=NULL for ca_cleanup safety
etcp_connection_create does NOT add conn to inst->connections list.
Without this, incoming INIT handler can't find the outbound conn
by peer_node_id and creates a new one, causing insert_link collision.
- ca_timeout_cb: removed etcp_connection_close, ETCP lives past 3s timeout
- ca_state.cancelled flag + chat_core_connect_auto_cancel() for external cancel
- chat_core_connect_auto returns ca_state* via out_state
- Rewritten auto_connect: cursor (ch,peer) instead of bulk collect
- GC every 1s: closes flights with no link_status after 3s
- ac_result_cb no longer clears ca_state (GC handles cleanup)
- stop: cancels all flights via chat_core_connect_auto_cancel
- chat_core_connect_auto: direct ETCP connect from SQLite (no BGP)
- auto_connect: parallel connect to peers with 3s timeout, retry 10s
- RTT saved to node_addresses on disconnect
- vertical status bar + circle badge with online count per channel
- ChannelListView prevents deselection
- Replace get_time_us() with utun_gettimeofday() for PUSH message timestamps
(db_sync.c, chat_core.c) — monotonic clocks differ across Linux/Windows
- Fix merkle_sync: restart session timer in _handle_request to prevent
double-sided timeout when both nodes start member_sync simultaneously
- Fix INIT_RESP short-format: don't mark synced when my_count > peer_count
- Add db_sync_get_last_timestamp() to avoid duplicate timestamp generation
between db_sync and chat_core on_db_sync_insert
- Fix db_sync_stub to generate timestamps consistently
- build.sh: auto-rebuild chatgui via CMake after utun build
chat_sync_push: add chain_hash parameter, use it instead of zeros
(fixes chain_hash mismatch → all PUSH messages were rejected)
on_db_sync_insert: pass computed chain_h to chat_sync_push
cs_handle_channel_join: call member_sync_start for the joiner
(server now initiates member sync when client joins.
Previously merkle_sync was only started by client → timeout
because server never responded)
cs_handle_welcome: add DEBUG_INFO before member_sync_start on client side
chat_sync_push: fix PUSH format to match cs_handle_push expectations
(was missing insert_record header: ts+dh+nid before ct+dlen+data)
Add DEBUG_INFO log with peer count after send.
on_db_sync_insert: call chat_sync_push after successful local insert
→ new messages are now pushed to all connected peers
Add DEBUG_ERROR to 4 silent returns (JSON parse fail, SQL errors)
chat_core_submit_message: add DEBUG_INFO entry log (ch, ct, len)
chat_core_insert_record: add DEBUG_WARN/ERROR to 7 silent returns
(truncated record, SQL prepare fail, unknown step error)
cs_handle_push: add DEBUG_INFO for ACK send, DEBUG_ERROR for insert fail
cs_handle_send_data: DEBUG_WARN when record truncated mid-loop
cs_on_conn_up: DEBUG_INFO sync path with channel count
Full trace now shows every message: SUBMIT → insert → PUSH → RECV PUSH → ACK
- cs_handle_init_resp: change silent reject len<37→len<5 (actual payload
sent is 6 bytes, plen=5 after stripping type byte).
Support short format (synced, peer_count+sparse_count) and long format
(divergence, with test_pos+peer_ch). Add INFO logs at each decision.
(fixes sync never starting after invite join — RECV INIT_RESP len=5
was silently rejected)
- All 12 silent return branches in handlers: add DEBUG_WARN with
handler name, peer, ch_id, and reason (makes malformed packets
visible in logs)
- Key sync flow INFO logs:
cs_handle_init_sync: peer_count, my_count
cs_handle_send_data: records sent/received count
cs_on_conn_up: invite vs sync path
chat_core_insert_record: successful insert
- on_db_sync_insert: parse JSON {"n":...,"ct":...,"d":...}, store
d→data, n→node_id, ct→content_type with proper chain_hash
(fixes JSON displayed instead of message text)
- chat_core_cursor_open: SELECT chain_hash column
- chat_core_cursor_next: include chain_hash(32) in output record
- cs_handle_send_data: parse chain_hash in received records
(fixes chain_hash mismatch → all sync records were dropped)
- cs_handle_channel_join: post GUI_EVT_MEMBERS_CHANGED
(fixes creator not seeing new member after join)
- cs_handle_welcome: trigger INIT_SYNC with inviter after join
(fixes no message sync after invite join)