Cover radio phone policy, BGP color flags, retries and caller choice timeout

This commit is contained in:
evgeny committed 2026-10-19 14:59:17 +02:00
1 parent 4683c98c08
commit 79b4235960
2 files changed
+82 -11

No files matched your search

+73 -8
View File
@@ -20,6 +20,7 @@
#include "member_sync.h"
#include "../radio/radio.h"
#include "../radio/radio_call.h"
#include "../call/call.h"
#include "../routing_layer/etcp_router.h"
#include "../routing_layer/topo_node_sqlite.h"
#include "../routing_layer/topo_group.h"
@@ -52,7 +53,7 @@
#define IDX_C 2
#define TICK_TB 100 /* 10 ms на такт */
#define MAX_TICKS 12000 /* включает минуту ожидания решения по вызову */
#define MAX_TICKS 24000 /* включает минутные deadline звонка и выбора продолжения */
#define N_FRAMES 5
enum rad_phase {
@@ -111,8 +112,9 @@ static int g_member_radio[3][3];
static int g_member_lists[3];
static int g_member_event_bad;
static int g_talk_on[3], g_talk_starts[3], g_talk_stops[3];
static struct { int state, reason, finished, incoming; uint64_t finished_tb; } g_calls[8][3];
static int g_call_ready, g_drop_result, g_drop_ack;
static struct { int state, reason, finished, incoming; uint64_t finished_tb; } g_calls[20][3];
static int g_call_ready, g_drop_result, g_drop_ack, g_drop_force;
static int g_member_phone[3][3];
static etcp_recv_fn g_call_recv[3];
/* Потеря приложения после router ACK: восстановить результат обязан сервис, не транспорт. */
@@ -122,7 +124,8 @@ static void call_packet_loss(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (idx < 0 || !entry) abort();
if (entry->len <= ROUTER_SVC_PAYLOAD_OFF) { g_call_recv[idx](conn, entry); return; }
int cmd = entry->dgram[ROUTER_SVC_PAYLOAD_OFF];
if ((idx == IDX_A && cmd == 3 && g_drop_result-- > 0) || (idx == IDX_C && cmd == 4 && g_drop_ack-- > 0)) {
if ((idx == IDX_A && cmd == 3 && g_drop_result-- > 0) || (idx == IDX_C && cmd == 4 && g_drop_ack-- > 0) ||
(idx == IDX_C && cmd == 6 && g_drop_force-- > 0)) {
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "test drops radio result/ACK dst=%d command=%d", idx, cmd);
queue_dgram_free(entry); queue_entry_free(entry); return;
}
@@ -163,7 +166,7 @@ static void member_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* da
memcpy(&id, data, 8); memcpy(&group, data + 8, 8); memcpy(&peer, data + 16, 8);
int idx = -1;
for (int i = 0; i < 3; ++i) if (inst->node_id == g_sh.nid[i]) idx = i;
if (idx < 0 || id < 100 || id > 107 || group != strtoull(CH_ID, NULL, 10)) { g_member_event_bad = 1; return; }
if (idx < 0 || id < 100 || id > 119 || group != strtoull(CH_ID, NULL, 10)) { g_member_event_bad = 1; return; }
g_calls[id - 100][idx].state = data[24]; g_calls[id - 100][idx].reason = data[25];
if (data[24] == RADIO_CALL_INCOMING) {
++g_calls[id - 100][idx].incoming;
@@ -212,8 +215,10 @@ static void member_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* da
if (chat_core_deserialize_member(data + off + i * CHAT_MEMBER_DISPLAY_SIZE, &member) < 0) {
g_member_event_bad = 1; return;
}
for (int j = 0; j < 3; j++)
if (member.node_id == g_sh.nid[j]) g_member_radio[dst][j] = !!(member.flags & CHAT_MEMBER_FLAG_RADIO);
for (int j = 0; j < 3; j++) if (member.node_id == g_sh.nid[j]) {
g_member_radio[dst][j] = !!(member.flags & CHAT_MEMBER_FLAG_RADIO);
g_member_phone[dst][j] = member.flags & (CHAT_MEMBER_FLAG_PHONE_KNOWN | CHAT_MEMBER_FLAG_PHONE_BUSY);
}
}
}
@@ -598,9 +603,69 @@ static void rad_tick(void* arg) {
t->result = 2; uasync_stop(t->ua); return;
}
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "test radio calls passed: 2s/60s, accept/decline/cancel/busy, lost result/ACK, idle has no timer");
t->phase = P_RADIO_ON;
call_set_phone_state(C, 2, CALL_POLICY_WARN_PHONE);
radio_action(A, 108, RADIO_CALL_START, nc); ++t->call_step;
}
break;
case 10:
if (g_calls[8][IDX_A].state != RADIO_CALL_WAIT_DECISION) break;
if (g_calls[8][IDX_C].incoming || g_member_phone[IDX_A][IDX_C]) goto phone_failed;
call_set_phone_state(C, 1, CALL_POLICY_WARN_PHONE);
t->call_started = now; ++t->call_step; break;
case 11:
if (now - t->call_started < 10000) break;
if (g_calls[8][IDX_C].incoming) goto phone_failed; // Освободившийся телефон сам не начинает вызов.
g_drop_force = 2;
radio_action(A, 108, RADIO_CALL_CONTINUE, 0); ++t->call_step; break;
case 12:
if (g_calls[8][IDX_A].state != RADIO_CALL_RINGING) break;
if (g_calls[8][IDX_C].incoming != 1 || g_drop_force > 0) goto phone_failed;
radio_action(C, 108, RADIO_CALL_DECLINE, 0); ++t->call_step; break;
case 13:
if (!g_calls[8][IDX_A].finished) break;
radio_action(A, 108, RADIO_CALL_CONTINUE, 0); // Запоздалое UI-подтверждение не оживляет попытку.
call_set_phone_state(C, 2, CALL_POLICY_PUBLISH_PHONE);
radio_action(A, 109, RADIO_CALL_START, nc); ++t->call_step; break;
case 14:
if (g_calls[9][IDX_A].state != RADIO_CALL_RINGING || g_member_phone[IDX_A][IDX_C] != 0xC0) break;
if (g_calls[9][IDX_C].incoming != 1 || g_calls[8][IDX_C].incoming != 1) goto phone_failed;
{
uint8_t member[CHAT_MEMBER_DISPLAY_SIZE];
if (chat_core_get_single_member(A, CH_ID, nc, member) || (member[10] & 0xC0) != 0xC0) goto phone_failed;
}
radio_action(A, 109, RADIO_CALL_CANCEL, 0); ++t->call_step; break;
case 15:
if (!g_calls[9][IDX_C].finished) break;
call_set_phone_state(C, 2, CALL_POLICY_WARN_PHONE | CALL_POLICY_REJECT_PHONE);
radio_action(A, 110, RADIO_CALL_START, nc); ++t->call_step; break;
case 16:
if (!g_calls[10][IDX_A].finished || g_member_phone[IDX_A][IDX_C]) break;
if (g_calls[10][IDX_A].reason != RADIO_CALL_PHONE_BUSY || g_calls[10][IDX_C].incoming) goto phone_failed;
call_set_phone_state(C, 0, CALL_POLICY_BLOCK_CALLS);
radio_action(A, 111, RADIO_CALL_START, nc); ++t->call_step; break;
case 17:
if (g_calls[11][IDX_A].state != RADIO_CALL_RINGING) break;
radio_action(A, 111, RADIO_CALL_CANCEL, 0); ++t->call_step; break;
case 18:
if (!g_calls[11][IDX_C].finished) break;
call_set_phone_state(C, 2, CALL_POLICY_BLOCK_RADIO | CALL_POLICY_WARN_PHONE);
radio_action(A, 112, RADIO_CALL_START, nc); ++t->call_step; break;
case 19:
if (!g_calls[12][IDX_A].finished) break;
if (g_calls[12][IDX_A].reason != RADIO_CALL_DECLINED || g_calls[12][IDX_C].incoming) goto phone_failed;
call_set_phone_state(C, 2, CALL_POLICY_WARN_PHONE);
t->call_started = now;
radio_action(A, 113, RADIO_CALL_START, nc); ++t->call_step; break;
case 20:
if (!g_calls[13][IDX_A].finished) break;
if (g_calls[13][IDX_A].reason != RADIO_CALL_NO_ANSWER || g_calls[13][IDX_C].incoming ||
now - t->call_started < RADIO_CALL_RING_TB || now - t->call_started > RADIO_CALL_RING_TB + 1000) goto phone_failed;
call_set_phone_state(C, 0, 0);
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "phone policy passed: hidden/published BGP, warn, override with loss, reject, independent blocks, 60s choice");
t->phase = P_RADIO_ON; break;
phone_failed:
DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "phone policy failed step=%d", t->call_step);
t->result = 2; uasync_stop(t->ua); return;
}
break;
}