Serialize group topology lazily through a cancellable backpressure sender

This commit is contained in:
evgeny committed 2026-09-28 02:45:00 +03:00
1 parent 792776a1f6
commit 0756a6e020
7 files changed
+336 -45

No files matched your search

+229 -40
View File
@@ -44,6 +44,11 @@ struct TOPO_PEER_REQUEST {
static int topo_group_begin_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn, int retain);
static int topo_group_peer_allowed(struct TOPO_GROUP* group, uint64_t node_id);
static void topo_tx_clear(struct TOPO_GROUP_CONN_ITEM* peer);
static int topo_tx_control(struct TOPO_GROUP_CONN_ITEM* peer, const void* data, size_t size);
static int topo_tx_node(struct TOPO_GROUP_CONN_ITEM* peer, uint64_t node_id);
static int topo_tx_table(struct TOPO_GROUP_CONN_ITEM* peer);
static int topo_control_wait(struct ETCP_CONN* conn, const void* data, size_t size);
static struct TOPO_GROUP_CONN_ITEM* topo_group_peer(const struct TOPO_GROUP* group, uint64_t peer_id) {
for (struct ll_entry* e = group && group->senders_list ? group->senders_list->head : NULL; e; e = e->next) {
@@ -59,6 +64,7 @@ int topo_group_peer_ready(const struct TOPO_GROUP* group, uint64_t peer_id) {
}
static void topo_group_peer_free(struct TOPO_GROUP_CONN_ITEM* peer) {
topo_tx_clear(peer);
while (peer->requests) {
struct TOPO_PEER_REQUEST* request = peer->requests;
peer->requests = request->next; request->peer = NULL; request->next = NULL;
@@ -119,7 +125,7 @@ int topo_group_peer_open(struct TOPO_GROUP* group, uint64_t node_id, struct TOPO
enum topo_peer_phase topo_group_peer_phase(const struct TOPO_PEER_REQUEST* request) {
struct TOPO_GROUP_CONN_ITEM* peer = request ? request->peer : NULL;
if (!peer) return TOPO_PEER_FAILED;
if (!peer || peer->tx_failed) return TOPO_PEER_FAILED;
if (!peer->conn || !peer->conn->links_up) return TOPO_PEER_CONNECTING;
return topo_group_peer_ready(peer->group, peer->node_id) ? TOPO_PEER_READY : TOPO_PEER_SYNCING;
}
@@ -163,7 +169,7 @@ static struct TOPOMSG_HEADER topo_header(struct TOPO_GROUP_CONN_ITEM* peer, uint
.src_epoch = peer->local_epoch, .dst_epoch = peer->peer_epoch };
}
static int topo_send_control(struct ETCP_CONN* conn, const void* data, size_t size) {
static int topo_emit_control(struct ETCP_CONN* conn, const void* data, size_t size) {
struct ll_entry* e = ll_alloc_lldgram(size);
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group control allocation failed size=%zu", size); return -1; }
memcpy(e->dgram, data, size); e->len = size;
@@ -173,7 +179,20 @@ static int topo_send_control(struct ETCP_CONN* conn, const void* data, size_t si
queue_dgram_free(e); queue_entry_free(e); return -1;
}
/* Сообщения сессии проходят одну FIFO. Stateless RESYNC/REJECT также ждут
* пустой транспортной очереди, но не создают групповое участие. */
static int topo_send_control(struct ETCP_CONN* conn, const void* data, size_t size) {
if (size >= sizeof(struct TOPOMSG_HEADER)) {
const struct TOPOMSG_HEADER* h = data;
struct TOPO_GROUP* group = topo_groups_find(conn->instance->topo_groups, h->group_id);
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
if (peer && peer->conn == conn && peer->local_epoch == h->src_epoch) return topo_tx_control(peer, data, size);
}
return topo_control_wait(conn, data, size);
}
static int topo_group_reset_exchange(struct TOPO_GROUP_CONN_ITEM* peer) {
topo_tx_clear(peer); peer->tx_failed = 0;
peer->accepted = 0; peer->table_received = 0; peer->table_sent = 0; peer->peer_epoch = 0;
uint64_t epoch;
if (random_bytes((uint8_t*)&epoch, sizeof(epoch)) != 0 || !epoch) {
@@ -212,7 +231,7 @@ static int topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP_
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
if (!peer || !peer->accepted) return -1;
struct TOPOMSG_HEADER msg = topo_header(peer, TOPO_SUBCMD_TABLE_COMPLETE);
return topo_send_control(conn, &msg, sizeof(msg));
return topo_emit_control(conn, &msg, sizeof(msg));
}
static void topo_group_reject(struct ETCP_CONN* conn, const struct TOPOMSG_HEADER* h, enum topo_join_reject reason) {
@@ -225,7 +244,6 @@ static void topo_group_reject(struct ETCP_CONN* conn, const struct TOPOMSG_HEADE
static int topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t target_id);
static int topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_CONN* conn, const struct TOPOMSG_JOIN_GROUP* msg);
static void topo_group_handle_resync(struct UTUN_INSTANCE* instance, struct ETCP_CONN* conn);
@@ -660,7 +678,7 @@ void topo_group_on_activity_change(struct UTUN_INSTANCE* instance, int active, v
struct ll_entry* se = g->senders_list->head;
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn, 0);
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn);
se = se->next;
}
}
@@ -806,7 +824,7 @@ void topo_group_set_radio(struct TOPO_GROUP* group, int on) {
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn && group->local_node)
topo_group_send_nodeinfo(group, group->local_node, item->conn, 0);
topo_group_send_nodeinfo(group, group->local_node, item->conn);
se = se->next;
}
}
@@ -1235,8 +1253,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
if (id != node_id) {
int found = 0; for (int i = 0; i < hop_count; i++) if (hop_list[i] == id) found = 1;
if (found == 0) {
uint16_t out_rtt = topo_get_chain_rtt(nodeinfo1);
topo_group_send_nodeinfo(group, nodeinfo1, item->conn, out_rtt);
topo_group_send_nodeinfo(group, nodeinfo1, item->conn);
}
}
}
@@ -1289,7 +1306,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
}
/* Сериализует и шлёт NODEINFO узла конкретному пиру. */
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
static int topo_emit_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
if (!group || !node || !conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: invalid arguments"); return -1; }
size_t max_sz = sizeof(struct TOPOMSG_NODEINFO_PKT) + TOPO_NODE_WIRE_MAX_SIZE;
@@ -1334,6 +1351,206 @@ int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* n
return 0;
}
/* NODEINFO сериализуется только при отправке: указатели на узлы не переживают callback. */
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn) {
if (!group || !node || !conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: invalid arguments"); return -1; }
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
if (!peer || !peer->accepted) return 0;
return topo_tx_node(peer, node->node_id);
}
enum topo_tx_kind { TOPO_TX_CONTROL, TOPO_TX_NODE, TOPO_TX_TABLE };
struct topo_tx_item {
struct topo_tx_item* next;
enum topo_tx_kind kind;
uint64_t node_id;
struct ll_entry* packet;
uint64_t* nodes;
size_t count, pos, sent;
};
static void topo_tx_item_free(struct topo_tx_item* item) {
if (item->packet) { queue_dgram_free(item->packet); queue_entry_free(item->packet); }
u_free(item->nodes); u_free(item);
}
static void topo_tx_clear(struct TOPO_GROUP_CONN_ITEM* peer) {
if (peer->tx_wake) { uasync_call_soon_cancel(peer->group->instance->ua, peer->tx_wake); peer->tx_wake = NULL; }
if (peer->conn && peer->conn->send_input_q) queue_waiter_cancel(peer->conn->send_input_q, &peer->tx_waiter);
while (peer->tx_head) {
struct topo_tx_item* item = peer->tx_head; peer->tx_head = item->next; topo_tx_item_free(item);
}
peer->tx_tail = NULL;
}
static void topo_tx_fail(struct TOPO_GROUP_CONN_ITEM* peer) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group sender failed: group=%016llx peer=%016llx epoch=%016llx",
(unsigned long long)peer->group->group_id, (unsigned long long)peer->node_id, (unsigned long long)peer->local_epoch);
topo_tx_clear(peer); peer->tx_failed = 1; peer->table_sent = 0;
topo_recovery_changed(peer->group);
}
static void topo_tx_wait(void* arg);
static void topo_tx_schedule(struct TOPO_GROUP_CONN_ITEM* peer) {
if (!peer->tx_head || peer->tx_failed || peer->tx_wake || peer->tx_waiter.internal || peer->tx_waiter.call_soon_id) return;
peer->tx_wake = uasync_call_soon(peer->group->instance->ua, peer, topo_tx_wait);
if (!peer->tx_wake) topo_tx_fail(peer);
}
static int topo_tx_append(struct TOPO_GROUP_CONN_ITEM* peer, struct topo_tx_item* item) {
if (!item || peer->tx_failed) { if (item) topo_tx_item_free(item); topo_tx_fail(peer); return -1; }
if (peer->tx_tail) peer->tx_tail->next = item; else peer->tx_head = item;
peer->tx_tail = item; topo_tx_schedule(peer);
return peer->tx_failed ? -1 : 0;
}
static int topo_tx_control(struct TOPO_GROUP_CONN_ITEM* peer, const void* data, size_t size) {
struct topo_tx_item* item = u_calloc(1, sizeof(*item));
if (!item) { topo_tx_fail(peer); return -1; }
item->packet = ll_alloc_lldgram(size);
if (!item->packet) { u_free(item); topo_tx_fail(peer); return -1; }
memcpy(item->packet->dgram, data, size); item->packet->len = size;
item->kind = TOPO_TX_CONTROL;
return topo_tx_append(peer, item);
}
static int topo_tx_node(struct TOPO_GROUP_CONN_ITEM* peer, uint64_t node_id) {
/* Последнее изменение занимает своё место после уже ожидающих WITHDRAW.
* На один узел хранится не более одного несериализованного NODEINFO. */
struct topo_tx_item** link = &peer->tx_head;
struct topo_tx_item* prev = NULL;
struct topo_tx_item* item = NULL;
while (*link) {
if ((*link)->kind == TOPO_TX_NODE && (*link)->node_id == node_id) {
item = *link; *link = item->next;
if (peer->tx_tail == item) peer->tx_tail = prev;
item->next = NULL; break;
}
prev = *link; link = &(*link)->next;
}
if (!item) item = u_calloc(1, sizeof(*item));
if (!item) { topo_tx_fail(peer); return -1; }
item->kind = TOPO_TX_NODE; item->node_id = node_id;
return topo_tx_append(peer, item);
}
static int topo_tx_table(struct TOPO_GROUP_CONN_ITEM* peer) {
for (struct topo_tx_item* item = peer->tx_head; item; item = item->next)
if (item->kind == TOPO_TX_TABLE) return 0;
struct TOPO_GROUP* group = peer->group;
struct topo_tx_item* item = u_calloc(1, sizeof(*item));
if (!item) { topo_tx_fail(peer); return -1; }
item->kind = TOPO_TX_TABLE;
size_t capacity = (size_t)queue_entry_count(group->nodes) + 1;
item->nodes = u_malloc(capacity * sizeof(*item->nodes));
if (!item->nodes) { u_free(item); topo_tx_fail(peer); return -1; }
item->nodes[item->count++] = group->local_node->node_id;
for (struct ll_entry* e = group->nodes->head; e; e = e->next) {
struct TOPO_GROUP_NODE* node = (struct TOPO_GROUP_NODE*)e;
if (node != group->local_node && topo_group_should_send_to(node, peer->node_id)) item->nodes[item->count++] = node->node_id;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "group table queued: group=%016llx peer=%016llx epoch=%016llx nodes=%zu",
(unsigned long long)group->group_id, (unsigned long long)peer->node_id, (unsigned long long)peer->local_epoch, item->count);
return topo_tx_append(peer, item);
}
static int topo_tx_emit_node(struct TOPO_GROUP_CONN_ITEM* peer, uint64_t id) {
struct TOPO_GROUP* group = peer->group;
struct TOPO_GROUP_NODE* node = id == group->local_node->node_id ? group->local_node : topo_node_find_by_id(group, id);
if (!node || (node != group->local_node && !topo_group_should_send_to(node, peer->node_id))) return 0;
return topo_emit_nodeinfo(group, node, peer->conn, node == group->local_node ? 0 : topo_get_chain_rtt(node)) < 0 ? -1 : 1;
}
static void topo_tx_ready(struct ll_queue* queue, void* arg) {
struct TOPO_GROUP_CONN_ITEM* peer = arg;
/* Deferred waiters must recheck: another producer can occupy the queue first. */
if (queue_entry_count(queue)) { topo_tx_schedule(peer); return; }
struct topo_tx_item* item = peer->tx_head;
if (!item) return;
int result = 0, complete = 1;
if (item->kind == TOPO_TX_CONTROL) {
result = etcp_send(peer->conn, item->packet);
if (result == 0) item->packet = NULL;
} else if (item->kind == TOPO_TX_NODE) result = topo_tx_emit_node(peer, item->node_id);
else {
if (item->pos < item->count) {
result = topo_tx_emit_node(peer, item->nodes[item->pos++]);
if (result > 0) item->sent++;
complete = 0;
} else {
result = topo_group_send_table_complete(peer->group, peer->conn);
if (result == 0) {
peer->table_sent = 1; topo_group_log_exchange(peer->group, peer);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "group table sent: group=%016llx peer=%016llx epoch=%016llx nodes=%zu",
(unsigned long long)peer->group->group_id, (unsigned long long)peer->node_id,
(unsigned long long)peer->local_epoch, item->sent);
}
}
}
if (result < 0) { topo_tx_fail(peer); return; }
topo_group_peer_progressed(peer->group, peer->node_id);
if (complete) {
peer->tx_head = item->next;
if (!peer->tx_head) peer->tx_tail = NULL;
topo_tx_item_free(item);
}
topo_tx_schedule(peer);
}
static void topo_tx_wait(void* arg) {
struct TOPO_GROUP_CONN_ITEM* peer = arg;
peer->tx_wake = NULL;
if (!peer->conn || !peer->conn->send_input_q || peer->conn->close_requested ||
queue_waiter_wait(peer->conn->send_input_q, &peer->tx_waiter, topo_tx_ready, peer) < 0) topo_tx_fail(peer);
}
/* Небольшой ответ вне групповой сессии владеет NCD только до постановки пакета
* в транспорт. CLOSED/DOWN отменяет waiter до уничтожения транспортной очереди. */
struct topo_control {
struct NODE_CONN_DIRECT* handle;
struct ll_queue* queue;
struct queue_waiter_handle waiter;
struct ll_entry* packet;
};
static void topo_control_free(struct topo_control* control) {
queue_waiter_cancel(control->queue, &control->waiter);
node_conn_direct_close(control->handle);
queue_dgram_free(control->packet); queue_entry_free(control->packet); u_free(control);
}
static void topo_control_event(struct NODE_CONN_DIRECT* handle, enum ncd_event event, void* arg) {
(void)handle;
if (event == NCD_EVENT_UP) return;
DEBUG_WARN(DEBUG_CATEGORY_BGP, "pending group control cancelled transport_event=%d", event);
topo_control_free(arg);
}
static void topo_control_ready(struct ll_queue* queue, void* arg) {
struct topo_control* control = arg;
if (queue_entry_count(queue)) {
if (queue_waiter_wait(queue, &control->waiter, topo_control_ready, control) >= 0) return;
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot rearm group control waiter");
} else if (etcp_send(node_conn_direct_get_conn(control->handle), control->packet) == 0) control->packet = NULL;
else DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot send pending group control");
topo_control_free(control);
}
static int topo_control_wait(struct ETCP_CONN* conn, const void* data, size_t size) {
if (!conn->send_input_q || conn->close_requested) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "group control on closing transport"); return -1; }
if (!queue_entry_count(conn->send_input_q)) return topo_emit_control(conn, data, size);
struct topo_control* control = u_calloc(1, sizeof(*control));
if (!control) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group control allocation failed"); return -1; }
control->queue = conn->send_input_q; control->packet = ll_alloc_lldgram(size);
if (!control->packet) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "group control packet allocation failed"); u_free(control); return -1; }
memcpy(control->packet->dgram, data, size); control->packet->len = size;
if (node_conn_direct_open(conn->instance, conn->peer_node_id, topo_control_event, control, &control->handle, NULL) == NCD_ERR ||
queue_waiter_wait(control->queue, &control->waiter, topo_control_ready, control) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot retain pending group control"); topo_control_free(control); return -1;
}
return 0;
}
/* Добавляет conn в senders_list (дедуп), если его там ещё нет. */
static int topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
if (!group || !conn || !group->senders_list) return -1;
@@ -1420,7 +1637,7 @@ static void topo_leave_ready(struct ll_queue* queue, void* arg) {
(unsigned long long)leave->group_id);
topo_leave_finish(leave); return;
}
int result = topo_send_control(conn, &leave->message, sizeof(leave->message));
int result = topo_emit_control(conn, &leave->message, sizeof(leave->message));
if (result != 0) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot send LEAVE_GROUP group=%016llx", (unsigned long long)leave->group_id);
else DEBUG_INFO(DEBUG_CATEGORY_BGP, "LEAVE_GROUP sent: peer=%016llx group=%016llx",
(unsigned long long)node_conn_direct_node_id(leave->handle), (unsigned long long)leave->group_id);
@@ -1454,38 +1671,10 @@ int topo_group_leave_peer(struct TOPO_GROUP* group, struct NODE_CONN_DIRECT* han
return 0;
}
/* Шлёт пиру полную таблицу узлов группы (все узлы, кроме достижимых через него). */
static int topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
uint64_t target = conn->peer_node_id;
struct ll_entry* e = group->nodes ? group->nodes->head : NULL;
while (e) {
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
if (nq->node_id == group->instance->node_id) { e = e->next; continue; }
if (!nq->paths) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "node has no paths"); e = e->next; continue; }
if (topo_group_should_send_to(nq, target) && topo_group_send_nodeinfo(group, nq, conn, topo_get_chain_rtt(nq)) < 0) return -1;
e = e->next;
}
return 0;
}
/* Обрабатывает REQUEST_TABLE: шлёт свой nodeinfo + полную таблицу + TABLE_COMPLETE. */
/* Повторный REQUEST_TABLE той же сессии не создаёт второй снимок. */
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
if (!group || !conn) return;
if (!topo_group_peer_allowed(group, conn->peer_node_id)) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "table request deferred: member unknown peer=%016llx group=%016llx",
(unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id);
return;
}
if (topo_group_send_nodeinfo(group, group->local_node, conn, 0) < 0 || topo_group_send_full_table(group, conn) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table exchange incomplete group=%016llx peer=%016llx",
(unsigned long long)group->group_id, (unsigned long long)conn->peer_node_id);
return;
}
/* senders_list заполняется только через topo_group_new_conn (add + BGP);
здесь не добавляем, иначе new_conn (на JOIN_GROUP) упирается в дедуп и не шлёт TABLE_REQ обратно. */
if (topo_group_send_table_complete(group, conn) < 0) return;
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
if (peer && peer->conn == conn && !peer->table_sent) { peer->table_sent = 1; topo_group_log_exchange(group, peer); }
if (peer && peer->accepted && !peer->table_sent) topo_tx_table(peer);
}
/* Обрабатывает JOIN_GROUP: для UTUN — добавить запросившего и инициировать BGP обратно. */
+13 -2
View File
@@ -51,6 +51,7 @@ struct CONN_MGR;
struct TOPO_RECOVERY_CTX;
struct TOPO_GROUP_CONNECT;
struct TOPO_PEER_REQUEST;
struct topo_tx_item;
struct broadcast_ctx;
struct radio_ctx;
@@ -106,6 +107,11 @@ void topo_fire_nodeinfo_cbk(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* g
* оба поколения и принимаются только в согласованной сессии. TABLE_COMPLETE
* отправляется после передачи транспорту всей таблицы отправителя.
* READY = живой транспорт + ACCEPT + table_sent + table_received.
* Исходящие команды одной сессии сохраняют FIFO-порядок. Снимок таблицы хранит
* только node_id; NODEINFO сериализуется при освобождении send_input_q. Удалённые
* узлы пропускаются, изменения после запроса идут за снимком. Повторный запрос
* не создаёт вторую таблицу. REINIT/leave/stop отменяют остаток и waiter; уже
* переданные транспорту пакеты защищены поколениями на принимающей стороне.
*
* Новое присоединение и REINIT создают новое поколение; REINIT сохраняет пути.
* Поколения защищают сообщения, а доступность существующего пути определяется
@@ -173,6 +179,10 @@ struct TOPO_GROUP_CONN_ITEM {
uint8_t retained; // участие запрошено постоянным владельцем или достигло READY
uint64_t local_epoch, peer_epoch; // поколения сторон текущего присоединения
uint8_t accepted; // JOIN_ACCEPT подтвердил local_epoch
uint8_t tx_failed;
struct topo_tx_item *tx_head, *tx_tail;
struct queue_waiter_handle tx_waiter;
void* tx_wake;
uint8_t table_received; // TABLE_COMPLETE текущей сессии принят
uint8_t table_sent; // ответ на запрос пира целиком передан транспорту
};
@@ -341,9 +351,10 @@ int topo_group_leave_peer(struct TOPO_GROUP* group, struct NODE_CONN_DIRECT* han
int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* sender, const uint8_t* data, size_t len);
/**
* @brief Отправляет NODEINFO пакет одному conn (всегда local_node).
* @brief Планирует NODEINFO узла одному пиру с backpressure.
* Запись и RTT читаются при отправке; повторные изменения узла объединяются.
*/
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt);
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn);
/**
* @brief Отправляет WITHDRAW для node_id (вызывает broadcast_withdraw).
+1 -1
View File
@@ -1207,7 +1207,7 @@ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
struct ll_entry* se = g->senders_list->head;
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn, 0);
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn);
se = se->next;
}
}
+1 -1
View File
@@ -1906,7 +1906,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
struct ll_entry* se = g->senders_list->head;
while (se) {
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)se->data;
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn, 0);
if (item && item->conn) topo_group_send_nodeinfo(g, g->local_node, item->conn);
se = se->next;
}
}