|
|
|
|
@ -47,10 +47,12 @@ struct chat_sync {
|
|
|
|
|
void* info_req_timer; |
|
|
|
|
void* join_timer; |
|
|
|
|
void* sync_timer; |
|
|
|
|
void* invite_send_timer; /* timer waiting for joiner to respond to CHANNEL_INVITE */ |
|
|
|
|
uint8_t initialized; |
|
|
|
|
uint8_t sync_scheduled; |
|
|
|
|
uint64_t pending_invite_ch_id; |
|
|
|
|
uint64_t pending_invite_node_id; |
|
|
|
|
uint8_t pending_invite_is_inviter; /* 1 = inviter sends CHANNEL_INVITE on conn_up, 0 = joiner sends CHANNEL_INFO_REQ */ |
|
|
|
|
char pending_password[128]; /* пароль для CHANNEL_INFO_REQ */ |
|
|
|
|
/* Pending incoming invites (для ask/deny) */ |
|
|
|
|
uint64_t pending_inv_in_ch_id[4]; |
|
|
|
|
@ -61,6 +63,7 @@ struct chat_sync {
|
|
|
|
|
#define CS_ID "chat_sync" |
|
|
|
|
#define CS_INFO_REQ_TIMEOUT_MS 5000 |
|
|
|
|
#define CS_JOIN_TIMEOUT_MS 8000 |
|
|
|
|
#define CS_INVITE_SEND_TIMEOUT_MS 3000 /* inviter waits for joiner to respond */ |
|
|
|
|
#define CS_SYNC_INTERVAL_MS 1000 |
|
|
|
|
|
|
|
|
|
static const char* cs_msg_name(uint8_t type) { |
|
|
|
|
@ -86,6 +89,7 @@ static const char* cs_msg_name(uint8_t type) {
|
|
|
|
|
static void cs_cancel_proto_timers(struct chat_sync* cs) { |
|
|
|
|
if (cs->info_req_timer) { uasync_cancel_timeout(cs->inst->ua, cs->info_req_timer); cs->info_req_timer = NULL; } |
|
|
|
|
if (cs->join_timer) { uasync_cancel_timeout(cs->inst->ua, cs->join_timer); cs->join_timer = NULL; } |
|
|
|
|
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ── Forward decl ── */ |
|
|
|
|
@ -145,6 +149,9 @@ static void cs_handle_peer_remove(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
const char* ch_id, const uint8_t* pl, size_t len); |
|
|
|
|
static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer, |
|
|
|
|
const char* ch_id, const uint8_t* pl, size_t len); |
|
|
|
|
static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* inst, |
|
|
|
|
const char* ch_id, uint64_t target_node_id, const char* ch_name, |
|
|
|
|
const uint8_t* ch_x25519, const uint8_t* ch_ed, const uint8_t* ch_sig); |
|
|
|
|
|
|
|
|
|
/* ── Recv dispatcher ── */ |
|
|
|
|
|
|
|
|
|
@ -226,6 +233,23 @@ static void cs_join_timeout_cb(void* arg) {
|
|
|
|
|
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20); |
|
|
|
|
cs->pending_invite_node_id = 0; |
|
|
|
|
cs->pending_invite_ch_id = 0; |
|
|
|
|
cs->pending_invite_is_inviter = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cs_invite_send_timeout_cb(void* arg) { |
|
|
|
|
struct chat_sync* cs = (struct chat_sync*)arg; |
|
|
|
|
if (!cs || !cs->initialized) return; |
|
|
|
|
cs->invite_send_timer = NULL; |
|
|
|
|
uint64_t peer = cs->pending_invite_node_id; |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE timeout — joiner did not respond peer=%016llx ch=%llu", |
|
|
|
|
CS_ID, (unsigned long long)peer, (unsigned long long)cs->pending_invite_ch_id); |
|
|
|
|
uint8_t err[20]; memcpy(err, &peer, 8); |
|
|
|
|
int r = CONN_EVENT_TIMEOUT; memcpy(err + 8, &r, 4); |
|
|
|
|
memcpy(err + 12, &cs->pending_invite_ch_id, 8); |
|
|
|
|
chat_event_post(CHAT_EVT_CONNECT_RESULT, err, 20); |
|
|
|
|
cs->pending_invite_node_id = 0; |
|
|
|
|
cs->pending_invite_ch_id = 0; |
|
|
|
|
cs->pending_invite_is_inviter = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ── helper: find active ETCP_CONN for node ── */ |
|
|
|
|
@ -447,7 +471,21 @@ static void cs_on_conn_up(struct ETCP_CONN* conn, int event, void* arg) { (void)
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_DB_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) { |
|
|
|
|
/* 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); |
|
|
|
|
char ch_name[128]; uint8_t ch_x2[32], ch_ed2[32], ch_sig[64]; |
|
|
|
|
if (topo_node_sqlite_channel_get(g_cs->inst->topo_sqlite_db, |
|
|
|
|
ch_id, ch_name, (int)sizeof(ch_name), NULL, ch_x2, ch_ed2, ch_sig) == 0) { |
|
|
|
|
cs_send_channel_invite(g_cs, g_cs->inst, ch_id, peer, ch_name, 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"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
cs_start_channel_join(g_cs, peer); |
|
|
|
|
} |
|
|
|
|
cs_on_peer_status_changed(peer, 1); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
@ -590,6 +628,7 @@ void chat_sync_destroy(struct UTUN_INSTANCE* inst) {
|
|
|
|
|
if (!cs || !inst) return; |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_DB_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_destroy(inst); |
|
|
|
|
cs->initialized = 0; g_cs = NULL; |
|
|
|
|
@ -855,6 +894,9 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
const char* ch_id, const uint8_t* pl, size_t len) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: INFO_REQ ch=%s from=%016llx len=%zu", CS_ID, ch_id, (unsigned long long)peer, len); |
|
|
|
|
|
|
|
|
|
/* joiner responded to our CHANNEL_INVITE — cancel invite send timer */ |
|
|
|
|
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; } |
|
|
|
|
|
|
|
|
|
/* Parse password from request (v2 format: type + pass_len + optional_password) */ |
|
|
|
|
char req_password[128] = ""; |
|
|
|
|
if (len >= 1) { |
|
|
|
|
@ -1241,6 +1283,19 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN starting member_sync with joiner node=0x%016llx ch=%s done_cb=%s", |
|
|
|
|
CS_ID, (unsigned long long)node_id, ch_id, sa ? "yes" : "no"); |
|
|
|
|
|
|
|
|
|
/* if we're the inviter — joiner joined successfully, notify GUI */ |
|
|
|
|
if (cs->pending_invite_ch_id != 0 && cs->pending_invite_is_inviter) { |
|
|
|
|
uint64_t ch_id_num = strtoull(ch_id, NULL, 10); |
|
|
|
|
uint8_t evt[20]; memcpy(evt, &node_id, 8); int r = 0; memcpy(evt + 8, &r, 4); |
|
|
|
|
memcpy(evt + 12, &ch_id_num, 8); |
|
|
|
|
chat_event_post(CHAT_EVT_CONNECT_RESULT, evt, 20); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN posted CHAT_EVT_CONNECT_RESULT to GUI node=0x%016llx ch=%s", |
|
|
|
|
CS_ID, (unsigned long long)node_id, ch_id); |
|
|
|
|
cs->pending_invite_node_id = 0; cs->pending_invite_ch_id = 0; |
|
|
|
|
cs->pending_invite_is_inviter = 0; |
|
|
|
|
if (cs->invite_send_timer) { uasync_cancel_timeout(cs->inst->ua, cs->invite_send_timer); cs->invite_send_timer = NULL; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN accepted node=0x%016llx ch=%s addrs=%d", |
|
|
|
|
CS_ID, (unsigned long long)node_id, ch_id, addr_cnt); |
|
|
|
|
} |
|
|
|
|
@ -1587,6 +1642,50 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ─── helper: build and send CS_MSG_CHANNEL_INVITE to peer ─── */ |
|
|
|
|
|
|
|
|
|
static int cs_send_channel_invite(struct chat_sync* cs, struct UTUN_INSTANCE* inst, |
|
|
|
|
const char* ch_id, uint64_t target_node_id, |
|
|
|
|
const char* ch_name, const uint8_t* ch_x25519, |
|
|
|
|
const uint8_t* ch_ed, const uint8_t* ch_sig) { |
|
|
|
|
uint64_t owner = inst->node_id; |
|
|
|
|
uint8_t join_sig[64] = {0}; uint64_t join_ts = 0; |
|
|
|
|
{ sqlite3* vdb = inst->topo_sqlite_db; |
|
|
|
|
topo_node_sqlite_member_get_join(vdb, ch_id, inst->node_id, join_sig, &join_ts); } |
|
|
|
|
uint8_t upd_sig[64] = {0}; uint64_t upd_ts = (uint64_t)ntp_time_get_seconds(inst); |
|
|
|
|
{ |
|
|
|
|
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", inst->name[0] ? inst->name : ""); |
|
|
|
|
uint8_t umsg[256]; size_t ulen = 0; |
|
|
|
|
memcpy(umsg + ulen, join_sig, 64); ulen += 64; |
|
|
|
|
memcpy(umsg + ulen, &upd_ts, 8); ulen += 8; |
|
|
|
|
size_t jl = strlen(juser); memcpy(umsg + ulen, juser, jl); umsg[ulen + jl] = '\0'; ulen += jl + 1; |
|
|
|
|
cs_ed25519_sign(inst->my_ed25519_privkey, umsg, ulen, upd_sig); |
|
|
|
|
} |
|
|
|
|
uint8_t buf[1024]; size_t boff = 0; |
|
|
|
|
buf[boff++] = CS_MSG_CHANNEL_INVITE; |
|
|
|
|
uint8_t cnl = (uint8_t)strlen(ch_name); |
|
|
|
|
buf[boff++] = cnl; memcpy(buf + boff, ch_name, cnl); boff += cnl; |
|
|
|
|
memcpy(buf + boff, &owner, 8); boff += 8; |
|
|
|
|
memcpy(buf + boff, ch_x25519, 32); boff += 32; |
|
|
|
|
memcpy(buf + boff, ch_ed, 32); boff += 32; |
|
|
|
|
memcpy(buf + boff, ch_sig, 64); boff += 64; |
|
|
|
|
uint8_t inv_flags = (join_sig[0] || join_ts) ? PEERS_FLAG_HAS_JOIN : 0; |
|
|
|
|
buf[boff++] = inv_flags; |
|
|
|
|
if (inv_flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
memcpy(buf + boff, join_sig, 64); boff += 64; |
|
|
|
|
memcpy(buf + boff, &join_ts, 8); boff += 8; |
|
|
|
|
} |
|
|
|
|
memcpy(buf + boff, upd_sig, 64); boff += 64; |
|
|
|
|
memcpy(buf + boff, &upd_ts, 8); boff += 8; |
|
|
|
|
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", inst->name[0] ? inst->name : ""); |
|
|
|
|
uint8_t il = (uint8_t)strlen(juser); |
|
|
|
|
buf[boff++] = il; memcpy(buf + boff, juser, il); boff += il; |
|
|
|
|
int rc = cs_send(cs, ch_id, target_node_id, buf, boff); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s rc=%d", |
|
|
|
|
CS_ID, (unsigned long long)target_node_id, ch_id, rc); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ─── chat_sync_invite_to_channel: пригласить узел в наш канал ─── */ |
|
|
|
|
|
|
|
|
|
void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id) { |
|
|
|
|
@ -1644,46 +1743,145 @@ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id,
|
|
|
|
|
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; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Already connected — send invite now */ |
|
|
|
|
uint8_t join_sig[64] = {0}; uint64_t join_ts = 0; |
|
|
|
|
{ sqlite3* vdb = inst->topo_sqlite_db; |
|
|
|
|
topo_node_sqlite_member_get_join(vdb, ch_id, inst->node_id, join_sig, &join_ts); } |
|
|
|
|
uint8_t upd_sig[64] = {0}; uint64_t upd_ts = (uint64_t)ntp_time_get_seconds(inst); |
|
|
|
|
{ |
|
|
|
|
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", inst->name[0] ? inst->name : ""); |
|
|
|
|
uint8_t umsg[256]; size_t ulen = 0; |
|
|
|
|
memcpy(umsg + ulen, join_sig, 64); ulen += 64; |
|
|
|
|
memcpy(umsg + ulen, &upd_ts, 8); ulen += 8; |
|
|
|
|
size_t jl = strlen(juser); memcpy(umsg + ulen, juser, jl); umsg[ulen + jl] = '\0'; ulen += jl + 1; |
|
|
|
|
cs_ed25519_sign(inst->my_ed25519_privkey, umsg, ulen, upd_sig); |
|
|
|
|
/* Already connected — send invite now, wait for joiner to respond */ |
|
|
|
|
cs_send_channel_invite(g_cs, inst, ch_id, target_node_id, ch_name, 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"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ─── chat_sync_invite_to_channel_with_addrs: как invite_to_channel, но с адресами ─── */ |
|
|
|
|
|
|
|
|
|
struct cs_invite_wrap { |
|
|
|
|
uint64_t channel_id; |
|
|
|
|
uint64_t target_node_id; |
|
|
|
|
uint8_t pubkey[32]; |
|
|
|
|
int addr_count; |
|
|
|
|
int addrs_len; |
|
|
|
|
uint8_t addrs_data[]; /* flexible array */ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
uint64_t channel_id = w->channel_id; |
|
|
|
|
uint64_t target_node_id = w->target_node_id; |
|
|
|
|
|
|
|
|
|
if (channel_id == 0 || target_node_id == 0 || target_node_id == inst->node_id) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid params ch=%llu target=0x%016llx", |
|
|
|
|
CS_ID, (unsigned long long)channel_id, (unsigned long long)target_node_id); |
|
|
|
|
u_free(w); return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint8_t buf[1024]; size_t boff = 0; |
|
|
|
|
buf[boff++] = CS_MSG_CHANNEL_INVITE; |
|
|
|
|
uint8_t cnl = (uint8_t)strlen(ch_name); |
|
|
|
|
buf[boff++] = cnl; memcpy(buf + boff, ch_name, cnl); boff += cnl; |
|
|
|
|
memcpy(buf + boff, &owner, 8); boff += 8; |
|
|
|
|
memcpy(buf + boff, ch_x25519, 32); boff += 32; |
|
|
|
|
memcpy(buf + boff, ch_ed, 32); boff += 32; |
|
|
|
|
memcpy(buf + boff, ch_sig, 64); boff += 64; |
|
|
|
|
uint8_t inv_flags = (join_sig[0] || join_ts) ? PEERS_FLAG_HAS_JOIN : 0; |
|
|
|
|
buf[boff++] = inv_flags; |
|
|
|
|
if (inv_flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
memcpy(buf + boff, join_sig, 64); boff += 64; |
|
|
|
|
memcpy(buf + boff, &join_ts, 8); boff += 8; |
|
|
|
|
char ch_id[64]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)channel_id); |
|
|
|
|
|
|
|
|
|
/* Check if already connected */ |
|
|
|
|
struct ETCP_CONN* conn = cs_find_conn_for_node(inst, target_node_id); |
|
|
|
|
if (conn && conn->links_up && conn->initialized) { |
|
|
|
|
char ch_name[128]; uint8_t ch_x2[32], ch_ed2[32], ch_sig[64]; |
|
|
|
|
if (topo_node_sqlite_channel_get(inst->topo_sqlite_db, |
|
|
|
|
ch_id, ch_name, (int)sizeof(ch_name), NULL, ch_x2, ch_ed2, ch_sig) == 0) { |
|
|
|
|
cs_send_channel_invite(g_cs, inst, ch_id, target_node_id, ch_name, 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"); |
|
|
|
|
} |
|
|
|
|
u_free(w); return; |
|
|
|
|
} |
|
|
|
|
memcpy(buf + boff, upd_sig, 64); boff += 64; |
|
|
|
|
memcpy(buf + boff, &upd_ts, 8); boff += 8; |
|
|
|
|
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", inst->name[0] ? inst->name : ""); |
|
|
|
|
uint8_t il = (uint8_t)strlen(juser); |
|
|
|
|
buf[boff++] = il; memcpy(buf + boff, juser, il); boff += il; |
|
|
|
|
|
|
|
|
|
cs_send(g_cs, ch_id, target_node_id, buf, boff); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: sent CHANNEL_INVITE to 0x%016llx ch=%s", |
|
|
|
|
CS_ID, (unsigned long long)target_node_id, ch_id); |
|
|
|
|
/* Not connected — build TOPO_NODE with addresses and connect */ |
|
|
|
|
if (!inst->topo_groups) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs — no topo_groups, cannot connect", CS_ID); |
|
|
|
|
u_free(w); return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni)); |
|
|
|
|
if (!ni) { u_free(w); return; } |
|
|
|
|
ni->node_id = target_node_id; memcpy(ni->public_key, w->pubkey, 32); |
|
|
|
|
|
|
|
|
|
const uint8_t* ap = w->addrs_data; |
|
|
|
|
const uint8_t* ap_end = ap + w->addrs_len; |
|
|
|
|
for (int i = 0; i < w->addr_count && ap + 1 <= ap_end; i++) { |
|
|
|
|
uint8_t family = *ap++; uint8_t sock_id = *ap++; uint8_t proto = *ap++; |
|
|
|
|
if (family == 4 && ap + 6 <= ap_end) { |
|
|
|
|
struct TOPO_ADDR4* a4 = u_calloc(1, sizeof(*a4)); |
|
|
|
|
if (!a4) break; |
|
|
|
|
memcpy(a4->addr, ap, 4); ap += 4; |
|
|
|
|
a4->port = ((uint16_t)ap[0] << 8) | ap[1]; ap += 2; |
|
|
|
|
a4->type = TOPO_ADDR_NAT; a4->protocol = proto; |
|
|
|
|
a4->next = ni->v4_addrs; ni->v4_addrs = a4; |
|
|
|
|
} else if (family == 6 && ap + 18 <= ap_end) { |
|
|
|
|
struct TOPO_ADDR6* a6 = u_calloc(1, sizeof(*a6)); |
|
|
|
|
if (!a6) break; |
|
|
|
|
memcpy(a6->addr, ap, 16); ap += 16; |
|
|
|
|
a6->port = ((uint16_t)ap[0] << 8) | ap[1]; ap += 2; |
|
|
|
|
a6->type = TOPO_ADDR_NAT; a6->protocol = proto; |
|
|
|
|
a6->next = ni->v6_addrs; ni->v6_addrs = a6; |
|
|
|
|
} else { break; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ni->v4_addrs && !ni->v6_addrs) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs no valid addrs for node=0x%016llx", |
|
|
|
|
CS_ID, (unsigned long long)target_node_id); |
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
int r = conn_mgr_open_invite(inst, channel_id, ni, target_node_id, cs_invite_conn_cb, NULL, NULL); |
|
|
|
|
if (r < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs conn_mgr_open_invite 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void chat_sync_invite_to_channel_with_addrs( |
|
|
|
|
struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id, |
|
|
|
|
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) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid args", CS_ID); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
uint64_t channel_id = strtoull(ch_id, NULL, 10); |
|
|
|
|
if (channel_id == 0 || target_node_id == 0 || target_node_id == inst->node_id) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs invalid params ch=%s target=0x%016llx", |
|
|
|
|
CS_ID, ch_id, (unsigned long long)target_node_id); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct cs_invite_wrap* w = u_calloc(1, sizeof(*w) + (size_t)addrs_data_len); |
|
|
|
|
if (!w) return; |
|
|
|
|
w->channel_id = channel_id; |
|
|
|
|
w->target_node_id = target_node_id; |
|
|
|
|
memcpy(w->pubkey, pubkey_bin, 32); |
|
|
|
|
w->addr_count = addr_count; |
|
|
|
|
w->addrs_len = addrs_data_len; |
|
|
|
|
memcpy(w->addrs_data, addrs_data, (size_t)addrs_data_len); |
|
|
|
|
|
|
|
|
|
uasync_post(inst->ua, cs_invite_trampoline, w); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_with_addrs posted to uasync ch=%s target=0x%016llx addrs=%d", |
|
|
|
|
CS_ID, ch_id, (unsigned long long)target_node_id, addr_count); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ─── accept/deny incoming invite ─── */ |
|
|
|
|
|