Commit Graph
3286 Commits
Author SHA1 Message Date
Evgeny 3f0fdad754 config_updater: поддержка создания конфига с нуля (без файла); новый файл — собирается с нуля, существующий — insert_or_replace 2026-07-15 23:47:00 +03:00
Evgeny e325b84a8e config: одно открытие файла — parse_config_from_buf вместо повторного fopen; убран read_file_to_mem 2026-07-15 23:39:01 +03:00
Evgeny ef24af7d24 Ключи: node_id из SHA-256(privkey) через весь конфиг; приоритет privkey — pubkey/node_id всегда выводятся из него; CHANNEL_INFO_RESP: верификация inviter_join_sig через ETCP-ключи 2026-07-15 23:13:29 +03:00
Evgeny da86841516 Диагностика: WARN при мутации конфига (ключи/node_id) + детали при invalid sig в JOIN/CHANNEL_INFO_RESP + предупреждение при расхождении node_id инвайта и ETCP 2026-07-15 22:44:33 +03:00
Evgeny 895eb0abbf Убрал спам-логи ETCP SEND/RECV/DECRYPT OK + добавил диагностику синхронизации мемберов (DEBUG_CATEGORY_DEBUG) в ключевые точки topo_group, merkle_sync, member_sync, chat_sync 2026-07-15 22:25:19 +03:00
Evgeny e708940bcd debug: upgrade router_deliver to DEBUG_INFO, show cb ptr
Router deliver now visible without trace — shows svc_id, len, remote_node_id, conn ptr, callback ptr
This will confirm whether CHANNEL_INFO_REQ reaches chat_sync on the server side
2026-07-15 22:06:54 +03:00
Evgeny d161782b46 fix: merkle_sync.c linked-list -> queue lookup, upgrade debug logs to INFO
- merkle_sync.c ms_find_conn_for_node: replace c=c->next with queue_find_data_by_index
- chat_sync.c cs_find_conn_for_node, cs_on_conn_up: DEBUG_DEBUG -> DEBUG_INFO
- etcp.c queue_set_ready: DEBUG_DEBUG -> DEBUG_INFO
2026-07-15 21:59:29 +03:00
Evgeny d71753fa79 debug: add diagnostic logs for chat invite connect flow
- cs_find_conn_for_node: show queue state, entry found/missing, conn flags
- cs_on_conn_up: log when skipping due to !initialized
- etcp_conn_queue_set_ready: log reindex details (old/new entry, count)
- etcp_conn_set_peer_node_id: show state+reindexed flag
2026-07-15 21:42:16 +03:00
Evgeny a7ecee01f5 etcp: replace connections linked-list with indexed ll_queue, add state/ref_count lifecycle
- Remove ETCP_CONN.next linked-list, UTUN_INSTANCE.connections list/count
- Unified connections in single ll_queue indexed by peer_node_id (0=pending)
- struct conn_queue_entry { peer_node_id, conn* } for uniform queue data
- Connection lifecycle via etcp.c: create→pending, conn_ready→indexed, close→detach+deferred free
- Close split: phase1 detach from external world, phase2 deferred via uasync_call_soon
- etcp_conn_set_peer_node_id: reindex on ID change (WARN)
- etcp_conn_ref_take/free: blocking close until refcount returns to 0
- Remove chat_connections — use unified connections queue directly
- Update all iteration/search patterns across 40 files (src + tests + chatgui)
2026-07-15 19:56:47 +03:00
Evgeny 6902f5fd95 chat: add ll_queue with index for P2P connections (replaces linear search)
- 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)
2026-07-15 18:15:16 +03:00
Evgeny d0af503d01 config: fix allow_all parsing — accept yes/1/true like other bool options
- config_parser.c: allowed_keys_allow_all now uses strcasecmp(yes/1/true) instead of atoi()
- node_config.cpp: keep allow_all=yes
2026-07-15 18:01:54 +03:00
Evgeny 3368abad2a etcp+chat: add DEBUG_INFO logs for invite/crypto handshake debugging
- etcp_connections: DECRYPT FAIL now logs my_pub/peer_pub/session_ready at INFO level (debug category)
- chat_sync: log invite start with pubkey/node_id/addr_count
- chat_core: log pubkey set on invite connect (my_pub + peer_pub)
- joindialog: GUI_INFO on decoded invite
2026-07-15 17:53:25 +03:00
Evgeny d83d281fa0 config: add [allowed_keys] allow_all=yes by default, add [gui] as valid section
- node_config.cpp: add [allowed_keys] allow_all=yes to default config
- config_parser.c: add SECTION_GUI to suppress 'Key outside section' warnings
2026-07-15 17:34:48 +03:00
Evgeny 4c8e5f6223 db_sync+chat_sync+etcp: fix conn init race, reduce keepalive log spam
- etcp_connections: keepalive SEND/RECV/DECRYPT_OK: DEBUG→TRACE; DECRYPT_FAIL: WARN→DEBUG
- db_sync_on_conn_up: skip sync if !conn->initialized, wait for next UP event
- db_sync peer_check_timer+instance_add: also check conn->initialized
- chat_sync cs_on_conn_up: ignore conn_up before initialized (cs_send fails otherwise)
- db_sync_on_conn_up log now includes init= and links=
2026-07-15 17:25:14 +03:00
Evgeny 5b749d6cc8 chatgui: db_path is now a directory (chat_data/) with chats.db and sync/ inside
- Default db_path changed from 'chats.db' to 'chat_data' directory
- chat_core_init receives <db_path>/chats.db
- db_sync receives <db_path> (creates <db_path>/sync internally)
- Directory auto-created on startup via QDir::mkpath
2026-07-15 17:09:11 +03:00
Evgeny 6252556a02 chatgui: migrate message sync from chat_sync to db_sync
- 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
2026-07-15 17:02:47 +03:00
Evgeny e86944d661 style: reformat db_sync.c — break 500-char lines into readable ~130-char max 2026-07-15 16:32:36 +03:00
Evgeny acaa3a767c refactor: move chat_sync and member_sync to direct ETCP P2P, bypass etcp_router
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).
2026-07-15 16:13:45 +03:00
Evgeny d840b458a7 fix: pause router retransmits before clearing ETCP queues on reinit
When etcp_conn_reinit is called, it clears ETCP queues (input_wait_ack
etc.) which frees dgram objects to data_pool. If a router retransmit
timer fires concurrently, it sends through the same conn → normalizer
allocates from corrupted data_pool → SIGSEGV.

Fix: call etcp_router_pause_retrans_for_node() BEFORE etcp_conn_reset()
to cancel retrans timers and free inflight_q entries for all router
connections to the peer. No callbacks, no close notifications —
lightweight pause, router connections stay alive and resume when
ETCP connection comes back up.
2026-07-15 15:37:03 +03:00
Evgeny 9378b18ce7 fix: defer connection_close in ready_cb using uasync_call_soon
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.
2026-07-15 15:00:05 +03:00
Evgeny f669254da3 feat: hard crash on etcp_connection_close from callback chain
Added callbacks_running flag to ETCP_CONN:
- set to 1 before up_cbks / down_cbks / ready_cbks iteration
- reset to 0 after iteration completes
- etcp_connection_close checks flag and does intentional SIGSEGV
  with FATAL log message if called during callback chain

This catches illegal synchronous close from within callbacks
instead of producing cryptic UAF segfaults later.
2026-07-15 14:43:47 +03:00
Evgeny 371208d489 chatgui: выпилить все записи в БД из GUI потока (DbManager)
- DbManager теперь read-only, получает sqlite3* handle через setDb()
- chat_core — единственный владелец БД (SQLITE_OPEN_FULLMUTEX + WAL)
- initTables/seedStubData/createChannel/insertMessage/setUiState удалены из DbManager
- seed 5 stub-аккаунтов перенесён в chat_core_init()
- GUI_EVT_DB_READY — уведомление о готовности БД
- setUiState заменён на QSettings
- каналы загружаются по DB_READY коллбэку
- убран двойной sqlite3_open (один файл, один хендл)
2026-07-15 14:26:32 +03:00
Evgeny 409a99f56b feat: cross-connect collision resolution via is_server master + collision flag
Protocol: added collision field to INIT_REQUEST_PKT (1 byte before ed25519_pubkey).
When two peers connect simultaneously, the one with is_server=0 (API-created
outbound link) is the master. Resolution by smaller node_id:
- We have master link + smaller node_id → send our INIT with collision=1
- We have master link + larger node_id → yield, process as slave
- Remote sends collision=1 → become slave unconditionally
- session_id change always forces reinit (genuine restart)

Removed unconditional etcp_conn_reinit on INIT_RESPONSE(0x03) — guarded by
reset_done flag. Server-side reinit now has collision check BEFORE reset_done
guard; session_id change penetrates reset_done protection.

Closes cross-connect reinit loop causing endless UP/DOWN flapping.
2026-07-15 13:53:15 +03:00
Evgeny 0912499309 fix: segfault in callback chain iteration — save next before invoke
In etcp_conn_ready / etcp_on_up / etcp_on_down / etcp_connection_create /
tcp_server_on_link, callback chains were iterated with:
  while (cbe) { cbe->fn(...); cbe = cbe->next; }
If the callback removes itself from the chain (e.g. ca_ready_cb calls
etcp_conn_remove_ready_cbk which u_free's the entry), cbe->next reads
freed memory → SIGSEGV.

Fixed by saving next pointer before invoking the callback:
  while (cbe) { n = cbe->next; cbe->fn(...); cbe = n; }
2026-07-15 12:46:37 +03:00
Evgeny abbb6de701 fix: block redundant conn reinit on cross-connect INIT (reset_done flag)
Problem: when two peers connect simultaneously, each incoming
INIT_REQUEST(0x02) or INIT_RESPONSE(0x03) triggers etcp_conn_reinit
unconditionally, causing endless UP/DOWN flapping loop.

Fix: add reset_done flag to ETCP_CONN:
- 0 at creation and after explicit reinit (reinit allowed)
- set to 1 in etcp_conn_ready (connection stable, block reinit)

Three call sites guarded with !conn->reset_done:
- client: handle_init_response_client (INIT_RESPONSE 0x03)
- server: existing link INIT_REQUEST processing
- server: new link INIT_REQUEST processing

send_reset logic preserved unconditionally — only etcp_conn_reinit
itself is blocked when already stable.
2026-07-15 12:17:14 +03:00
Evgeny 2bf7dcc6f0 debug: comprehensive connection diagnostics — recv/send/reinit paths
- RECV: log every packet (src addr, link found, session_ready, decrypt result)
- RECV: log init decrypt rejection with packet code (catches 0x03 INIT_RESPONSE
  silently dropped by init path)
- SEND: log destination addr+fd in send_init_response and etcp_encrypt_send
- REINIT: log full reason in server and client paths (code, session, got_init,
  initialized, links_up state before reinit)
2026-07-15 11:46:44 +03:00
Evgeny f7d88e5532 fix segfault in ca_ready_cb: ca_state owns all ca_ctx, single cleanup point
- 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
2026-07-15 11:21:31 +03:00
Evgeny 1e7585438d chat_core_connect_auto: add outbound conn to inst->connections
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.
2026-07-15 11:05:27 +03:00
Evgeny a8164baf41 chat_core_connect_auto: set peer_node_id on ETCP_CONN
Without peer_node_id, incoming INIT handler can't find the existing
outbound connection, creates a new one, and fails on insert_link collision.
2026-07-15 10:51:53 +03:00
Evgeny fc6a873b5c etcp_connections: reuse existing outbound link for incoming INIT by addr
When two peers send INIT simultaneously, the first link occupies the socket.
Incoming INIT arriving after finds the existing outbound link by (ip,port)
instead of failing with 'Can not insert link to socket'.
2026-07-15 10:46:33 +03:00
Evgeny 0adf7d07ef chat_core_connect_auto: dedup addresses by (addr,port) 2026-07-15 10:32:06 +03:00
Evgeny 33aa6bbd5a auto-connect: cursor-based, no close on timeout, GC every 1s, cancel API
- 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
2026-07-15 10:24:44 +03:00
Evgeny dccf54b30b auto-connect + GUI per-channel indicators
- 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
2026-07-15 06:00:43 +03:00
Evgeny 1a0229fd4f add NTP time synchronization module 2026-07-14 20:14:00 +03:00
Evgeny f3719a28df fix: change timestamp unit from microseconds to milliseconds
- db_sync.c: last_timestamp_us → last_timestamp_ms, use tv_sec*1000 + tv_usec/1000
- db_sync_stub.c: same change
- QDateTime::fromMSecsSinceEpoch() in chatgui expects milliseconds
- 1 µs → 1 ms change fixes 'minutes ticking like seconds' display bug
2026-07-14 19:33:16 +03:00
Evgeny 5fc621690a fix: wall-clock timestamps + merkle_sync timeout + build script
- 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
2026-07-14 19:23:02 +03:00
Evgeny 4636a69225 fix chatgui: pass chain_hash in PUSH + start member_sync on server join
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
2026-07-14 18:43:04 +03:00
Evgeny f9f516c2e9 fix chatgui: PUSH new messages to peers + comprehensive debug logging
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
2026-07-14 18:34:24 +03:00
Evgeny 58b9f28149 fix chatgui: prevent invite deadlock on connection flap
cs_on_conn_down: remove invite state zeroing on disconnection.
Only timeout callbacks and explicit protocol end (CS_MSG_ERROR,
transition to JOIN phase) clear the invite state.

Connection flap now causes automatic retry:
  conn_up → pending_invite_ch_id != 0 && !info_req_timer → resend
  CHANNEL_INFO_REQ. No deadlock possible.
2026-07-14 18:22:05 +03:00
Evgeny 8c41b44718 fix chatgui: repair INIT_RESP handler, add debug logging to all sync handlers
- 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
2026-07-14 18:07:57 +03:00
Evgeny 2d179ec41d fix chatgui: message format, member notify, chain_hash sync
- 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)
2026-07-14 17:46:33 +03:00
Evgeny c4751557b1 fix chatgui: ensure msg table + db_sync instance on join and restart
- chat_core_ensure_channel_ready(ch_id): idempotent — creates
  msg_<id> table + registers db_sync instance if missing
- chat_core_create_channel: refactored to use ensure_channel_ready
- cs_handle_channel_info_resp: call ensure_channel_ready on join
- chat_core_init: iterate existing channels on restart
- Fixes 'no such table: msg_<id>' after invite join
- Fixes 'no db_sync instance for ch=<id>' after restart
2026-07-14 17:22:01 +03:00
Evgeny 4254ab97bb fix chatgui: db_sync_stub + chat_sync_init for invite link join
- db_sync_stub.c: complete rewrite — proper structs, all API functions
  (db_sync_instance_add, insert_signed, set_insert_cb, select)
  Fixes db_sync_instance_add returning NULL (inst->db_sync was NULL)
- libutun/CMakeLists.txt: remove src/db_sync.c, stub replaces it
- chatgui/CMakeLists.txt: add transport/db_sync_stub.c
- utun_node.cpp: remove redundant db_sync_init/destroy,
  add chat_sync_init/destroy — server now registers svc_id=48
  Fixes 'no handler for svc_id=48' on incoming CHANNEL_INFO_REQ
2026-07-14 17:03:00 +03:00
Evgeny ccd25813f6 refactor: extract merkle_sync — universal Merkle-tree sync module
- merkle_sync.h/c: tree (5-level prefix, SHA256 buckets), wire protocol
  (HASHES/REQUEST/BATCH), sessions (10s timeout, 3 retries), async API
  with done_cb
- member_sync: thin glue layer, implements 3 data model callbacks
  (update_bucket_hash, get_items, apply_items) for chat members
- chat_sync: updated member_sync_start() calls with done_cb callback
- member_tree_hash table renamed to merkle_tree_hash
- member_sync.h public API preserved, internal tree/wire logic removed
2026-07-14 16:35:58 +03:00
Evgeny f617dcd68e db_sync: LMDB→SQLite, multi-instance, etcp_api, chatgui integration
- src/db_sync: LMDB replaced with SQLite (separate tables per instance: db_sync_name_id)
  TTL index (author, timestamp), WAL mode, per-instance peers/timers
  opaque DB_SYNC_INSTANCE* handle, insert callback, select API
  new fields: author_signature, delivered_peers, delivery_chain
  transport: etcp_api direct P2P (was etcp_router)

- src/db_sync.h: user-oriented API docs, multi-instance lifecycle

- lib/Makefile.am: liblmdb sources removed
- lib/sqlite3.c+h: SQLite amalgamation added

- topo_node: LMDB→SQLite (src/topo_node_sqlite.c moved from chatgui)

- chatgui: real db_sync.c replaces db_sync_stub.c
  chat_core: db_sync_insert_signed + dual-write insert callback
  utun_node: db_sync_init/destroy replaces chat_sync_init/destroy
  CMakeLists: stubs removed, real db_sync.c added
2026-07-14 14:17:43 +03:00
Evgeny 37417ba49d Fix: my_node_name insert inside [global] section, add button tooltips in channellist 2026-07-14 09:17:01 +03:00
Evgeny cca3511503 fix: replace deprecated SHA256 API with EVP, conditional dl linkage for Windows 2026-07-14 09:07:03 +03:00
Evgeny d70cdbb040 chatgui: preserve active channel selection on reload, members sync, profile settings, member list model 2026-07-14 08:52:10 +03:00
Evgeny c3f946fb63 chat_sync: fix join group stall — remove node_id match in cs_on_conn_up, add CS_MSG_ERROR protocol response 2026-07-13 18:11:18 +03:00
jeka 93de0aa591 agents 2026-07-13 15:46:29 +03:00