Skip to content

Commit 3d2479e

Browse files
Enhance filtering logic for virtual and external endpoints (#6290)
* Enhance filtering logic for virtual and external endpoints Signed-off-by: Miguel Company <miguelcompany@eprosima.com> * Restore proper filtering for external endpoint discovery matching Signed-off-by: Raül <raulojeda@eprosima.com> * Uncrustify Signed-off-by: Raül <raulojeda@eprosima.com> * Add DS test checking external-to-external relay Signed-off-by: Raül <raulojeda@eprosima.com> * Add additional logic to reader_gives_info and uncrustify Signed-off-by: Raül <raulojeda@eprosima.com> * Remove unnecessary comment Signed-off-by: Raül <raulojeda@eprosima.com> * Remove leaseDuration config to trigger test error in previous code Signed-off-by: Raül <raulojeda@eprosima.com> * Add additional logic to writer_gives_info Signed-off-by: Raül <raulojeda@eprosima.com> * Remove unnecessary extra logic on match_writer_reader Signed-off-by: Raül <raulojeda@eprosima.com> * Apply revision Signed-off-by: Raül <raulojeda@eprosima.com> * Add explicit _not_virtual to _is_local variable name Signed-off-by: Raül <raulojeda@eprosima.com> * Fix DS test failing in windows CI Signed-off-by: Raül <raulojeda@eprosima.com> --------- Signed-off-by: Miguel Company <miguelcompany@eprosima.com> Signed-off-by: Raül <raulojeda@eprosima.com> Co-authored-by: Raül <raulojeda@eprosima.com>
1 parent 80d8fee commit 3d2479e

3 files changed

Lines changed: 191 additions & 27 deletions

File tree

src/cpp/rtps/builtin/discovery/database/DiscoveryDataBase.cpp

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -504,15 +504,17 @@ void DiscoveryDataBase::process_pdp_data_queue()
504504
if (data_queue_info.change()->kind == eprosima::fastdds::rtps::ALIVE)
505505
{
506506
// Update participants map
507-
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE, "DATA(p) of entity " << data_queue_info.change()->instanceHandle <<
508-
" received from: " << data_queue_info.change()->writerGUID);
507+
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE, "DATA(p) of entity " << data_queue_info.change()->instanceHandle
508+
<< " received from: "
509+
<< data_queue_info.change()->writerGUID);
509510
create_participant_from_change_(data_queue_info.change(), data_queue_info.participant_change_data());
510511
}
511512
// If the change is a DATA(Up)
512513
else
513514
{
514-
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE, "DATA(Up) of entity " << data_queue_info.change()->instanceHandle <<
515-
" received from: " << data_queue_info.change()->writerGUID);
515+
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE, "DATA(Up) of entity " << data_queue_info.change()->instanceHandle
516+
<< " received from: "
517+
<< data_queue_info.change()->writerGUID);
516518
process_dispose_participant_(data_queue_info.change());
517519
}
518520
}
@@ -1197,31 +1199,59 @@ void DiscoveryDataBase::match_writer_reader_(
11971199
}
11981200
DiscoveryParticipantInfo& reader_participant_info = p_rit->second;
11991201

1200-
// Always exchange all information between all participants (no filtering)
1201-
// Skip only if it's a virtual endpoint matching with another virtual endpoint
1202+
// Virtual endpoints do not exchange info
12021203
if (writer_info.is_virtual() && reader_info.is_virtual())
12031204
{
12041205
return;
12051206
}
12061207

1207-
// Add writer's participant to reader's relevant list
1208-
if (!reader_participant_info.is_relevant_participant(writer_guid.guidPrefix))
1209-
{
1210-
reader_participant_info.add_or_update_ack_participant(writer_guid.guidPrefix);
1211-
}
1212-
if (!reader_info.is_relevant_participant(writer_guid.guidPrefix))
1213-
{
1214-
reader_info.add_or_update_ack_participant(writer_guid.guidPrefix);
1215-
}
1208+
// Classify writer and reader types
1209+
const bool writer_is_virtual = writer_info.is_virtual();
1210+
const bool writer_is_local_not_virtual = !writer_is_virtual && writer_participant_info.is_local();
1211+
const bool writer_is_external_not_virtual = !writer_is_virtual && !writer_is_local_not_virtual;
12161212

1217-
// Add reader's participant to writer's relevant list
1218-
if (!writer_participant_info.is_relevant_participant(reader_guid.guidPrefix))
1213+
const bool reader_is_virtual = reader_info.is_virtual();
1214+
const bool reader_is_local_not_virtual = !reader_is_virtual && reader_participant_info.is_local();
1215+
const bool reader_is_external_not_virtual = !reader_is_virtual && !reader_is_local_not_virtual;
1216+
1217+
// Determine info exchange based on endpoint types:
1218+
// - Local endpoints both need and give info
1219+
// - Virtual endpoints only need info (never give)
1220+
// - External endpoints only give info (never need)
1221+
// Additionally, servers do not redirect between remote clients,
1222+
// so external endpoints only exchange with local endpoints
1223+
const bool writer_needs_info = writer_is_virtual || writer_is_local_not_virtual;
1224+
const bool writer_gives_info = writer_is_local_not_virtual ||
1225+
(writer_is_external_not_virtual && reader_is_local_not_virtual);
1226+
1227+
const bool reader_needs_info = reader_is_virtual || reader_is_local_not_virtual;
1228+
const bool reader_gives_info = reader_is_local_not_virtual ||
1229+
(reader_is_external_not_virtual && writer_is_local_not_virtual);
1230+
1231+
// Writer needs info from reader: add writer's guid prefix to reader's ack lists
1232+
if (writer_needs_info && reader_gives_info)
12191233
{
1220-
writer_participant_info.add_or_update_ack_participant(reader_guid.guidPrefix);
1234+
if (!reader_participant_info.is_relevant_participant(writer_guid.guidPrefix))
1235+
{
1236+
reader_participant_info.add_or_update_ack_participant(writer_guid.guidPrefix);
1237+
}
1238+
if (!reader_info.is_relevant_participant(writer_guid.guidPrefix))
1239+
{
1240+
reader_info.add_or_update_ack_participant(writer_guid.guidPrefix);
1241+
}
12211242
}
1222-
if (!writer_info.is_relevant_participant(reader_guid.guidPrefix))
1243+
1244+
// Reader needs info from writer: add reader's guid prefix to writer's ack lists
1245+
if (reader_needs_info && writer_gives_info)
12231246
{
1224-
writer_info.add_or_update_ack_participant(reader_guid.guidPrefix);
1247+
if (!writer_participant_info.is_relevant_participant(reader_guid.guidPrefix))
1248+
{
1249+
writer_participant_info.add_or_update_ack_participant(reader_guid.guidPrefix);
1250+
}
1251+
if (!writer_info.is_relevant_participant(reader_guid.guidPrefix))
1252+
{
1253+
writer_info.add_or_update_ack_participant(reader_guid.guidPrefix);
1254+
}
12251255
}
12261256
}
12271257

@@ -1775,8 +1805,9 @@ void DiscoveryDataBase::AckedFunctor::operator () (
17751805
auto remote_server_it = db_->participants_.find(*it);
17761806
if (remote_server_it == db_->participants_.end())
17771807
{
1778-
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE, "Change " << change_->instanceHandle <<
1779-
"check as acked for " << reader_proxy->guid() << " as it has not answered pinging yet");
1808+
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE,
1809+
"Change " << change_->instanceHandle << "check as acked for " << reader_proxy->guid()
1810+
<< " as it has not answered pinging yet");
17801811
return;
17811812
}
17821813

@@ -2544,8 +2575,8 @@ bool DiscoveryDataBase::from_json(
25442575
}
25452576

25462577
EPROSIMA_LOG_INFO(DISCOVERY_DATABASE,
2547-
"Writer " << guid_aux << " created with instance handle " <<
2548-
wit.first->second.change()->instanceHandle);
2578+
"Writer " << guid_aux << " created with instance handle "
2579+
<< wit.first->second.change()->instanceHandle);
25492580

25502581
if (change->kind != fastdds::rtps::ALIVE)
25512582
{

test/blackbox/common/BlackboxTestsDiscovery.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,6 +2202,139 @@ TEST_P(Discovery, discovery_server_pdp_messages_sent)
22022202
EXPECT_EQ(num_data_p_sends.load(std::memory_order::memory_order_seq_cst), 9u);
22032203
}
22042204

2205+
// This test checks that a client connected to a Discovery Server does not receive
2206+
// discovery information about clients connected to a different server from a server
2207+
// different than their own.
2208+
TEST(Discovery, discovery_server_no_external_to_external_relay)
2209+
{
2210+
using namespace eprosima::fastdds::dds;
2211+
2212+
// Define a specific port for client_1's metatraffic
2213+
uint32_t client_1_metatraffic_port = global_port + 10;
2214+
2215+
// Declare a test transport that will count messages sent from server_2 to client_1
2216+
std::atomic<size_t> num_messages_to_client_1{ 0 };
2217+
2218+
auto test_transport_server_2 = std::make_shared<test_UDPv4TransportDescriptor>();
2219+
test_transport_server_2->locator_filter_ = [&](
2220+
const eprosima::fastdds::rtps::Locator& destination, int32_t)
2221+
{
2222+
// Check if destination port matches client_1's metatraffic port
2223+
if (destination.port == client_1_metatraffic_port)
2224+
{
2225+
std::cout << "Message from server_2 to client_1 detected on port "
2226+
<< destination.port << std::endl;
2227+
num_messages_to_client_1.fetch_add(1u, std::memory_order_seq_cst);
2228+
}
2229+
return false; // Don't drop the message
2230+
};
2231+
2232+
// Create server 1
2233+
auto server_1 = std::make_shared<PubSubParticipant<HelloWorldPubSubType>>(0, 0, 0, 0);
2234+
2235+
Locator_t locator_server_1; // UDPv4 locator by default
2236+
eprosima::fastdds::rtps::IPLocator::setIPv4(locator_server_1, 127, 0, 0, 1);
2237+
eprosima::fastdds::rtps::IPLocator::setPhysicalPort(locator_server_1, global_port);
2238+
2239+
WireProtocolConfigQos server_wp_qos_1;
2240+
server_wp_qos_1.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol::SERVER;
2241+
server_wp_qos_1.builtin.metatrafficUnicastLocatorList.push_back(locator_server_1);
2242+
server_wp_qos_1.builtin.discovery_config.initial_announcements.count = 1;
2243+
2244+
server_1->wire_protocol(server_wp_qos_1)
2245+
.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::UDPv4);
2246+
2247+
// Start server 1
2248+
ASSERT_TRUE(server_1->init_participant());
2249+
2250+
// Create server 2 (federated with server 1) with test transport
2251+
auto server_2 = std::make_shared<PubSubParticipant<HelloWorldPubSubType>>(0, 0, 0, 0);
2252+
2253+
Locator_t locator_server_2; // UDPv4 locator by default
2254+
eprosima::fastdds::rtps::IPLocator::setIPv4(locator_server_2, 127, 0, 0, 1);
2255+
eprosima::fastdds::rtps::IPLocator::setPhysicalPort(locator_server_2, global_port + 1);
2256+
2257+
WireProtocolConfigQos server_wp_qos_2;
2258+
server_wp_qos_2.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol::SERVER;
2259+
server_wp_qos_2.builtin.metatrafficUnicastLocatorList.push_back(locator_server_2);
2260+
server_wp_qos_2.builtin.discovery_config.initial_announcements.count = 1;
2261+
// Federate server 2 with server 1
2262+
server_wp_qos_2.builtin.discovery_config.m_DiscoveryServers.push_back(locator_server_1);
2263+
2264+
server_2->disable_builtin_transport()
2265+
.add_user_transport_to_pparams(test_transport_server_2)
2266+
.wire_protocol(server_wp_qos_2);
2267+
2268+
// Start server 2
2269+
ASSERT_TRUE(server_2->init_participant());
2270+
2271+
// Wait for servers to discover each other
2272+
server_1->wait_discovery(std::chrono::seconds(5), 1, true);
2273+
server_2->wait_discovery(std::chrono::seconds(5), 1, true);
2274+
2275+
// Record baseline message count after server federation
2276+
size_t baseline_count = num_messages_to_client_1.load(std::memory_order_seq_cst);
2277+
ASSERT_EQ(baseline_count, 0u); // No messages should ever be sent from server2 to client1
2278+
2279+
// Create client 1 connected ONLY to server 1 with a specific metatraffic port
2280+
PubSubWriter<HelloWorldPubSubType> client_1(TEST_TOPIC_NAME);
2281+
2282+
// Set up client_1's metatraffic unicast locator with a specific port
2283+
Locator_t client_1_metatraffic_locator;
2284+
eprosima::fastdds::rtps::IPLocator::setIPv4(client_1_metatraffic_locator, 127, 0, 0, 1);
2285+
client_1_metatraffic_locator.port = client_1_metatraffic_port;
2286+
2287+
WireProtocolConfigQos client_1_qos;
2288+
client_1_qos.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol::CLIENT;
2289+
client_1_qos.builtin.discovery_config.m_DiscoveryServers.push_back(locator_server_1);
2290+
client_1_qos.builtin.discovery_config.initial_announcements.count = 1;
2291+
client_1_qos.builtin.metatrafficUnicastLocatorList.push_back(client_1_metatraffic_locator);
2292+
2293+
client_1.set_wire_protocol_qos(client_1_qos)
2294+
.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::UDPv4)
2295+
.init();
2296+
2297+
ASSERT_TRUE(client_1.isInitialized());
2298+
2299+
// Wait for server_1 to discover client_1
2300+
server_1->wait_discovery(std::chrono::seconds(5), 2, true); // server_2 + client_1
2301+
2302+
// Record message count after client_1 connects
2303+
size_t messages_after_client_1 = num_messages_to_client_1.load(std::memory_order_seq_cst);
2304+
ASSERT_EQ(messages_after_client_1, 0u); // No messages should ever be sent from server2 to client1
2305+
2306+
// Create client 2 connected ONLY to server 2
2307+
PubSubReader<HelloWorldPubSubType> client_2(TEST_TOPIC_NAME);
2308+
2309+
WireProtocolConfigQos client_2_qos;
2310+
client_2_qos.builtin.discovery_config.discoveryProtocol = DiscoveryProtocol::CLIENT;
2311+
client_2_qos.builtin.discovery_config.m_DiscoveryServers.push_back(locator_server_2);
2312+
client_2_qos.builtin.discovery_config.initial_announcements.count = 1;
2313+
2314+
client_2.set_wire_protocol_qos(client_2_qos)
2315+
.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::UDPv4)
2316+
.init();
2317+
2318+
ASSERT_TRUE(client_2.isInitialized());
2319+
2320+
// Wait for server_2 to discover client_2
2321+
server_2->wait_discovery(std::chrono::seconds(5), 2, true); // server_1 + client_2
2322+
2323+
// Give enough time for any potential (incorrect) relay of discovery information
2324+
std::this_thread::sleep_for(std::chrono::seconds(5));
2325+
2326+
// Record final message count
2327+
size_t messages_final = num_messages_to_client_1.load(std::memory_order_seq_cst);
2328+
2329+
// Verify that server_2 did NOT send messages directly to client_1 after client_2 connected
2330+
EXPECT_EQ(messages_final, baseline_count)
2331+
<< "Server_2 sent " << (messages_final - baseline_count) << " messages directly to client_1. "
2332+
<< "This suggests external-to-external relay is happening. "
2333+
<< "Baseline: " << baseline_count
2334+
<< ", After client_1: " << messages_after_client_1
2335+
<< ", Final: " << messages_final;
2336+
}
2337+
22052338
// This test checks that a Discover Server does not send duplicated EDP messages when its routine
22062339
// is triggered by EDP Listeners while it waits for ACKs
22072340
TEST_P(Discovery, discovery_server_edp_messages_sent)

test/blackbox/common/DDSBlackboxTestsDiscovery.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,9 +2050,9 @@ TEST(DDSDiscovery, client_server_participants_with_different_domain_ids_discover
20502050
client_domain_3.init();
20512051
EXPECT_TRUE(client_domain_3.isInitialized());
20522052

2053-
server_domain_1.wait_discovery(std::chrono::seconds(2));
2054-
client_domain_2.wait_discovery(std::chrono::seconds(2));
2055-
client_domain_3.wait_discovery(std::chrono::seconds(2));
2053+
server_domain_1.wait_discovery(std::chrono::seconds(5));
2054+
client_domain_2.wait_discovery(2, std::chrono::seconds(5));
2055+
client_domain_3.wait_discovery(std::chrono::seconds(5));
20562056

20572057
ASSERT_TRUE(client_domain_2.is_matched());
20582058
ASSERT_TRUE(client_domain_3.is_matched());

0 commit comments

Comments
 (0)