diff --git a/src/routing_layer/topo_node_doc.md b/src/routing_layer/topo_node_doc.md index b57c8a37..4f76be08 100644 --- a/src/routing_layer/topo_node_doc.md +++ b/src/routing_layer/topo_node_doc.md @@ -40,8 +40,9 @@ uint8_t buf[4096]; int len = topo_node_serialize(ni, nq, group_id, flags, buf, sizeof(buf), cumulative_rtt); ``` Запаковывает `TOPO_NODE` + per-group данные (`TOPO_GROUP_NODE`) в буфер: заголовок -`TOPOMSG_NODE`, затем имя узла, v4/v6 sock_meta, v4/v6 адреса, подсети (если -`TOPO_FLAG_SEND_SUBNETS`) и hop-лист (через `topo_node_best_hop_list`). +`TOPOMSG_NODE`, затем имя, SOCKMETA4, ADDR4, SOCKMETA6, ADDR6, REALITY-сокеты, +подсети (если `TOPO_FLAG_SEND_SUBNETS`) и hop-лист (через `topo_node_best_hop_list`). +Без флага подсети не записываются, а оба их счётчика в заголовке равны нулю. **Десериализация при получении NODEINFO:** ```c @@ -51,9 +52,17 @@ uint64_t* hop_list = NULL; uint8_t hop_count = 0; uint16_t cumulative_rtt = 0; topo_node_deserialize(group, data, data_len, &ni, &subnets, &hop_list, &hop_count, &cumulative_rtt); ``` -Восстанавливает `TOPO_NODE` (через `u_calloc`), подсети и hop-лист. Освобождение: +При успехе (0) восстанавливает `TOPO_NODE` (через `u_calloc`) и запрошенные подсети/hop-лист. +`out_ni` обязателен; остальные выходы независимы и могут быть NULL. Все присутствующие +секции проходят проверку и занимают своё место в пакете, даже если их выход не запрошен. +Проверяются точная длина, согласованность флага/счётчиков подсетей, профили и длины префиксов. +Подпись и допустимость BGP-пути проверяются отдельно. При ошибке (-1) выходы обнулены, +частичные объекты освобождены. Освобождение успешного результата: + - `topo_node_destroy(groups, ni)` — освободить `TOPO_NODE` (списки адресов + имя). -- `topo_nodeq_free_group_fields(groups, nq)` — освободить per-group поля (`subnets`, `paths`-элементы). +- Подсети передаются в `TOPO_GROUP_NODE`; `topo_nodeq_free_group_fields` освобождает их и снимает registry ref. + Контейнер/записи путей освобождает отдельный `topo_nodeq_clear_paths`. Для целого узла используют `topo_nodeq_remove_node`. +- `u_free(hop_list)` — освободить отдельно выделенный массив переходов. **Поиск узла по ID:** ```c @@ -82,8 +91,10 @@ topo_node_format_all(group, buf, size); // в строку - **TOPO_CONNECTIVITY** — локальное состояние связности (не передаётся по BGP): probe_status (NONE/IN_PROGRESS/DONE/DEFERRED), RTT и статусы interface/nat/real, `probe_deferred_wait`. - **TOPO_FLAG_SEND_SUBNETS** — если установлен, подсети сериализуются; для chat-групп сброшен. + Ненулевые счётчики подсетей без флага недопустимы, в том числе при `out_subnets=NULL`. - **Wire-протокол**: заголовок `TOPOMSG_NODE` (packed) + динамика: `node_name`, `SOCKMETA4*N`, - `ADDR4*N`, `SOCKMETA6*N`, `ADDR6*N`, опционально подсети, hop-лист. Размер динамики — `topo_node_dyn_size()`. + `ADDR4*N`, `SOCKMETA6*N`, `ADDR6*N`, REALITY-сокеты, опционально подсети, hop-лист. + `topo_node_dyn_size()` возвращает размер динамики либо -1 при некорректном сочетании флага/счётчиков. ## 3. API diff --git a/tests/test_reality_bgp.c b/tests/test_reality_bgp.c index 7bd478ed..7b4ff399 100644 --- a/tests/test_reality_bgp.c +++ b/tests/test_reality_bgp.c @@ -8,7 +8,9 @@ #include "topo_node.h" #include "topo_group.h" #include "etcp_connections.h" +#include "utun_instance.h" #include "../lib/debug_config.h" +#include "../lib/mem.h" #include #include @@ -67,7 +69,10 @@ int main(void) { uint8_t buf[2048]; int len = topo_node_serialize(&ni, &nq, 0x1234, 0, buf, sizeof(buf), 0); CHECK(len > 0, "serialize ok"); - struct TOPO_GROUP g; memset(&g, 0, sizeof(g)); + struct UTUN_INSTANCE instance = {0}; + struct TOPO_GROUPS groups = {.instance = &instance}; + instance.topo_groups = &groups; + struct TOPO_GROUP g = {.instance = &instance}; struct TOPO_NODE* out_ni = NULL; struct TOPO_NODESUBNETS* out_sub = NULL; uint64_t* hop = NULL; uint8_t hopc = 0; uint16_t rtt = 0; @@ -87,6 +92,9 @@ int main(void) { CHECK(rr1 != NULL && !strcmp(rr1->server_name, long_sni), "round-trip: full server_name"); CHECK(rr1 != NULL && rr1->version[0] == 1 && rr1->version[1] == 2 && rr1->version[2] == 3, "round-trip: version"); } + CHECK(!out_sub && !hop && !hopc && !rtt, "round-trip: empty optional sections"); + topo_node_destroy(&groups, out_ni); + u_free(hop); if (test_failed) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "=== Reality BGP Test: FAILED ===");