|
|
|
|
@ -95,19 +95,19 @@ static struct ETCP_CONN* cs_find_conn_for_node(struct UTUN_INSTANCE* inst, uint6
|
|
|
|
|
|
|
|
|
|
static int cs_send(struct chat_sync* cs, const char* ch_id, uint64_t dst, |
|
|
|
|
const uint8_t* payload, size_t len) { |
|
|
|
|
if (len < 1) return -1; |
|
|
|
|
if (len < 1) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send len<1", CS_ID); return -1; } |
|
|
|
|
uint8_t ch_len = (uint8_t)strlen(ch_id); |
|
|
|
|
if (ch_len > 63) return -1; |
|
|
|
|
if (ch_len > 63) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send ch_len=%u > 63", CS_ID, ch_len); return -1; } |
|
|
|
|
size_t total = 1 + 1 + ch_len + len; |
|
|
|
|
uint8_t* buf = u_malloc(total); |
|
|
|
|
if (!buf) return -1; |
|
|
|
|
if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send alloc(%zu) failed", CS_ID, total); return -1; } |
|
|
|
|
uint8_t* p = buf; |
|
|
|
|
*p++ = ETCP_RT_ID_CHAT_SYNC; |
|
|
|
|
*p++ = ch_len; |
|
|
|
|
memcpy(p, ch_id, ch_len); p += ch_len; |
|
|
|
|
memcpy(p, payload, len); |
|
|
|
|
struct ll_entry* entry = queue_entry_new(0); |
|
|
|
|
if (!entry) { u_free(buf); return -1; } |
|
|
|
|
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send queue_entry_new failed", CS_ID); u_free(buf); return -1; } |
|
|
|
|
entry->dgram = buf; entry->len = total; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: SEND %s to=%016llx ch=%s len=%zu", |
|
|
|
|
CS_ID, cs_msg_name(payload[0]), (unsigned long long)dst, ch_id, len); |
|
|
|
|
@ -150,7 +150,10 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
|
|
|
|
|
static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { |
|
|
|
|
if (!entry || entry->len < 4) { |
|
|
|
|
if (entry) { if (entry->dgram) u_free(entry->dgram); queue_entry_free(entry); } |
|
|
|
|
if (entry) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: recv short entry len=%zu conn=%s", CS_ID, entry->len, conn ? conn->log_name : "?"); |
|
|
|
|
if (entry->dgram) u_free(entry->dgram); queue_entry_free(entry); |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!g_cs || !g_cs->initialized) { u_free(entry->dgram); queue_entry_free(entry); return; } |
|
|
|
|
@ -725,7 +728,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct chat_invite* inv = u_calloc(1, sizeof(struct chat_invite)); |
|
|
|
|
if (!inv) return; |
|
|
|
|
if (!inv) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite calloc failed", CS_ID); return; } |
|
|
|
|
|
|
|
|
|
inv->channel_id = channel_id; |
|
|
|
|
inv->node_id = node_id; |
|
|
|
|
@ -733,7 +736,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
|
|
|
|
|
|
|
|
|
size_t addrs_sz = addrs_data_len > 0 ? (size_t)addrs_data_len : (size_t)addr_count * 9; |
|
|
|
|
inv->addrs_data = u_malloc(addrs_sz); |
|
|
|
|
if (!inv->addrs_data) { u_free(inv); return; } |
|
|
|
|
if (!inv->addrs_data) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite malloc(%zu) failed", CS_ID, addrs_sz); u_free(inv); return; } |
|
|
|
|
memcpy(inv->addrs_data, addrs_data, addrs_sz); |
|
|
|
|
inv->addr_count = addr_count; |
|
|
|
|
|
|
|
|
|
@ -765,7 +768,9 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id,
|
|
|
|
|
/* ─── 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 || !inst || !ch_id || !ch_id[0]) return; |
|
|
|
|
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; } |
|
|
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: inst=NULL", CS_ID); return; } |
|
|
|
|
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: ch_id NULL/empty", CS_ID); return; } |
|
|
|
|
uint64_t channel_id = strtoull(ch_id, NULL, 10); |
|
|
|
|
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel invalid ch_id='%s'", CS_ID, ch_id); return; } |
|
|
|
|
|
|
|
|
|
@ -832,7 +837,7 @@ static int _get_node_name(sqlite3* db, uint64_t node_id, char* out, size_t sz) {
|
|
|
|
|
if (!db || !out || !sz) return -1; |
|
|
|
|
sqlite3_stmt* st = NULL; |
|
|
|
|
sqlite3_prepare_v2(db, "SELECT name FROM nodes WHERE node_id=?", -1, &st, NULL); |
|
|
|
|
if (!st) return -1; |
|
|
|
|
if (!st) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: _get_node_name prepare failed node=0x%016llx", CS_ID, (unsigned long long)node_id); return -1; } |
|
|
|
|
sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id); |
|
|
|
|
int rc = -1; |
|
|
|
|
if (sqlite3_step(st) == SQLITE_ROW) { |
|
|
|
|
@ -956,7 +961,9 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
uint8_t inv_flags = *p++; |
|
|
|
|
const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0; |
|
|
|
|
if (inv_flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
if (p + 72 > pl + len) return; inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } |
|
|
|
|
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP truncated at inviter_join_sig peer=%016llx", CS_ID, (unsigned long long)peer); return; } |
|
|
|
|
inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; |
|
|
|
|
} |
|
|
|
|
const uint8_t* inviter_update_sig = p; p += 64; uint64_t inviter_update_ts; |
|
|
|
|
memcpy(&inviter_update_ts, p, 8); p += 8; |
|
|
|
|
uint8_t inv_userinfo_len = *p++; |
|
|
|
|
@ -1157,7 +1164,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
uint8_t sid = *p++; |
|
|
|
|
uint8_t proto = *p++; |
|
|
|
|
int ip_len = (fm == 4) ? 4 : 16; |
|
|
|
|
if (p + ip_len + 2 > pl + len) break; |
|
|
|
|
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN addr truncated node=0x%016llx fm=%u i=%u", CS_ID, (unsigned long long)node_id, fm, i); break; } |
|
|
|
|
const uint8_t* ip = p; p += ip_len; |
|
|
|
|
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; |
|
|
|
|
|
|
|
|
|
@ -1251,14 +1258,14 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
uint16_t pc; memcpy(&pc, p, 2); p += 2; |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME ch=%s from=%016llx peers=%u", CS_ID, ch_id, (unsigned long long)peer, pc); |
|
|
|
|
for (uint16_t i = 0; i < pc; i++) { |
|
|
|
|
if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) break; /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */ |
|
|
|
|
if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME peer[%u] truncated at %td len=%zu", CS_ID, i, p - pl, len); break; } /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */ |
|
|
|
|
uint64_t node_id; memcpy(&node_id, p, 8); p += 8; |
|
|
|
|
const uint8_t* x25519 = p; p += 32; |
|
|
|
|
const uint8_t* ed_pub = p; p += 32; |
|
|
|
|
uint8_t flags = *p++; |
|
|
|
|
const uint8_t* join_sig = NULL; uint64_t join_ts = 0; |
|
|
|
|
if (flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
if (p + 64 + 8 > pl + len) break; |
|
|
|
|
if (p + 64 + 8 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME join_sig truncated node=0x%016llx i=%u", CS_ID, (unsigned long long)node_id, i); break; } |
|
|
|
|
join_sig = p; p += 64; |
|
|
|
|
memcpy(&join_ts, p, 8); p += 8; |
|
|
|
|
} |
|
|
|
|
@ -1313,28 +1320,27 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac); |
|
|
|
|
for (uint8_t j = 0; j < ac; j++) { |
|
|
|
|
if (p + 2 > pl + len) break; |
|
|
|
|
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] header truncated node=0x%016llx", CS_ID, j, (unsigned long long)node_id); break; } |
|
|
|
|
uint8_t fm = *p++; |
|
|
|
|
uint8_t sid = *p++; |
|
|
|
|
uint8_t proto = *p++; |
|
|
|
|
int ip_len = (fm == 4) ? 4 : 16; |
|
|
|
|
if (p + ip_len + 2 > pl + len) break; |
|
|
|
|
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, j, (unsigned long long)node_id, fm); break; } |
|
|
|
|
const uint8_t* ip = p; p += ip_len; |
|
|
|
|
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; |
|
|
|
|
|
|
|
|
|
char sql[256]; snprintf(sql, sizeof(sql), |
|
|
|
|
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" |
|
|
|
|
" VALUES(?,?,?,?,?,0,?)"); |
|
|
|
|
sqlite3_stmt* stmt = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) { |
|
|
|
|
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); |
|
|
|
|
sqlite3_bind_int(stmt, 2, fm); |
|
|
|
|
sqlite3_bind_int(stmt, 3, (int)proto); |
|
|
|
|
sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC); |
|
|
|
|
sqlite3_bind_int(stmt, 5, (int)port); |
|
|
|
|
sqlite3_bind_int(stmt, 6, (int)sid); |
|
|
|
|
sqlite3_step(stmt); sqlite3_finalize(stmt); |
|
|
|
|
} |
|
|
|
|
sqlite3_stmt* stmt2 = NULL; |
|
|
|
|
if (sqlite3_prepare_v2(db, sql, -1, &stmt2, NULL) == SQLITE_OK) { |
|
|
|
|
sqlite3_bind_int64(stmt2, 1, (sqlite3_int64)node_id); |
|
|
|
|
sqlite3_bind_int(stmt2, 2, fm); |
|
|
|
|
sqlite3_bind_blob(stmt2, 3, ip, ip_len, SQLITE_STATIC); |
|
|
|
|
sqlite3_bind_int(stmt2, 4, (int)port); |
|
|
|
|
sqlite3_bind_int(stmt2, 5, (int)sid); |
|
|
|
|
sqlite3_step(stmt2); sqlite3_finalize(stmt2); |
|
|
|
|
} |
|
|
|
|
if (fm == 4) |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d", |
|
|
|
|
CS_ID, (unsigned long long)node_id, sid, ip[0], ip[1], ip[2], ip[3], port); |
|
|
|
|
@ -1427,12 +1433,12 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] PEER_UPSERT save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac); |
|
|
|
|
for (uint8_t i = 0; i < ac; i++) { |
|
|
|
|
if (p + 2 > pl + len) break; |
|
|
|
|
if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] header truncated node=0x%016llx", CS_ID, i, (unsigned long long)node_id); break; } |
|
|
|
|
uint8_t fm = *p++; |
|
|
|
|
uint8_t sid = *p++; |
|
|
|
|
uint8_t proto = *p++; |
|
|
|
|
int ip_len = (fm == 4) ? 4 : 16; |
|
|
|
|
if (p + ip_len + 2 > pl + len) break; |
|
|
|
|
if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, i, (unsigned long long)node_id, fm); break; } |
|
|
|
|
const uint8_t* ip = p; p += ip_len; |
|
|
|
|
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; |
|
|
|
|
|
|
|
|
|
@ -1509,7 +1515,8 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
uint8_t inv_flags = *p++; |
|
|
|
|
const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0; |
|
|
|
|
if (inv_flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
if (p + 72 > pl + len) return; inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } |
|
|
|
|
if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE truncated at join_sig/ts from=%016llx", CS_ID, (unsigned long long)peer); return; } |
|
|
|
|
inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } |
|
|
|
|
/* skip inviter_update_sig/ts/userinfo for now — verify channel sig only */ |
|
|
|
|
p += 64; uint64_t inviter_update_ts; memcpy(&inviter_update_ts, p, 8); p += 8; |
|
|
|
|
uint8_t userinfo_len = *p++; p += userinfo_len; |
|
|
|
|
@ -1583,8 +1590,11 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
/* ─── 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 || !inst || !ch_id || !ch_id[0]) return; |
|
|
|
|
if (target_node_id == 0 || target_node_id == inst->node_id) return; |
|
|
|
|
if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; } |
|
|
|
|
if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: inst=NULL", CS_ID); return; } |
|
|
|
|
if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: ch_id NULL/empty", CS_ID); return; } |
|
|
|
|
if (target_node_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: target_node_id=0", CS_ID); return; } |
|
|
|
|
if (target_node_id == inst->node_id) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: self-invite rejected self=0x%016llx", CS_ID, (unsigned long long)inst->node_id); return; } |
|
|
|
|
|
|
|
|
|
uint64_t channel_id = strtoull(ch_id, NULL, 10); |
|
|
|
|
if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel invalid ch_id='%s'", CS_ID, ch_id); return; } |
|
|
|
|
|