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:
evgeny committed 2026-09-15 21:09:17 +03:00
1 parent 761f64cf76
commit 73fe99b33f
123 files changed
+14095 -1270

No files matched your search

+17 -20
View File
@@ -38,13 +38,11 @@ struct join_key_entry {
uint64_t expiry_tb; /* timebase (0.1ms) истечения */
};
static struct join_key_entry* g_keys = NULL;
static uint64_t _now_tb(void) { return get_time_tb(); }
static void _keys_purge_expired(void) {
static void _keys_purge_expired(struct UTUN_INSTANCE* inst) {
uint64_t now = _now_tb();
struct join_key_entry** p = &g_keys;
struct join_key_entry** p = &inst->join_keys;
while (*p) {
if ((*p)->expiry_tb <= now) {
struct join_key_entry* r = *p;
@@ -59,30 +57,30 @@ static void _keys_purge_expired(void) {
}
}
static void _keys_put(uint64_t channel_id, uint64_t join_key, uint64_t inviter_id) {
_keys_purge_expired();
static void _keys_put(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t join_key, uint64_t inviter_id) {
_keys_purge_expired(inst);
struct join_key_entry* e = u_malloc(sizeof(*e));
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: join-key alloc failed", CJ_ID); return; }
e->join_key = join_key; e->channel_id = channel_id; e->inviter_id = inviter_id;
e->expiry_tb = _now_tb() + (uint64_t)JOIN_KEY_TTL_SECONDS * 10000ULL;
e->next = g_keys;
g_keys = e;
e->next = inst->join_keys;
inst->join_keys = e;
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: join-key stored key=%016llx ch=%llu inviter=%016llx ttl=%ds",
CJ_ID, (unsigned long long)join_key, (unsigned long long)channel_id,
(unsigned long long)inviter_id, JOIN_KEY_TTL_SECONDS);
}
static struct join_key_entry* _keys_find(uint64_t channel_id, uint64_t join_key) {
_keys_purge_expired();
for (struct join_key_entry* e = g_keys; e; e = e->next)
static struct join_key_entry* _keys_find(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t join_key) {
_keys_purge_expired(inst);
for (struct join_key_entry* e = inst->join_keys; e; e = e->next)
if (e->channel_id == channel_id && e->join_key == join_key) return e;
return NULL;
}
static void _keys_free_all(void) {
struct join_key_entry* e = g_keys;
static void _keys_free_all(struct UTUN_INSTANCE* inst) {
struct join_key_entry* e = inst->join_keys;
while (e) { struct join_key_entry* n = e->next; u_free(e); e = n; }
g_keys = NULL;
inst->join_keys = NULL;
}
/* ── Сериализация member-блока ── */
@@ -142,7 +140,7 @@ void chat_join_process_request(struct UTUN_INSTANCE* inst, uint64_t group_id,
sqlite3* db = inst->topo_sqlite_db;
/* 0. верификация join-ключа: принимаем только выданные нами (инвайтером) ключи */
struct join_key_entry* ke = _keys_find(group_id, join_key);
struct join_key_entry* ke = _keys_find(inst, group_id, join_key);
if (!ke || ke->inviter_id != inst->node_id) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "%s: process_request invalid join key ch=%s from=%016llx key=%016llx — drop",
CJ_ID, ch_id, (unsigned long long)from_node, (unsigned long long)join_key);
@@ -228,7 +226,7 @@ static void join_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
/* payload: [subcmd:1][join_key:8] */
if (plen < 1 + 8) { queue_dgram_free(entry); queue_entry_free(entry); return; }
uint64_t join_key; memcpy(&join_key, payload + 1, 8);
_keys_put(group_id, join_key, from_node);
_keys_put(inst, group_id, join_key, from_node);
} else if (subcmd == JOIN_SUBCMD_REQUEST_FWD) {
/* payload: [subcmd:1][join_key:8][member...] */
if (plen < 1 + 8) { queue_dgram_free(entry); queue_entry_free(entry); return; }
@@ -256,7 +254,7 @@ int chat_join_init(struct UTUN_INSTANCE* inst) {
void chat_join_destroy(struct UTUN_INSTANCE* inst) {
if (!inst) return;
etcp_router_unbind(inst, ETCP_RT_ID_JOIN);
_keys_free_all();
_keys_free_all(inst);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: destroyed", CJ_ID);
}
@@ -267,7 +265,7 @@ void chat_join_register_key(struct UTUN_INSTANCE* inst, uint64_t channel_id,
if (!inst || channel_id == 0 || join_key == 0) return;
/* инвайтер всегда хранит выданный ключ локально — для верификации REQUEST_FWD */
_keys_put(channel_id, join_key, inst->node_id);
_keys_put(inst, channel_id, join_key, inst->node_id);
if (target_node_id == inst->node_id || target_node_id == 0) {
return;
@@ -297,8 +295,7 @@ void chat_join_register_key(struct UTUN_INSTANCE* inst, uint64_t channel_id,
}
uint64_t chat_join_lookup_inviter(struct UTUN_INSTANCE* inst, uint64_t channel_id, uint64_t join_key) {
(void)inst;
struct join_key_entry* e = _keys_find(channel_id, join_key);
struct join_key_entry* e = _keys_find(inst, channel_id, join_key);
return e ? e->inviter_id : 0;
}