Separate core, UTUN and chat lifecycles with owned asynchronous work
This commit is contained in:
1 parent
5838e63cde
commit
72fee9e245
47 files changed
+708
-337
No files matched your search
@@ -1356,18 +1356,18 @@ void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, ui
|
||||
struct queue_waiter_handle* h,
|
||||
queue_threshold_callback_fn callback, void* arg) {
|
||||
if (!inst || !h) return;
|
||||
etcp_router_cancel_send_ready(inst, group_id, node_id, svc_id, h);
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, node_id, svc_id);
|
||||
if (!rconn || !rconn->send_q) return;
|
||||
h->defer_q = rconn->send_q; /* Keep the registration queue across route/session replacement. */
|
||||
queue_waiter_wait(rconn->send_q, h, callback, arg);
|
||||
}
|
||||
|
||||
// Backpressure: отменить waiter на send_q для (group_id, node_id, svc_id).
|
||||
void etcp_router_cancel_send_ready(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t node_id, uint8_t svc_id,
|
||||
struct queue_waiter_handle* h) {
|
||||
if (!inst || !h) return;
|
||||
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, group_id, node_id, svc_id);
|
||||
if (!rconn || !rconn->send_q) return;
|
||||
queue_waiter_cancel(rconn->send_q, h);
|
||||
(void)inst; (void)group_id; (void)node_id; (void)svc_id;
|
||||
if (h && (h->internal || h->call_soon_id)) queue_waiter_cancel(h->defer_q, h);
|
||||
}
|
||||
|
||||
// Backpressure: есть ли место в send_q (без регистрации waiter). 1 — есть, 0 — нет.
|
||||
@@ -1466,3 +1466,25 @@ void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t gr
|
||||
for (int i = 0; i < count; i++)
|
||||
router_close_and_notify((struct ETCP_ROUTER_CONN*)to_close[i]);
|
||||
}
|
||||
|
||||
/* Service stop: discard every logical channel in a group before its routes disappear.
|
||||
* Call after service producers have cancelled their waiters. */
|
||||
void etcp_router_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id) {
|
||||
if (!inst) return;
|
||||
/* Notifications may close other channels too; do not retain list cursors across them. */
|
||||
while (inst->router_conns) {
|
||||
struct ll_entry* entry = inst->router_conns->head;
|
||||
while (entry && ((struct ETCP_ROUTER_CONN*)entry)->group_id != group_id) entry = entry->next;
|
||||
if (!entry) break;
|
||||
router_close_and_notify((struct ETCP_ROUTER_CONN*)entry);
|
||||
}
|
||||
for (struct ll_entry* e = inst->connections ? inst->connections->head : NULL; e; e = e->next) {
|
||||
struct ETCP_CONN* conn = ((struct conn_queue_entry*)e->data)->conn;
|
||||
if (!conn) continue;
|
||||
struct ll_entry* entry = conn->transit_queues ? conn->transit_queues->head : NULL;
|
||||
while (entry) {
|
||||
struct TRANSIT_QUEUE* transit = (struct TRANSIT_QUEUE*)entry; entry = entry->next;
|
||||
if (transit->group_id == group_id) transit_queue_destroy(conn, transit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,6 +253,7 @@ int etcp_router_send_q_has_room(struct UTUN_INSTANCE* inst, uint64_t group_id, u
|
||||
void etcp_router_pause_retrans_for_node(struct UTUN_INSTANCE* inst, uint64_t remote_node_id);
|
||||
|
||||
// Закрыть все router_conn для указанного (group_id, remote_node_id) (peer умер)
|
||||
void etcp_router_close_group(struct UTUN_INSTANCE* inst, uint64_t group_id);
|
||||
void etcp_router_conn_close_all_for_node(struct UTUN_INSTANCE* inst, uint64_t group_id, uint64_t remote_node_id);
|
||||
|
||||
// Начать новую локальную сессию для конкретного peer+svc в группе и уведомить сервис.
|
||||
|
||||
@@ -281,7 +281,7 @@ void routing_destroy(struct UTUN_INSTANCE* instance) {
|
||||
(unsigned long long)instance->node_id);
|
||||
|
||||
// Unbind DATA handler from etcp_router
|
||||
etcp_router_unbind(instance, ETCP_RT_ID_DATA);
|
||||
if (instance->router_bindings.callbacks[ETCP_RT_ID_DATA]) etcp_router_unbind(instance, ETCP_RT_ID_DATA);
|
||||
|
||||
// Clean up route table if exists
|
||||
if (instance->rt) {
|
||||
|
||||
@@ -563,6 +563,16 @@ static void topo_group_destroy(struct TOPO_GROUP* group) {
|
||||
radio_destroy(group);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 2c radio_destroy done");
|
||||
|
||||
/* A stopped service must withdraw membership even if another group keeps ETCP alive. */
|
||||
if (group->instance->running) {
|
||||
struct ll_entry* current = group->senders_list->head;
|
||||
while (current) {
|
||||
struct TOPO_GROUP_CONN_ITEM* peer = (struct TOPO_GROUP_CONN_ITEM*)current->data;
|
||||
current = current->next;
|
||||
if (peer->conn && peer->conn->links_up) topo_group_leave_peer(group, peer->handle);
|
||||
}
|
||||
}
|
||||
|
||||
struct ll_entry* e;
|
||||
while ((e = queue_data_get(group->senders_list)) != NULL) {
|
||||
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)e->data;
|
||||
@@ -574,6 +584,7 @@ static void topo_group_destroy(struct TOPO_GROUP* group) {
|
||||
queue_free(group->senders_list);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 3 senders_list done");
|
||||
|
||||
etcp_router_close_group(group->instance, group->group_id);
|
||||
if (group->conn_mgr) { conn_mgr_destroy(group->conn_mgr); group->conn_mgr = NULL; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 4 conn_mgr done");
|
||||
|
||||
@@ -589,6 +600,7 @@ static void topo_group_destroy(struct TOPO_GROUP* group) {
|
||||
if (nc) DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 4b nodes cleaned (%d)", nc);
|
||||
}
|
||||
if (group->local_node) {
|
||||
route_delete(group->instance->rt, group->local_node);
|
||||
if (group->local_node->paths) { queue_free(group->local_node->paths); group->local_node->paths = NULL; }
|
||||
topo_nodeq_free_group_fields(group->instance->topo_groups, group->local_node);
|
||||
u_free(group->local_node);
|
||||
@@ -601,15 +613,16 @@ static void topo_group_destroy(struct TOPO_GROUP* group) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[GRP_DESTROY] 5 done");
|
||||
}
|
||||
|
||||
/* Удаляет группу из контейнера (кроме UTUN-группы по умолчанию). */
|
||||
/* Удаляет группу и все принадлежащие ей ресурсы. */
|
||||
void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id) {
|
||||
if (!g || !g->group_list || group_id == TOPO_GROUP_UTUN) return;
|
||||
if (!g || !g->group_list) return;
|
||||
struct TOPO_GROUP* group = topo_groups_find(g, group_id);
|
||||
if (!group) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "remove_group: group %016llx not found", (unsigned long long)group_id); return; }
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "remove_group: id=%016llx type=%d ch=%s",
|
||||
(unsigned long long)group_id, group->group_type, group->channel_id);
|
||||
|
||||
if (g->instance->conn_mgr == group->conn_mgr) g->instance->conn_mgr = NULL;
|
||||
queue_remove_data(g->group_list, &group->ll);
|
||||
topo_group_destroy(group); /* node_cbks освобождаются внутри */
|
||||
queue_entry_free(&group->ll);
|
||||
@@ -637,9 +650,10 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
|
||||
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 (instance->config && instance->config->global.db_path[0]) {
|
||||
char db_file[512];
|
||||
snprintf(db_file, sizeof(db_file), "%s/chats.db", instance->config->global.db_path);
|
||||
{
|
||||
char db_file[512] = ":memory:";
|
||||
if (instance->config && instance->config->global.db_path[0])
|
||||
snprintf(db_file, sizeof(db_file), "%s/chats.db", instance->config->global.db_path);
|
||||
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) {
|
||||
@@ -661,18 +675,7 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
|
||||
|
||||
instance->topo_groups = g;
|
||||
|
||||
struct TOPO_GROUP* default_group = topo_group_create(instance, TOPO_GROUP_UTUN, TOPO_GROUP_TYPE_UTUN);
|
||||
if (!default_group) {
|
||||
memory_pool_destroy(g->v4_sock_meta_pool); memory_pool_destroy(g->v4_addr_pool);
|
||||
memory_pool_destroy(g->v6_sock_meta_pool); memory_pool_destroy(g->v6_addr_pool);
|
||||
memory_pool_destroy(g->v4_subnet_pool); memory_pool_destroy(g->v6_subnet_pool);
|
||||
queue_free(g->node_registry); queue_free(g->group_list); u_free(g);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "failed to create default group");
|
||||
return NULL;
|
||||
}
|
||||
queue_data_put_with_index(g->group_list, &default_group->ll);
|
||||
|
||||
instance->conn_mgr = default_group->conn_mgr; /* recv handler shortcut */
|
||||
if (topo_node_init_self(instance) < 0) { topo_groups_destroy(instance); return NULL; }
|
||||
|
||||
etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk);
|
||||
etcp_add_conn_status_cbk(instance, topo_group_conn_status, g);
|
||||
@@ -680,7 +683,7 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
|
||||
ETCP_SOCKET_EVENT_ADDR_CHANGED | ETCP_SOCKET_EVENT_STATUS_CHANGED);
|
||||
utun_add_activity_cbk(instance, topo_group_on_activity_change, NULL);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TOPO groups initialized (with default group)");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TOPO registry initialized (services create their own groups)");
|
||||
return g;
|
||||
}
|
||||
|
||||
@@ -1655,8 +1658,12 @@ static void topo_leave_event(struct NODE_CONN_DIRECT* handle, enum ncd_event eve
|
||||
}
|
||||
|
||||
static void topo_leave_ready(struct ll_queue* queue, void* arg) {
|
||||
(void)queue;
|
||||
struct topo_leave* leave = arg;
|
||||
if (queue_entry_count(queue)) {
|
||||
if (queue_waiter_wait(queue, &leave->waiter, topo_leave_ready, leave) >= 0) return;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot rearm LEAVE_GROUP waiter");
|
||||
topo_leave_finish(leave); return;
|
||||
}
|
||||
struct ETCP_CONN* conn = node_conn_direct_get_conn(leave->handle);
|
||||
struct TOPO_GROUP* group = topo_groups_find(leave->instance->topo_groups, leave->group_id);
|
||||
if (group && topo_group_has_sender(group, conn)) {
|
||||
|
||||
@@ -281,8 +281,8 @@ struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t grou
|
||||
* @brief Удаляет одну группу по id (разрушает conn_mgr, connect-цикл, broadcast,
|
||||
* recovery, узлы и подписчиков node_cbks) и извлекает её из group_list.
|
||||
*
|
||||
* Используется при локальном удалении чат-канала. Группу по умолчанию
|
||||
* (TOPO_GROUP_UTUN) удалять нельзя — функция это игнорирует.
|
||||
* Используется при удалении канала и остановке сервиса. UTUN-группой
|
||||
* управляет utun_service_start/stop.
|
||||
*/
|
||||
void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id);
|
||||
|
||||
|
||||
@@ -122,8 +122,7 @@ static void tgi_handle_info_req(struct ETCP_CONN* conn, const uint8_t* data, siz
|
||||
char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)req->group_id);
|
||||
|
||||
struct TOPO_GROUP* grp = topo_groups_find(inst->topo_groups, req->group_id);
|
||||
struct TOPO_GROUP* sg = grp ? grp : topo_groups_get_default(inst->topo_groups);
|
||||
struct TOPO_NODE* ln = sg && sg->local_node ? topo_node_registry_find(inst->topo_groups, sg->local_node->node_id) : NULL;
|
||||
struct TOPO_NODE* ln = topo_node_registry_find(inst->topo_groups, inst->node_id);
|
||||
const char* nm = ln ? ln->node_name : NULL; size_t nl = nm ? strlen(nm) : 0; if (nl > 255) nl = 255;
|
||||
|
||||
sqlite3* db = inst->topo_sqlite_db;
|
||||
@@ -138,7 +137,7 @@ static void tgi_handle_info_req(struct ETCP_CONN* conn, const uint8_t* data, siz
|
||||
struct TGI_INVITE_RESP* resp = (struct TGI_INVITE_RESP*)rb;
|
||||
resp->cmd = ETCP_RT_ID_GROUP_INVITE; resp->subcmd = TGI_SUBCMD_INFO_RESP;
|
||||
resp->group_id = req->group_id; resp->is_member = 0;
|
||||
if (sg) memcpy(resp->ed25519_pubkey, sg->ed25519_public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(resp->ed25519_pubkey, inst->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
resp->node_name_len = (uint8_t)nl; if (nl) memcpy(resp->node_name, nm, nl);
|
||||
struct ll_entry* qe = queue_entry_new(0);
|
||||
if (qe) { qe->dgram = rb; qe->len = (uint16_t)rs;
|
||||
@@ -207,7 +206,7 @@ static void tgi_handle_info_req(struct ETCP_CONN* conn, const uint8_t* data, siz
|
||||
{ struct TGI_INVITE_RESP* resp = (struct TGI_INVITE_RESP*)rb;
|
||||
resp->cmd = ETCP_RT_ID_GROUP_INVITE; resp->subcmd = TGI_SUBCMD_INFO_RESP;
|
||||
resp->group_id = req->group_id; resp->is_member = 1;
|
||||
if (sg) memcpy(resp->ed25519_pubkey, sg->ed25519_public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(resp->ed25519_pubkey, inst->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
resp->node_name_len = (uint8_t)nl; if (nl) memcpy(resp->node_name, nm, nl); }
|
||||
|
||||
uint8_t* ch = rb + TGI_INVITE_RESP_HDR_SIZE + nl;
|
||||
|
||||
@@ -58,7 +58,7 @@ int topo_group_invite_join(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||||
* Инвайтера сторона: прямое подключение (ncd) к целевому узлу для последующей
|
||||
* отправки CHANNEL_INVITE (через chat_sync, по ETCP_CONN_STATUS_UP).
|
||||
* Без INVITE_INFO-проверки членства. ni может быть NULL — тогда адреса грузятся
|
||||
* из БД (node_conn_direct_open). Handle сохраняется в nq->handle.
|
||||
* из БД. Группа владеет NCD; инициатор держит отменяемый групповой запрос.
|
||||
*/
|
||||
int topo_group_invite_to_channel(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
||||
struct TOPO_NODE* ni, uint64_t node_id);
|
||||
|
||||
@@ -192,6 +192,7 @@ void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_
|
||||
void topo_nodeq_remove_node(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* nq) {
|
||||
if (!group || !nq) return;
|
||||
route_connectivity_cancel_node(nq);
|
||||
if (group->instance) route_delete(group->instance->rt, nq);
|
||||
if (nq->paths) { queue_free(nq->paths); nq->paths = NULL; }
|
||||
queue_remove_data(group->nodes, &nq->ll);
|
||||
topo_nodeq_free_group_fields(group->instance ? group->instance->topo_groups : NULL, nq);
|
||||
@@ -928,6 +929,25 @@ int topo_node_format_all(struct TOPO_GROUP* group, char* buf, size_t buf_size) {
|
||||
|
||||
// ===== update my nodeinfo =====
|
||||
|
||||
/* Core owns one reference independently of all services. */
|
||||
int topo_node_init_self(struct UTUN_INSTANCE* instance) {
|
||||
struct TOPO_NODE* ni = u_calloc(1, sizeof(*ni));
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "local identity allocation failed"); return -1; }
|
||||
ni->node_id = instance->node_id; ni->ver = 1;
|
||||
ni->client_type = instance->client_type; ni->client_activity = instance->client_activity;
|
||||
memcpy(ni->public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE);
|
||||
memcpy(ni->ed25519_public_key, instance->my_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
ni->node_name = u_strdup(instance->name);
|
||||
if (!ni->node_name || topo_node_sign_self(instance, ni) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot initialize local identity");
|
||||
topo_node_destroy(instance->topo_groups, ni); return -1;
|
||||
}
|
||||
if (!topo_node_registry_store(instance->topo_groups, ni)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot register local identity"); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Пересоздаёт local_node группы при изменении имени/подсетей/ключей, инкрементируя версию. */
|
||||
int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group) {
|
||||
if (!instance || !group) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; }
|
||||
@@ -1039,8 +1059,6 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
|
||||
/* Пересобирает списки адресов своего узла из ETCP-сокетов; при изменении — подпись, БД, рассылка. */
|
||||
int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
|
||||
if (!instance || !instance->topo_groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); return -1; }
|
||||
struct TOPO_GROUP* default_group = topo_groups_get_default(instance->topo_groups);
|
||||
if (!default_group || !default_group->local_node) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "no local_node"); return -1; }
|
||||
struct TOPO_NODE* ni = topo_node_registry_find(instance->topo_groups, instance->node_id);
|
||||
if (!ni) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "my node not in registry"); return -1; }
|
||||
|
||||
|
||||
@@ -243,6 +243,7 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
uint64_t* topo_node_best_hop_list(struct TOPO_GROUP_NODE* nq, uint8_t* out_count, uint16_t* out_rtt);
|
||||
|
||||
int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group);
|
||||
int topo_node_init_self(struct UTUN_INSTANCE* instance);
|
||||
int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance); /* 1=changed, 0=unchanged, -1=error */
|
||||
void topo_node_on_socket_changed(struct ETCP_SOCKET* sock, int event, void* arg);
|
||||
void topo_node_dump_all(struct TOPO_GROUP* group);
|
||||
|
||||
Reference in new issue
Block a user