Skip to content

Commit 69a1457

Browse files
mergify[bot]MiguelCompanycferreiragonz
authored
Assert liveliness with periodic heartbeats in secure participants (#6411) (#6414)
* Assert liveliness with periodic heartbeats in secure participants (#6411) * Refs #24372. Assert liveliness with periodic heartbeats in secure participants. Signed-off-by: Juan Lopez Fernandez <juanlopez@eprosima.com> * Refs #24372. Added regression test. Signed-off-by: danipiza <dpizarrogallego@gmail.com> * Refs #24372. Revert change in returned value. Signed-off-by: Miguel Company <miguelcompany@eprosima.com> * Refs #24372. Improve null pointer checks. Signed-off-by: Miguel Company <miguelcompany@eprosima.com> * Refs #24372. Uncrustify. Signed-off-by: Miguel Company <miguelcompany@eprosima.com> --------- Signed-off-by: Juan Lopez Fernandez <juanlopez@eprosima.com> Signed-off-by: danipiza <dpizarrogallego@gmail.com> Signed-off-by: Miguel Company <miguelcompany@eprosima.com> Co-authored-by: Juan Lopez Fernandez <juanlopez@eprosima.com> Co-authored-by: danipiza <dpizarrogallego@gmail.com> (cherry picked from commit 910ac99) # Conflicts: # src/cpp/rtps/builtin/discovery/participant/PDPSimple.cpp * Solve conflicts Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com> * Uncrustify Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com> --------- Signed-off-by: Carlos Ferreira González <carlosferreira@eprosima.com> Co-authored-by: Miguel Company <miguelcompany@eprosima.com> Co-authored-by: Carlos Ferreira González <carlosferreira@eprosima.com>
1 parent d7bec6e commit 69a1457

3 files changed

Lines changed: 118 additions & 2 deletions

File tree

include/fastrtps/config.h.in

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
// Log Info
8686
#ifndef FASTDDS_ENFORCE_LOG_INFO
8787
#cmakedefine FASTDDS_ENFORCE_LOG_INFO
88-
#endif
88+
#endif // ifndef FASTDDS_ENFORCE_LOG_INFO
8989
#ifndef HAVE_LOG_NO_INFO
9090
#define HAVE_LOG_NO_INFO @HAVE_LOG_NO_INFO@
9191
#endif /* ifndef HAVE_LOG_NO_INFO */
@@ -128,6 +128,15 @@
128128
#define FASTDDS_SER_METHOD_DEPRECATED(major, entity_name, msg) FASTDDS_DEPRECATED_UNTIL(major, entity_name, msg)
129129
#else
130130
#define FASTDDS_SER_METHOD_DEPRECATED(major, entity_name, msg)
131-
#endif
131+
#endif // if FASTCDR_VERSION_MAJOR > 1
132+
133+
#if defined(_MSC_VER) && !defined(__clang__)
134+
# define FASTDDS_UNREACHABLE() __assume(0)
135+
#elif defined(__GNUC__) || defined(__clang__)
136+
# define FASTDDS_UNREACHABLE() __builtin_unreachable()
137+
#else
138+
# include <cstdlib>
139+
# define FASTDDS_UNREACHABLE() std::abort()
140+
#endif // if defined(_MSC_VER) && !defined(__clang__)
132141

133142
#endif // _FASTRTPS_CONFIG_H_

src/cpp/rtps/builtin/discovery/participant/PDPSimple.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,22 @@ void PDPSimple::announceParticipantState(
287287
if (!(dispose || new_change))
288288
{
289289
endpoints->writer.writer_->send_periodic_announcement();
290+
291+
#if HAVE_SECURITY
292+
if (mp_RTPSParticipant->is_secure())
293+
{
294+
// PDP non-secure endpoints are unmatched after participant authentication succeeds (and secure PDP
295+
// endpoints are matched), and since the secure ones are TRANSIENT_LOCAL, we send periodic heartbeats
296+
// to assert liveliness on remote participants
297+
auto secure = dynamic_cast<fastdds::rtps::SimplePDPEndpointsSecure*>(builtin_endpoints_.get());
298+
assert(secure && secure->secure_writer.writer_);
299+
if (!secure || !secure->secure_writer.writer_)
300+
{
301+
FASTDDS_UNREACHABLE(); // “cannot happen” invariant
302+
}
303+
secure->secure_writer.writer_->send_periodic_heartbeat(true, true);
304+
}
305+
#endif // HAVE_SECURITY
290306
}
291307
}
292308
}

test/blackbox/common/BlackboxTestsSecurity.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,97 @@ TEST_P(Security, RemoveParticipantProxyDataonSecurityManagerLeaseExpired_validat
13191319

13201320
}
13211321

1322+
// Regression test for secure PDP liveliness maintenance without user traffic.
1323+
TEST(Security, SecureParticipantsDoNotLoseDiscoveryWithoutUserTraffic)
1324+
{
1325+
PubSubReader<HelloWorldPubSubType> reader("HelloWorldTopic_secure_participant_liveliness");
1326+
PubSubWriter<HelloWorldPubSubType> writer("HelloWorldTopic_secure_participant_liveliness");
1327+
const auto idle_timeout = std::chrono::seconds(6);
1328+
const auto data_timeout = std::chrono::seconds(10);
1329+
// Keep the lease short so loss of secure PDP liveliness shows up quickly
1330+
const auto lease_duration = eprosima::fastrtps::Duration_t(3, 0);
1331+
const auto announcement_period = eprosima::fastrtps::Duration_t(1, 0);
1332+
// Use UDP transport to later block the fallback participant DATA(P) traffic
1333+
auto reader_transport = std::make_shared<test_UDPv4TransportDescriptor>();
1334+
auto writer_transport = std::make_shared<test_UDPv4TransportDescriptor>();
1335+
1336+
const std::string governance_file("governance_helloworld_all_enable.smime");
1337+
const std::string permissions_file("permissions_helloworld.smime");
1338+
1339+
CommonPermissionsConfigure(reader, writer, governance_file, permissions_file);
1340+
// Force the test through UDP to avoid local shortcuts masking the secure discovery behavior
1341+
reader.disable_builtin_transport().add_user_transport_to_pparams(reader_transport);
1342+
writer.disable_builtin_transport().add_user_transport_to_pparams(writer_transport);
1343+
1344+
// Two secure participants that authenticate, discover each other, and exchange user data
1345+
reader.lease_duration(lease_duration, announcement_period)
1346+
.history_depth(10)
1347+
.reliability(eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS)
1348+
.init();
1349+
ASSERT_TRUE(reader.isInitialized());
1350+
1351+
writer.lease_duration(lease_duration, announcement_period)
1352+
.history_depth(10)
1353+
.reliability(eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS)
1354+
.init();
1355+
ASSERT_TRUE(writer.isInitialized());
1356+
1357+
reader.wait_authorized();
1358+
writer.wait_authorized();
1359+
1360+
// Wait until both endpoints are matched
1361+
reader.wait_discovery();
1362+
writer.wait_discovery();
1363+
1364+
// Verify discovery state stayed stable
1365+
auto assert_still_discovered = [&reader, &writer]()
1366+
{
1367+
ASSERT_TRUE(reader.is_matched());
1368+
ASSERT_TRUE(writer.is_matched());
1369+
ASSERT_EQ(reader.get_matched(), 1u);
1370+
ASSERT_EQ(writer.get_matched(), 1u);
1371+
1372+
const auto reader_status = reader.get_subscription_matched_status();
1373+
const auto writer_status = writer.get_publication_matched_status();
1374+
ASSERT_EQ(reader_status.total_count, 1);
1375+
ASSERT_EQ(writer_status.total_count, 1);
1376+
};
1377+
1378+
// Check the secure participants must not be undiscovered just because user traffic stops
1379+
auto assert_idle_period_keeps_discovery = [&reader, &writer, &idle_timeout, &assert_still_discovered]()
1380+
{
1381+
ASSERT_FALSE(reader.wait_participant_undiscovery(idle_timeout));
1382+
ASSERT_FALSE(writer.wait_participant_undiscovery(idle_timeout));
1383+
1384+
assert_still_discovered();
1385+
};
1386+
1387+
// Discovery is only useful if data can still flow after the idle window
1388+
auto assert_data_flow = [&reader, &writer, &data_timeout, &assert_still_discovered]()
1389+
{
1390+
auto data = default_helloworld_data_generator(2);
1391+
1392+
reader.startReception(data);
1393+
writer.send(data);
1394+
1395+
ASSERT_TRUE(data.empty());
1396+
ASSERT_EQ(reader.block_for_all(data_timeout), 2u);
1397+
assert_still_discovered();
1398+
};
1399+
1400+
ASSERT_NO_FATAL_FAILURE(assert_still_discovered());
1401+
1402+
// After the secure PDP endpoints are established, stop the unprotected participant DATA(P)
1403+
// traffic, to depend on the secure liveliness maintenance path
1404+
test_UDPv4Transport::always_drop_participant_builtin_topic_data = true;
1405+
1406+
// Exercise the idle scenario twice to catch both immediate loss and unstable recovery/rematch behavior
1407+
ASSERT_NO_FATAL_FAILURE(assert_idle_period_keeps_discovery());
1408+
ASSERT_NO_FATAL_FAILURE(assert_data_flow());
1409+
ASSERT_NO_FATAL_FAILURE(assert_idle_period_keeps_discovery());
1410+
ASSERT_NO_FATAL_FAILURE(assert_data_flow());
1411+
}
1412+
13221413
TEST(Security, AllowUnauthenticatedParticipants_EntityCreationFailsIfRTPSProtectionIsNotNONE)
13231414
{
13241415
PubSubReader<HelloWorldPubSubType> reader("HelloWorldTopic");

0 commit comments

Comments
 (0)