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

/*
* 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);
}