Test radio invitation isolation and active invitation revocation

This commit is contained in:
evgeny committed 2026-11-03 20:35:38 +01:00
1 parent 8b9adff206
commit 509368b76d
1 file changed
+54 -2
+54 -2
View File
@@ -9,7 +9,10 @@
#include "config_updater.h"
#include "broadcast.h"
#include "chat/member_sync.h"
#include "chat/chat_event.h"
#include "radio/radio.h"
#include "radio/radio_call.h"
#include "ntp_time.h"
#include "member_files/private.h"
#include "member_files/disk.h"
#include "routing_layer/topo_group.h"
@@ -46,6 +49,8 @@ static struct {
pthread_cond_t disk_condition;
int disk_started, disk_released;
uint64_t block_request;
unsigned call_incoming[2][2], call_finished[2];
uint8_t call_reason[2];
} fixture = { .disk_mutex = PTHREAD_MUTEX_INITIALIZER, .disk_condition = PTHREAD_COND_INITIALIZER };
/* Лог содержит и проверяемый эффект, и результат; отрицательный тест не обрывает соседние проверки. */
@@ -317,6 +322,52 @@ static void file_response(void* arg, const struct mf_message* response) {
mf_status_text(response->status), response->data_len);
}
static void invitation_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int bytes) {
if (type != CHAT_EVT_RADIO_CALL || bytes != 27) return;
unsigned node = inst == fixture.nodes[0] ? 0 : 1;
uint64_t group; memcpy(&group, data + 8, 8);
if (data[24] == RADIO_CALL_INCOMING && group >= 111 && group <= 112) fixture.call_incoming[node][group - 111]++;
if (data[24] == RADIO_CALL_FINISHED) { fixture.call_finished[node]++; fixture.call_reason[node] = data[25]; }
}
static int invitation_isolation(void) {
struct UTUN_INSTANCE* server = fixture.nodes[0]; struct UTUN_INSTANCE* client = fixture.nodes[1];
REQUIRE(sqlite3_exec(server->topo_sqlite_db, "UPDATE peers_112 SET admitted=1", NULL, NULL, NULL) == SQLITE_OK);
for (unsigned i = 0; i < 2; i++) { REQUIRE(!radio_call_init(fixture.nodes[i])); chat_event_set_handler(fixture.nodes[i], invitation_event); }
struct radio_call_request request = {.inst = client, .id = 7000, .group = 112, .peer = server->node_id, .action = RADIO_CALL_START};
radio_call_execute(&request);
uint64_t deadline = get_time_tb() + 10000;
while (!fixture.call_incoming[0][1] && get_time_tb() < deadline) uasync_poll(fixture.ua, 1);
REQUIRE(fixture.call_incoming[0][1] == 1 && radio_call_busy(server));
check("admitted radio invitation reaches B", 1);
struct ETCP_ROUTER_CONN* route = etcp_router_conn_get(server, 112, client->node_id, ETCP_RT_ID_RADIO_CALL); REQUIRE(route);
struct SVC_ROUTE_HDR saved = {.cmd = ETCP_ID_SVC_ROUTE, .group_id = 112, .src_node_id = client->node_id,
.dst_node_id = server->node_id, .svc_id = ETCP_RT_ID_RADIO_CALL, .reset_id = route->peer_reset_id,
.peer_reset_id = route->reset_id, .seq = route->rx_seq};
char sql[160]; snprintf(sql, sizeof(sql), "UPDATE peers_112 SET admitted=0 WHERE node_id=%lld", (long long)client->node_id);
REQUIRE(sqlite3_exec(server->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
topo_group_revalidate_members(fixture.groups[0][1]);
check("revocation stops incoming radio invitation", !radio_call_busy(server) && fixture.call_finished[0] == 1 &&
fixture.call_reason[0] == RADIO_CALL_UNAVAILABLE);
uint8_t payload[18] = {1}; // RC_INVITE: command, id, expiry_us, reason.
uint64_t id = 7001; int64_t expires = ntp_time_get_us(client) + 2000000;
memcpy(payload + 1, &id, 8); memcpy(payload + 9, &expires, 8);
REQUIRE(!send_routed(&saved, payload, sizeof(payload), ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT));
check("revoked signed invitation creates no incoming call", !radio_call_busy(server) && fixture.call_incoming[0][1] == 1);
struct radio_call_request denied = {.inst = server, .id = 7001, .group = 112, .peer = client->node_id, .action = RADIO_CALL_START};
radio_call_execute(&denied);
check("local radio invitation obeys current group admission", !radio_call_busy(server) && fixture.call_finished[0] == 2 &&
fixture.call_reason[0] == RADIO_CALL_UNAVAILABLE);
request.action = RADIO_CALL_CANCEL; radio_call_execute(&request);
request.id = 7002; request.group = 111; request.action = RADIO_CALL_START; radio_call_execute(&request);
deadline = get_time_tb() + 10000;
while (!fixture.call_incoming[0][0] && get_time_tb() < deadline) uasync_poll(fixture.ua, 1);
check("radio invitation in neighbouring A still works", fixture.call_incoming[0][0] == 1 && radio_call_busy(server) &&
fixture.transport == instance_find_conn(client, server->node_id) && fixture.transport->links_up);
for (unsigned i = 0; i < 2; i++) { radio_call_destroy(fixture.nodes[i]); chat_event_set_handler(fixture.nodes[i], NULL); }
return 0;
}
static int file_isolation(unsigned running) {
struct UTUN_INSTANCE* server = fixture.nodes[0];
struct UTUN_INSTANCE* client = fixture.nodes[1];
@@ -401,7 +452,7 @@ int main(void) {
debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG);
}
if (setup() || run()) fixture.failed++;
if (setup() || run() || invitation_isolation()) fixture.failed++;
else {
for (unsigned i = 0; i < 2; i++) if (member_files_init(fixture.nodes[i])) fixture.failed++;
if (!fixture.failed) {
@@ -423,7 +474,8 @@ int main(void) {
pthread_mutex_unlock(&fixture.disk_mutex);
for (unsigned i = 0; i < 2; i++) if (fixture.handles[i]) conn_mgr_close(fixture.handles[i]);
for (unsigned i = 0; i < 2; i++) if (fixture.nodes[i]) {
member_files_destroy(fixture.nodes[i]); member_sync_destroy(fixture.nodes[i]); utun_instance_destroy(fixture.nodes[i]);
radio_call_destroy(fixture.nodes[i]); member_files_destroy(fixture.nodes[i]);
member_sync_destroy(fixture.nodes[i]); utun_instance_destroy(fixture.nodes[i]);
}
if (fixture.ua) uasync_destroy(fixture.ua, 0);
pthread_cond_destroy(&fixture.disk_condition); pthread_mutex_destroy(&fixture.disk_mutex);