Files
utun2/src/routing_layer/topo_node_sqlite.h
T

176 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* topo_node_sqlite — хранение подписанных снимков узлов, адресов, каналов и блоков мемберов в общей SQLite.
* Модель/проверка подписей/registry — topo_node и member_sync; этот модуль реализует SQL-операции в uasync-потоке.
* Только snapshot_put/load проверяют подпись; остальные записи требуют проверенных вызывающим данных.
* snapshot_put сохраняет более свежий timestamp; node_load предпочитает snapshot.
* db/groups заимствованы. Возвращённый TOPO_NODE без registry ref: передать registry либо уничтожить через topo_node_destroy.
* Массивы out_ids/out_ch_ids/out_peers принадлежат вызывающему и освобождаются u_free. */
#ifndef TOPO_NODE_SQLITE_H
#define TOPO_NODE_SQLITE_H
#include <sqlite3.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>
#include "topo_node.h"
#define PEERS_JOIN_SIG_SIZE 64
#define PEERS_JOIN_TS_SIZE 8
#define PEERS_UPDATE_SIG_SIZE 64
/* flags byte in wire format */
#define PEERS_FLAG_HAS_JOIN 0x01
/* Создать/обновить nodes, node_addresses, node_snapshots, channels; 0/-1. db открывает и закрывает вызывающий. */
int topo_node_sqlite_init(sqlite3* db);
/* Проверить и сохранить полный подписанный NODEINFO без групповых полей; старый/равный timestamp даёт 0 без замены. */
int topo_node_sqlite_snapshot_put(sqlite3* db, struct TOPO_NODE* ni);
/* Максимальный сохранённый timestamp (Unix microseconds), в том числе после инвалидирования record; 0 — нет/ошибка. */
uint64_t topo_node_sqlite_snapshot_timestamp(sqlite3* db, uint64_t node_id);
/* Незарегистрированный проверенный снимок, включая снимок без адресов; NULL — нет/невалиден/ошибка.
* groups и groups->instance->topo_groups должны обозначать один контейнер с пулами. */
struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id);
/* Персистентная запись адресов узла в node_addresses (источник истины — BGP/topo_group).
* DELETE + INSERT из ni->v4_addrs/v6_addrs под savepoint, включая пустой набор; 0/-1, отказ откатывает замену.
* mapping/inbound/source берутся из SOCKMETA; проверку ni выполняет вызывающий. RTT при замене не сохраняется. */
int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* ni);
/* Есть ли строка хотя бы в одной peers_*: включая source=1 и deleted=1; 1/0, при ошибке также 0. */
int topo_node_sqlite_member_exists(sqlite3* db, uint64_t node_id);
/* Числовые ненулевые channel_id таблиц peers_*, содержащих строку узла; включает placeholders/deleted.
* 0/-1; пустой результат NULL/0, при ошибке частичный массив не выдаётся. */
int topo_node_sqlite_get_member_channels(sqlite3* db, uint64_t node_id,
uint64_t** out_ch_ids, int* out_count);
/* Создать peers_<id> и сохранить канал; 0/-1. Ключи — по 32, signature — 64 байта, privkey необязательны.
* При обновлении публичные ключи обязаны совпасть; имя/владелец/подпись заменяются, NULL privkey сохраняет прежний.
* Подпись/пары ключей не проверяет. Табличный суффикс: первые 63 символа, вне [A-Za-z0-9_] заменены на '_'. */
int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id,
const char* name, 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);
/* Добавить radio_muted=0 в существующую peers_<id>, если поля ещё нет; 0/-1, идемпотентно. */
int topo_node_sqlite_member_local_init(sqlite3* db, const char* channel_id);
/* Полное локальное удаление канала: DROP peers_<id>/msg_<id>, DELETE channels,
* Удаляются feedback_<id> и merkle_tree_hash всех datasets канала (если таблица есть).
* 0/-1; savepoint откатывает в том числе DROP TABLE, внешняя транзакция сохраняется. */
int topo_node_sqlite_channel_delete(sqlite3* db, const char* channel_id);
/* Вставить source=1 с нулевой join_sig; существующую строку не менять. 0/-1; ключи по 32 байта.
* Плейсхолдер не участвует в Merkle-хеше; канал/peers_<id> должны уже существовать. */
int topo_node_sqlite_member_placeholder_put(sqlite3* db, const char* channel_id, uint64_t node_id,
const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey);
/* Обновляет только блок мембера (keys/join/update_sig/update_ts/userinfo), не трогая блок владельца.
* signed_by/signature — дерево приглашений: кто подписал pubkey узла (0 = корень, ключом группы).
* 0/-1; подписи по 64, ключи по 32 байта. NULL join_sig даёт нулевую подпись, userinfo=NULL даёт ''.
* Сбрасывает source=0; свежесть/подписи проверяет вызывающий, owner/local-поля сохраняются. */
int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint64_t node_id,
const uint8_t* join_sig, uint64_t join_ts,
const uint8_t* update_sig, uint64_t update_ts,
const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey, const char* userinfo,
const uint8_t* creator_sig, uint64_t signed_by, const uint8_t* signature);
/* Прочитать дерево приглашений мембера (signed_by + signature). 0=ок, -1=нет записи/полей. */
int topo_node_sqlite_member_get_sign(sqlite3* db, const char* channel_id, uint64_t node_id,
uint64_t* signed_by_out, uint8_t signature_out[64]);
/* Есть ли строка в peers_<id>, включая placeholders/deleted. 1/0; ошибка также даёт 0. */
int topo_node_sqlite_member_in_channel(sqlite3* db, const char* channel_id, uint64_t node_id);
/* Обновить owner-блок и deleted из adm_tags; 0/-1, отсутствующая строка даёт 0 без вставки.
* adm_tags/adm_tags_sig могут быть NULL; ненулевая подпись — 64 байта, проверяется вызывающим. */
int topo_node_sqlite_member_owner_put(sqlite3* db, const char* channel_id, uint64_t node_id,
const char* adm_tags, const uint8_t* adm_tags_sig, int storage);
/* Прочитать ровно 64 байта join_sig и join_ts; 0/-1, выходы обязательны и при неуспехе не меняются. */
int topo_node_sqlite_member_get_join(sqlite3* db, const char* channel_id, uint64_t node_id,
uint8_t* join_sig_out, uint64_t* join_ts_out);
/* Физически удалить строку участника; 0/-1. Отсутствующая строка даёт 0; tombstone/Merkle не создаёт. */
int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t node_id);
/* Записать проверенные вызывающим ключи/имя в nodes; 0/-1. Пустое имя сохраняет прежнее при UPDATE.
* Ключи заменяются независимо от update_ts; update_ts хранит максимум, created_at сохраняется, если не NULL.
* Новая строка online=1, при UPDATE online сохраняется. Подпись и свежесть здесь не проверяются. */
int topo_node_sqlite_node_update_verified(sqlite3* db, uint64_t node_id,
const char* name, const uint8_t* x25519, const uint8_t* ed25519, uint64_t update_ts, time_t created_at);
/* Метаданные канала; 0/-1. Все выходы необязательны; name_sz включает NUL, ключи по 32, подпись 64 байта. */
int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id,
char* name_out, int name_sz, uint64_t* owner_node_id,
uint8_t* x25519_pub, uint8_t* ed25519_pub, uint8_t* signature);
/* Прочитать первые 32 байта Ed25519 privkey; 0/-1, отсутствующий/короткий ключ даёт -1. */
int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id,
uint8_t* ed25519_priv_out);
/* Прочитать оба канальных privkey (x25519 + ed25519). Возвращает 0 если оба есть. */
int topo_node_sqlite_channel_get_privs(sqlite3* db, const char* channel_id,
uint8_t* x25519_priv_out, uint8_t* ed25519_priv_out);
/* Записать оба канальных privkey по 32 байта (импорт прав админа); 0/-1, без проверки пары/подписи.
* Отсутствующая строка даёт 0 без вставки; наличие канала проверяет вызывающий. */
int topo_node_sqlite_channel_set_privs(sqlite3* db, const char* channel_id,
const uint8_t* x25519_priv, const uint8_t* ed25519_priv);
/* Установить online=0/1 существующей строки; 0/-1. Отсутствующая строка даёт 0 без вставки. */
int topo_node_sqlite_node_set_online(sqlite3* db, uint64_t node_id, int online);
/* online из nodes; 0, если записи нет или запрос не выполнен. */
int topo_node_sqlite_node_get_online(sqlite3* db, uint64_t node_id);
/* Скопировать ровно 32 байта Ed25519 из nodes: 0 — найден, -1 — отсутствует/другая длина/ошибка SQLite.
* Значение байтов не определяет наличие ключа; криптографическую пригодность проверяет операция verify. */
int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t pubkey_out[32]);
/* Атомарно пересчитать node_type/storage/deleted во всех peers_* по адресам и adm_tags; 0/-1.
* node_type: 0 нет адресов, 1 прямой/локальный/strict, 2 NAT/contact, 4 supernode=yes.
* storage=yes действует только при наличии ADDR_TYPE_DIRECT, deleted берётся из adm_tags.deleted=yes. */
int topo_node_sqlite_nodeinfo_updated(sqlite3* db, uint64_t node_id);
/* Обновить node_addresses.rtt и все peers_*.node_RTT, единицы 0.1 ms; ошибки логируются, обновление неатомарно. */
void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt);
/**
* @brief Загружает TOPO_NODE из SQLite (ref_count=0).
* @param groups нужен для выделения адресов из memory_pool
* @return TOPO_NODE* или NULL, если нет пригодной записи/адресов bootstrap либо при ошибке
*
* Сначала загружает и проверяет подписанный snapshot; при его отсутствии собирает сведения nodes/node_addresses.
* Snapshot может быть без адресов. Bootstrap требует адресов и получает timestamp=0, профиль UNKNOWN.
* При отказе SQL/памяти частичная запись освобождается. groups->instance->topo_groups должен совпадать с groups.
* Вызывающий передаёт владение через topo_node_registry_store() либо вызывает topo_node_destroy().
*/
struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id);
/* Записать connected=0/1 существующего участника; 0/-1, без вставки отсутствующей строки. */
int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t node_id, int connected);
/* Кандидат CHAT-подключения: роль канальная, тип устройства из подписанного snapshot.
* UINT8_MAX означает отсутствие сведений о типе; адреса не ограничивают выборку. */
struct topo_connect_peer {
uint64_t node_id;
uint8_t client_type, supernode;
};
/* Все неудалённые участники, включая self; сначала connected, затем RTT/node_id.
* 0/-1; массив принадлежит вызывающему и освобождается u_free(). */
int topo_node_sqlite_get_connect_peers(sqlite3* db, const char* channel_id,
struct topo_connect_peer** out, size_t* out_count);
/* Нижеследующие выборки: 0/-1, пусто/ошибка — NULL/0, частичный массив не выдаётся; освобождение u_free.
* connected/supernode ограничены участниками канала, self не исключают, deleted=1 исключают.
* public/local — глобальные адреса с записью nodes, исключены self и deleted=1 в указанном канале;
* наличие членства в канале не требуется. public: addr_type 1/2, local: 0/3; фильтра port!=0 нет. */
int topo_node_sqlite_get_connected_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count);
int topo_node_sqlite_get_public_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id);
int topo_node_sqlite_get_local_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id);
int topo_node_sqlite_get_supernode_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count);
/* node_type узла в канале (peers_<ch>.node_type); -1 если нет записи/ошибка. */
int topo_node_sqlite_get_node_type(sqlite3* db, const char* channel_id, uint64_t node_id);
#endif