diff --git a/src/chat/group_policy.c b/src/chat/group_policy.c index 9a14c61f7..af58852d0 100644 --- a/src/chat/group_policy.c +++ b/src/chat/group_policy.c @@ -217,13 +217,14 @@ int group_policy_refresh(struct UTUN_INSTANCE* inst, const char* channel) { { int rc = sqlite3_finalize(st); st = NULL; if (rc != SQLITE_OK) goto done; } if (sqlite3_exec(db, "COMMIT /* admission */", NULL, NULL, NULL) != SQLITE_OK) goto done; result = 0; + struct TOPO_GROUP* group = inst->topo_groups ? topo_groups_find(inst->topo_groups, chat_channel_id(channel)) : NULL; + if (group) topo_group_revalidate_members(group); for (size_t i = 0; i < count; i++) if (m[i].previous != m[i].allowed) { DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "group admission ch=%s node=%016llx signer=%016llx allowed=%u all=%u version=%llu", channel, (unsigned long long)m[i].node, (unsigned long long)m[i].signer, m[i].allowed, policy.all_members, (unsigned long long)policy.version); struct TOPO_GROUP* g = inst->topo_groups ? topo_groups_find(inst->topo_groups, chat_channel_id(channel)) : NULL; struct ETCP_CONN* conn = instance_find_conn(inst, m[i].node); - if (g && conn && !m[i].allowed) topo_group_remove_conn(g, conn, TOPO_REMOVE_MEMBER_INVALID); if (g && conn && m[i].allowed && conn->links_up && !conn->close_requested) topo_group_new_conn(g, conn); } if (changes) { @@ -258,7 +259,14 @@ int group_policy_can_invite(struct UTUN_INSTANCE* inst, const char* channel, uin /* Выбор передаётся строковыми uint64 ID: JSON number не сохраняет точность в интерфейсах. */ static int gp_select(sqlite3* db, struct gp_member* m, size_t count, const char* json) { sqlite3_stmt* st = NULL; - int rc = sqlite3_prepare_v2(db, "SELECT type,value FROM json_each(?1) WHERE json_type(?1)='array'", -1, &st, NULL); + int rc = sqlite3_prepare_v2(db, "SELECT json_type(?1)", -1, &st, NULL); + if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 1, json ? json : "[]", -1, SQLITE_STATIC); + if (rc == SQLITE_OK) rc = sqlite3_step(st); + if (rc != SQLITE_ROW || !sqlite3_column_text(st, 0) || strcmp((const char*)sqlite3_column_text(st, 0), "array")) { + rc = SQLITE_MISMATCH; goto done; + } + rc = sqlite3_finalize(st); st = NULL; + if (rc == SQLITE_OK) rc = sqlite3_prepare_v2(db, "SELECT type,value FROM json_each(?1)", -1, &st, NULL); if (rc == SQLITE_OK) rc = sqlite3_bind_text(st, 1, json ? json : "[]", -1, SQLITE_STATIC); if (rc != SQLITE_OK) goto done; while ((rc = sqlite3_step(st)) == SQLITE_ROW) { diff --git a/src/routing_layer/topo_group.c b/src/routing_layer/topo_group.c index a6652ff8c..5d8b452ef 100644 --- a/src/routing_layer/topo_group.c +++ b/src/routing_layer/topo_group.c @@ -407,7 +407,24 @@ static int topo_group_has_sender(struct TOPO_GROUP* group, struct ETCP_CONN* con static int topo_group_peer_allowed(struct TOPO_GROUP* group, uint64_t node_id) { if (group->group_type != TOPO_GROUP_TYPE_CHAT) return 1; sqlite3* db = group->instance->topo_sqlite_db; - return db && group->channel_id[0] && topo_node_sqlite_member_allowed(db, group->channel_id, node_id); + return db && group->channel_id[0] && topo_node_sqlite_member_allowed(db, group->channel_id, group->instance->node_id) && + topo_node_sqlite_member_allowed(db, group->channel_id, node_id); +} + +void topo_group_revalidate_members(struct TOPO_GROUP* group) { + if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT || group->stopping) return; + /* Удаление вызывает callbacks и меняет список; каждый раз ищем следующего заново. */ + for (;;) { + struct TOPO_GROUP_CONN_ITEM* invalid = NULL; + for (struct ll_entry* e = group->senders_list ? group->senders_list->head : NULL; e; e = e->next) { + struct TOPO_GROUP_CONN_ITEM* p = (struct TOPO_GROUP_CONN_ITEM*)e->data; + if (!topo_group_peer_allowed(group, p->node_id)) { invalid = p; break; } + } + if (!invalid) break; + if (invalid->conn) topo_group_remove_conn(group, invalid->conn, TOPO_REMOVE_MEMBER_INVALID); + else topo_group_pending_remove(invalid); + } + topo_group_connect_changed(group); } /* Политика знакомого пира принадлежит группам/БД; транспорт передаёт только ключ, без SQL и таблиц. */ diff --git a/src/routing_layer/topo_group.h b/src/routing_layer/topo_group.h index fb96c3f2e..a5e883c93 100644 --- a/src/routing_layer/topo_group.h +++ b/src/routing_layer/topo_group.h @@ -385,6 +385,8 @@ enum topo_group_remove_reason { * При DOWN живые запросы сохраняют NCD для повторного UP. Только потеря транспорта * запускает recovery каскадно потерянных маршрутов. */ void topo_group_remove_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn, enum topo_group_remove_reason reason); +/* После пересчёта admitted: закрыть недопущенные сессии/запросы только этой группы. Общий транспорт сохраняется. */ +void topo_group_revalidate_members(struct TOPO_GROUP* group); /** * @brief Обрабатывает пакет NODEINFO.