diff --git a/src/routing_layer/conn_mgr_indirect.c b/src/routing_layer/conn_mgr_indirect.c index 35ae6305..01059c5b 100644 --- a/src/routing_layer/conn_mgr_indirect.c +++ b/src/routing_layer/conn_mgr_indirect.c @@ -17,6 +17,7 @@ void cm_start_phase_indirect(struct CONN_MGR_ENTRY* entry) { struct CONN_MGR* mgr = entry->mgr; if (!entry->indirect_started) { entry->indirect_started = 1; entry->exchange_request_id = ++mgr->next_request_id; + if (!entry->exchange_request_id) entry->exchange_request_id = ++mgr->next_request_id; DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "conn_mgr: INDIRECT start peer=%016llx elapsed=%llums candidates=%u", (unsigned long long)entry->node_id, (unsigned long long)((get_time_tb() - entry->start_tb) / 10), mgr->best_candidate_count); @@ -185,7 +186,8 @@ void cm_handle_interm_ack(struct CONN_MGR* mgr, uint64_t src, const uint8_t* dat void cm_handle_interm_exchange_req(uint64_t src, struct CONN_MGR* mgr, struct CM_EXCHANGE_REQ* req) { if (!mgr) return; - if (req->candidate_count > CONN_MGR_MAX_CANDIDATES || !topo_node_registry_find(mgr->instance->topo_groups, src)) { + if (!req->request_id || !src || src == mgr->instance->node_id || req->candidate_count > CONN_MGR_MAX_CANDIDATES || + !topo_node_registry_find(mgr->instance->topo_groups, src)) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "conn_mgr: invalid EXCHANGE_REQ peer=%016llx count=%u", (unsigned long long)src, req->candidate_count); return; } diff --git a/tests/test_conn_mgr_handles.c b/tests/test_conn_mgr_handles.c index 472500fe..56437d70 100644 --- a/tests/test_conn_mgr_handles.c +++ b/tests/test_conn_mgr_handles.c @@ -178,14 +178,25 @@ static void test3_verify(void* arg) { #ifdef __linux__ if (rejected_soon) { fail("test4: cleanup attempted to allocate call_soon"); return; } #endif - fprintf(stderr, "Test 5: remote cleanup detaches handles and cancels pending UP\n"); + fprintf(stderr, "Test 5: obsolete DISCONNECT preserves demand; local cleanup detaches handles\n"); if (conn_mgr_open(g_a, TOPO_GROUP_UTUN, g_nid_b, ccb1, NULL, &gh1) != 0) { fail("test5: open failed"); return; } cb1_ok = 0; conn_mgr_routes_changed(mgr); if (!gh1->entry->refresh_token) { fail("test5: refresh not scheduled"); return; } - cm_handle_disconnect(mgr, g_nid_b); + struct CONN_MGR_ENTRY* attached = gh1->entry; + struct ll_entry* obsolete = ll_alloc_lldgram(ROUTER_SVC_HDR_SIZE + 10); + if (!obsolete) { fail("test5: packet allocation failed"); return; } + memset(obsolete->dgram, 0, ROUTER_SVC_HDR_SIZE + 10); obsolete->len = ROUTER_SVC_HDR_SIZE + 10; + memcpy(obsolete->dgram + ROUTER_SVC_GROUP_OFF, &mgr->group->group_id, 8); + memcpy(obsolete->dgram + ROUTER_SVC_SRC_OFF, &g_nid_b, 8); + obsolete->dgram[ROUTER_SVC_PAYLOAD_OFF] = ETCP_RT_ID_CONN_MGR; + obsolete->dgram[ROUTER_SVC_PAYLOAD_OFF + 1] = 0x06; + memcpy(obsolete->dgram + ROUTER_SVC_PAYLOAD_OFF + 2, &g_nid_b, 8); + conn_mgr_router_recv_handler(instance_find_conn(g_a, g_nid_b), obsolete); + if (gh1->entry != attached) { fail("test5: remote packet detached local demand"); return; } + cm_entry_cleanup(attached); if (gh1->entry || gh1->deliver_up_token || conn_mgr_get_conn(gh1)) { fail("test5: handle not detached"); return; } conn_mgr_close(gh1); gh1 = NULL; uasync_poll(ua, 0);