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.
 
 
 
 
 
 

203 lines
8.4 KiB

#include "topo_node_sqlite.h"
#include "../../../src/topo_node.h"
#include "../../../lib/debug_config.h"
#include <string.h>
#include <stdio.h>
#define PEERS_JOIN_SIG_SIZE 64
static void sanitize_ch_id(const char* ch_id, char* out, size_t out_sz) {
size_t i = 0;
while (*ch_id && i < out_sz - 1) {
char c = *ch_id++;
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '_')
out[i++] = c;
else
out[i++] = '_';
}
out[i] = '\0';
}
static void peers_table_name(const char* ch_id, char* buf, size_t sz) {
char san[64]; sanitize_ch_id(ch_id, san, sizeof(san));
snprintf(buf, sz, "peers_%s", san);
}
int topo_node_sqlite_init(sqlite3* db) {
if (!db) return -1;
const char* sql =
"CREATE TABLE IF NOT EXISTS nodes ("
" node_id INTEGER PRIMARY KEY,"
" name TEXT,"
" x25519_pubkey BLOB NOT NULL,"
" ed25519_pubkey BLOB,"
" last_seen_at INTEGER,"
" created_at INTEGER DEFAULT (unixepoch())"
");"
"CREATE TABLE IF NOT EXISTS node_addresses ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" node_id INTEGER NOT NULL REFERENCES nodes(node_id) ON DELETE CASCADE,"
" family INTEGER NOT NULL CHECK(family IN (4, 6)),"
" protocol INTEGER NOT NULL DEFAULT 1,"
" address BLOB NOT NULL,"
" port INTEGER NOT NULL CHECK(port > 0 AND port <= 65535),"
" rtt INTEGER,"
" is_nat INTEGER DEFAULT 0,"
" created_at INTEGER DEFAULT (unixepoch())"
");"
"CREATE INDEX IF NOT EXISTS idx_na_node ON node_addresses(node_id);"
"CREATE TABLE IF NOT EXISTS channels ("
" channel_id TEXT PRIMARY KEY,"
" name TEXT NOT NULL,"
" owner_node_id INTEGER,"
" is_dm INTEGER DEFAULT 0,"
" x25519_pubkey BLOB NOT NULL,"
" x25519_privkey BLOB,"
" ed25519_pubkey BLOB NOT NULL,"
" ed25519_privkey BLOB,"
" signature BLOB NOT NULL,"
" last_read_msg_id INTEGER,"
" last_pos_msg_id INTEGER,"
" created_at INTEGER DEFAULT (unixepoch())"
");";
char* err = NULL;
int rc = sqlite3_exec(db, sql, NULL, NULL, &err);
if (rc != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "topo_node_sqlite_init: %s", err);
sqlite3_free(err);
return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "topo_node_sqlite tables initialized");
return 0;
}
int topo_node_sqlite_node_put(sqlite3* db, struct TOPO_NODEQ* nq) {
if (!db || !nq || !nq->node) return -1;
struct TOPO_NODE* ni = nq->node;
sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db,
"INSERT OR REPLACE INTO nodes(node_id, name, x25519_pubkey, ed25519_pubkey, last_seen_at)"
" VALUES(?,?,?,?,unixepoch())", -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ni->node_id);
sqlite3_bind_text(stmt, 2, ni->node_name ? ni->node_name : "", -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 3, ni->public_key, 32, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 4, ni->ed25519_public_key, 32, SQLITE_STATIC);
sqlite3_step(stmt); sqlite3_finalize(stmt);
}
sqlite3_stmt* del_stmt = NULL;
if (sqlite3_prepare_v2(db, "DELETE FROM node_addresses WHERE node_id=?", -1, &del_stmt, NULL) == SQLITE_OK) {
sqlite3_bind_int64(del_stmt, 1, (sqlite3_int64)ni->node_id);
sqlite3_step(del_stmt); sqlite3_finalize(del_stmt);
}
sqlite3_stmt* addr_stmt = NULL;
if (sqlite3_prepare_v2(db,
"INSERT INTO node_addresses(node_id, family, protocol, address, port, rtt, is_nat)"
" VALUES(?,?,?,?,?,?,?)", -1, &addr_stmt, NULL) == SQLITE_OK) {
struct TOPO_ADDR4* a4 = ni->v4_addrs;
while (a4) {
sqlite3_bind_int64(addr_stmt, 1, (sqlite3_int64)ni->node_id);
sqlite3_bind_int(addr_stmt, 2, 4);
sqlite3_bind_int(addr_stmt, 3, a4->protocol);
sqlite3_bind_blob(addr_stmt, 4, a4->addr, 4, SQLITE_STATIC);
sqlite3_bind_int(addr_stmt, 5, a4->port);
sqlite3_bind_null(addr_stmt, 6);
sqlite3_bind_int(addr_stmt, 7, a4->type == 1 ? 1 : 0);
sqlite3_step(addr_stmt); sqlite3_reset(addr_stmt);
a4 = a4->next;
}
struct TOPO_ADDR6* a6 = ni->v6_addrs;
while (a6) {
sqlite3_bind_int64(addr_stmt, 1, (sqlite3_int64)ni->node_id);
sqlite3_bind_int(addr_stmt, 2, 6);
sqlite3_bind_int(addr_stmt, 3, a6->protocol);
sqlite3_bind_blob(addr_stmt, 4, a6->addr, 16, SQLITE_STATIC);
sqlite3_bind_int(addr_stmt, 5, a6->port);
sqlite3_bind_null(addr_stmt, 6);
sqlite3_bind_int(addr_stmt, 7, a6->type == 1 ? 1 : 0);
sqlite3_step(addr_stmt); sqlite3_reset(addr_stmt);
a6 = a6->next;
}
sqlite3_finalize(addr_stmt);
}
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
return 0;
}
int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
const char* name, int is_dm, uint64_t owner_node_id,
const uint8_t* x25519_pub, const uint8_t* x25519_priv,
const uint8_t* ed25519_pub, const uint8_t* ed25519_priv,
const uint8_t* signature) {
if (!db || !channel_id || !name || !x25519_pub || !ed25519_pub || !signature) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[512];
snprintf(sql, sizeof(sql),
"CREATE TABLE IF NOT EXISTS \"%s\" ("
" node_id INTEGER NOT NULL,"
" join_sig BLOB NOT NULL,"
" creator_sig BLOB,"
" comment TEXT,"
" joined_at INTEGER DEFAULT (unixepoch()),"
" PRIMARY KEY (node_id))", peers_tbl);
char* err = NULL;
sqlite3_exec(db, sql, NULL, NULL, &err);
if (err) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "topo_node_sqlite_channel_put peers: %s", err); sqlite3_free(err); }
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db,
"INSERT OR REPLACE INTO channels(channel_id, name, owner_node_id, is_dm,"
" x25519_pubkey, x25519_privkey, ed25519_pubkey, ed25519_privkey, signature)"
" VALUES(?,?,?,?,?,?,?,?,?)", -1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_text(stmt, 1, channel_id, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 3, (sqlite3_int64)owner_node_id);
sqlite3_bind_int(stmt, 4, is_dm);
sqlite3_bind_blob(stmt, 5, x25519_pub, 32, SQLITE_STATIC);
if (x25519_priv) sqlite3_bind_blob(stmt, 6, x25519_priv, 32, SQLITE_STATIC);
else sqlite3_bind_null(stmt, 6);
sqlite3_bind_blob(stmt, 7, ed25519_pub, 32, SQLITE_STATIC);
if (ed25519_priv) sqlite3_bind_blob(stmt, 8, ed25519_priv, 32, SQLITE_STATIC);
else sqlite3_bind_null(stmt, 8);
sqlite3_bind_blob(stmt, 9, signature, 64, SQLITE_STATIC);
int rc = sqlite3_step(stmt); sqlite3_finalize(stmt);
return rc == SQLITE_DONE ? 0 : -1;
}
int topo_node_sqlite_member_put(sqlite3* db, const char* channel_id, uint64_t node_id) {
if (!db || !channel_id) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[256];
snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO \"%s\"(node_id, join_sig) VALUES(?,?)", peers_tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
static const unsigned char zero_sig[PEERS_JOIN_SIG_SIZE] = {0};
sqlite3_bind_blob(stmt, 2, zero_sig, PEERS_JOIN_SIG_SIZE, SQLITE_STATIC);
sqlite3_step(stmt); sqlite3_finalize(stmt);
return 0;
}
int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t node_id) {
if (!db || !channel_id) return -1;
char peers_tbl[80]; peers_table_name(channel_id, peers_tbl, sizeof(peers_tbl));
char sql[256];
snprintf(sql, sizeof(sql), "DELETE FROM \"%s\" WHERE node_id=?", peers_tbl);
sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
sqlite3_step(stmt); sqlite3_finalize(stmt);
return 0;
}