Release partial SQL bootstrap records on allocation failures

This commit is contained in:
evgeny committed 2026-10-24 14:03:48 +02:00
1 parent 99608de811
commit 26b5da6835
2 files changed
+171 -124

No files matched your search

+135 -123
View File
@@ -1140,157 +1140,157 @@ struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS
}
struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id) {
if (!db || !groups) return NULL;
if (!db || !groups || !groups->instance || groups->instance->topo_groups != groups) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node load: invalid database/groups node=%016llx", (unsigned long long)node_id); return NULL;
}
struct TOPO_NODE* snapshot = topo_node_sqlite_snapshot_load(db, groups, node_id);
if (snapshot) return snapshot;
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node load: allocation failed node=%016llx", (unsigned long long)node_id); return NULL; }
sqlite3_stmt* s = NULL;
uint8_t pubkey[32] = {0}, ed_pubkey[32] = {0};
char* name = NULL;
uint8_t client_type = 0;
int found = 0;
{
sqlite3_stmt* s = NULL;
if (sqlite3_prepare_v2(db, "SELECT name,x25519_pubkey,ed25519_pubkey,client_type FROM nodes WHERE node_id=?",
-1, &s, NULL) == SQLITE_OK) {
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id);
if (sqlite3_step(s) == SQLITE_ROW) {
const char* n = (const char*)sqlite3_column_text(s, 0);
if (n) name = u_strdup(n);
const void* pk = sqlite3_column_blob(s, 1);
if (pk && sqlite3_column_bytes(s, 1) >= 32) memcpy(pubkey, pk, 32);
const void* ep = sqlite3_column_blob(s, 2);
if (ep && sqlite3_column_bytes(s, 2) >= 32) memcpy(ed_pubkey, ep, 32);
client_type = (uint8_t)sqlite3_column_int(s, 3);
found = 1;
}
sqlite3_finalize(s);
}
}
if (!found) { u_free(name); return NULL; }
struct TOPO_ADDR4* v4_head = NULL; struct TOPO_ADDR4* v4_tail = NULL;
struct TOPO_SOCKMETA4* m4_head = NULL; struct TOPO_SOCKMETA4* m4_tail = NULL;
struct TOPO_ADDR6* v6_head = NULL; struct TOPO_ADDR6* v6_tail = NULL;
struct TOPO_SOCKMETA6* m6_head = NULL; struct TOPO_SOCKMETA6* m6_tail = NULL;
struct TOPO_REALITY_SOCK* r_head = NULL; struct TOPO_REALITY_SOCK* r_tail = NULL;
{
sqlite3_stmt* s = NULL;
if (sqlite3_prepare_v2(db, "SELECT name,x25519_pubkey,ed25519_pubkey,client_type FROM nodes WHERE node_id=?",
-1, &s, NULL) != SQLITE_OK) goto sql_failed;
if (sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id) != SQLITE_OK) goto sql_failed;
int rc = sqlite3_step(s);
if (rc == SQLITE_ROW) {
const char* n = (const char*)sqlite3_column_text(s, 0);
if (n) { name = u_strdup(n); if (!name) goto allocation_failed; }
const void* pk = sqlite3_column_blob(s, 1);
if (pk && sqlite3_column_bytes(s, 1) >= 32) memcpy(pubkey, pk, 32);
const void* ep = sqlite3_column_blob(s, 2);
if (ep && sqlite3_column_bytes(s, 2) >= 32) memcpy(ed_pubkey, ep, 32);
client_type = (uint8_t)sqlite3_column_int(s, 3);
found = 1;
} else if (rc != SQLITE_DONE) goto sql_failed;
sqlite3_finalize(s); s = NULL;
}
if (!found) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "node load: missing node=%016llx", (unsigned long long)node_id); goto failed; }
{
if (sqlite3_prepare_v2(db,
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_mapping,options,address_kind FROM node_addresses"
" WHERE node_id=? AND family=4 ORDER BY addr_type",
-1, &s, NULL) == SQLITE_OK) {
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id);
while (sqlite3_step(s) == SQLITE_ROW) {
const void* addr = sqlite3_column_blob(s, 0);
if (!addr || sqlite3_column_bytes(s, 0) < 4) continue;
int port = sqlite3_column_int(s, 1);
int sock_id_raw = sqlite3_column_int(s, 3);
uint8_t sock_id = (uint8_t)sock_id_raw;
uint8_t type = (uint8_t)sqlite3_column_int(s, 8);
struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool);
if (!a4) continue;
memset(a4, 0, sizeof(*a4));
int proto = sqlite3_column_int(s, 4);
memcpy(a4->addr, addr, 4); a4->port = (uint16_t)port;
a4->type = type; a4->socket_id = sock_id; a4->protocol = (uint8_t)proto;
if (!v4_head) v4_head = v4_tail = a4;
else { v4_tail->next = a4; v4_tail = a4; }
-1, &s, NULL) != SQLITE_OK) goto sql_failed;
if (sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id) != SQLITE_OK) goto sql_failed;
int rc;
while ((rc = sqlite3_step(s)) == SQLITE_ROW) {
const void* addr = sqlite3_column_blob(s, 0);
if (!addr || sqlite3_column_bytes(s, 0) < 4) continue;
int port = sqlite3_column_int(s, 1);
int sock_id_raw = sqlite3_column_int(s, 3);
uint8_t sock_id = (uint8_t)sock_id_raw;
uint8_t type = (uint8_t)sqlite3_column_int(s, 8);
struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool);
if (!a4) goto allocation_failed;
memset(a4, 0, sizeof(*a4));
int proto = sqlite3_column_int(s, 4);
memcpy(a4->addr, addr, 4); a4->port = (uint16_t)port;
a4->type = type; a4->socket_id = sock_id; a4->protocol = (uint8_t)proto;
if (!v4_head) v4_head = v4_tail = a4;
else { v4_tail->next = a4; v4_tail = a4; }
struct TOPO_SOCKMETA4* ex = m4_head;
while (ex && ex->id != sock_id) ex = ex->next;
if (!ex) {
struct TOPO_SOCKMETA4* m4 = memory_pool_alloc(groups->v4_sock_meta_pool);
if (m4) {
m4->id = sock_id;
m4->config_type = (uint8_t)sqlite3_column_int(s, 5);
/* Без подписанного snapshot профиль из SQL-проекции не считается доказательством. */
memset(&m4->address_profile, 0, sizeof(m4->address_profile));
m4->next = NULL;
if (!m4_head) m4_head = m4_tail = m4;
else { m4_tail->next = m4; m4_tail = m4; }
}
}
if (sqlite3_column_type(s, 7) == SQLITE_BLOB
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE
&& (proto & TOPO_PROTO_REALITY)) {
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7);
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r));
if (r) {
r->socket_id = sock_id;
memcpy(r->short_id, o->short_id, 8);
memcpy(r->server_pubkey, o->server_pubkey, 32);
memcpy(r->version, o->version, 3);
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX);
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
if (!r_head) r_head = r_tail = r;
else { r_tail->next = r; r_tail = r; }
}
}
struct TOPO_SOCKMETA4* ex = m4_head;
while (ex && ex->id != sock_id) ex = ex->next;
if (!ex) {
struct TOPO_SOCKMETA4* m4 = memory_pool_alloc(groups->v4_sock_meta_pool);
if (!m4) goto allocation_failed;
m4->id = sock_id;
m4->config_type = (uint8_t)sqlite3_column_int(s, 5);
/* Без подписанного snapshot профиль из SQL-проекции не считается доказательством. */
memset(&m4->address_profile, 0, sizeof(m4->address_profile));
m4->next = NULL;
if (!m4_head) m4_head = m4_tail = m4;
else { m4_tail->next = m4; m4_tail = m4; }
}
if (sqlite3_column_type(s, 7) == SQLITE_BLOB
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE
&& (proto & TOPO_PROTO_REALITY)) {
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7);
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r));
if (!r) goto allocation_failed;
r->socket_id = sock_id;
memcpy(r->short_id, o->short_id, 8);
memcpy(r->server_pubkey, o->server_pubkey, 32);
memcpy(r->version, o->version, 3);
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX);
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
if (!r_head) r_head = r_tail = r;
else { r_tail->next = r; r_tail = r; }
}
sqlite3_finalize(s);
}
if (rc != SQLITE_DONE) goto sql_failed;
sqlite3_finalize(s); s = NULL;
}
/* IPv6 addresses */
struct TOPO_ADDR6* v6_head = NULL; struct TOPO_ADDR6* v6_tail = NULL;
struct TOPO_SOCKMETA6* m6_head = NULL; struct TOPO_SOCKMETA6* m6_tail = NULL;
{
sqlite3_stmt* s = NULL;
if (sqlite3_prepare_v2(db,
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_mapping,options,address_kind FROM node_addresses"
" WHERE node_id=? AND family=6 ORDER BY addr_type",
-1, &s, NULL) == SQLITE_OK) {
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id);
while (sqlite3_step(s) == SQLITE_ROW) {
const void* addr = sqlite3_column_blob(s, 0);
if (!addr || sqlite3_column_bytes(s, 0) < 16) continue;
int port = sqlite3_column_int(s, 1);
int sock_id_raw = sqlite3_column_int(s, 3);
uint8_t sock_id = (uint8_t)sock_id_raw;
uint8_t type = (uint8_t)sqlite3_column_int(s, 8);
struct TOPO_ADDR6* a6 = memory_pool_alloc(groups->v6_addr_pool);
if (!a6) continue;
memset(a6, 0, sizeof(*a6));
int proto6 = sqlite3_column_int(s, 4);
memcpy(a6->addr, addr, 16); a6->port = (uint16_t)port;
a6->type = type; a6->socket_id = sock_id; a6->protocol = (uint8_t)proto6;
if (!v6_head) v6_head = v6_tail = a6;
else { v6_tail->next = a6; v6_tail = a6; }
-1, &s, NULL) != SQLITE_OK) goto sql_failed;
if (sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id) != SQLITE_OK) goto sql_failed;
int rc;
while ((rc = sqlite3_step(s)) == SQLITE_ROW) {
const void* addr = sqlite3_column_blob(s, 0);
if (!addr || sqlite3_column_bytes(s, 0) < 16) continue;
int port = sqlite3_column_int(s, 1);
int sock_id_raw = sqlite3_column_int(s, 3);
uint8_t sock_id = (uint8_t)sock_id_raw;
uint8_t type = (uint8_t)sqlite3_column_int(s, 8);
struct TOPO_ADDR6* a6 = memory_pool_alloc(groups->v6_addr_pool);
if (!a6) goto allocation_failed;
memset(a6, 0, sizeof(*a6));
int proto6 = sqlite3_column_int(s, 4);
memcpy(a6->addr, addr, 16); a6->port = (uint16_t)port;
a6->type = type; a6->socket_id = sock_id; a6->protocol = (uint8_t)proto6;
if (!v6_head) v6_head = v6_tail = a6;
else { v6_tail->next = a6; v6_tail = a6; }
struct TOPO_SOCKMETA6* ex = m6_head;
while (ex && ex->id != sock_id) ex = ex->next;
if (!ex) {
struct TOPO_SOCKMETA6* m6 = memory_pool_alloc(groups->v6_sock_meta_pool);
if (m6) {
m6->id = sock_id;
m6->config_type = (uint8_t)sqlite3_column_int(s, 5);
memset(&m6->address_profile, 0, sizeof(m6->address_profile));
m6->next = NULL;
if (!m6_head) m6_head = m6_tail = m6;
else { m6_tail->next = m6; m6_tail = m6; }
}
}
if (sqlite3_column_type(s, 7) == SQLITE_BLOB
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE
&& (proto6 & TOPO_PROTO_REALITY)) {
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7);
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r));
if (r) {
r->socket_id = sock_id;
memcpy(r->short_id, o->short_id, 8);
memcpy(r->server_pubkey, o->server_pubkey, 32);
memcpy(r->version, o->version, 3);
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX);
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
if (!r_head) r_head = r_tail = r;
else { r_tail->next = r; r_tail = r; }
}
}
struct TOPO_SOCKMETA6* ex = m6_head;
while (ex && ex->id != sock_id) ex = ex->next;
if (!ex) {
struct TOPO_SOCKMETA6* m6 = memory_pool_alloc(groups->v6_sock_meta_pool);
if (!m6) goto allocation_failed;
m6->id = sock_id;
m6->config_type = (uint8_t)sqlite3_column_int(s, 5);
memset(&m6->address_profile, 0, sizeof(m6->address_profile));
m6->next = NULL;
if (!m6_head) m6_head = m6_tail = m6;
else { m6_tail->next = m6; m6_tail = m6; }
}
if (sqlite3_column_type(s, 7) == SQLITE_BLOB
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE
&& (proto6 & TOPO_PROTO_REALITY)) {
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7);
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r));
if (!r) goto allocation_failed;
r->socket_id = sock_id;
memcpy(r->short_id, o->short_id, 8);
memcpy(r->server_pubkey, o->server_pubkey, 32);
memcpy(r->version, o->version, 3);
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX);
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
if (!r_head) r_head = r_tail = r;
else { r_tail->next = r; r_tail = r; }
}
sqlite3_finalize(s);
}
if (rc != SQLITE_DONE) goto sql_failed;
sqlite3_finalize(s); s = NULL;
}
if (!v4_head && !v6_head) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "node load: no bootstrap addresses node=%016llx", (unsigned long long)node_id); goto failed;
}
if (!v4_head && !v6_head) { u_free(name); DEBUG_WARN(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx has no addresses (may be stub/seed — will retry when addresses arrive)", (unsigned long long)node_id); return NULL; }
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!ni) { u_free(name); return NULL; }
ni->node_id = node_id; ni->ver = 1; ni->group_ref_count = 0;
ni->client_type = client_type;
memcpy(ni->public_key, pubkey, 32); memcpy(ni->ed25519_public_key, ed_pubkey, 32);
@@ -1306,6 +1306,18 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
topo_list_count((struct _topo_head*)v4_head),
topo_list_count((struct _topo_head*)v6_head));
return ni;
sql_failed:
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node load SQL failed node=%016llx rc=%d: %s",
(unsigned long long)node_id, sqlite3_extended_errcode(db), sqlite3_errmsg(db));
goto failed;
allocation_failed:
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node load: bootstrap allocation failed node=%016llx", (unsigned long long)node_id);
failed:
sqlite3_finalize(s);
ni->node_name = name; ni->v4_addrs = v4_head; ni->v4_sock_meta = m4_head;
ni->v6_addrs = v6_head; ni->v6_sock_meta = m6_head; ni->reality_socks = r_head;
topo_node_destroy(groups, ni);
return NULL;
}
int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t node_id, int connected) {