|
|
|
|
@ -360,6 +360,31 @@ static int setup(void) {
|
|
|
|
|
config_ensure_keys_and_node_id(ca); config_ensure_keys_and_node_id(cb); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Предварительный отбор не создаёт транспорт; reverse допускается при недоступном исходящем адресе. */ |
|
|
|
|
static void test_compatibility(void) { |
|
|
|
|
struct TOPO_NODE* peer = topo_node_registry_find(g_a->topo_groups, nid_b); |
|
|
|
|
struct TOPO_NODE* self = topo_node_registry_find(g_a->topo_groups, nid_a); |
|
|
|
|
if (!self) { |
|
|
|
|
if (inject_node(g_a, nid_a, pubkey_a, pa) != 0) { fail("inject self compatibility snapshot"); return; } |
|
|
|
|
self = topo_node_registry_find(g_a->topo_groups, nid_a); |
|
|
|
|
} |
|
|
|
|
struct ETCP_SOCKET* socket = test_etcp_bound_socket(g_a, "s1"); |
|
|
|
|
if (!peer || !self || !socket || !peer->v4_sock_meta || !self->v4_sock_meta) { fail("compatibility fixture"); return; } |
|
|
|
|
if (!node_conn_direct_compatible(g_a, nid_b) || instance_find_conn(g_a, nid_b)) { fail("direct compatibility mutated transport"); return; } |
|
|
|
|
struct sockaddr_storage saved_interface = socket->interface_addr; |
|
|
|
|
struct sockaddr_in* interface = (struct sockaddr_in*)&socket->interface_addr; |
|
|
|
|
interface->sin_addr.s_addr = htonl(UINT32_C(0x08080808)); |
|
|
|
|
uint8_t saved_cfg = peer->v4_sock_meta->config_type, saved_self = self->v4_sock_meta->config_type; |
|
|
|
|
peer->v4_sock_meta->config_type = CFG_SERVER_TYPE_LOCAL; |
|
|
|
|
int reverse = node_conn_direct_compatible(g_a, nid_b); |
|
|
|
|
self->v4_sock_meta->config_type = CFG_SERVER_TYPE_LOCAL; |
|
|
|
|
int incompatible = node_conn_direct_compatible(g_a, nid_b); |
|
|
|
|
peer->v4_sock_meta->config_type = saved_cfg; self->v4_sock_meta->config_type = saved_self; |
|
|
|
|
socket->interface_addr = saved_interface; |
|
|
|
|
if (!reverse || incompatible || instance_find_conn(g_a, nid_b)) { fail("reverse/local compatibility or read-only contract"); return; } |
|
|
|
|
fprintf(stderr, "[PASS] compatibility: direct, reverse-only, incompatible local and no transport mutation\n"); |
|
|
|
|
} |
|
|
|
|
static void cleanup(void) { test_unlink(ca); test_unlink(cb); test_rmdir(tdir); } |
|
|
|
|
|
|
|
|
|
int main(void) { |
|
|
|
|
@ -377,6 +402,7 @@ int main(void) {
|
|
|
|
|
(unsigned long long)nid_a, pa, (unsigned long long)nid_b, pb); fflush(stderr); |
|
|
|
|
utun_instance_init(g_a); utun_instance_init(g_b); |
|
|
|
|
if (inject_node(g_a, nid_b, pubkey_b, pb) != 0) { fail("inject_node"); goto done; } |
|
|
|
|
test_compatibility(); if (g_result == 2) goto done; |
|
|
|
|
if (inject_node(g_b, nid_a, pubkey_a, pa) != 0) { fail("inject_node A→B"); goto done; } |
|
|
|
|
fprintf(stderr, "injected B→A and A→B registries\n"); fflush(stderr); |
|
|
|
|
uasync_call_soon(ua, NULL, t1); |
|
|
|
|
|