You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
9.4 KiB
190 lines
9.4 KiB
/* |
|
* chat_profile.c — профиль узла: имя, адреса, ui_state |
|
* |
|
* Вынесено из chat_core.c для уменьшения размера модуля. |
|
*/ |
|
|
|
#include "chat_core_priv.h" |
|
#include "chat_event.h" |
|
#include "../../lib/json_flat.h" |
|
#include "../routing_layer/topo_node_sqlite.h" |
|
#include "member_sync.h" |
|
|
|
#include "../utun_instance.h" |
|
#include "../transport_layer/etcp.h" |
|
#include "../transport_layer/secure_channel.h" |
|
#include "../ntp_time.h" |
|
#include "../../lib/u_async.h" |
|
#include "../../lib/mem.h" |
|
#include "../../lib/platform_compat.h" |
|
|
|
#include <openssl/evp.h> |
|
|
|
void chat_core_set_my_node_id(uint64_t node_id) { |
|
g_cc.my_node_id = node_id; |
|
} |
|
|
|
void chat_core_update_my_name(const char* name) { |
|
if (!g_cc.initialized || !name) return; |
|
topo_node_sqlite_node_update_verified(g_cc.db, g_cc.my_node_id, |
|
name, g_cc.inst->my_keys.public_key, g_cc.inst->my_ed25519_pubkey, |
|
(uint64_t)ntp_time_get_seconds(g_cc.inst), 0); |
|
snprintf(g_cc.inst->name, sizeof(g_cc.inst->name), "%s", name); |
|
|
|
uint64_t myid = g_cc.my_node_id; |
|
sqlite3_stmt* cs = NULL; |
|
sqlite3_prepare_v2(g_cc.db, "SELECT channel_id, x25519_pubkey, ed25519_pubkey FROM channels", -1, &cs, NULL); |
|
if (cs) { |
|
while (sqlite3_step(cs) == SQLITE_ROW) { |
|
const char* ch = (const char*)sqlite3_column_text(cs, 0); |
|
const uint8_t* ch_x25519 = sqlite3_column_blob(cs, 1); |
|
const uint8_t* ch_ed25519 = sqlite3_column_blob(cs, 2); |
|
if (!ch || !ch_x25519 || !ch_ed25519) continue; |
|
char tbl[80]; peers_table_name(ch, tbl, sizeof(tbl)); |
|
char buf[256]; snprintf(buf, sizeof(buf), "SELECT 1 FROM \"%s\" WHERE node_id=?", tbl); |
|
sqlite3_stmt* ps = NULL; |
|
if (sqlite3_prepare_v2(g_cc.db, buf, -1, &ps, NULL) == SQLITE_OK) { |
|
sqlite3_bind_int64(ps, 1, (sqlite3_int64)myid); |
|
if (sqlite3_step(ps) == SQLITE_ROW) { |
|
uint8_t join_msg[256]; size_t mlen = 0; |
|
memcpy(join_msg + mlen, ch_x25519, 32); mlen += 32; |
|
memcpy(join_msg + mlen, ch_ed25519, 32); mlen += 32; |
|
memcpy(join_msg + mlen, &myid, 8); mlen += 8; |
|
memcpy(join_msg + mlen, g_cc.inst->my_keys.public_key, 32); mlen += 32; |
|
uint64_t join_ts = (uint64_t)ntp_time_get_seconds(g_cc.inst); |
|
memcpy(join_msg + mlen, &join_ts, 8); mlen += 8; |
|
uint8_t new_sig[64]; memset(new_sig, 0, 64); |
|
EVP_PKEY* pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, |
|
g_cc.inst->my_ed25519_privkey, 32); |
|
if (pkey) { |
|
EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); |
|
if (mdctx) { |
|
if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) == 1) |
|
EVP_DigestSign(mdctx, new_sig, &(size_t){64}, join_msg, mlen); |
|
EVP_MD_CTX_free(mdctx); |
|
} |
|
EVP_PKEY_free(pkey); |
|
} |
|
char juser[256]; snprintf(juser, sizeof(juser), "{\"name\":\"%s\"}", name); |
|
int r1 = topo_node_sqlite_member_put(g_cc.db, ch, myid, new_sig, join_ts, NULL, 0, |
|
g_cc.inst->my_keys.public_key, g_cc.inst->my_ed25519_pubkey, juser, NULL, NULL, NULL, 0); |
|
if (r1 != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r1); |
|
int r2 = member_sync_put(g_cc.inst, ch, myid, g_cc.inst->my_keys.public_key, |
|
g_cc.inst->my_ed25519_pubkey, new_sig, join_ts, NULL, 0, juser, NULL, 0, NULL, NULL, 0); |
|
if (r2 != 0) DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: member_sync_put(my_name) FAILED ch=%s rc=%d", CC_ID, ch, r2); |
|
uint8_t evt[65]; uint8_t cl = (uint8_t)strlen(ch); |
|
evt[0] = cl; memcpy(evt + 1, ch, cl); |
|
chat_event_post(CHAT_EVT_MEMBERS_CHANGED, evt, 1 + cl); |
|
} |
|
sqlite3_finalize(ps); |
|
} |
|
} |
|
sqlite3_finalize(cs); |
|
} |
|
} |
|
|
|
void chat_core_update_my_name_trampoline(void* arg) { |
|
chat_core_update_my_name((const char*)arg); |
|
u_free(arg); |
|
} |
|
|
|
void chat_core_sync_my_addresses(void) { |
|
if (!g_cc.initialized || !g_cc.db || !g_cc.inst) return; |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] sync_my_addresses START my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id); |
|
|
|
sqlite3_stmt* del = NULL; |
|
sqlite3_prepare_v2(g_cc.db, "DELETE FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &del, NULL); |
|
if (del) { |
|
sqlite3_bind_int64(del, 1, (sqlite3_int64)g_cc.my_node_id); |
|
sqlite3_step(del); |
|
int deleted = sqlite3_changes(g_cc.db); |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] DELETE addr_type=0 for my_node=0x%016llx: %d rows deleted", CC_ID, (unsigned long long)g_cc.my_node_id, deleted); |
|
sqlite3_finalize(del); |
|
} |
|
|
|
sqlite3_stmt* ins = NULL; |
|
sqlite3_prepare_v2(g_cc.db, |
|
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" |
|
" VALUES(?,?,1,?,?,0,?)", -1, &ins, NULL); |
|
if (!ins) { |
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] FAIL prepare INSERT stmt my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id); |
|
return; |
|
} |
|
|
|
struct ETCP_SOCKET* sock = g_cc.inst->etcp_sockets; |
|
int sock_count = 0, written = 0; |
|
while (sock) { |
|
sock_count++; |
|
int sock_family = sock->local_addr.ss_family ? sock->local_addr.ss_family : 0; |
|
struct sockaddr_storage* sa = (sock->interface_addr.ss_family == sock_family) ? &sock->interface_addr : NULL; |
|
if (!sa) sa = sock->local_addr.ss_family ? &sock->local_addr : NULL; |
|
if (!sa) { DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] socket %d — no address for family=%d", CC_ID, sock_count, sock_family); sock = sock->next; continue; } |
|
|
|
if (sa->ss_family == AF_INET) { |
|
struct sockaddr_in* sin = (struct sockaddr_in*)sa; |
|
sqlite3_bind_int64(ins, 1, (sqlite3_int64)g_cc.my_node_id); |
|
sqlite3_bind_int(ins, 2, 4); |
|
sqlite3_bind_blob(ins, 3, &sin->sin_addr, 4, SQLITE_STATIC); |
|
sqlite3_bind_int(ins, 4, (int)ntohs(sin->sin_port)); |
|
sqlite3_bind_int(ins, 5, (int)sock->sock_id); |
|
sqlite3_step(ins); sqlite3_reset(ins); |
|
uint8_t* ip = (uint8_t*)&sin->sin_addr; |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT my_node=0x%016llx sock=%d %d.%d.%d.%d:%d", |
|
CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, ip[0], ip[1], ip[2], ip[3], (int)ntohs(sin->sin_port)); |
|
written++; |
|
} else if (sa->ss_family == AF_INET6) { |
|
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; |
|
sqlite3_bind_int64(ins, 1, (sqlite3_int64)g_cc.my_node_id); |
|
sqlite3_bind_int(ins, 2, 6); |
|
sqlite3_bind_blob(ins, 3, &sin6->sin6_addr, 16, SQLITE_STATIC); |
|
sqlite3_bind_int(ins, 4, (int)ntohs(sin6->sin6_port)); |
|
sqlite3_bind_int(ins, 5, (int)sock->sock_id); |
|
sqlite3_step(ins); sqlite3_reset(ins); |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] INSERT v6 my_node=0x%016llx sock=%d port=%d", |
|
CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, (int)ntohs(sin6->sin6_port)); |
|
written++; |
|
} |
|
sock = sock->next; |
|
} |
|
sqlite3_finalize(ins); |
|
|
|
if (sock_count == 0) |
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] etcp_sockets is NULL — NO sockets, addresses NOT written!", CC_ID); |
|
else if (written == 0) |
|
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] %d sockets found but 0 addresses written (all have no interface_addr nor local_addr)", CC_ID, sock_count); |
|
else |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] DONE: %d of %d sockets written, my_node=0x%016llx", |
|
CC_ID, written, sock_count, (unsigned long long)g_cc.my_node_id); |
|
|
|
sqlite3_stmt* chk = NULL; |
|
sqlite3_prepare_v2(g_cc.db, "SELECT COUNT(*) FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &chk, NULL); |
|
if (chk) { |
|
sqlite3_bind_int64(chk, 1, (sqlite3_int64)g_cc.my_node_id); |
|
int cnt = sqlite3_step(chk) == SQLITE_ROW ? sqlite3_column_int(chk, 0) : -1; |
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] VERIFY: total addr_type=0 rows for my_node=0x%016llx = %d", |
|
CC_ID, (unsigned long long)g_cc.my_node_id, cnt); |
|
sqlite3_finalize(chk); |
|
} |
|
} |
|
|
|
void chat_core_save_ui_state(const char* key, const char* value) { |
|
if (!g_cc.initialized || !key || !value) return; |
|
sqlite3_stmt* st = NULL; |
|
sqlite3_prepare_v2(g_cc.db, |
|
"INSERT OR REPLACE INTO ui_state(key, value) VALUES(?, ?)", -1, &st, NULL); |
|
if (st) { |
|
sqlite3_bind_text(st, 1, key, -1, SQLITE_STATIC); |
|
sqlite3_bind_text(st, 2, value, -1, SQLITE_STATIC); |
|
sqlite3_step(st); sqlite3_finalize(st); |
|
} |
|
} |
|
|
|
struct save_ui_state_arg { char data[256]; }; |
|
void chat_core_save_ui_state_trampoline(void* arg) { |
|
struct save_ui_state_arg* a = (struct save_ui_state_arg*)arg; |
|
const char* key = a->data; |
|
const char* value = key + strlen(key) + 1; |
|
chat_core_save_ui_state(key, value); |
|
u_free(arg); |
|
}
|
|
|