etcp_router: корректный handshake/restart без таймаут-петли

- START на первом пакете сеанса (seq=0), гейт отправки до первого ACK
- дедуп рестарта по payload init-пакета (ретрансмит START не триггерит рестарт)
- RST переинициализирует только отправку (без CLOSE_ALL), дедуп повторных RST
This commit is contained in:
evgeny committed 2026-09-06 00:33:45 +03:00
1 parent 232ad2de6b
commit 53bce51201
3 files changed
+107 -20

No files matched your search

+29 -3
View File
@@ -672,7 +672,7 @@ static int pump_data(etcp_recv_fn recv_cb, struct UTUN_INSTANCE* inst,
// ======================== Restart/session tests ========================
static int test_rst_flag(void) {
TEST("RST flag — local state reset, service notified");
TEST("RST flag — send-side restart, no service notify");
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
SETUP();
g_notify_count = 0;
@@ -684,11 +684,13 @@ static int test_rst_flag(void) {
g_notify_count = 0;
inject(recv_cb, &inst, TEST_REMOTE_NODE, TEST_SVC_ID, 0, NULL, 0, 1, ROUTER_FLAG_RST);
if (g_notify_count != 1) FAIL("RST should notify service");
if (g_notify_count != 0) FAIL("RST should NOT notify service");
struct ETCP_ROUTER_CONN* c = etcp_router_conn_get(&inst, TOPO_GROUP_UTUN, TEST_REMOTE_NODE, TEST_SVC_ID);
if (!c) FAIL("rconn should still exist after reset");
if (c->tx_seq != 0 || c->rx_seq != 0 || c->start_sent != 0) FAIL("rconn not reset by RST");
if (c->tx_seq != 0 || c->start_sent != 0) FAIL("send side not reset by RST");
if (c->rx_seq != (uint32_t)n) FAIL("rx side should be untouched by RST");
if (!c->send_restart_pending) FAIL("send_restart_pending not set by RST");
etcp_router_conn_close(c);
TEARDOWN();
@@ -696,6 +698,29 @@ static int test_rst_flag(void) {
return 0;
}
static int test_start_retransmit_no_restart(void) {
TEST("START retransmit (same payload) — no restart");
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
SETUP();
g_notify_count = 0;
int n = rand() % 10 + 1;
rx_reset(0xC1);
pump_data(recv_cb, &inst, 0xC1, n, 0);
if (rx.delivered != n) FAIL("initial pump failed");
g_notify_count = 0;
// ретрансмит первого пакета (seq=0, START, тот же payload) — не должен рестартовать
uint8_t data[] = { TEST_SVC_ID, 0xC1, 0 };
inject(recv_cb, &inst, TEST_REMOTE_NODE, TEST_SVC_ID, 0, data + 1, 2, 0, ROUTER_FLAG_START);
if (g_notify_count != 0) FAIL("START retransmit should NOT restart");
if (rx.delivered != n) FAIL("duplicate START should not deliver");
TEARDOWN();
PASS();
return 0;
}
static int test_client_restart(void) {
TEST("client restart — START flag detected after random data");
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
@@ -1157,6 +1182,7 @@ int main(void) {
test_timestamp();
test_conn_send_no_bgp();
test_rst_flag();
test_start_retransmit_no_restart();
test_client_restart();
test_sess_id_increment();
test_server_reinit();