10 spammers (1-30ms random) + 2 observers (1-10ms), star topology via hub.
5s of concurrent modifications, then verify all 13 merkle root hashes
are identical and tree is internally consistent (recompute vs stored).
- _recompute_bucket: skip INSERT OR REPLACE when hash unchanged,
also skip DELETE when row doesn't exist (was always writing)
- bg_check interval: 100ms → 5000ms (was writing 10x/sec × 4KB/page
into WAL = ~1.4GB over hours)
- bg_timer: round-robin across channels instead of only first
- bg_timer: periodic WAL checkpoint (every ~60s) to prevent
unbounded WAL growth from any source
- test: sync ms_session struct copy with real definition
- stcp_link: handle race where conn already CLOSED before close
- stcp_client: remove double-free c->free_on_close = cli
- etcp_connections: stcp_link_close on TCP link down
- u_async: round sub-ms timeouts to 1ms to avoid busy-loop
- ntp_node_time.c: respond to TIME_SYNC only when peer is unsynced (not always)
Prevents infinite 10-byte ping-pong that ate bandwidth when both sides synced.
- pkt_normalizer.c: add in_total_pkts/in_total_bytes increments in
etcp_input_ready_cb (real send path), matching pn_packer_send (test path).
- conn_mgr_core.c/conn_mgr_priv.h: full INVITE_INFO_RESP with channel info
auto_socket.c: create_iface_tcp_socket returns stcp_server* instead of int,
ifa->v4_tcp/ifa->v6_tcp now properly track the created server, preventing
duplicate bind/listen on every reconcile_iface call.
etcp_connections.c: tcp_socket_add now resolves interface_addr via
get_interface_ip_by_index/get_interface_ipv6_addr_nl for any type (not just
PUBLIC), preventing NAT TCP v4 sockets from being destroyed due to INADDR_ANY.
auto_socket.c: remove tsrv from inst->stcp_servers before stcp_link_server_destroy
when TCP socket has null addr — freed pointer stayed in linked list corrupting it
on next stcp_server_listen->stcp_server_list_add, causing hang
utun_instance.c: apply debug_level + per-category debug from config in
utun_instance_create_from_config (was only in utun_instance_create)
chat_core.c: verbose error log on invalid args
1a: tcp_server_on_link — close existing TCP links before creating new ETCP_LINK
1b: etcp_tcp_send — skip send if stcp_link not ready
3a+3b+3c: stcp_conn_set_on_close → stcp_link_on_stcp_close → marks link DOWN → triggers reconnect
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll
- stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close
- utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP),
add deferred drain in both Phase J and L
- stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39,
exchange ed25519_pubkey in both handshake directions
- etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in
etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb
- chat_sync.c: fix lk->conn NULL dereference for TCP links
- test_stcp.c: update stcp_server_create/stcp_client_connect callsites
- tools/chat_tcp_test: change transport udp→tcp
tcp_server_on_link sets conn->peer_node_id after etcp_connection_create
which adds the entry with peer_node_id=0. instance_find_conn couldnt
find TCP connections until the queue entry was re-indexed.
- stcp_server: send handshake response BEFORE on_ready to prevent ETCP INIT data mixing into client recv buffer (crc mismatch)
- conn_mgr: relax peer_node_id match for INVITE_INFO_RESP when peer_node_id==0 (STCP connections)
- chat_tcp_test: remove invalid 'local' outside function
- etcp_connections.h: add WIRE_OVERHEAD, IP_UDP_OVERHEAD_V4/V6, SC_ENCRYPT_OVERHEAD
(properly accounts for v6 IP(40)+UDP(8)+SC(3)+CCM tag(16) = 67 vs old UDP_HDR_SIZE=28)
- etcp_connections.c etcp_encrypt_send: use WIRE_OVERHEAD instead of UDP_HDR_SIZE
- etcp_connections.c send_init_response: clamp padding to max_data = mtu - WIRE_OVERHEAD
- chat_core_priv.h: add addr_type_from_ip() classifier
- chat_profile.c, chat_sync.c, member_sync.c: use classified addr_type instead of hardcoded 0
- chat_sync.c: skip zero nat_addr in JOIN, fall back to interface_addr
- topo_node_sqlite.c, member_sync.c: remove addr_type=0 filter from SELECT/DELETE
- chat_profile.c, member_sync.c: DELETE all addresses (not just addr_type=0)
- node_put/node_update_verified: set online=1 on INSERT (nodes created when conn is UP)
- channel_peers_all: fix peer_needed calculation (atl byte was missing)
- cs_send_channel_join: add proto byte to address serialization matching all parsers
Root cause: instance_lite_restart was creating new thread without
re-setting g_event_handler, causing all chat events (CHANNEL_UPDATED,
CONNECT_RESULT, etc.) to be silently dropped after app restart.
Fixes:
- instance_lite_restart: save/restore g_event_handler across hard restart
- instance_thread restart loop: re-call chat_event_set_handler after uasync_create
- utun_bridge_restart: call instance_lite_set_event_handler before restart
- AppEventHandler SharedFlow replay: 1 → 16 to not lose early init events
- ViewModel: added diagnostic logging for channel/connect events
- Keep diagnostic logs in instance_lite (set_handler, chat_event_forward NULL check)
- instance_event_handler: removed static for cross-block forward declaration
- auto_socket.c/h: создание/удаление UDP сокетов автоматически при изменении интерфейсов через netlink/route socket
При auto_sockets=yes пропускает ручные [server] сокеты
Тип сокета: PUBLIC если публичный IP, иначе NAT
Для новых сокетов добавляются линки ко всем активным NCD-соединениям
При удалении интерфейса линки убираются, сокет закрывается
Platform-agnostic API для использования из Android/chatgui
- node_conn_direct.h/c: ncd_add_socket_links / ncd_remove_socket_links — управление линками на конкретном сокете
- socket_monitor.h/c: экспорт socket_monitor_update_if_addr для auto_socket
- config_parser.h/c: опция auto_sockets в [global]
- init_sockets(): пропуск ручных сокетов при auto_sockets=yes
- utun_instance: интеграция auto_socket_init/destroy
- media_delivery: fix stack-buffer-overflow ack[3] → ack[9]
- topo_node: fix heap-use-after-free в topo_group_update_my_nodeinfo — сохранение node_id/ver перед registry_store, использование return value
- etcp.c:466: %d→%s for log_name (was printing garbage like -2012603448)
- etcp_connections.c:2235: Server type %d→%s with server_type_str()
- etcp_connections.c:845,1578,1587: type=%d/nat_type=%d→%s with helpers
conn_mgr_router_recv_handler (etcp_router_bind): DIRECT_REQ, INTERM_EXCHANGE, DISCONNECT
conn_mgr_direct_recv_handler (etcp_bind): INVITE_INFO_REQ, INVITE_INFO_RESP
Each transport path now has its own handler — no more mixed concerns.
svc_id=17 (ETCP_RT_ID_CONN_MGR) is a singleton resource — bind once
at utun_instance_init, unbind once at utun_instance_destroy.
Previously each conn_mgr (one per group) called bind/unbind separately,
causing 'overwriting' and 'not bound' WARNs on every group init/shutdown.
Handler dispatches by group_id from message — no need for per-group binding.