From ab5c077600468f29896ba2e29771643e4ab8aafc Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 15:49:42 +0200 Subject: [PATCH] Unwind topology initialization on pool and SQLite failures --- src/routing_layer/topo_group.c | 36 +++++++++++++++++++++------------- src/routing_layer/topo_group.h | 14 +++++++++---- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/routing_layer/topo_group.c b/src/routing_layer/topo_group.c index a8e4c543..e36aa090 100644 --- a/src/routing_layer/topo_group.c +++ b/src/routing_layer/topo_group.c @@ -722,9 +722,11 @@ void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id) { queue_entry_free(&group->ll); } -/* Инициализация контейнера групп: реестр, пулы, SQLite, default-группа, подписки. */ +/* Инициализация контейнера групп: реестр, пулы, SQLite и подписки; группы создают сервисы. */ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { - if (!instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "instance is NULL"); return NULL; } + if (!instance || instance->topo_groups || instance->topo_sqlite_db) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid or already initialized topology/SQLite instance=%p", (void*)instance); return NULL; + } DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_id=%016llx", (unsigned long long)instance->node_id); struct TOPO_GROUPS* g = u_calloc(1, sizeof(struct TOPO_GROUPS)); @@ -736,6 +738,7 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { g->node_registry = queue_new(instance->ua, TOPO_NODE_REGISTRY_HASH_SIZE, 0, 8, "node_registry"); if (!g->node_registry) { queue_free(g->group_list); u_free(g); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node_registry queue creation failed"); return NULL; } + instance->topo_groups = g; g->v4_sock_meta_pool = memory_pool_init(sizeof(struct TOPO_SOCKMETA4), "to_v4sock"); g->v4_addr_pool = memory_pool_init(sizeof(struct TOPO_ADDR4), "to_v4addr"); @@ -743,6 +746,10 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { g->v6_addr_pool = memory_pool_init(sizeof(struct TOPO_ADDR6), "to_v6addr"); g->v4_subnet_pool = memory_pool_init(sizeof(struct TOPO_SUBNET4), "to_v4sub"); g->v6_subnet_pool = memory_pool_init(sizeof(struct TOPO_SUBNET6), "to_v6sub"); + if (!g->v4_sock_meta_pool || !g->v4_addr_pool || !g->v6_sock_meta_pool || !g->v6_addr_pool || + !g->v4_subnet_pool || !g->v6_subnet_pool) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot initialize topology memory pools"); goto fail; + } { char db_file[512] = ":memory:"; @@ -751,25 +758,22 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { int rc = sqlite3_open_v2(db_file, &instance->topo_sqlite_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); if (rc == SQLITE_OK && instance->topo_sqlite_db) { - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA wal_autocheckpoint=10000", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA cache_size=-32768", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA mmap_size=134217728", NULL, NULL, NULL); - sqlite3_exec(instance->topo_sqlite_db, "PRAGMA temp_store=MEMORY", NULL, NULL, NULL); - topo_node_sqlite_init(instance->topo_sqlite_db); + rc = sqlite3_exec(instance->topo_sqlite_db, "PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;" + " PRAGMA synchronous=NORMAL; PRAGMA wal_autocheckpoint=10000; PRAGMA cache_size=-32768;" + " PRAGMA mmap_size=134217728; PRAGMA temp_store=MEMORY", NULL, NULL, NULL); + if (rc != SQLITE_OK || topo_node_sqlite_init(instance->topo_sqlite_db) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot initialize SQLite %s: rc=%d %s", + db_file, rc, sqlite3_errmsg(instance->topo_sqlite_db)); goto fail; + } DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SQLite opened: %s rc=%d db=%p", db_file, rc, (void*)instance->topo_sqlite_db); } else { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "sqlite3_open(%s) failed: %s", db_file, instance->topo_sqlite_db ? sqlite3_errmsg(instance->topo_sqlite_db) : "null db"); - if (instance->topo_sqlite_db) { sqlite3_close(instance->topo_sqlite_db); instance->topo_sqlite_db = NULL; } + goto fail; } } - instance->topo_groups = g; - - if (topo_node_init_self(instance) < 0) { topo_groups_destroy(instance); return NULL; } + if (topo_node_init_self(instance) < 0) goto fail; etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk); etcp_add_conn_status_cbk(instance, topo_group_conn_status, g); @@ -779,6 +783,10 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "TOPO registry initialized (services create their own groups)"); return g; +fail: + topo_groups_destroy(instance); + if (instance->topo_sqlite_db) { sqlite3_close(instance->topo_sqlite_db); instance->topo_sqlite_db = NULL; } + return NULL; } /* Callback смены active/standby: обновляет свой nodeinfo и рассылает его пирам. */ diff --git a/src/routing_layer/topo_group.h b/src/routing_layer/topo_group.h index 37fb4970..123ace93 100644 --- a/src/routing_layer/topo_group.h +++ b/src/routing_layer/topo_group.h @@ -266,7 +266,11 @@ struct TOPO_GROUPS { * @brief Создаёт реестр и локальную идентичность; сервисных групп пока нет. * Открывает общую SQLite: db_path/chats.db, без db_path — :memory:. * - * @param instance экземпляр utun с node_id и конфигом + * При ошибке выделения пулов, открытия/инициализации SQLite или локальной записи + * освобождает созданные ресурсы; instance->topo_groups/topo_sqlite_db остаются NULL. + * Повторная инициализация уже имеющихся topology/SQLite запрещена. + * + * @param instance экземпляр utun с uasync, node_id и конфигом; topology/SQLite пока NULL * @return TOPO_GROUPS или NULL при ошибке */ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance); @@ -302,7 +306,7 @@ struct TOPO_GROUP* topo_groups_find(struct TOPO_GROUPS* g, uint64_t group_id); * @param group_id уникальный идентификатор * @param group_type TOPO_GROUP_TYPE_UTUN или TOPO_GROUP_TYPE_CHAT * @param channel_id идентификатор канала для групп типа CHAT (может быть NULL) - * @return TOPO_GROUP или NULL при ошибке + * @return TOPO_GROUP с local_node, conn_mgr, broadcast и radio или NULL с полным откатом создания */ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t group_id, uint8_t group_type, const char* channel_id); @@ -428,8 +432,10 @@ void topo_group_set_nat_check_local(struct TOPO_GROUP* group, int allow); /* ── Рация (PTT walkie-talkie, per-CHAT-группа) ── */ -/* Включить/выключить прослушивание рации канала: выставляет local_node->radio и - * рассылает NODEINFO (TOPO_FLAG_RADIO) через BGP. Работает только для CHAT-групп. */ +/* Включить/выключить прослушивание рации канала: публикует local_node->radio и + * рассылает NODEINFO (TOPO_FLAG_RADIO) через BGP. Только CHAT-группы. + * Ошибка подготовки/подписи сохраняет прежние radio_active/local_node и логируется; + * повтор такой же команды снова пробует публикацию. */ void topo_group_set_radio(struct TOPO_GROUP* group, int on); /* Число узлов группы, слушающих рацию (radio==1), без учёта себя. */