Files
utun2/src/routing_layer/topo_node_sqlite.h
T

213 lines
19 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
/* Результаты channel_get/get_ed25519_pubkey: отсутствие зависимости и отказ чтения различаются. */
#define TOPO_SQLITE_LOOKUP_MISSING (-1)
#define TOPO_SQLITE_LOOKUP_ERROR (-2)
/* 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 без замены.
* Возврат0/-1,свой savepoint проверяет bind/step/finalize/RELEASE;отказ откатывает запись.
* При неудачном rollback открытая транзакция требует rollback/закрытия БД владельцем. */
int topo_node_sqlite_snapshot_put(sqlite3* db, struct TOPO_NODE* ni);
/* Сохранённый timestamp (Unix microseconds),в том числе после инвалидирования record;отсутствие даёт0.
* Возвращает0/-1;при SQL/форматной ошибке *out не меняется. out обязателен. */
int topo_node_sqlite_snapshot_timestamp(sqlite3* db, uint64_t node_id, uint64_t* out);
/* Незарегистрированный проверенный снимок, включая снимок без адресов; 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 сохраняет прежний.
* Свой savepoint включает peers/индексы/описание; проверяет DDL,все bind/step/changes1/finalize/release.
* Ошибка сохраняет прежние данные/схему. Внешняя транзакция допустима и не завершается.
* Отказ rollback не выполняет release:caller должен откатить/закрыть оставшуюся транзакцию.
* Подпись/пары ключей не проверяет. Табличный суффикс: первые 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 канала (если таблица есть).
* Проверяются finalize и отсутствие канала/хешей после DELETE, включая RAISE(IGNORE).
* Локальные каскадные triggers (в том числе attachment) входят в ту же транзакцию.
* 0/-1; savepoint откатывает в том числе DROP TABLE, внешняя транзакция сохраняется.
* При ошибке rollback вызывающий проверяет autocommit; открытая транзакция требует остановки/закрытия БД владельцем. */
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-поля сохраняются. */
/* Проверяет все bind,step,changes1 и finalize;при отказе caller откатывает свою транзакцию записи/индекса. */
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);
/* Допуск участника: source=0, deleted=0 и admitted=1 последней контрольной точки политики/цепочек.
* 1/0, ошибка логируется и даёт 0. BGP-placeholder и неподходящая цепочка доступа не дают. */
int topo_node_sqlite_member_allowed(sqlite3* db, const char* channel_id, uint64_t node_id);
/* Транспорт для первой MEMBERS сверки: полная неудалённая запись, ещё без admitted. 1/0; ошибка запрещает. */
int topo_node_sqlite_member_transport_allowed(sqlite3* db, const char* channel_id, uint64_t node_id);
/* Проверить точный X25519-ключ полного действующего мембера: 1 — есть, 0 — нет/ошибка (закрытый отказ).
* node_id вычисляется из key, SQL также сверяет все 32 байта; заглушки source=1 и deleted исключены. */
int topo_node_sqlite_member_key_allowed(sqlite3* db, const char* channel_id, const uint8_t key[32]);
/* Обновить owner-блок и deleted из adm_tags в одной существующей строке;0/-1,отсутствующая строка — ошибка.
* adm_tags/adm_tags_sig могут быть NULL;ненулевая подпись64 байта,проверяется вызывающим.
* Проверяет все bind/step/changes=1/finalize.
* Работает в транзакции caller;при отказе caller откатывает её до любых runtime-уведомлений. */
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 сохраняется. Подпись и свежесть здесь не проверяются.
* Проверяет changes=1:подавленная trigger запись не считается успехом. Транзакцией управляет caller. */
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 — успех, LOOKUP_MISSING — нет строки/запрошенного ключа,
* LOOKUP_ERROR — аргументы/SQL/повреждённый размер. Выходы действительны только при 0.
* Все выходы необязательны; 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);
/* Прочитать Ed25519 privkey ровно32 байта BLOB; 0/-1, отсутствие/повреждение/SQL-ошибка даёт -1.
* Проверяются bind/step/finalize; при отказе выход не меняется. */
int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id,
uint8_t* ed25519_priv_out);
/* Прочитать оба канальных privkey (x25519 + ed25519), каждый ровно32 байта BLOB.
* 0 — оба прочитаны, -1 — отказ с сохранением обоих выходов. Временные ключи очищаются. */
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.
* Savepoint проверяет все SQL-операции и откатывает запись при отказе; отсутствие строки — ошибка.
* При внешней транзакции её commit остаётся вызывающему; событие успеха до него запрещено.
* Соответствие пары/подпись проверяет вызывающий. Аргументы обязательны; rollback-отказ логируется. */
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 — найден, LOOKUP_MISSING — нет строки/ключа,
* LOOKUP_ERROR — аргументы/SQL/повреждённый размер. При отказе выход не меняется.
* Значение байтов не определяет наличие ключа; криптографическую пригодность проверяет операция 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);
/* Загрузить только известную идентичность nodes, без адресов/подписи/timestamp.
* Для NCD с независимо подтверждённым LAN-адресом. Проверяет размеры ключей и node_id=derive(X25519).
* Владельческий TOPO_NODE или NULL; уничтожить topo_node_destroy либо передать registry. */
struct TOPO_NODE* topo_node_sqlite_identity_load(sqlite3* db, 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;
};
/* Все полные неудалённые участники (source=0, deleted=0), включая 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