diff --git a/include/fastdds/rtps/builtin/discovery/participant/PDP.h b/include/fastdds/rtps/builtin/discovery/participant/PDP.h index f9eb5f2731b..9993eaf10bd 100644 --- a/include/fastdds/rtps/builtin/discovery/participant/PDP.h +++ b/include/fastdds/rtps/builtin/discovery/participant/PDP.h @@ -22,9 +22,12 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC #include +#include #include #include #include +#include +#include #include #include @@ -70,6 +73,7 @@ class RTPSWriter; class RTPSReader; class WriterHistory; class ReaderHistory; +struct RTPSParticipantAllocationAttributes; class RTPSParticipantImpl; class RTPSParticipantListener; class BuiltinProtocols; @@ -79,6 +83,7 @@ class ReaderProxyData; class WriterProxyData; class ParticipantProxyData; class ReaderListener; +class PDPEndpoints; class PDPListener; class PDPServerListener; class ITopicPayloadPool; diff --git a/src/cpp/rtps/participant/RTPSParticipantImpl.cpp b/src/cpp/rtps/participant/RTPSParticipantImpl.cpp index 921257b3926..644295d8dc5 100644 --- a/src/cpp/rtps/participant/RTPSParticipantImpl.cpp +++ b/src/cpp/rtps/participant/RTPSParticipantImpl.cpp @@ -232,6 +232,127 @@ static bool get_unique_flows_parameters( return true; } +// -- The following is a backport from 3.x of a PDP method +static void local_participant_attributes_update_nts( + const RTPSParticipantAttributes& new_atts, + PDP* pdp, + RTPSParticipantImpl* participant) +{ + auto participant_data = pdp->getLocalParticipantProxyData(); + participant_data->m_userData.data_vec(new_atts.userData); + + // If we are intraprocess only, we do not need to update locators + bool announce_locators = !participant->is_intraprocess_only(); + if (announce_locators) + { + // Clear all locators + participant_data->metatraffic_locators.unicast.clear(); + participant_data->metatraffic_locators.multicast.clear(); + participant_data->default_locators.unicast.clear(); + participant_data->default_locators.multicast.clear(); + + // Update default locators + for (const Locator_t& loc : new_atts.defaultUnicastLocatorList) + { + participant_data->default_locators.add_unicast_locator(loc); + } + for (const Locator_t& loc : new_atts.defaultMulticastLocatorList) + { + participant_data->default_locators.add_multicast_locator(loc); + } + + // Update metatraffic locators + for (const auto& locator : new_atts.builtin.metatrafficUnicastLocatorList) + { + participant_data->metatraffic_locators.add_unicast_locator(locator); + } + if (!new_atts.builtin.avoid_builtin_multicast || + participant_data->metatraffic_locators.unicast.empty()) + { + for (const auto& locator : new_atts.builtin.metatrafficMulticastLocatorList) + { + participant_data->metatraffic_locators.add_multicast_locator(locator); + } + } + + fastdds::rtps::network::external_locators::add_external_locators(*participant_data, + new_atts.builtin.metatraffic_external_unicast_locators, + new_atts.default_external_unicast_locators); + } +} + +// -- The following is a backport from 3.x of a PDP method +static void update_endpoint_locators_if_default_nts( + const std::vector& writers, + const std::vector& readers, + const RTPSParticipantAttributes& old_atts, + const RTPSParticipantAttributes& new_atts, + PDP* pdp) +{ + // Check if default locators have changed + const auto& old_default_unicast = old_atts.defaultUnicastLocatorList; + const auto& old_default_multicast = old_atts.defaultMulticastLocatorList; + const auto& new_default_unicast = new_atts.defaultUnicastLocatorList; + const auto& new_default_multicast = new_atts.defaultMulticastLocatorList; + + // Early return if there is no change in default unicast locators + if ((old_default_unicast == new_default_unicast) && + (old_default_multicast == new_default_multicast)) + { + return; + } + + // Update proxies of endpoints with default configured locators + EDP* edp = pdp->getEDP(); + for (RTPSWriter* writer : writers) + { + if ((old_default_multicast == writer->getAttributes().multicastLocatorList) && + (old_default_unicast == writer->getAttributes().unicastLocatorList)) + { + writer->getAttributes().multicastLocatorList = new_default_multicast; + writer->getAttributes().unicastLocatorList = new_default_unicast; + + WriterProxyData* wdata = nullptr; + GUID_t participant_guid; + wdata = pdp->addWriterProxyData(writer->getGuid(), participant_guid, + [](WriterProxyData* proxy, bool is_update, + const ParticipantProxyData& participant) + { + static_cast(is_update); + assert(is_update); + proxy->set_locators(participant.default_locators); + return true; + }); + assert(wdata != nullptr); + edp->processLocalWriterProxyData(writer, wdata); + } + } + for (RTPSReader* reader : readers) + { + if ((old_default_multicast == reader->getAttributes().multicastLocatorList) && + (old_default_unicast == reader->getAttributes().unicastLocatorList)) + { + reader->getAttributes().multicastLocatorList = new_default_multicast; + reader->getAttributes().unicastLocatorList = new_default_unicast; + + ReaderProxyData* rdata = nullptr; + GUID_t participant_guid; + rdata = pdp->addReaderProxyData(reader->getGuid(), participant_guid, + [](ReaderProxyData* proxy, bool is_update, + const ParticipantProxyData& participant) + { + static_cast(is_update); + assert(is_update); + + proxy->set_locators(participant.default_locators); + return true; + }); + assert(rdata != nullptr); + edp->processLocalReaderProxyData(reader, rdata); + } + } +} + Locator_t& RTPSParticipantImpl::applyLocatorAdaptRule( Locator_t& loc) { @@ -1526,37 +1647,46 @@ bool RTPSParticipantImpl::registerReader( void RTPSParticipantImpl::update_attributes( const RTPSParticipantAttributes& patt) { + // Avoid ABBA with PDP mutex by using a local copy of the attributes + RTPSParticipantAttributes temp_atts; + { + std::lock_guard guard(*mp_mutex); + temp_atts = m_att; + } + bool local_interfaces_changed = false; // Update cached network interfaces if (!SystemInfo::update_interfaces()) { EPROSIMA_LOG_WARNING(RTPS_PARTICIPANT, - "Failed to update cached network interfaces during " << m_att.getName() << + "Failed to update cached network interfaces during " << temp_atts.getName() << " attributes update"); } // Check if new interfaces have been added if (internal_metatraffic_locators_) { - LocatorList_t metatraffic_unicast_locator_list = m_att.builtin.metatrafficUnicastLocatorList; - get_default_metatraffic_locators(); - if (!(metatraffic_unicast_locator_list == m_att.builtin.metatrafficUnicastLocatorList)) + LocatorList_t metatraffic_unicast_locator_list = temp_atts.builtin.metatrafficUnicastLocatorList; + temp_atts.builtin.metatrafficUnicastLocatorList.clear(); + get_default_metatraffic_locators(temp_atts); + if (!(metatraffic_unicast_locator_list == temp_atts.builtin.metatrafficUnicastLocatorList)) { local_interfaces_changed = true; - EPROSIMA_LOG_INFO(RTPS_PARTICIPANT, m_att.getName() << " updated its metatraffic locators"); + EPROSIMA_LOG_INFO(RTPS_PARTICIPANT, temp_atts.getName() << " updated its metatraffic locators"); } } if (internal_default_locators_) { - LocatorList_t default_unicast_locator_list = m_att.defaultUnicastLocatorList; - get_default_unicast_locators(); - if (!(default_unicast_locator_list == m_att.defaultUnicastLocatorList)) + LocatorList_t default_unicast_locator_list = temp_atts.defaultUnicastLocatorList; + temp_atts.defaultUnicastLocatorList.clear(); + get_default_unicast_locators(temp_atts); + if (!(default_unicast_locator_list == temp_atts.defaultUnicastLocatorList)) { local_interfaces_changed = true; EPROSIMA_LOG_INFO(RTPS_PARTICIPANT, - m_att.getName() << " updated default unicast locator list, current locators: " - << m_att.defaultUnicastLocatorList); + temp_atts.getName() << " updated default unicast locator list, current locators: " + << temp_atts.defaultUnicastLocatorList); } } @@ -1571,9 +1701,9 @@ void RTPSParticipantImpl::update_attributes( // Check if discovery servers need to be updated eprosima::fastdds::rtps::RemoteServerList_t converted_discovery_servers = patt.builtin.discovery_config.m_DiscoveryServers; - if (patt.builtin.discovery_config.m_DiscoveryServers != m_att.builtin.discovery_config.m_DiscoveryServers) + if (converted_discovery_servers != temp_atts.builtin.discovery_config.m_DiscoveryServers) { - for (auto& transportDescriptor : m_att.userTransports) + for (auto& transportDescriptor : temp_atts.userTransports) { TCPTransportDescriptor* pT = dynamic_cast(transportDescriptor.get()); if (pT) @@ -1598,8 +1728,8 @@ void RTPSParticipantImpl::update_attributes( } // Check if there are changes - if (converted_discovery_servers != m_att.builtin.discovery_config.m_DiscoveryServers - || patt.userData != m_att.userData + if (converted_discovery_servers != temp_atts.builtin.discovery_config.m_DiscoveryServers + || patt.userData != temp_atts.userData || local_interfaces_changed) { update_pdp = true; @@ -1607,7 +1737,7 @@ void RTPSParticipantImpl::update_attributes( LocatorList_t modified_locators; // Update RTPSParticipantAttributes members - m_att.userData = patt.userData; + temp_atts.userData = patt.userData; // If there's no PDP don't process Discovery-related attributes. if (!pdp) @@ -1620,19 +1750,19 @@ void RTPSParticipantImpl::update_attributes( using namespace fastdds::rtps::network::external_locators; if (local_interfaces_changed && internal_metatraffic_locators_) { - set_listening_locators(m_att.builtin.metatraffic_external_unicast_locators, - m_att.builtin.metatrafficUnicastLocatorList); + set_listening_locators(temp_atts.builtin.metatraffic_external_unicast_locators, + temp_atts.builtin.metatrafficUnicastLocatorList); } if (local_interfaces_changed && internal_default_locators_) { - set_listening_locators(m_att.default_external_unicast_locators, - m_att.defaultUnicastLocatorList); + set_listening_locators(temp_atts.default_external_unicast_locators, + temp_atts.defaultUnicastLocatorList); } } // Check that the remote servers list is consistent: all the already known remote servers must be included in // the list and either new remote servers are added or remote server listening locator is modified. - for (auto existing_server : m_att.builtin.discovery_config.m_DiscoveryServers) + for (auto existing_server : temp_atts.builtin.discovery_config.m_DiscoveryServers) { bool contained = false; for (auto incoming_server : converted_discovery_servers) @@ -1671,34 +1801,22 @@ void RTPSParticipantImpl::update_attributes( } } + // Update discovery information { std::lock_guard lock(*pdp->getMutex()); + local_participant_attributes_update_nts(temp_atts, pdp, this); - // Update user data - auto local_participant_proxy_data = pdp->getLocalParticipantProxyData(); - local_participant_proxy_data->m_userData.data_vec(m_att.userData); - - // Update metatraffic locators - for (auto locator : m_att.builtin.metatrafficMulticastLocatorList) - { - local_participant_proxy_data->metatraffic_locators.add_multicast_locator(locator); - } - for (auto locator : m_att.builtin.metatrafficUnicastLocatorList) - { - local_participant_proxy_data->metatraffic_locators.add_unicast_locator(locator); - } - - // Update default locators - for (auto locator : m_att.defaultUnicastLocatorList) + if (local_interfaces_changed && internal_default_locators_) { - local_participant_proxy_data->default_locators.add_unicast_locator(locator); + std::lock_guard _(endpoints_list_mutex); + update_endpoint_locators_if_default_nts(m_userWriterList, m_userReaderList, m_att, temp_atts, pdp); } if (local_interfaces_changed) { - createSenderResources(m_att.builtin.metatrafficMulticastLocatorList); - createSenderResources(m_att.builtin.metatrafficUnicastLocatorList); - createSenderResources(m_att.defaultUnicastLocatorList); + createSenderResources(temp_atts.builtin.metatrafficMulticastLocatorList); + createSenderResources(temp_atts.builtin.metatrafficUnicastLocatorList); + createSenderResources(temp_atts.defaultUnicastLocatorList); } if (!modified_locators.empty()) { @@ -1706,17 +1824,17 @@ void RTPSParticipantImpl::update_attributes( } // Update remote servers list - if (m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::CLIENT || - m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SUPER_CLIENT || - m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SERVER || - m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::BACKUP) + if (temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::CLIENT || + temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SUPER_CLIENT || + temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SERVER || + temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::BACKUP) { // Add incoming servers if we don't know about them already or the listening locator has been modified for (auto incoming_server : converted_discovery_servers) { eprosima::fastdds::rtps::RemoteServerList_t::iterator server_it; - for (server_it = m_att.builtin.discovery_config.m_DiscoveryServers.begin(); - server_it != m_att.builtin.discovery_config.m_DiscoveryServers.end(); server_it++) + for (server_it = temp_atts.builtin.discovery_config.m_DiscoveryServers.begin(); + server_it != temp_atts.builtin.discovery_config.m_DiscoveryServers.end(); server_it++) { if (server_it->guidPrefix == incoming_server.guidPrefix) { @@ -1733,21 +1851,21 @@ void RTPSParticipantImpl::update_attributes( break; } } - if (server_it == m_att.builtin.discovery_config.m_DiscoveryServers.end()) + if (server_it == temp_atts.builtin.discovery_config.m_DiscoveryServers.end()) { - m_att.builtin.discovery_config.m_DiscoveryServers.push_back(incoming_server); + temp_atts.builtin.discovery_config.m_DiscoveryServers.push_back(incoming_server); } } // Update the servers list in builtin protocols { std::unique_lock disc_lock(mp_builtinProtocols->getDiscoveryMutex()); - mp_builtinProtocols->m_DiscoveryServers = m_att.builtin.discovery_config.m_DiscoveryServers; + mp_builtinProtocols->m_DiscoveryServers = temp_atts.builtin.discovery_config.m_DiscoveryServers; } // Notify PDPServer - if (m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SERVER || - m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::BACKUP) + if (temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SERVER || + temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::BACKUP) { fastdds::rtps::PDPServer* pdp_server = static_cast(pdp); pdp_server->update_remote_servers_list(); @@ -1758,8 +1876,8 @@ void RTPSParticipantImpl::update_attributes( } } // Notify PDPClient - else if (m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::CLIENT || - m_att.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SUPER_CLIENT) + else if (temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::CLIENT || + temp_atts.builtin.discovery_config.discoveryProtocol == DiscoveryProtocol::SUPER_CLIENT) { fastdds::rtps::PDPClient* pdp_client = static_cast(pdp); pdp_client->update_remote_servers_list(); @@ -1771,6 +1889,12 @@ void RTPSParticipantImpl::update_attributes( } } } + + // Update the attributes data member + { + std::lock_guard guard(*mp_mutex); + m_att = temp_atts; + } } if (update_pdp) @@ -2853,22 +2977,34 @@ void RTPSParticipantImpl::environment_file_has_changed() void RTPSParticipantImpl::get_default_metatraffic_locators() { - uint32_t metatraffic_multicast_port = m_att.port.getMulticastPort(domain_id_); + get_default_metatraffic_locators(m_att); +} + +void RTPSParticipantImpl::get_default_metatraffic_locators( + RTPSParticipantAttributes& att) +{ + uint32_t metatraffic_multicast_port = att.port.getMulticastPort(domain_id_); - m_network_Factory.getDefaultMetatrafficMulticastLocators(m_att.builtin.metatrafficMulticastLocatorList, + m_network_Factory.getDefaultMetatrafficMulticastLocators(att.builtin.metatrafficMulticastLocatorList, metatraffic_multicast_port); - m_network_Factory.NormalizeLocators(m_att.builtin.metatrafficMulticastLocatorList); + m_network_Factory.NormalizeLocators(att.builtin.metatrafficMulticastLocatorList); - m_network_Factory.getDefaultMetatrafficUnicastLocators(m_att.builtin.metatrafficUnicastLocatorList, + m_network_Factory.getDefaultMetatrafficUnicastLocators(att.builtin.metatrafficUnicastLocatorList, metatraffic_unicast_port_); - m_network_Factory.NormalizeLocators(m_att.builtin.metatrafficUnicastLocatorList); + m_network_Factory.NormalizeLocators(att.builtin.metatrafficUnicastLocatorList); } void RTPSParticipantImpl::get_default_unicast_locators() { - uint32_t unicast_port = metatraffic_unicast_port_ + m_att.port.offsetd3 - m_att.port.offsetd1; - m_network_Factory.getDefaultUnicastLocators(m_att.defaultUnicastLocatorList, unicast_port); - m_network_Factory.NormalizeLocators(m_att.defaultUnicastLocatorList); + get_default_unicast_locators(m_att); +} + +void RTPSParticipantImpl::get_default_unicast_locators( + RTPSParticipantAttributes& att) +{ + uint32_t unicast_port = metatraffic_unicast_port_ + att.port.offsetd3 - att.port.offsetd1; + m_network_Factory.getDefaultUnicastLocators(att.defaultUnicastLocatorList, unicast_port); + m_network_Factory.NormalizeLocators(att.defaultUnicastLocatorList); } bool RTPSParticipantImpl::is_participant_ignored( diff --git a/src/cpp/rtps/participant/RTPSParticipantImpl.h b/src/cpp/rtps/participant/RTPSParticipantImpl.h index 25059076623..372e48daafb 100644 --- a/src/cpp/rtps/participant/RTPSParticipantImpl.h +++ b/src/cpp/rtps/participant/RTPSParticipantImpl.h @@ -783,11 +783,17 @@ class RTPSParticipantImpl */ void get_default_metatraffic_locators(); + void get_default_metatraffic_locators( + RTPSParticipantAttributes& att); + /** * Get default unicast locators when not provided by the user. */ void get_default_unicast_locators(); + void get_default_unicast_locators( + RTPSParticipantAttributes& att); + bool match_local_endpoints_ = true; bool should_match_local_endpoints( diff --git a/test/dds/communication/CMakeLists.txt b/test/dds/communication/CMakeLists.txt index d2696757422..37e11ef4f00 100644 --- a/test/dds/communication/CMakeLists.txt +++ b/test/dds/communication/CMakeLists.txt @@ -314,3 +314,7 @@ if(Python3_Interpreter_FOUND) endif() endif() + +if(UNIX AND NOT(APPLE) AND NOT(QNXNTO) AND NOT(ANDROID)) + add_subdirectory(dyn_network) +endif() diff --git a/test/dds/communication/PubSubMain.cpp b/test/dds/communication/PubSubMain.cpp index 46553c9f64b..11ea78de1ee 100644 --- a/test/dds/communication/PubSubMain.cpp +++ b/test/dds/communication/PubSubMain.cpp @@ -52,7 +52,7 @@ void publisher_run( publisher->wait_discovery(wait); } - publisher->run(samples, loops, interval); + publisher->run(samples, 0, loops, interval); } int main( @@ -197,7 +197,7 @@ int main( DomainParticipantFactory::get_instance()->load_XML_profiles_file(xml_file); } - SubscriberModule subscriber(publishers, samples, fixed_type, zero_copy); + SubscriberModule subscriber(publishers, samples, fixed_type, zero_copy, false, false); PublisherModule publisher(exit_on_lost_liveliness, fixed_type, zero_copy); uint32_t result = 1; @@ -208,7 +208,7 @@ int main( if (subscriber.init(seed, magic)) { - result = subscriber.run(notexit, timeout) ? 0 : -1; + result = subscriber.run(notexit, 0, timeout) ? 0 : -1; } publisher_thread.join(); diff --git a/test/dds/communication/PublisherMain.cpp b/test/dds/communication/PublisherMain.cpp index 0d72b20ae5b..3124e1c592d 100644 --- a/test/dds/communication/PublisherMain.cpp +++ b/test/dds/communication/PublisherMain.cpp @@ -29,9 +29,11 @@ using namespace eprosima::fastdds::dds; * --seed * --wait * --samples + * --loops + * --interval * --magic * --xmlfile - * --interval + * --rescan */ int main( @@ -46,7 +48,9 @@ int main( uint32_t wait = 0; char* xml_file = nullptr; uint32_t samples = 4; + uint32_t loops = 0; uint32_t interval = 250; + uint32_t rescan_interval_seconds = 0; std::string magic; while (arg_count < argc) @@ -93,6 +97,16 @@ int main( samples = strtol(argv[arg_count], nullptr, 10); } + else if (strcmp(argv[arg_count], "--loops") == 0) + { + if (++arg_count >= argc) + { + std::cout << "--loops expects a parameter" << std::endl; + return -1; + } + + loops = strtol(argv[arg_count], nullptr, 10); + } else if (strcmp(argv[arg_count], "--interval") == 0) { if (++arg_count >= argc) @@ -123,6 +137,16 @@ int main( xml_file = argv[arg_count]; } + else if (strcmp(argv[arg_count], "--rescan") == 0) + { + if (++arg_count >= argc) + { + std::cout << "--rescan expects a parameter" << std::endl; + return -1; + } + + rescan_interval_seconds = strtol(argv[arg_count], nullptr, 10); + } else { std::cout << "Wrong argument " << argv[arg_count] << std::endl; @@ -146,7 +170,7 @@ int main( publisher.wait_discovery(wait); } - publisher.run(samples, 0, interval); + publisher.run(samples, rescan_interval_seconds, loops, interval); return 0; } diff --git a/test/dds/communication/PublisherModule.cpp b/test/dds/communication/PublisherModule.cpp index d798a5c8434..f43a4c3062d 100644 --- a/test/dds/communication/PublisherModule.cpp +++ b/test/dds/communication/PublisherModule.cpp @@ -134,6 +134,7 @@ void PublisherModule::wait_discovery( void PublisherModule::run( uint32_t samples, + const uint32_t rescan_interval, const uint32_t loops, uint32_t interval) { @@ -141,6 +142,22 @@ void PublisherModule::run( uint16_t index = 1; void* sample = nullptr; + std::thread net_rescan_thread([this, rescan_interval]() + { + if (rescan_interval > 0) + { + auto interval = std::chrono::seconds(rescan_interval); + while (run_) + { + std::this_thread::sleep_for(interval); + if (run_) + { + participant_->set_qos(participant_->get_qos()); + } + } + } + }); + while (run_ && (loops == 0 || loops > current_loop)) { if (zero_copy_) @@ -187,6 +204,9 @@ void PublisherModule::run( std::this_thread::sleep_for(std::chrono::milliseconds(interval)); } + + run_ = false; + net_rescan_thread.join(); } void PublisherModule::on_publication_matched( diff --git a/test/dds/communication/PublisherModule.hpp b/test/dds/communication/PublisherModule.hpp index fb144821a0a..593d224c6d6 100644 --- a/test/dds/communication/PublisherModule.hpp +++ b/test/dds/communication/PublisherModule.hpp @@ -19,6 +19,11 @@ #ifndef TEST_DDS_COMMUNICATION_PUBLISHERMODULE_HPP #define TEST_DDS_COMMUNICATION_PUBLISHERMODULE_HPP +#include +#include +#include +#include + #include #include #include @@ -27,9 +32,6 @@ #include "types/FixedSizedPubSubTypes.h" #include "types/HelloWorldPubSubTypes.h" -#include -#include - namespace eprosima { namespace fastdds { namespace dds { @@ -41,8 +43,8 @@ class PublisherModule PublisherModule( bool exit_on_lost_liveliness, - bool fixed_type = false, - bool zero_copy = false) + bool fixed_type, + bool zero_copy) : exit_on_lost_liveliness_(exit_on_lost_liveliness) , fixed_type_(zero_copy || fixed_type) // If zero copy active, fixed type is required , zero_copy_(zero_copy) @@ -80,8 +82,9 @@ class PublisherModule void run( uint32_t samples, - uint32_t loops = 0, - uint32_t interval = 250); + const uint32_t rescan_interval, + uint32_t loops, + uint32_t interval); private: @@ -93,7 +96,7 @@ class PublisherModule bool exit_on_lost_liveliness_ = false; bool fixed_type_ = false; bool zero_copy_ = false; - bool run_ = true; + std::atomic_bool run_{true}; DomainParticipant* participant_ = nullptr; TypeSupport type_; Publisher* publisher_ = nullptr; diff --git a/test/dds/communication/SubscriberMain.cpp b/test/dds/communication/SubscriberMain.cpp index cb96f16ffb8..eee9b3e0e1e 100644 --- a/test/dds/communication/SubscriberMain.cpp +++ b/test/dds/communication/SubscriberMain.cpp @@ -26,13 +26,15 @@ using namespace eprosima::fastdds::dds; * --notexit * --fixed_type * --zero_copy + * --succeed_on_timeout * --seed * --samples * --magic + * --timeout * --xmlfile * --publishers - * --succeed_on_timeout - * --timeout + * --die_on_data_received + * --rescan */ int main( @@ -49,6 +51,7 @@ int main( uint32_t samples = 4; uint32_t publishers = 1; uint32_t timeout = 86400000; // 24 h in ms + uint32_t rescan_interval_seconds = 0; char* xml_file = nullptr; std::string magic; @@ -134,6 +137,16 @@ int main( { die_on_data_received = true; } + else if (strcmp(argv[arg_count], "--rescan") == 0) + { + if (++arg_count >= argc) + { + std::cout << "--rescan expects a parameter" << std::endl; + return -1; + } + + rescan_interval_seconds = strtol(argv[arg_count], nullptr, 10); + } else { std::cout << "Wrong argument " << argv[arg_count] << std::endl; @@ -152,7 +165,7 @@ int main( if (subscriber.init(seed, magic)) { - return subscriber.run(notexit, timeout) ? 0 : -1; + return subscriber.run(notexit, rescan_interval_seconds, timeout) ? 0 : -1; } return -1; diff --git a/test/dds/communication/SubscriberModule.cpp b/test/dds/communication/SubscriberModule.cpp index 77992bbd823..d0336e6dc73 100644 --- a/test/dds/communication/SubscriberModule.cpp +++ b/test/dds/communication/SubscriberModule.cpp @@ -132,17 +132,35 @@ bool SubscriberModule::init( bool SubscriberModule::run( bool notexit, + const uint32_t rescan_interval, uint32_t timeout) { - return run_for(notexit, std::chrono::milliseconds(timeout)); + return run_for(notexit, rescan_interval, std::chrono::milliseconds(timeout)); } bool SubscriberModule::run_for( bool notexit, + const uint32_t rescan_interval, const std::chrono::milliseconds& timeout) { bool returned_value = false; + std::thread net_rescan_thread([this, rescan_interval]() + { + if (rescan_interval > 0) + { + auto interval = std::chrono::seconds(rescan_interval); + while (run_) + { + std::this_thread::sleep_for(interval); + if (run_) + { + participant_->set_qos(participant_->get_qos()); + } + } + } + }); + while (notexit && run_) { std::this_thread::sleep_for(std::chrono::milliseconds(250)); @@ -192,6 +210,9 @@ bool SubscriberModule::run_for( returned_value = false; } + run_ = false; + net_rescan_thread.join(); + return returned_value; } diff --git a/test/dds/communication/SubscriberModule.hpp b/test/dds/communication/SubscriberModule.hpp index 901e3137dc7..964d28cbbc0 100644 --- a/test/dds/communication/SubscriberModule.hpp +++ b/test/dds/communication/SubscriberModule.hpp @@ -19,6 +19,12 @@ #ifndef TEST_COMMUNICATION_SUBSCRIBER_HPP #define TEST_COMMUNICATION_SUBSCRIBER_HPP +#include +#include +#include +#include +#include + #include #include #include @@ -27,11 +33,6 @@ #include "types/FixedSizedPubSubTypes.h" #include "types/HelloWorldPubSubTypes.h" -#include -#include -#include -#include - namespace eprosima { namespace fastdds { namespace dds { @@ -44,10 +45,10 @@ class SubscriberModule SubscriberModule( const uint32_t publishers, const uint32_t max_number_samples, - bool fixed_type = false, - bool zero_copy = false, - bool succeed_on_timeout = false, - bool die_on_data_received = false) + bool fixed_type, + bool zero_copy, + bool succeed_on_timeout, + bool die_on_data_received) : publishers_(publishers) , max_number_samples_(max_number_samples) , fixed_type_(zero_copy || fixed_type) // If zero copy active, fixed type is required @@ -86,10 +87,12 @@ class SubscriberModule bool run( bool notexit, - uint32_t timeout = 86400000); + const uint32_t rescan_interval, + uint32_t timeout); bool run_for( bool notexit, + const uint32_t rescan_interval, const std::chrono::milliseconds& timeout); private: @@ -103,7 +106,7 @@ class SubscriberModule std::map number_samples_; bool fixed_type_ = false; bool zero_copy_ = false; - bool run_ = true; + std::atomic_bool run_{true}; bool succeed_on_timeout_ = false; DomainParticipant* participant_ = nullptr; TypeSupport type_; diff --git a/test/dds/communication/dyn_network/CMakeLists.txt b/test/dds/communication/dyn_network/CMakeLists.txt new file mode 100644 index 00000000000..0d95ac665e0 --- /dev/null +++ b/test/dds/communication/dyn_network/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +message(STATUS "Configuring dynamic network interfaces tests") + +# Find docker +find_program(DOCKER_EXECUTABLE docker) +if(NOT DOCKER_EXECUTABLE) + message(FATAL_ERROR "Docker not found") +endif() + +set(SHELL_EXECUTABLE "") +set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "") +set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH "") + +# Linux configurations +if(UNIX AND NOT(APPLE) AND NOT(QNXNTO) AND NOT(ANDROID)) + # Find bash + find_program(BASH_EXECUTABLE bash) + if(NOT BASH_EXECUTABLE) + message(FATAL_ERROR "bash not found") + endif() + + set(SHELL_EXECUTABLE ${BASH_EXECUTABLE}) + +# Windows configurations +elseif(WIN32) + # We don't know which docker image to use for Windows yet + message(FATAL_ERROR "Windows not supported yet") + +# Unsupported platform +else() + message(FATAL_ERROR "Unsupported platform") +endif() + +# Configure TinyXML2 library path if installed in user library path +if(NOT (TINYXML2_FROM_SOURCE OR TINYXML2_FROM_THIRDPARTY)) + get_filename_component(TINYXML2_LIB_DIR ${TINYXML2_LIBRARY} DIRECTORY) + set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/fastdds:ro") + set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/fastdds") +endif() + +configure_file(Dockerfile + ${CMAKE_CURRENT_BINARY_DIR}/Dockerfile @ONLY) +configure_file(dynamic_interfaces.compose.yml + ${CMAKE_CURRENT_BINARY_DIR}/dynamic_interfaces.compose.yml @ONLY) +configure_file(launch_subscriber.bash + ${CMAKE_CURRENT_BINARY_DIR}/launch_subscriber.bash @ONLY) +add_test(NAME dds.communication.dynamic_interfaces + COMMAND ${DOCKER_EXECUTABLE} compose -f ${CMAKE_CURRENT_BINARY_DIR}/dynamic_interfaces.compose.yml up + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/test/dds/communication/dyn_network/Dockerfile b/test/dds/communication/dyn_network/Dockerfile new file mode 100644 index 00000000000..ebdcae10bba --- /dev/null +++ b/test/dds/communication/dyn_network/Dockerfile @@ -0,0 +1,27 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Tag, branch, or commit in github.com/eProsima/DDS-Suite +ARG ubuntu_version=22.04 +FROM ubuntu:$ubuntu_version AS ubuntu-net-tools + +# Needed for a dependency that forces to set timezone +ENV TZ=Europe/Madrid +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Avoids using interactions during building +ENV DEBIAN_FRONTEND=noninteractive + +# Install apt dependencies +RUN apt-get update && apt-get install --yes net-tools && rm -rf /var/lib/apt/lists/* diff --git a/test/dds/communication/dyn_network/dynamic_interfaces.compose.yml b/test/dds/communication/dyn_network/dynamic_interfaces.compose.yml new file mode 100644 index 00000000000..9d45abbbc48 --- /dev/null +++ b/test/dds/communication/dyn_network/dynamic_interfaces.compose.yml @@ -0,0 +1,42 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +version: "3" + +services: + publisher: + image: ubuntu:22.04 + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/test/dds/communication + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/DDSCommunicationPublisher --xmlfile $${EXAMPLE_DIR}/simple_reliable_profile.xml --wait 1 --samples 10 --loops 1 --seed 0 --magic T" + + subscriber: + build: . + image: ubuntu-net-tools:22.04 + privileged: true + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ + environment: + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/test/dds/communication + working_dir: @PROJECT_BINARY_DIR@/test/dds/communication + command: @SHELL_EXECUTABLE@ "dyn_network/launch_subscriber.bash" + depends_on: + - publisher diff --git a/test/dds/communication/dyn_network/launch_subscriber.bash b/test/dds/communication/dyn_network/launch_subscriber.bash new file mode 100755 index 00000000000..9ee62e1338b --- /dev/null +++ b/test/dds/communication/dyn_network/launch_subscriber.bash @@ -0,0 +1,33 @@ +# Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#!/bin/bash + +# Note: This script is intended to be used in a privileged container, since it requires to bring down and up the eth0 interface. + +echo "Putting down eth0 interface..." +ifconfig eth0 down + +echo "Launching subscriber..." +${EXAMPLE_DIR}/DDSCommunicationSubscriber --xmlfile ${EXAMPLE_DIR}/simple_reliable_profile.xml --samples 10 --seed 0 --magic T --rescan 2 & +subs_pid=$! +echo "Subscriber launched." + +echo "Waiting 2 seconds and bring up eth0 interface..." +sleep 2s +ifconfig eth0 up +echo "eth0 interface is up." + +echo "Waiting 3s for the subscriber (process id $subs_pid) to finish..." +wait $subs_pid diff --git a/test/dds/communication/security/PublisherMain.cpp b/test/dds/communication/security/PublisherMain.cpp index 2b87543a7d6..35a8e692c49 100644 --- a/test/dds/communication/security/PublisherMain.cpp +++ b/test/dds/communication/security/PublisherMain.cpp @@ -29,9 +29,10 @@ using namespace eprosima::fastdds::dds; * --seed * --wait * --samples + * --interval * --magic * --xmlfile - * --interval + * --rescan */ int main( @@ -48,6 +49,7 @@ int main( char* xml_file = nullptr; uint32_t samples = 4; uint32_t interval = 250; + uint32_t rescan_interval_seconds = 0; std::string magic; while (arg_count < argc) @@ -128,6 +130,16 @@ int main( xml_file = argv[arg_count]; } + else if (strcmp(argv[arg_count], "--rescan") == 0) + { + if (++arg_count >= argc) + { + std::cout << "--rescan expects a parameter" << std::endl; + return -1; + } + + rescan_interval_seconds = strtol(argv[arg_count], nullptr, 10); + } else { std::cout << "Wrong argument " << argv[arg_count] << std::endl; @@ -151,7 +163,7 @@ int main( publisher.wait_discovery(wait); } - publisher.run(samples, 0, interval); + publisher.run(samples, rescan_interval_seconds, 0, interval); return 0; } diff --git a/test/dds/communication/security/PublisherModule.cpp b/test/dds/communication/security/PublisherModule.cpp index ca7f60843b4..809822164f9 100644 --- a/test/dds/communication/security/PublisherModule.cpp +++ b/test/dds/communication/security/PublisherModule.cpp @@ -134,6 +134,7 @@ void PublisherModule::wait_discovery( void PublisherModule::run( uint32_t samples, + const uint32_t rescan_interval, const uint32_t loops, uint32_t interval) { @@ -141,6 +142,22 @@ void PublisherModule::run( uint16_t index = 1; void* sample = nullptr; + std::thread net_rescan_thread([this, rescan_interval]() + { + if (rescan_interval > 0) + { + auto interval = std::chrono::seconds(rescan_interval); + while (run_) + { + std::this_thread::sleep_for(interval); + if (run_) + { + participant_->set_qos(participant_->get_qos()); + } + } + } + }); + while (run_ && (loops == 0 || loops > current_loop)) { if (zero_copy_) @@ -187,6 +204,9 @@ void PublisherModule::run( std::this_thread::sleep_for(std::chrono::milliseconds(interval)); } + + run_ = false; + net_rescan_thread.join(); } void PublisherModule::on_publication_matched( diff --git a/test/dds/communication/security/PublisherModule.hpp b/test/dds/communication/security/PublisherModule.hpp index e4e99d5743c..3b91aec0087 100644 --- a/test/dds/communication/security/PublisherModule.hpp +++ b/test/dds/communication/security/PublisherModule.hpp @@ -19,6 +19,10 @@ #ifndef TEST_DDS_COMMUNICATION_PUBLISHERMODULE_HPP #define TEST_DDS_COMMUNICATION_PUBLISHERMODULE_HPP +#include +#include +#include + #include #include #include @@ -27,9 +31,6 @@ #include "types/FixedSizedPubSubTypes.h" #include "types/HelloWorldPubSubTypes.h" -#include -#include - namespace eprosima { namespace fastdds { namespace dds { @@ -42,8 +43,8 @@ class PublisherModule PublisherModule( bool exit_on_lost_liveliness, bool exit_on_disposal_received, - bool fixed_type = false, - bool zero_copy = false) + bool fixed_type, + bool zero_copy) : exit_on_lost_liveliness_(exit_on_lost_liveliness) , exit_on_disposal_received_(exit_on_disposal_received) , fixed_type_(zero_copy || fixed_type) // If zero copy active, fixed type is required @@ -82,8 +83,9 @@ class PublisherModule void run( uint32_t samples, - uint32_t loops = 0, - uint32_t interval = 250); + const uint32_t rescan_interval, + uint32_t loops, + uint32_t interval); private: @@ -96,7 +98,7 @@ class PublisherModule bool exit_on_disposal_received_ = false; bool fixed_type_ = false; bool zero_copy_ = false; - bool run_ = true; + std::atomic_bool run_ {true}; DomainParticipant* participant_ = nullptr; TypeSupport type_; Publisher* publisher_ = nullptr; diff --git a/test/dds/communication/security/SubscriberMain.cpp b/test/dds/communication/security/SubscriberMain.cpp index f1f0d513ee6..3f0e01effff 100644 --- a/test/dds/communication/security/SubscriberMain.cpp +++ b/test/dds/communication/security/SubscriberMain.cpp @@ -31,6 +31,8 @@ using namespace eprosima::fastdds::dds; * --magic * --xmlfile * --publishers + * --die_on_data_received + * --rescan */ int main( @@ -45,6 +47,7 @@ int main( uint32_t seed = 7800; uint32_t samples = 4; uint32_t publishers = 1; + uint32_t rescan_interval_seconds = 0; char* xml_file = nullptr; std::string magic; @@ -116,6 +119,16 @@ int main( { die_on_data_received = true; } + else if (strcmp(argv[arg_count], "--rescan") == 0) + { + if (++arg_count >= argc) + { + std::cout << "--rescan expects a parameter" << std::endl; + return -1; + } + + rescan_interval_seconds = strtol(argv[arg_count], nullptr, 10); + } else { std::cout << "Wrong argument " << argv[arg_count] << std::endl; @@ -134,7 +147,7 @@ int main( if (subscriber.init(seed, magic)) { - return subscriber.run(notexit) ? 0 : -1; + return subscriber.run(notexit, rescan_interval_seconds) ? 0 : -1; } return -1; diff --git a/test/dds/communication/security/SubscriberModule.cpp b/test/dds/communication/security/SubscriberModule.cpp index 4160e127297..102231a5566 100644 --- a/test/dds/communication/security/SubscriberModule.cpp +++ b/test/dds/communication/security/SubscriberModule.cpp @@ -130,17 +130,35 @@ bool SubscriberModule::init( } bool SubscriberModule::run( - bool notexit) + bool notexit, + const uint32_t rescan_interval) { - return run_for(notexit, std::chrono::hours(24)); + return run_for(notexit, rescan_interval, std::chrono::hours(24)); } bool SubscriberModule::run_for( bool notexit, + const uint32_t rescan_interval, const std::chrono::milliseconds& timeout) { bool returned_value = false; + std::thread net_rescan_thread([this, rescan_interval]() + { + if (rescan_interval > 0) + { + auto interval = std::chrono::seconds(rescan_interval); + while (run_) + { + std::this_thread::sleep_for(interval); + if (run_) + { + participant_->set_qos(participant_->get_qos()); + } + } + } + }); + while (notexit && run_) { std::this_thread::sleep_for(std::chrono::milliseconds(250)); @@ -184,6 +202,9 @@ bool SubscriberModule::run_for( returned_value = false; } + run_ = false; + net_rescan_thread.join(); + return returned_value; } diff --git a/test/dds/communication/security/SubscriberModule.hpp b/test/dds/communication/security/SubscriberModule.hpp index 980c6c5acc6..dd73934f990 100644 --- a/test/dds/communication/security/SubscriberModule.hpp +++ b/test/dds/communication/security/SubscriberModule.hpp @@ -19,6 +19,12 @@ #ifndef TEST_COMMUNICATION_SUBSCRIBER_HPP #define TEST_COMMUNICATION_SUBSCRIBER_HPP +#include +#include +#include +#include +#include + #include #include #include @@ -27,11 +33,6 @@ #include "types/FixedSizedPubSubTypes.h" #include "types/HelloWorldPubSubTypes.h" -#include -#include -#include -#include - namespace eprosima { namespace fastdds { namespace dds { @@ -44,9 +45,9 @@ class SubscriberModule SubscriberModule( const uint32_t publishers, const uint32_t max_number_samples, - bool fixed_type = false, - bool zero_copy = false, - bool die_on_data_received = false) + bool fixed_type, + bool zero_copy, + bool die_on_data_received) : publishers_(publishers) , max_number_samples_(max_number_samples) , fixed_type_(zero_copy || fixed_type) // If zero copy active, fixed type is required @@ -83,10 +84,12 @@ class SubscriberModule const std::string& magic); bool run( - bool notexit); + bool notexit, + const uint32_t rescan_interval); bool run_for( bool notexit, + const uint32_t rescan_interval, const std::chrono::milliseconds& timeout); private: @@ -100,7 +103,7 @@ class SubscriberModule std::map number_samples_; bool fixed_type_ = false; bool zero_copy_ = false; - bool run_ = true; + std::atomic_bool run_{true}; DomainParticipant* participant_ = nullptr; TypeSupport type_; Subscriber* subscriber_ = nullptr;