dm: прямой обмен сообщениями (DM) + soundtouch + архитектура звонков
- src/dm/: dm_core/dm_crypto/dm_mailbox — прямой обмен сообщениями (DM) - lib/soundtouch-master/: vendored SoundTouch (изменение темпа/высоты аудио) - doc/dm_arch.md, doc/chat_call_arch.md: архитектура DM и звонков - tests: test_dm.c, test_dm_e2e.c - chat: рефакторинг chat_* модулей, member_sync, invite_build - chatgui/chatgui-android: синхронизация с новым API чата - lib/u_async, debug_config, utun_instance: сопутствующие изменения
This commit is contained in:
1 parent
761f64cf76
commit
73fe99b33f
123 files changed
+14095
-1270
No files matched your search
+195
-190
@@ -35,7 +35,9 @@
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
static struct chat_sync* g_cs = NULL;
|
||||
static inline struct chat_sync* cs_of(struct UTUN_INSTANCE* inst) {
|
||||
return inst ? inst->chat_sync : NULL;
|
||||
}
|
||||
|
||||
struct channel_cache {
|
||||
char channel_id[64];
|
||||
@@ -194,7 +196,8 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!g_cs || !g_cs->initialized) { u_free(entry->dgram); queue_entry_free(entry); return; }
|
||||
struct chat_sync* cs = cs_of(conn->instance);
|
||||
if (!cs || !cs->initialized) { u_free(entry->dgram); queue_entry_free(entry); return; }
|
||||
|
||||
uint64_t peer = conn ? conn->peer_node_id : 0;
|
||||
const uint8_t* d = entry->dgram;
|
||||
@@ -203,7 +206,7 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
uint64_t group_id = be64toh(*(const uint64_t*)(d + 1));
|
||||
uint8_t type = d[9];
|
||||
char ch_id[64];
|
||||
if (cs_group_id_to_ch_id(g_cs->inst, group_id, ch_id, sizeof(ch_id)) != 0) {
|
||||
if (cs_group_id_to_ch_id(cs->inst, group_id, ch_id, sizeof(ch_id)) != 0) {
|
||||
/* CHANNEL_INVITE/JOIN_INFO_REQ приходят для ещё не созданного у нас канала:
|
||||
group_id == channel_id (numeric), поэтому выводим ch_id напрямую. */
|
||||
if (type == CS_MSG_CHANNEL_INVITE || type == CS_MSG_JOIN_INFO_REQ || type == CS_MSG_JOIN_REQUEST) {
|
||||
@@ -221,19 +224,19 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
CS_ID, cs_msg_name(type), (unsigned long long)peer, ch_id, plen);
|
||||
|
||||
switch (type) {
|
||||
case CS_MSG_JOIN_INFO_REQ: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_INFO_REQ", CS_ID); cs_handle_join_info_req(g_cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_INFO_RESP: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_INFO_RESP", CS_ID); cs_handle_join_info_resp(g_cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_REQUEST: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_REQUEST", CS_ID); cs_handle_join_request(g_cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_READY: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_READY", CS_ID); cs_handle_join_ready(g_cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_INFO_REQ: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_INFO_REQ", CS_ID); cs_handle_join_info_req(cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_INFO_RESP: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_INFO_RESP", CS_ID); cs_handle_join_info_resp(cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_REQUEST: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_REQUEST", CS_ID); cs_handle_join_request(cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_JOIN_READY: DEBUG_TRACE(DEBUG_CATEGORY_MEMBER_SYNC, "%s: → handle JOIN_READY", CS_ID); cs_handle_join_ready(cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_ERROR: {
|
||||
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; }
|
||||
if (cs->info_req_timer) { uasync_cancel_timeout(cs->inst->ua, cs->info_req_timer); 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);
|
||||
g_cs->pending_invite_node_id = 0; g_cs->pending_invite_ch_id = 0;
|
||||
memcpy(err + 12, &cs->pending_invite_ch_id, 8); chat_event_post(cs->inst, CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0;
|
||||
break;
|
||||
}
|
||||
case CS_MSG_CHANNEL_INVITE: cs_handle_channel_invite(g_cs, peer, ch_id, pl, plen); break;
|
||||
case CS_MSG_CHANNEL_INVITE: cs_handle_channel_invite(cs, peer, ch_id, pl, plen); 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);
|
||||
@@ -251,7 +254,7 @@ static void cs_info_req_timeout_cb(void* arg) {
|
||||
uint8_t err[20]; memcpy(err, &cs->pending_invite_node_id, 8);
|
||||
int r = 2; memcpy(err + 8, &r, 4); /* timeout */
|
||||
memcpy(err + 12, &cs->pending_invite_ch_id, 8);
|
||||
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
cs->pending_invite_node_id = 0;
|
||||
cs->pending_invite_ch_id = 0;
|
||||
}
|
||||
@@ -266,7 +269,7 @@ static void cs_join_timeout_cb(void* arg) {
|
||||
uint8_t err[20]; memcpy(err, &peer, 8);
|
||||
int r = 2; memcpy(err + 8, &r, 4); /* timeout */
|
||||
memcpy(err + 12, &cs->pending_invite_ch_id, 8);
|
||||
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
cs->pending_invite_node_id = 0;
|
||||
cs->pending_invite_ch_id = 0;
|
||||
cs->pending_invite_is_inviter = 0;
|
||||
@@ -282,7 +285,7 @@ static void cs_invite_send_timeout_cb(void* arg) {
|
||||
uint8_t err[20]; memcpy(err, &peer, 8);
|
||||
int r = 2; memcpy(err + 8, &r, 4); /* timeout */
|
||||
memcpy(err + 12, &cs->pending_invite_ch_id, 8);
|
||||
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CONNECT_RESULT, err, 20);
|
||||
cs->pending_invite_node_id = 0;
|
||||
cs->pending_invite_ch_id = 0;
|
||||
cs->pending_invite_is_inviter = 0;
|
||||
@@ -350,7 +353,7 @@ static void cs_post_channel_online(struct chat_sync* cs, const char* ch_id) {
|
||||
uint8_t evt[66]; evt[0] = (uint8_t)cl;
|
||||
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);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CHANNEL_PEERS_ONLINE, evt, 1 + (int)cl + 2);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: PEERS_ONLINE ch=%.*s total_online=%d", CS_ID, (int)cl, ch_id, online);
|
||||
}
|
||||
|
||||
@@ -367,7 +370,7 @@ static void cs_flush_sync(struct chat_sync* cs) {
|
||||
if (pid == myid || !cs_is_peer_online(cs->inst, pid)) continue;
|
||||
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, _on_member_sync_done, NULL);
|
||||
member_sync_start(cs->inst, pid, ch->channel_id, _on_member_sync_done, cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,52 +394,53 @@ static void cs_schedule_sync(struct chat_sync* cs) {
|
||||
|
||||
/* ── Peer status change (GUI + online-бар + schedule_sync; онлайн в БД не хранится) ── */
|
||||
|
||||
static void cs_on_peer_status_changed(uint64_t peer, int online) {
|
||||
static void cs_on_peer_status_changed(struct chat_sync* cs, uint64_t peer, int online) {
|
||||
/* 1. GUI + online-бар */
|
||||
int found_in_channel = 0;
|
||||
for (int i = 0; i < g_cs->channel_count; i++) {
|
||||
for (int j = 0; j < g_cs->channels[i].peer_count; j++) {
|
||||
if (g_cs->channels[i].peer_ids[j] == peer) {
|
||||
for (int i = 0; i < cs->channel_count; i++) {
|
||||
for (int j = 0; j < cs->channels[i].peer_count; j++) {
|
||||
if (cs->channels[i].peer_ids[j] == peer) {
|
||||
found_in_channel = 1;
|
||||
const char* ch_id = g_cs->channels[i].channel_id;
|
||||
const char* ch_id = cs->channels[i].channel_id;
|
||||
size_t cl = strlen(ch_id);
|
||||
uint8_t mevt[1 + 64 + 1 + CHAT_MEMBER_DISPLAY_SIZE];
|
||||
mevt[0] = (uint8_t)cl;
|
||||
memcpy(mevt + 1, ch_id, cl);
|
||||
mevt[1 + cl] = 1;
|
||||
if (chat_core_get_single_member(ch_id, peer, mevt + 1 + cl + 1) == 0)
|
||||
chat_event_post(CHAT_EVT_MEMBER_UPDATED, mevt, 1 + (int)cl + 1 + CHAT_MEMBER_DISPLAY_SIZE);
|
||||
cs_post_channel_online(g_cs, ch_id);
|
||||
if (chat_core_get_single_member(cs->inst, ch_id, peer, mevt + 1 + cl + 1) == 0)
|
||||
chat_event_post(cs->inst, CHAT_EVT_MEMBER_UPDATED, mevt, 1 + (int)cl + 1 + CHAT_MEMBER_DISPLAY_SIZE);
|
||||
cs_post_channel_online(cs, ch_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
CS_ID, (unsigned long long)peer, online, cs->channel_count, found_in_channel);
|
||||
|
||||
/* 2. Запланировать member_sync_start (throttled) */
|
||||
cs_schedule_sync(g_cs);
|
||||
cs_schedule_sync(cs);
|
||||
}
|
||||
|
||||
static void cs_resume_db_sync(const char* ch_id) {
|
||||
if (!g_cs || !ch_id || !ch_id[0]) return;
|
||||
struct DB_SYNC_INSTANCE* si = si_find(ch_id);
|
||||
static void cs_resume_db_sync(struct chat_sync* cs, const char* ch_id) {
|
||||
if (!cs || !ch_id || !ch_id[0]) return;
|
||||
struct DB_SYNC_INSTANCE* si = si_find(cs->inst, ch_id);
|
||||
if (si) db_sync_instance_set_gated(si, 0);
|
||||
}
|
||||
|
||||
static void _on_member_sync_done(uint64_t peer, const char* ns, int result, void* arg) {
|
||||
(void)arg;
|
||||
struct chat_sync* cs = (struct chat_sync*)arg;
|
||||
if (result == MT_OK) {
|
||||
struct channel_cache* ch = g_cs ? cs_find(g_cs, ns) : NULL;
|
||||
struct channel_cache* ch = cs ? cs_find(cs, ns) : NULL;
|
||||
if (ch) ch->synced = CS_SYNC_DONE;
|
||||
cs_resume_db_sync(ns);
|
||||
cs_resume_db_sync(cs, ns);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
struct invite_sync_arg {
|
||||
struct chat_sync* cs;
|
||||
uint64_t node_id;
|
||||
char ch_id[64];
|
||||
};
|
||||
@@ -446,13 +450,13 @@ static void _on_invite_sync_done(uint64_t peer, const char* ns, int result, void
|
||||
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 (result == MT_OK && sa && sa->cs) {
|
||||
if (sa->node_id == 0 || sa->ch_id[0] == '\0') {
|
||||
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);
|
||||
cs_resume_db_sync(sa->ch_id);
|
||||
cs_post_channel_online(sa->cs, sa->ch_id);
|
||||
cs_resume_db_sync(sa->cs, sa->ch_id);
|
||||
}
|
||||
}
|
||||
u_free(sa);
|
||||
@@ -482,62 +486,62 @@ static void cs_start_channel_join(struct chat_sync* cs, uint64_t peer) {
|
||||
/* ── Connection callbacks ── */
|
||||
|
||||
static void cs_on_conn_up(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
(void)arg;
|
||||
if (!conn || !g_cs) return;
|
||||
struct chat_sync* cs = (struct chat_sync*)arg;
|
||||
if (!conn || !cs) return;
|
||||
uint64_t peer = conn->peer_node_id;
|
||||
if (peer == 0 || peer == g_cs->inst->node_id) return;
|
||||
if (peer == 0 || peer == cs->inst->node_id) 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_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);
|
||||
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)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)
|
||||
if (cs->pending_invite_ch_id != 0) {
|
||||
if (cs->pending_invite_node_id != 0 && cs->pending_invite_node_id != peer)
|
||||
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) {
|
||||
CS_ID, (unsigned long long)cs->pending_invite_node_id, (unsigned long long)peer);
|
||||
cs->pending_invite_node_id = peer;
|
||||
if (cs->pending_invite_is_inviter) {
|
||||
/* we are the inviter — send CHANNEL_INVITE to the joiner */
|
||||
char ch_id[64]; snprintf(ch_id, sizeof(ch_id), "%llu",
|
||||
(unsigned long long)g_cs->pending_invite_ch_id);
|
||||
(unsigned long long)cs->pending_invite_ch_id);
|
||||
char ch_name[128]; uint8_t ch_x2[32], ch_ed2[32], ch_sig[64]; uint64_t ch_owner;
|
||||
if (topo_node_sqlite_channel_get(g_cs->inst->topo_sqlite_db,
|
||||
if (topo_node_sqlite_channel_get(cs->inst->topo_sqlite_db,
|
||||
ch_id, ch_name, (int)sizeof(ch_name), &ch_owner, ch_x2, ch_ed2, ch_sig) == 0) {
|
||||
cs_send_channel_invite(g_cs, g_cs->inst, ch_id, peer, ch_name, ch_owner, ch_x2, ch_ed2, ch_sig);
|
||||
if (g_cs->invite_send_timer) { uasync_cancel_timeout(g_cs->inst->ua, g_cs->invite_send_timer); }
|
||||
g_cs->invite_send_timer = uasync_set_timeout(g_cs->inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, g_cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
cs_send_channel_invite(cs, cs->inst, ch_id, peer, ch_name, ch_owner, ch_x2, ch_ed2, ch_sig);
|
||||
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); }
|
||||
cs->invite_send_timer = uasync_set_timeout(cs->inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
}
|
||||
} else {
|
||||
cs_start_channel_join(g_cs, peer);
|
||||
cs_start_channel_join(cs, peer);
|
||||
}
|
||||
cs_on_peer_status_changed(peer, 1);
|
||||
cs_on_peer_status_changed(cs, peer, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
cs_on_peer_status_changed(peer, 1);
|
||||
cs_on_peer_status_changed(cs, peer, 1);
|
||||
}
|
||||
|
||||
static void cs_on_conn_down(struct ETCP_CONN* conn, int event, void* arg) { (void)event;
|
||||
(void)arg;
|
||||
if (!conn || !g_cs) return;
|
||||
struct chat_sync* cs = (struct chat_sync*)arg;
|
||||
if (!conn || !cs) return;
|
||||
uint64_t peer = conn->peer_node_id;
|
||||
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_on_peer_status_changed(cs, peer, 0);
|
||||
|
||||
cs_cancel_proto_timers(g_cs);
|
||||
if (g_cs->pending_invite_node_id == peer) {
|
||||
cs_cancel_proto_timers(cs);
|
||||
if (cs->pending_invite_node_id == peer) {
|
||||
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 */
|
||||
}
|
||||
for (int i = 0; i < g_cs->channel_count; i++) {
|
||||
for (int i = 0; i < cs->channel_count; i++) {
|
||||
int found = 0;
|
||||
for (int j = 0; j < g_cs->channels[i].peer_count; j++)
|
||||
if (g_cs->channels[i].peer_ids[j] == peer) { found = 1; break; }
|
||||
for (int j = 0; j < cs->channels[i].peer_count; j++)
|
||||
if (cs->channels[i].peer_ids[j] == peer) { found = 1; break; }
|
||||
if (found)
|
||||
g_cs->channels[i].synced = CS_SYNC_NONE;
|
||||
cs->channels[i].synced = CS_SYNC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,21 +554,11 @@ static void cs_on_conn_status(struct ETCP_CONN* conn, int status, void* arg) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* replaced by cs_on_conn_status */
|
||||
static void cs_on_new_conn(struct ETCP_CONN* conn, void* arg) {
|
||||
(void)arg;
|
||||
if (!conn) return;
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ── Periodic refresh from DB ── */
|
||||
|
||||
static void cs_refresh_channels(struct chat_sync* cs) {
|
||||
uint8_t buf[4096]; size_t buf_len;
|
||||
if (chat_core_list_channels(buf, sizeof(buf), &buf_len) != 0) return;
|
||||
if (chat_core_list_channels(cs->inst, buf, sizeof(buf), &buf_len) != 0) return;
|
||||
if (buf_len < 2) return;
|
||||
|
||||
uint16_t cnt; memcpy(&cnt, buf, 2);
|
||||
@@ -584,15 +578,15 @@ static void cs_refresh_channels(struct chat_sync* cs) {
|
||||
cs->channels[i].channel_id[id_len] = '\0';
|
||||
p += id_len; rem -= id_len;
|
||||
|
||||
cs->channels[i].msg_count = chat_core_count(cs->channels[i].channel_id);
|
||||
cs->channels[i].msg_count = chat_core_count(cs->inst, cs->channels[i].channel_id);
|
||||
if (cs->channels[i].msg_count > 0)
|
||||
chat_core_chain_hash_at(cs->channels[i].channel_id,
|
||||
chat_core_chain_hash_at(cs->inst, cs->channels[i].channel_id,
|
||||
cs->channels[i].msg_count - 1, cs->channels[i].last_chain_hash);
|
||||
else
|
||||
memset(cs->channels[i].last_chain_hash, 0, 32);
|
||||
|
||||
uint8_t peer_buf[2048]; size_t peer_len;
|
||||
if (chat_core_list_peers(cs->channels[i].channel_id, peer_buf,
|
||||
if (chat_core_list_peers(cs->inst, cs->channels[i].channel_id, peer_buf,
|
||||
sizeof(peer_buf), &peer_len) == 0 && peer_len >= 2) {
|
||||
uint16_t pc; memcpy(&pc, peer_buf, 2);
|
||||
cs->channels[i].peer_ids = u_calloc(pc, sizeof(uint64_t));
|
||||
@@ -607,18 +601,18 @@ static void cs_refresh_channels(struct chat_sync* cs) {
|
||||
}
|
||||
|
||||
static void refresh_timer_cb(void* arg) {
|
||||
(void)arg;
|
||||
if (!g_cs || !g_cs->initialized) return;
|
||||
struct chat_sync* cs = (struct chat_sync*)arg;
|
||||
if (!cs || !cs->initialized) return;
|
||||
#ifdef UTUN_HAVE_STANDBY
|
||||
if (standby_get_sleep_tb() > 0) {
|
||||
g_cs->refresh_wait = standby_wait(g_cs, refresh_timer_cb);
|
||||
cs->refresh_wait = standby_wait(cs, refresh_timer_cb);
|
||||
return;
|
||||
}
|
||||
g_cs->refresh_wait = NULL;
|
||||
cs->refresh_wait = NULL;
|
||||
#endif
|
||||
cs_refresh_channels(g_cs);
|
||||
g_cs->refresh_timer = uasync_set_timeout(g_cs->inst->ua,
|
||||
30u * 10000u, g_cs, refresh_timer_cb, "cs_refresh");
|
||||
cs_refresh_channels(cs);
|
||||
cs->refresh_timer = uasync_set_timeout(cs->inst->ua,
|
||||
30u * 10000u, cs, refresh_timer_cb, "cs_refresh");
|
||||
}
|
||||
|
||||
/* ── TTL cleanup ── */
|
||||
@@ -633,10 +627,10 @@ int chat_sync_init(struct UTUN_INSTANCE* inst) {
|
||||
if (!cs) return -1;
|
||||
cs->inst = inst;
|
||||
cs->initialized = 1;
|
||||
g_cs = cs;
|
||||
inst->chat_sync = cs;
|
||||
|
||||
etcp_bind(inst, ETCP_RT_ID_CHAT_SYNC, chat_sync_recv_cb);
|
||||
etcp_add_conn_status_cbk(inst, cs_on_conn_status, NULL);
|
||||
etcp_add_conn_status_cbk(inst, cs_on_conn_status, cs);
|
||||
|
||||
cs_refresh_channels(cs);
|
||||
|
||||
@@ -646,7 +640,7 @@ int chat_sync_init(struct UTUN_INSTANCE* inst) {
|
||||
cs->join_timer = NULL;
|
||||
|
||||
member_sync_init(inst);
|
||||
member_sync_add_apply_cbk(cs_on_member_applied, cs);
|
||||
member_sync_add_apply_cbk(inst, cs_on_member_applied, cs);
|
||||
chat_admin_init(inst);
|
||||
chat_join_init(inst);
|
||||
|
||||
@@ -655,21 +649,21 @@ int chat_sync_init(struct UTUN_INSTANCE* inst) {
|
||||
}
|
||||
|
||||
void chat_sync_destroy(struct UTUN_INSTANCE* inst) {
|
||||
struct chat_sync* cs = g_cs;
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !inst) return;
|
||||
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); }
|
||||
member_sync_remove_apply_cbk(cs_on_member_applied, cs);
|
||||
member_sync_remove_apply_cbk(inst, cs_on_member_applied, cs);
|
||||
cs_pending_free_all(cs);
|
||||
member_sync_destroy(inst);
|
||||
chat_admin_destroy(inst);
|
||||
chat_join_destroy(inst);
|
||||
cs->initialized = 0; g_cs = NULL;
|
||||
cs->initialized = 0; inst->chat_sync = NULL;
|
||||
|
||||
etcp_unbind(inst, ETCP_RT_ID_CHAT_SYNC);
|
||||
etcp_remove_conn_status_cbk(inst, cs_on_conn_status, NULL);
|
||||
etcp_remove_conn_status_cbk(inst, cs_on_conn_status, cs);
|
||||
if (cs->refresh_timer) { uasync_cancel_timeout(inst->ua, cs->refresh_timer); cs->refresh_timer = NULL; }
|
||||
#ifdef UTUN_HAVE_STANDBY
|
||||
if (cs->refresh_wait) { standby_wait_cancel(cs->refresh_wait); cs->refresh_wait = NULL; }
|
||||
@@ -683,14 +677,15 @@ void chat_sync_destroy(struct UTUN_INSTANCE* inst) {
|
||||
}
|
||||
|
||||
void chat_sync_retry_channels_on_socket_change(struct UTUN_INSTANCE* inst) {
|
||||
if (!g_cs || !g_cs->initialized || !inst->topo_groups) return;
|
||||
for (int i = 0; i < g_cs->channel_count; i++) {
|
||||
uint64_t gid = strtoull(g_cs->channels[i].channel_id, NULL, 10);
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !cs->initialized || !inst->topo_groups) return;
|
||||
for (int i = 0; i < cs->channel_count; i++) {
|
||||
uint64_t gid = strtoull(cs->channels[i].channel_id, NULL, 10);
|
||||
struct TOPO_GROUP* group = topo_groups_find(inst->topo_groups, gid);
|
||||
if (!group || !group->connect) continue;
|
||||
if (topo_group_connect_active_count(group) == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: socket change — restarting connect for ch=%s (no active connections)",
|
||||
CS_ID, g_cs->channels[i].channel_id);
|
||||
CS_ID, cs->channels[i].channel_id);
|
||||
topo_group_connect_restart(group);
|
||||
}
|
||||
}
|
||||
@@ -701,14 +696,14 @@ void chat_sync_connect_node(struct UTUN_INSTANCE* inst, uint64_t node_id) {
|
||||
}
|
||||
|
||||
void chat_sync_on_channel_deleted(struct UTUN_INSTANCE* inst, const char* ch_id) {
|
||||
(void)inst;
|
||||
if (!g_cs || !ch_id || !ch_id[0]) return;
|
||||
for (int i = 0; i < g_cs->channel_count; i++) {
|
||||
if (strcmp(g_cs->channels[i].channel_id, ch_id) != 0) continue;
|
||||
if (g_cs->channels[i].peer_ids) u_free(g_cs->channels[i].peer_ids);
|
||||
memmove(&g_cs->channels[i], &g_cs->channels[i + 1],
|
||||
(size_t)(g_cs->channel_count - i - 1) * sizeof(struct channel_cache));
|
||||
g_cs->channel_count--;
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !ch_id || !ch_id[0]) return;
|
||||
for (int i = 0; i < cs->channel_count; i++) {
|
||||
if (strcmp(cs->channels[i].channel_id, ch_id) != 0) continue;
|
||||
if (cs->channels[i].peer_ids) u_free(cs->channels[i].peer_ids);
|
||||
memmove(&cs->channels[i], &cs->channels[i + 1],
|
||||
(size_t)(cs->channel_count - i - 1) * sizeof(struct channel_cache));
|
||||
cs->channel_count--;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: channel removed from cache ch=%s", CS_ID, ch_id);
|
||||
return;
|
||||
}
|
||||
@@ -721,9 +716,11 @@ struct chat_invite {
|
||||
uint8_t* addrs_data;
|
||||
int addrs_data_len;
|
||||
int addr_count;
|
||||
uint64_t join_key;
|
||||
char password[128];
|
||||
};
|
||||
|
||||
struct cm_invite_wrap { struct chat_invite inv; };
|
||||
struct cm_invite_wrap { struct UTUN_INSTANCE* inst; struct chat_invite inv; };
|
||||
|
||||
/* Парсит reality-префикс addrs_data: has(1) + [short_id(8) pubkey(32) ver(3) snlen(1) sn(N)].
|
||||
Сдвигает *ap за префикс. Возвращает 1, если reality присутствует (и params заполнены). */
|
||||
@@ -762,13 +759,23 @@ static void invite_reality_sock_append(struct TOPO_NODE* ni, uint8_t socket_id,
|
||||
static void cm_invite_trampoline(void* arg) {
|
||||
struct cm_invite_wrap* w = (struct cm_invite_wrap*)arg;
|
||||
struct chat_invite* inv = &w->inv;
|
||||
struct UTUN_INSTANCE* inst = chat_core_get_inst();
|
||||
struct UTUN_INSTANCE* inst = w->inst;
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
uint64_t node_id = inv->node_id;
|
||||
uint64_t channel_id = inv->channel_id;
|
||||
|
||||
if (!cs) { u_free(inv->addrs_data); u_free(w); return; }
|
||||
|
||||
/* Параметры invite храним в cs->pending_* здесь, в uasync-потоке (не на вызывающем):
|
||||
* их читает cs_start_channel_join/cs_on_conn_up из uasync-потока. */
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = node_id;
|
||||
cs->pending_join_key = inv->join_key;
|
||||
snprintf(cs->pending_password, sizeof(cs->pending_password), "%s", inv->password);
|
||||
|
||||
/* build TOPO_NODE from invite data */
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
|
||||
if (!ni) { u_free(w); return; }
|
||||
if (!ni) { u_free(inv->addrs_data); u_free(w); return; }
|
||||
ni->node_id = node_id; memcpy(ni->public_key, inv->pubkey, 32);
|
||||
const uint8_t* ap = inv->addrs_data;
|
||||
const uint8_t* ap_end = inv->addrs_data + inv->addrs_data_len;
|
||||
@@ -814,50 +821,52 @@ static void cm_invite_trampoline(void* arg) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "invite: no valid addrs for node=0x%016llx", (unsigned long long)node_id);
|
||||
while (ni->v4_addrs) { struct TOPO_ADDR4* n = ni->v4_addrs->next; u_free(ni->v4_addrs); ni->v4_addrs = n; }
|
||||
while (ni->v6_addrs) { struct TOPO_ADDR6* n = ni->v6_addrs->next; u_free(ni->v6_addrs); ni->v6_addrs = n; }
|
||||
u_free(ni); u_free(w); return;
|
||||
u_free(ni); u_free(inv->addrs_data); u_free(w); return;
|
||||
}
|
||||
|
||||
/* topo_group_invite_to_channel: прямое ncd-подключение к connection-узлу БЕЗ INVITE_INFO.
|
||||
Реальный join-протокол (JOIN_INFO_REQ → … → JOIN_READY) запускается по cs_on_conn_up. */
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "channel invite: connecting to 0x%016llx via %d addresses",
|
||||
(unsigned long long)node_id, inv->addr_count);
|
||||
int r = topo_group_invite_to_channel(inst, channel_id, ni, node_id);
|
||||
if (r < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "channel invite: FAILED — topo_group_invite_to_channel error=%d", r);
|
||||
/* если линк к узлу уже есть и он up — не открываем новое подключение,
|
||||
сразу запускаем join-хендшейк (JOIN_INFO_REQ → … → JOIN_READY) */
|
||||
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
|
||||
if (conn && conn->links_up && conn->initialized) {
|
||||
cs->pending_invite_node_id = node_id;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL,
|
||||
"channel invite: link to 0x%016llx already up — skipping connect, join handshake directly",
|
||||
(unsigned long long)node_id);
|
||||
cs_start_channel_join(cs, node_id);
|
||||
} else {
|
||||
/* если уже подключены к connection-узлу — cs_on_conn_up отработал до установки
|
||||
pending_invite_ch_id и повторно не сработает, поэтому запускаем join-хендшейк напрямую */
|
||||
struct ETCP_CONN* conn = instance_find_conn(inst, node_id);
|
||||
if (conn && conn->links_up && conn->initialized) {
|
||||
g_cs->pending_invite_node_id = node_id;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: already connected to 0x%016llx — starting join handshake directly",
|
||||
CS_ID, (unsigned long long)node_id);
|
||||
cs_start_channel_join(g_cs, node_id);
|
||||
}
|
||||
/* topo_group_invite_to_channel: прямое ncd-подключение к connection-узлу БЕЗ INVITE_INFO.
|
||||
Реальный join-протокол (JOIN_INFO_REQ → … → JOIN_READY) запускается по cs_on_conn_up. */
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "channel invite: connecting to 0x%016llx via %d addresses",
|
||||
(unsigned long long)node_id, inv->addr_count);
|
||||
int r = topo_group_invite_to_channel(inst, channel_id, ni, node_id);
|
||||
if (r < 0)
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "channel invite: FAILED — topo_group_invite_to_channel error=%d", r);
|
||||
}
|
||||
|
||||
/* free caller-owned ni */
|
||||
while (ni->v4_addrs) { struct TOPO_ADDR4* n = ni->v4_addrs->next; u_free(ni->v4_addrs); ni->v4_addrs = n; }
|
||||
while (ni->v6_addrs) { struct TOPO_ADDR6* n = ni->v6_addrs->next; u_free(ni->v6_addrs); ni->v6_addrs = n; }
|
||||
u_free(ni);
|
||||
u_free(inv->addrs_data);
|
||||
u_free(w);
|
||||
}
|
||||
|
||||
void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
||||
void chat_sync_connect_from_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t node_id,
|
||||
const uint8_t* pubkey_bin,
|
||||
const uint8_t* addrs_data, int addr_count,
|
||||
int addrs_data_len,
|
||||
const char* password, uint64_t join_key) {
|
||||
if (!g_cs || !g_cs->inst || !g_cs->inst->ua) {
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !cs->inst || !cs->inst->ua) {
|
||||
int r = -7;
|
||||
#ifdef __ANDROID__
|
||||
__android_log_print(ANDROID_LOG_ERROR, "utun-chat", "invite ch=%llu node=%016llx REJECTED g_cs=%p inst=%p ua=%p",
|
||||
(long long)channel_id, (long long)node_id, (void*)g_cs,
|
||||
g_cs ? (void*)g_cs->inst : NULL,
|
||||
(g_cs && g_cs->inst) ? (void*)g_cs->inst->ua : NULL);
|
||||
__android_log_print(ANDROID_LOG_ERROR, "utun-chat", "invite ch=%llu node=%016llx REJECTED cs=%p inst=%p ua=%p",
|
||||
(long long)channel_id, (long long)node_id, (void*)cs,
|
||||
cs ? (void*)cs->inst : NULL,
|
||||
(cs && cs->inst) ? (void*)cs->inst->ua : NULL);
|
||||
#endif
|
||||
uint8_t err[12]; memcpy(err, &node_id, 8); memcpy(err + 8, &r, 4);
|
||||
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 12);
|
||||
chat_event_post(inst, CHAT_EVT_CONNECT_RESULT, err, 12);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -874,18 +883,9 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
||||
memcpy(inv->addrs_data, addrs_data, addrs_sz);
|
||||
inv->addrs_data_len = (int)addrs_sz;
|
||||
inv->addr_count = addr_count;
|
||||
|
||||
g_cs->pending_invite_ch_id = channel_id;
|
||||
g_cs->pending_invite_node_id = node_id;
|
||||
g_cs->pending_join_key = join_key;
|
||||
if (password && password[0]) {
|
||||
size_t pl = strlen(password);
|
||||
if (pl >= sizeof(g_cs->pending_password)) pl = sizeof(g_cs->pending_password) - 1;
|
||||
memcpy(g_cs->pending_password, password, pl);
|
||||
g_cs->pending_password[pl] = '\0';
|
||||
} else {
|
||||
g_cs->pending_password[0] = '\0';
|
||||
}
|
||||
inv->join_key = join_key;
|
||||
if (password && password[0]) snprintf(inv->password, sizeof(inv->password), "%s", password);
|
||||
else inv->password[0] = '\0';
|
||||
#ifdef __ANDROID__
|
||||
__android_log_print(ANDROID_LOG_INFO, "utun-chat", "invite ch=%llu node=%016llx addrs=%d pass=%s",
|
||||
(long long)channel_id, (long long)node_id, addr_count, password ? "yes" : "no");
|
||||
@@ -895,16 +895,18 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
||||
CS_ID, channel_id, node_id, *(const uint64_t*)pubkey_bin, addr_count, password && password[0] ? "yes" : "no");
|
||||
#endif
|
||||
|
||||
struct cm_invite_wrap { struct chat_invite inv; }* w = u_malloc(sizeof(struct cm_invite_wrap));
|
||||
struct cm_invite_wrap* w = u_malloc(sizeof(struct cm_invite_wrap));
|
||||
w->inst = inst;
|
||||
w->inv = *inv; u_free(inv);
|
||||
uasync_post(g_cs->inst->ua,
|
||||
uasync_post(cs->inst->ua,
|
||||
(void(*)(void*))cm_invite_trampoline, w);
|
||||
}
|
||||
|
||||
/* ─── 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_MEMBER_SYNC, "%s: join_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: join_channel: 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);
|
||||
@@ -920,10 +922,10 @@ void chat_sync_join_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint6
|
||||
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;
|
||||
g_cs->pending_invite_node_id = target_node_id;
|
||||
cs_start_channel_join(g_cs, target_node_id);
|
||||
cs_on_peer_status_changed(target_node_id, 1);
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
cs_start_channel_join(cs, target_node_id);
|
||||
cs_on_peer_status_changed(cs, target_node_id, 1);
|
||||
}
|
||||
|
||||
/* ─── Ed25519 sign / verify helpers ─── */
|
||||
@@ -1132,7 +1134,7 @@ static void cs_handle_join_info_resp(struct chat_sync* cs, uint64_t peer,
|
||||
|
||||
/* save channel */
|
||||
topo_node_sqlite_channel_put(cs->inst->topo_sqlite_db, ch_id, name, owner, ch_x25519, NULL, ch_ed, NULL, ch_sig);
|
||||
chat_core_ensure_channel_ready(ch_id);
|
||||
chat_core_ensure_channel_ready(cs->inst, ch_id);
|
||||
|
||||
/* добавить connection-узел в мемберы (дерево приглашений из INFO_RESP) */
|
||||
sqlite3* vdb = cs->inst->topo_sqlite_db;
|
||||
@@ -1325,18 +1327,18 @@ static void cs_handle_join_ready(struct chat_sync* cs, uint64_t peer,
|
||||
if (c) topo_group_new_conn(g, c);
|
||||
}
|
||||
}
|
||||
chat_core_ensure_channel_ready(ch_id);
|
||||
chat_core_ensure_channel_ready(cs->inst, ch_id);
|
||||
|
||||
uint8_t evt[65]; uint8_t ch_id_len = (uint8_t)strlen(ch_id);
|
||||
evt[0] = ch_id_len; memcpy(evt + 1, ch_id, ch_id_len);
|
||||
chat_event_post(CHAT_EVT_CHANNEL_UPDATED, evt, 1 + ch_id_len);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CHANNEL_UPDATED, evt, 1 + ch_id_len);
|
||||
cs_post_channel_online(cs, ch_id);
|
||||
cs_resume_db_sync(ch_id);
|
||||
cs_resume_db_sync(cs, ch_id);
|
||||
|
||||
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);
|
||||
chat_event_post(cs->inst, CHAT_EVT_CONNECT_RESULT, cevt, 20);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: JOIN_READY invite success ch=%s peer=%016llx", CS_ID, ch_id, (unsigned long long)peer);
|
||||
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0; cs->pending_join_key = 0;
|
||||
}
|
||||
@@ -1386,7 +1388,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
||||
int policy;
|
||||
{
|
||||
struct global_config *gcfg = &cs->inst->config->global;
|
||||
policy = gcfg->chatserver_enabled ? 0 : chat_setting_get_int("join_policy", 1);
|
||||
policy = gcfg->chatserver_enabled ? 0 : chat_setting_get_int(cs->inst, "join_policy", 1);
|
||||
}
|
||||
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);
|
||||
@@ -1405,7 +1407,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
||||
ch_id, name, owner, x25519, NULL, ed_pub, NULL, ch_sig);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: CHANNEL_INVITE channel_put rc=%d ch=%s ch_x25519=%016llx",
|
||||
CS_ID, cprc, ch_id, *(const uint64_t*)x25519);
|
||||
chat_core_ensure_channel_ready(ch_id);
|
||||
chat_core_ensure_channel_ready(cs->inst, ch_id);
|
||||
/* Initiate join: connect back and send CHANNEL_INFO_REQ */
|
||||
chat_sync_join_channel(cs->inst, ch_id, peer);
|
||||
return;
|
||||
@@ -1432,7 +1434,7 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
||||
memcpy(evt + epos, &peer, 8); epos += 8;
|
||||
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);
|
||||
chat_event_post(cs->inst, CHAT_EVT_INVITE_RECEIVED, evt, epos);
|
||||
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);
|
||||
}
|
||||
@@ -1483,7 +1485,8 @@ 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_MEMBER_SYNC, "%s: invite_to_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; }
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs) { DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_to_channel: 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; }
|
||||
@@ -1512,8 +1515,8 @@ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id,
|
||||
/* Already have a handle — connection in progress or established */
|
||||
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;
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1526,28 +1529,27 @@ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_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.
|
||||
But we need to distinguish this from the joiner-side invite flow.
|
||||
Use a separate flag. */
|
||||
g_cs->pending_invite_ch_id = channel_id;
|
||||
g_cs->pending_invite_node_id = target_node_id;
|
||||
g_cs->pending_invite_is_inviter = 1;
|
||||
/* Mark pending: after conn_up, we send CHANNEL_INVITE. */
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
cs->pending_invite_is_inviter = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Already connected — send invite now, wait for joiner to respond */
|
||||
cs_send_channel_invite(g_cs, inst, ch_id, target_node_id, ch_name, owner, ch_x25519, ch_ed, ch_sig);
|
||||
g_cs->pending_invite_ch_id = channel_id;
|
||||
g_cs->pending_invite_node_id = target_node_id;
|
||||
g_cs->pending_invite_is_inviter = 1;
|
||||
if (g_cs->invite_send_timer) { uasync_cancel_timeout(inst->ua, g_cs->invite_send_timer); }
|
||||
g_cs->invite_send_timer = uasync_set_timeout(inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, g_cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
cs_send_channel_invite(cs, inst, ch_id, target_node_id, ch_name, owner, ch_x25519, ch_ed, ch_sig);
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
cs->pending_invite_is_inviter = 1;
|
||||
if (cs->invite_send_timer) { uasync_cancel_timeout(inst->ua, cs->invite_send_timer); }
|
||||
cs->invite_send_timer = uasync_set_timeout(inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
}
|
||||
|
||||
/* ─── chat_sync_invite_to_channel_with_addrs: как invite_to_channel, но с адресами ─── */
|
||||
|
||||
struct cs_invite_wrap {
|
||||
struct UTUN_INSTANCE* inst;
|
||||
uint64_t channel_id;
|
||||
uint64_t target_node_id;
|
||||
uint8_t pubkey[32];
|
||||
@@ -1558,8 +1560,9 @@ struct cs_invite_wrap {
|
||||
|
||||
static void cs_invite_trampoline(void* arg) {
|
||||
struct cs_invite_wrap* w = (struct cs_invite_wrap*)arg;
|
||||
if (!g_cs || !g_cs->inst) { u_free(w); return; }
|
||||
struct UTUN_INSTANCE* inst = g_cs->inst;
|
||||
struct chat_sync* cs = cs_of(w->inst);
|
||||
if (!cs || !cs->inst) { u_free(w); return; }
|
||||
struct UTUN_INSTANCE* inst = cs->inst;
|
||||
uint64_t channel_id = w->channel_id;
|
||||
uint64_t target_node_id = w->target_node_id;
|
||||
|
||||
@@ -1577,13 +1580,13 @@ static void cs_invite_trampoline(void* arg) {
|
||||
char ch_name[128]; uint8_t ch_x2[32], ch_ed2[32], ch_sig[64]; uint64_t ch_owner;
|
||||
if (topo_node_sqlite_channel_get(inst->topo_sqlite_db,
|
||||
ch_id, ch_name, (int)sizeof(ch_name), &ch_owner, ch_x2, ch_ed2, ch_sig) == 0) {
|
||||
cs_send_channel_invite(g_cs, inst, ch_id, target_node_id, ch_name, ch_owner, ch_x2, ch_ed2, ch_sig);
|
||||
g_cs->pending_invite_ch_id = channel_id;
|
||||
g_cs->pending_invite_node_id = target_node_id;
|
||||
g_cs->pending_invite_is_inviter = 1;
|
||||
if (g_cs->invite_send_timer) { uasync_cancel_timeout(inst->ua, g_cs->invite_send_timer); }
|
||||
g_cs->invite_send_timer = uasync_set_timeout(inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, g_cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
cs_send_channel_invite(cs, inst, ch_id, target_node_id, ch_name, ch_owner, ch_x2, ch_ed2, ch_sig);
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
cs->pending_invite_is_inviter = 1;
|
||||
if (cs->invite_send_timer) { uasync_cancel_timeout(inst->ua, cs->invite_send_timer); }
|
||||
cs->invite_send_timer = uasync_set_timeout(inst->ua,
|
||||
CS_INVITE_SEND_TIMEOUT_MS * 10, cs, cs_invite_send_timeout_cb, "cs_invite_send");
|
||||
}
|
||||
u_free(w); return;
|
||||
}
|
||||
@@ -1629,15 +1632,15 @@ static void cs_invite_trampoline(void* arg) {
|
||||
u_free(ni); u_free(w); return;
|
||||
}
|
||||
|
||||
g_cs->pending_invite_ch_id = channel_id;
|
||||
g_cs->pending_invite_node_id = target_node_id;
|
||||
g_cs->pending_invite_is_inviter = 1;
|
||||
cs->pending_invite_ch_id = channel_id;
|
||||
cs->pending_invite_node_id = target_node_id;
|
||||
cs->pending_invite_is_inviter = 1;
|
||||
|
||||
int r = topo_group_invite_to_channel(inst, channel_id, ni, target_node_id);
|
||||
if (r < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs topo_group_invite_to_channel 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;
|
||||
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0;
|
||||
cs->pending_invite_is_inviter = 0;
|
||||
}
|
||||
|
||||
while (ni->v4_addrs) { struct TOPO_ADDR4* n = ni->v4_addrs->next; u_free(ni->v4_addrs); ni->v4_addrs = n; }
|
||||
@@ -1651,7 +1654,8 @@ void chat_sync_invite_to_channel_with_addrs(
|
||||
const uint8_t* pubkey_bin, const uint8_t* addrs_data, int addr_count,
|
||||
int addrs_data_len)
|
||||
{
|
||||
if (!g_cs || !inst || !ch_id || !ch_id[0] || !pubkey_bin || !addrs_data || addr_count <= 0 || addrs_data_len <= 0) {
|
||||
struct chat_sync* cs = cs_of(inst);
|
||||
if (!cs || !inst || !ch_id || !ch_id[0] || !pubkey_bin || !addrs_data || addr_count <= 0 || addrs_data_len <= 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "%s: invite_with_addrs invalid args", CS_ID);
|
||||
return;
|
||||
}
|
||||
@@ -1664,6 +1668,7 @@ void chat_sync_invite_to_channel_with_addrs(
|
||||
|
||||
struct cs_invite_wrap* w = u_calloc(1, sizeof(*w) + (size_t)addrs_data_len);
|
||||
if (!w) return;
|
||||
w->inst = inst;
|
||||
w->channel_id = channel_id;
|
||||
w->target_node_id = target_node_id;
|
||||
memcpy(w->pubkey, pubkey_bin, 32);
|
||||
@@ -1679,7 +1684,7 @@ void chat_sync_invite_to_channel_with_addrs(
|
||||
/* ─── accept/deny incoming invite ─── */
|
||||
|
||||
void chat_sync_accept_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t inviter_node_id) {
|
||||
if (!g_cs || !inst) return;
|
||||
if (!cs_of(inst) || !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_MEMBER_SYNC, "%s: accept_invite invalid params ch=%llu node=%016llx",
|
||||
@@ -1688,13 +1693,13 @@ void chat_sync_accept_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, ui
|
||||
}
|
||||
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_core_ensure_channel_ready(inst, ch_id);
|
||||
chat_sync_join_channel(inst, ch_id, inviter_node_id);
|
||||
}
|
||||
|
||||
void chat_sync_deny_invite(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t inviter_node_id) {
|
||||
(void)inst;
|
||||
if (!g_cs) return;
|
||||
if (!cs_of(inst)) return;
|
||||
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 */
|
||||
|
||||
Reference in new issue
Block a user