Make NODEINFO section parsing independent of requested outputs

This commit is contained in:
evgeny committed 2026-10-24 13:01:30 +02:00
1 parent f9a3830416
commit 790978458c
3 files changed
+190 -104

No files matched your search

+6 -1
View File
@@ -1265,7 +1265,12 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
}
int dyn = topo_node_dyn_size(ni);
if ((size_t)dyn + sizeof(struct TOPOMSG_NODEINFO_PKT) != len) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "Incorrect packet size (%s)", from->log_name); return -1; }
if (dyn < 0) return -1; // Причина уже записана в topo_node_dyn_size.
if ((size_t)dyn != len - sizeof(struct TOPOMSG_NODEINFO_PKT)) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO size mismatch from=%s node=%016llx length=%zu expected=%zu",
from->log_name, (unsigned long long)ni->node_id, len, sizeof(struct TOPOMSG_NODEINFO_PKT) + (size_t)dyn);
return -1;
}
uint64_t node_id = ni->node_id;
if (ni->hop_count >= MAX_HOPS) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO from %s dropped: too many hops (%d)", from->log_name, ni->hop_count); return -1; }
+175 -100
View File
@@ -475,15 +475,20 @@ int topo_node_verify(const struct TOPO_NODE* ni) {
/* Вычисляет суммарный размер динамической части NODEINFO по счётчикам заголовка. */
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
if (!msg) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO size: missing header"); return -1; }
if (!(msg->flags & TOPO_FLAG_SEND_SUBNETS) && (msg->local_v4_subnets || msg->local_v6_subnets)) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO size: subnets without flag node=%016llx flags=%02x v4=%u v6=%u",
(unsigned long long)msg->node_id, msg->flags, msg->local_v4_subnets, msg->local_v6_subnets);
return -1;
}
return msg->node_name_len
+ msg->local_v4_sockets * sizeof(struct TOPOMSG_SOCKMETA4)
+ msg->local_v4_addrs * sizeof(struct TOPOMSG_ADDR4)
+ msg->local_v6_sockets * sizeof(struct TOPOMSG_SOCKMETA6)
+ msg->local_v6_addrs * sizeof(struct TOPOMSG_ADDR6)
+ msg->local_reality_socks * sizeof(struct TOPOMSG_REALITY_SOCK)
+ ((msg->flags & TOPO_FLAG_SEND_SUBNETS)
? (msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4) + msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6))
: 0)
+ msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4)
+ msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6)
+ msg->hop_count * 8;
}
@@ -491,7 +496,7 @@ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
uint64_t group_id, uint8_t flags,
uint8_t* out, size_t out_max, uint16_t cumulative_rtt) {
if (!ni || !nq || !out) return -1;
if (!ni || !nq || !out) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO encode: missing node/group/output"); return -1; }
struct TOPOMSG_NODE msg;
memset(&msg, 0, sizeof(msg));
@@ -510,7 +515,8 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
topo_list_count((struct _topo_head*)ni->v6_sock_meta) > UINT8_MAX ||
topo_list_count((struct _topo_head*)ni->v6_addrs) > UINT8_MAX ||
topo_list_count((struct _topo_head*)ni->reality_socks) > UINT8_MAX ||
(nq->subnets && (topo_list_count((struct _topo_head*)nq->subnets->v4_subnets) > UINT8_MAX ||
((flags & TOPO_FLAG_SEND_SUBNETS) && nq->subnets &&
(topo_list_count((struct _topo_head*)nq->subnets->v4_subnets) > UINT8_MAX ||
topo_list_count((struct _topo_head*)nq->subnets->v6_subnets) > UINT8_MAX))) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node exceeds wire format limits"); return -1;
}
@@ -519,18 +525,25 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
msg.local_v6_sockets = topo_list_count((struct _topo_head*)ni->v6_sock_meta);
msg.local_v6_addrs = topo_list_count((struct _topo_head*)ni->v6_addrs);
msg.local_reality_socks = topo_list_count((struct _topo_head*)ni->reality_socks);
msg.local_v4_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v4_subnets) : 0;
msg.local_v6_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v6_subnets) : 0;
{ uint8_t hc; uint64_t* hl = topo_node_best_hop_list(nq, &hc, NULL);
msg.hop_count = hc; }
if ((flags & TOPO_FLAG_SEND_SUBNETS) && nq->subnets) {
msg.local_v4_subnets = topo_list_count((struct _topo_head*)nq->subnets->v4_subnets);
msg.local_v6_subnets = topo_list_count((struct _topo_head*)nq->subnets->v6_subnets);
}
uint64_t *hop_list = topo_node_best_hop_list(nq, &msg.hop_count, NULL);
msg.client_type = ni->client_type;
msg.client_activity = ni->client_activity;
msg.cumulative_rtt = cumulative_rtt;
if (nq->radio) msg.flags |= TOPO_FLAG_RADIO;
msg.flags |= nq->phone_status;
size_t total = TOPOMSG_NODE_HDR_SIZE + (size_t)topo_node_dyn_size(&msg);
if (total > out_max) return -1;
int dyn = topo_node_dyn_size(&msg);
if (dyn < 0) return -1; // Причина уже записана в topo_node_dyn_size.
size_t total = TOPOMSG_NODE_HDR_SIZE + (size_t)dyn;
if (total > out_max) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO encode: output too small node=%016llx need=%zu capacity=%zu",
(unsigned long long)ni->node_id, total, out_max);
return -1;
}
memcpy(out, &msg, TOPOMSG_NODE_HDR_SIZE);
uint8_t* dp = out + TOPOMSG_NODE_HDR_SIZE;
@@ -574,8 +587,9 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
}}
}
}
{ uint8_t hc; uint64_t* hl = topo_node_best_hop_list(nq, &hc, NULL);
if (hc && hl) { size_t sz = hc * 8; memcpy(dp, hl, sz); dp += sz; } }
if (msg.hop_count) { size_t size = msg.hop_count * sizeof(*hop_list); memcpy(dp, hop_list, size); dp += size; }
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "NODEINFO encoded: node=%016llx bytes=%zu flags=%02x subnets=%u/%u hops=%u",
(unsigned long long)ni->node_id, total, msg.flags, msg.local_v4_subnets, msg.local_v6_subnets, msg.hop_count);
return (int)(dp - out);
}
@@ -585,129 +599,190 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t len, struct TOPO_NODE** out_ni, struct TOPO_NODESUBNETS** out_subnets,
uint64_t** out_hop_list, uint8_t* out_hop_count,
uint16_t* out_cumulative_rtt) {
if (!group || !data || len < TOPOMSG_NODE_HDR_SIZE || !out_ni) return -1;
if (out_ni) *out_ni = NULL;
if (out_subnets) *out_subnets = NULL;
if (out_hop_list) *out_hop_list = NULL;
if (out_hop_count) *out_hop_count = 0;
if (out_cumulative_rtt) *out_cumulative_rtt = 0;
if (!group || !group->instance || !group->instance->topo_groups || !data || !out_ni) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO decode: missing group/instance/registry/data/output");
return -1;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "NODEINFO decode: length=%zu", len);
if (len < TOPOMSG_NODE_HDR_SIZE) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO decode: short header length=%zu need=%zu", len, TOPOMSG_NODE_HDR_SIZE);
return -1;
}
const struct TOPOMSG_NODE* msg = (const struct TOPOMSG_NODE*)data;
int dyn = topo_node_dyn_size(msg);
if ((size_t)dyn + TOPOMSG_NODE_HDR_SIZE != len) return -1;
if (dyn < 0) return -1; // Причина уже записана в topo_node_dyn_size.
if ((size_t)dyn != len - TOPOMSG_NODE_HDR_SIZE) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO decode: size mismatch node=%016llx length=%zu expected=%zu flags=%02x subnets=%u/%u hops=%u",
(unsigned long long)msg->node_id, len, TOPOMSG_NODE_HDR_SIZE + (size_t)dyn,
msg->flags, msg->local_v4_subnets, msg->local_v6_subnets, msg->hop_count);
return -1;
}
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc TOPO_NODE failed"); return -1; }
ni->group_ref_count = 0;
ni->node_id = msg->node_id;
ni->ver = msg->ver;
ni->timestamp = msg->timestamp;
struct TOPO_GROUPS* groups = group->instance->topo_groups;
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
struct TOPO_NODESUBNETS* subnets = NULL;
uint64_t* hops = NULL;
const uint8_t* dp = data + TOPOMSG_NODE_HDR_SIZE;
const char* section = "node";
unsigned index = 0;
if (!ni) goto no_memory;
ni->node_id = msg->node_id; ni->ver = msg->ver; ni->timestamp = msg->timestamp;
memcpy(ni->public_key, msg->public_key, SC_PUBKEY_SIZE);
memcpy(ni->ed25519_public_key, msg->ed25519_public_key, SC_PUBKEY_SIZE);
memcpy(ni->x25519_self_sig, msg->x25519_self_sig, 64);
ni->client_type = msg->client_type;
ni->client_activity = msg->client_activity;
const uint8_t* dp = data + TOPOMSG_NODE_HDR_SIZE;
ni->client_type = msg->client_type; ni->client_activity = msg->client_activity;
section = "name";
if (msg->node_name_len) {
ni->node_name = u_malloc(msg->node_name_len + 1);
if (ni->node_name) { memcpy(ni->node_name, dp, msg->node_name_len); ni->node_name[msg->node_name_len] = 0; }
dp += msg->node_name_len;
if (!ni->node_name) goto no_memory;
memcpy(ni->node_name, dp, msg->node_name_len); ni->node_name[msg->node_name_len] = 0;
}
dp += msg->node_name_len;
{ struct TOPO_SOCKMETA4* head = NULL; struct TOPO_SOCKMETA4* tail = NULL;
for (int i = 0; i < msg->local_v4_sockets; i++) {
/* Списки сразу принадлежат ni: общий выход ошибки видит и незавершённую секцию. */
section = "v4 socket metadata";
{ struct TOPO_SOCKMETA4** tail = &ni->v4_sock_meta;
for (index = 0; index < msg->local_v4_sockets; index++) {
const struct TOPOMSG_SOCKMETA4* w = (const struct TOPOMSG_SOCKMETA4*)dp; dp += sizeof(*w);
struct TOPO_SOCKMETA4* e = memory_pool_alloc(group->instance->topo_groups->v4_sock_meta_pool);
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
e->id = w->id; e->config_type = w->config_type; e->next = NULL;
if (sockmeta_wire_read((const uint8_t *)w, &e->address_profile)) {
memory_pool_free(group->instance->topo_groups->v4_sock_meta_pool, e);
ni->v4_sock_meta = head; topo_node_free_raw(group->instance->topo_groups, ni); return -1;
}
if (!head) head = tail = e; else { tail->next = e; tail = e; }
struct TOPO_SOCKMETA4* e = memory_pool_alloc(groups->v4_sock_meta_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
e->id = w->id; e->config_type = w->config_type;
if (sockmeta_wire_read((const uint8_t*)w, &e->address_profile)) goto invalid_profile;
}
ni->v4_sock_meta = head; }
{ struct TOPO_ADDR4* head = NULL; struct TOPO_ADDR4* tail = NULL;
for (int i = 0; i < msg->local_v4_addrs; i++) {
}
section = "v4 addresses";
{ struct TOPO_ADDR4** tail = &ni->v4_addrs;
for (index = 0; index < msg->local_v4_addrs; index++) {
const struct TOPOMSG_ADDR4* w = (const struct TOPOMSG_ADDR4*)dp; dp += sizeof(*w);
struct TOPO_ADDR4* e = memory_pool_alloc(group->instance->topo_groups->v4_addr_pool);
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
memcpy(e->addr, w->addr, 4); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol; e->next = NULL;
if (!head) head = tail = e; else { tail->next = e; tail = e; }
struct TOPO_ADDR4* e = memory_pool_alloc(groups->v4_addr_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
memcpy(e->addr, w->addr, 4); e->port = w->port; e->type = w->type;
e->socket_id = w->socket_id; e->protocol = w->protocol;
}
ni->v4_addrs = head; }
{ struct TOPO_SOCKMETA6* head = NULL; struct TOPO_SOCKMETA6* tail = NULL;
for (int i = 0; i < msg->local_v6_sockets; i++) {
}
section = "v6 socket metadata";
{ struct TOPO_SOCKMETA6** tail = &ni->v6_sock_meta;
for (index = 0; index < msg->local_v6_sockets; index++) {
const struct TOPOMSG_SOCKMETA6* w = (const struct TOPOMSG_SOCKMETA6*)dp; dp += sizeof(*w);
struct TOPO_SOCKMETA6* e = memory_pool_alloc(group->instance->topo_groups->v6_sock_meta_pool);
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
e->id = w->id; e->config_type = w->config_type; e->next = NULL;
if (sockmeta_wire_read((const uint8_t *)w, &e->address_profile)) {
memory_pool_free(group->instance->topo_groups->v6_sock_meta_pool, e);
ni->v6_sock_meta = head; topo_node_free_raw(group->instance->topo_groups, ni); return -1;
}
if (!head) head = tail = e; else { tail->next = e; tail = e; }
struct TOPO_SOCKMETA6* e = memory_pool_alloc(groups->v6_sock_meta_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
e->id = w->id; e->config_type = w->config_type;
if (sockmeta_wire_read((const uint8_t*)w, &e->address_profile)) goto invalid_profile;
}
ni->v6_sock_meta = head; }
{ struct TOPO_ADDR6* head = NULL; struct TOPO_ADDR6* tail = NULL;
for (int i = 0; i < msg->local_v6_addrs; i++) {
}
section = "v6 addresses";
{ struct TOPO_ADDR6** tail = &ni->v6_addrs;
for (index = 0; index < msg->local_v6_addrs; index++) {
const struct TOPOMSG_ADDR6* w = (const struct TOPOMSG_ADDR6*)dp; dp += sizeof(*w);
struct TOPO_ADDR6* e = memory_pool_alloc(group->instance->topo_groups->v6_addr_pool);
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
memcpy(e->addr, w->addr, 16); e->port = w->port; e->type = w->type; e->socket_id = w->socket_id; e->protocol = w->protocol; e->next = NULL;
if (!head) head = tail = e; else { tail->next = e; tail = e; }
struct TOPO_ADDR6* e = memory_pool_alloc(groups->v6_addr_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
memcpy(e->addr, w->addr, 16); e->port = w->port; e->type = w->type;
e->socket_id = w->socket_id; e->protocol = w->protocol;
}
ni->v6_addrs = head; }
{ struct TOPO_REALITY_SOCK* head = NULL; struct TOPO_REALITY_SOCK* tail = NULL;
for (int i = 0; i < msg->local_reality_socks; i++) {
}
section = "REALITY sockets";
{ struct TOPO_REALITY_SOCK** tail = &ni->reality_socks;
for (index = 0; index < msg->local_reality_socks; index++) {
const struct TOPOMSG_REALITY_SOCK* w = (const struct TOPOMSG_REALITY_SOCK*)dp; dp += sizeof(*w);
struct TOPO_REALITY_SOCK* e = u_calloc(1, sizeof(struct TOPO_REALITY_SOCK));
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
struct TOPO_REALITY_SOCK* e = u_calloc(1, sizeof(*e));
if (!e) goto no_memory;
*tail = e; tail = &e->next;
e->socket_id = w->socket_id;
memcpy(e->short_id, w->short_id, 8);
memcpy(e->server_pubkey, w->server_pubkey, 32);
memcpy(e->version, w->version, 3);
memcpy(e->server_name, w->server_name, TOPO_REALITY_SNAME_MAX);
memcpy(e->short_id, w->short_id, 8); memcpy(e->server_pubkey, w->server_pubkey, 32);
memcpy(e->version, w->version, 3); memcpy(e->server_name, w->server_name, TOPO_REALITY_SNAME_MAX);
e->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
e->next = NULL;
if (!head) head = tail = e; else { tail->next = e; tail = e; }
}
ni->reality_socks = head; }
}
if (out_subnets && (msg->flags & TOPO_FLAG_SEND_SUBNETS) && (msg->local_v4_subnets || msg->local_v6_subnets)) {
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
if (!r) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
for (int i = 0; i < msg->local_v4_subnets; i++) {
section = "subnets"; index = 0;
if (out_subnets && (msg->local_v4_subnets || msg->local_v6_subnets)) {
subnets = u_calloc(1, sizeof(*subnets));
if (!subnets) goto no_memory;
}
/* Курсор проходит все присутствующие секции; out_subnets управляет только выделением памяти. */
section = "v4 subnets";
{ struct TOPO_SUBNET4** tail = subnets ? &subnets->v4_subnets : NULL;
for (index = 0; index < msg->local_v4_subnets; index++) {
const struct TOPOMSG_SUBNET4* w = (const struct TOPOMSG_SUBNET4*)dp; dp += sizeof(*w);
struct TOPO_SUBNET4* e = memory_pool_alloc(group->instance->topo_groups->v4_subnet_pool);
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
if (w->prefix_length > 32) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO decode: invalid IPv4 prefix node=%016llx index=%u prefix=%u",
(unsigned long long)msg->node_id, index, w->prefix_length);
goto fail;
}
if (!subnets) continue;
struct TOPO_SUBNET4* e = memory_pool_alloc(groups->v4_subnet_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
memcpy(e->addr, w->addr, 4); e->prefix_length = w->prefix_length;
e->next = r->v4_subnets; r->v4_subnets = e;
}
for (int i = 0; i < msg->local_v6_subnets; i++) {
}
section = "v6 subnets";
{ struct TOPO_SUBNET6** tail = subnets ? &subnets->v6_subnets : NULL;
for (index = 0; index < msg->local_v6_subnets; index++) {
const struct TOPOMSG_SUBNET6* w = (const struct TOPOMSG_SUBNET6*)dp; dp += sizeof(*w);
struct TOPO_SUBNET6* e = memory_pool_alloc(group->instance->topo_groups->v6_subnet_pool);
if (!e) { u_free(r); topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
if (w->prefix_length > 128) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO decode: invalid IPv6 prefix node=%016llx index=%u prefix=%u",
(unsigned long long)msg->node_id, index, w->prefix_length);
goto fail;
}
if (!subnets) continue;
struct TOPO_SUBNET6* e = memory_pool_alloc(groups->v6_subnet_pool);
if (!e) goto no_memory;
*tail = e; tail = &e->next;
memcpy(e->addr, w->addr, 16); e->prefix_length = w->prefix_length;
e->next = r->v6_subnets; r->v6_subnets = e;
}
*out_subnets = r;
} else if (!(msg->flags & TOPO_FLAG_SEND_SUBNETS)) {
dp += msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4)
+ msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6);
if (out_subnets) *out_subnets = NULL;
} else {
if (out_subnets) *out_subnets = NULL;
}
if (out_hop_list && msg->hop_count > 0) {
size_t hsz = msg->hop_count * 8;
*out_hop_list = u_malloc(hsz);
if (!*out_hop_list) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
memcpy(*out_hop_list, dp, hsz); dp += hsz;
*out_hop_count = msg->hop_count;
section = "hops"; index = 0;
size_t hop_bytes = msg->hop_count * sizeof(*hops);
if (out_hop_list && hop_bytes) {
hops = u_malloc(hop_bytes);
if (!hops) goto no_memory;
memcpy(hops, dp, hop_bytes);
}
dp += hop_bytes;
if ((size_t)(dp - data) != len) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO decode: cursor mismatch node=%016llx consumed=%zu length=%zu",
(unsigned long long)msg->node_id, (size_t)(dp - data), len);
goto fail;
}
if (out_cumulative_rtt) *out_cumulative_rtt = msg->cumulative_rtt;
*out_ni = ni;
if (out_subnets) *out_subnets = subnets;
if (out_hop_list) *out_hop_list = hops;
if (out_hop_count) *out_hop_count = msg->hop_count;
if (out_cumulative_rtt) *out_cumulative_rtt = msg->cumulative_rtt;
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "NODEINFO decoded: node=%016llx bytes=%zu flags=%02x subnets=%u/%u hops=%u keep_subnets=%d keep_hops=%d",
(unsigned long long)msg->node_id, len, msg->flags, msg->local_v4_subnets, msg->local_v6_subnets,
msg->hop_count, out_subnets != NULL, out_hop_list != NULL);
return 0;
invalid_profile:
DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO decode: invalid profile node=%016llx section=%s index=%u",
(unsigned long long)msg->node_id, section, index);
goto fail;
no_memory:
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO decode: allocation failed node=%016llx section=%s index=%u offset=%zu",
(unsigned long long)msg->node_id, section, index, (size_t)(dp - data));
fail:
topo_node_free_raw(groups, ni);
if (subnets) {
free_v4_sub_list(groups->v4_subnet_pool, subnets->v4_subnets);
free_v6_sub_list(groups->v6_subnet_pool, subnets->v6_subnets);
u_free(subnets);
}
u_free(hops);
return -1;
}
/* Ищет per-group узел TOPO_GROUP_NODE в группе по node_id (NULL, если нет). */
+9 -3
View File
@@ -248,13 +248,19 @@ void topo_nodeq_clear_paths(struct TOPO_GROUP_NODE* nq);
* убирает из group->nodes и освобождает сам nq. Единственный корректный способ удаления узла. */
void topo_nodeq_remove_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq);
/* Размер переменной части NODEINFO по счётчикам заголовка. */
/* Размер переменной части NODEINFO или -1 при NULL/счётчиках подсетей без TOPO_FLAG_SEND_SUBNETS. */
int topo_node_dyn_size(const struct TOPOMSG_NODE* msg);
/* Собрать NODEINFO в out; длина или -1. Входные структуры остаются у вызывающего. */
/* Собрать NODEINFO в out[out_max]; длина или -1. Входные структуры остаются у вызывающего.
* Без TOPO_FLAG_SEND_SUBNETS обе секции подсетей отсутствуют, их счётчики равны 0. */
int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
uint64_t group_id, uint8_t flags,
uint8_t* out, size_t out_max, uint16_t cumulative_rtt);
/* Разобрать NODEINFO; 0/-1. Выходные объекты выделены отдельно и передаются вызывающему. */
/* Разобрать ровно len байт NODEINFO; 0/-1. group->instance->topo_groups содержит пулы списков.
* out_ni обязателен, остальные выходы независимы и необязательны. Отсутствие выхода не меняет обход/проверки секций.
* Перед разбором все переданные выходы обнуляются, прежние объекты не освобождаются.
* При успехе node уничтожается topo_node_destroy, подсети возвращаются в пулы groups, hops освобождается u_free.
* Пустые секции дают NULL/0; при ошибке выходы остаются NULL/0, частичные объекты освобождены.
* Проверяет размер, профили и /0..32, /0..128; подпись и допустимость BGP-пути проверяет вызывающий. */
int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t len, struct TOPO_NODE** out_ni, struct TOPO_NODESUBNETS** out_subnets,
uint64_t** out_hop_list, uint8_t* out_hop_count,
uint16_t* out_cumulative_rtt);