Cover UDP accept cancellation with surviving paths and NCD owners
This commit is contained in:
1 parent
942736d604
commit
fb995db489
1 file changed
+80
-10
@@ -6,6 +6,8 @@
|
||||
#include "etcp_api.h"
|
||||
#include "etcp_connections.h"
|
||||
#include "etcp_keepalive.h"
|
||||
#include "node_conn_direct.h"
|
||||
#include "routing_layer/topo_node.h"
|
||||
#include "utun_instance.h"
|
||||
#include "test_clock.h"
|
||||
#include "test_net.h"
|
||||
@@ -87,6 +89,18 @@ static struct ETCP_LINK* first_link(unsigned side) {
|
||||
|
||||
static void run_for(unsigned tb) { test_clock_run_for(ua, tb); }
|
||||
|
||||
static void start_source(unsigned count) {
|
||||
ep[0].conn = etcp_connection_create(ep[0].inst, "liveness"); CHECK(ep[0].conn);
|
||||
ep[0].conn->peer_node_id = ep[1].inst->node_id;
|
||||
CHECK(sc_init_ctx(&ep[0].conn->crypto_ctx, &ep[0].inst->my_keys) == SC_OK);
|
||||
CHECK(sc_set_peer_public_key(&ep[0].conn->crypto_ctx, ep[1].inst->my_keys.public_key, SC_PEER_PUBKEY_BIN) == SC_OK);
|
||||
etcp_conn_add_cbk(ep[0].conn, conn_event, &ep[0], ETCP_CBK_EVENT_UP | ETCP_CBK_EVENT_DOWN | ETCP_CBK_EVENT_REINIT);
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
struct ETCP_SOCKET* socket = i ? test_etcp_bound_socket(ep[0].inst, "extra") : ep[0].socket;
|
||||
CHECK(etcp_link_new(ep[0].conn, socket, &ep[1].socket->interface_addr, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/* Только ядро и одна явно выбранная UDP-пара: BGP/NCD не создают обходных путей. */
|
||||
static void setup(unsigned swapped, unsigned count) {
|
||||
memset(ep, 0, sizeof(ep)); close_action = close_fired = late_handshakes = 0;
|
||||
@@ -105,16 +119,7 @@ static void setup(unsigned swapped, unsigned count) {
|
||||
CHECK(etcp_bind(ep[side].inst, 253, receive) == 0);
|
||||
}
|
||||
if (!count) return; /* Отдельная проверка входящего INIT до создания транспорта. */
|
||||
ep[0].conn = etcp_connection_create(ep[0].inst, "liveness"); CHECK(ep[0].conn);
|
||||
ep[0].conn->peer_node_id = ep[1].inst->node_id;
|
||||
CHECK(sc_init_ctx(&ep[0].conn->crypto_ctx, &ep[0].inst->my_keys) == SC_OK);
|
||||
CHECK(sc_set_peer_public_key(&ep[0].conn->crypto_ctx, ep[1].inst->my_keys.public_key, SC_PEER_PUBKEY_BIN) == SC_OK);
|
||||
etcp_conn_add_cbk(ep[0].conn, conn_event, &ep[0], ETCP_CBK_EVENT_UP | ETCP_CBK_EVENT_DOWN | ETCP_CBK_EVENT_REINIT);
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
struct ETCP_SOCKET* socket = ep[0].socket;
|
||||
if (i) socket = test_etcp_bound_socket(ep[0].inst, "extra");
|
||||
CHECK(etcp_link_new(ep[0].conn, socket, &ep[1].socket->interface_addr, 0));
|
||||
}
|
||||
start_source(count);
|
||||
uint64_t end = get_time_tb() + 30000;
|
||||
while (get_time_tb() < end) {
|
||||
test_clock_poll(ua, 10);
|
||||
@@ -225,6 +230,69 @@ static void send_init_request_body(const struct ETCP_INIT_REQUEST_PKT *request,
|
||||
etcp_connections_read_callback_socket(ep[1].socket->fd, ep[1].socket);
|
||||
}
|
||||
|
||||
struct accept_case {
|
||||
struct NODE_CONN_DIRECT *owner;
|
||||
struct ETCP_LINK *replacement;
|
||||
unsigned with_owner, with_link, fired, indexed, closed;
|
||||
int open_result;
|
||||
};
|
||||
static void accept_owner_event(struct NODE_CONN_DIRECT *h, enum ncd_event event, void *arg) {
|
||||
(void)h;
|
||||
struct accept_case *test = arg;
|
||||
if (event == NCD_EVENT_CLOSED) test->closed++;
|
||||
}
|
||||
static void cancel_accept(struct ETCP_CONN *conn, struct ETCP_LINK *link, int old_state, int old_status, void *arg) {
|
||||
(void)old_status;
|
||||
struct accept_case *test = arg;
|
||||
if (test->fired || old_state != -1 || !link->is_server) return;
|
||||
test->fired++;
|
||||
ep[1].conn = conn; CHECK(etcp_conn_ref_take(conn) == 0);
|
||||
test->indexed = instance_find_conn(conn->instance, conn->peer_node_id) == conn;
|
||||
struct ETCP_SOCKET *socket = link->conn;
|
||||
struct sockaddr_storage remote = link->remote_addr;
|
||||
etcp_link_close(link);
|
||||
if (test->with_link) { test->replacement = etcp_link_new(conn, socket, &remote, 0); CHECK(test->replacement); }
|
||||
if (test->with_owner) {
|
||||
/* Адресов пока нет: владелец удерживает входящий транспорт и ждёт будущего линка. */
|
||||
struct TOPO_NODE peer = {.node_id = ep[0].inst->node_id};
|
||||
memcpy(peer.public_key, ep[0].inst->my_keys.public_key, SC_PUBKEY_SIZE);
|
||||
test->open_result = node_conn_direct_open_node(conn->instance, peer.node_id, accept_owner_event, test,
|
||||
&test->owner, &peer, socket);
|
||||
CHECK(test->open_result != NCD_ERR && test->owner);
|
||||
}
|
||||
}
|
||||
static void cancelled_accept(unsigned swapped, unsigned with_owner, unsigned with_link) {
|
||||
setup(swapped, 0);
|
||||
struct accept_case test = {.with_owner = with_owner, .with_link = with_link};
|
||||
etcp_add_link_status_cbk(ep[1].inst, cancel_accept, &test);
|
||||
struct ETCP_INIT_REQUEST_PKT request = {.code = ETCP_INIT_REQUEST, .link_id = 1};
|
||||
for (unsigned i = 0; i < 8; i++) request.node_id[i] = ep[0].inst->node_id >> (56 - 8 * i);
|
||||
request.mtu[0] = ep[0].socket->mtu >> 8; request.mtu[1] = ep[0].socket->mtu;
|
||||
send_init_request_body(&request, sizeof(request), 0);
|
||||
etcp_remove_link_status_cbk(ep[1].inst, cancel_accept, &test);
|
||||
CHECK(test.fired == 1 && ep[1].conn);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "UDP cancelled accept swapped=%u other_link=%u owner=%u: indexed=%u closing=%u owner_conn=%p conn=%p",
|
||||
swapped, with_link, with_owner, test.indexed, ep[1].conn->close_requested,
|
||||
(void*)node_conn_direct_get_conn(test.owner), (void*)ep[1].conn);
|
||||
CHECK(test.indexed && !late_handshakes);
|
||||
if (with_owner || with_link) {
|
||||
CHECK(!ep[1].conn->close_requested && instance_find_conn(ep[1].inst, ep[0].inst->node_id) == ep[1].conn);
|
||||
CHECK(ep[1].inst->connections->count == 1 && !test.closed);
|
||||
if (with_owner) CHECK(test.open_result == NCD_REUSED && node_conn_direct_get_conn(test.owner) == ep[1].conn);
|
||||
if (with_link) CHECK(ep[1].conn->links == test.replacement && !test.replacement->closing);
|
||||
start_source(1); run_for(10000);
|
||||
CHECK(ep[0].conn->links_up && ep[1].conn->links_up && !test.closed);
|
||||
for (unsigned side = 0; side < 2; side++) {
|
||||
struct ll_entry *entry = ll_alloc_lldgram(2); CHECK(entry);
|
||||
entry->len = 2; entry->dgram[0] = 253; entry->dgram[1] = 17;
|
||||
CHECK(etcp_send(ep[side].conn, entry) == 0);
|
||||
}
|
||||
run_for(10000); CHECK(ep[0].received == 1 && ep[1].received == 1);
|
||||
} else CHECK(ep[1].conn->close_requested);
|
||||
node_conn_direct_force_close(test.owner);
|
||||
teardown();
|
||||
}
|
||||
|
||||
static void request_boundaries(unsigned established) {
|
||||
setup(0, established);
|
||||
unsigned drained = 0; uint8_t pending;
|
||||
@@ -481,6 +549,8 @@ int main(void) {
|
||||
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_DEBUG);
|
||||
}
|
||||
size_t baseline = u_get_allocated_count();
|
||||
for (unsigned swapped = 0; swapped < 2; swapped++) for (unsigned owner = 0; owner < 2; owner++)
|
||||
for (unsigned link = 0; link < 2; link++) { cancelled_accept(swapped, owner, link); check_memory(baseline); }
|
||||
for (unsigned swapped = 0; swapped < 2; swapped++) for (unsigned stage = 0; stage < 3; stage++)
|
||||
for (unsigned action = 0; action < 3; action++) { transition_callbacks(swapped, stage, action); check_memory(baseline); }
|
||||
for (unsigned established = 0; established < 2; established++) { request_boundaries(established); check_memory(baseline); }
|
||||
|
||||
Reference in new issue
Block a user