From de8d4044d163ae3282a70f0defe46199bb08c470 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:46:08 +0100 Subject: [PATCH] Use `SO_EXCLUSIVEADDRUSE` for Win32 unicast listening sockets (#4056) (#4071) * Refs #19587. Added regression unit tests. Signed-off-by: Miguel Company * Refs #19587. Added regression blackbox test. Signed-off-by: Miguel Company * Refs #19587. Fix issue. Signed-off-by: Miguel Company * Refs #19587. Linters. Signed-off-by: Miguel Company --------- Signed-off-by: Miguel Company (cherry picked from commit bb2702becfaa807e96ef2cb76206d1c13e04c05e) Co-authored-by: Miguel Company --- src/cpp/rtps/transport/UDPv4Transport.cpp | 7 +++++ src/cpp/rtps/transport/UDPv6Transport.cpp | 7 +++++ .../common/BlackboxTestsNetworkConf.cpp | 31 +++++++++++++++++++ test/unittest/transport/UDPv4Tests.cpp | 21 +++++++++++++ test/unittest/transport/UDPv6Tests.cpp | 21 +++++++++++++ .../transport/mock/MockReceiverResource.h | 5 +++ 6 files changed, 92 insertions(+) diff --git a/src/cpp/rtps/transport/UDPv4Transport.cpp b/src/cpp/rtps/transport/UDPv4Transport.cpp index b1ee54d6f61..7c8353faf1f 100644 --- a/src/cpp/rtps/transport/UDPv4Transport.cpp +++ b/src/cpp/rtps/transport/UDPv4Transport.cpp @@ -305,6 +305,13 @@ eProsimaUDPSocket UDPv4Transport::OpenAndBindInputSocket( ASIO_OS_DEF(SOL_SOCKET), SO_REUSEPORT>(true)); #endif // if defined(__QNX__) } + else + { +#if defined(_WIN32) + getSocketPtr(socket)->set_option(asio::detail::socket_option::integer< + ASIO_OS_DEF(SOL_SOCKET), SO_EXCLUSIVEADDRUSE>(1)); +#endif // if defined(_WIN32) + } getSocketPtr(socket)->bind(generate_endpoint(sIp, port)); return socket; diff --git a/src/cpp/rtps/transport/UDPv6Transport.cpp b/src/cpp/rtps/transport/UDPv6Transport.cpp index 24a929ab214..81b20700245 100644 --- a/src/cpp/rtps/transport/UDPv6Transport.cpp +++ b/src/cpp/rtps/transport/UDPv6Transport.cpp @@ -308,6 +308,13 @@ eProsimaUDPSocket UDPv6Transport::OpenAndBindInputSocket( ASIO_OS_DEF(SOL_SOCKET), SO_REUSEPORT>(true)); #endif // if defined(__QNX__) } + else + { +#if defined(_WIN32) + getSocketPtr(socket)->set_option(asio::detail::socket_option::integer< + ASIO_OS_DEF(SOL_SOCKET), SO_EXCLUSIVEADDRUSE>(1)); +#endif // if defined(_WIN32) + } getSocketPtr(socket)->bind(generate_endpoint(sIp, port)); diff --git a/test/blackbox/common/BlackboxTestsNetworkConf.cpp b/test/blackbox/common/BlackboxTestsNetworkConf.cpp index 963f285e96f..48cefc22454 100644 --- a/test/blackbox/common/BlackboxTestsNetworkConf.cpp +++ b/test/blackbox/common/BlackboxTestsNetworkConf.cpp @@ -412,6 +412,37 @@ TEST_P(NetworkConfig, PubGetSendingLocatorsWhitelist) } } +// Regression test for redmine issue #19587 +TEST_P(NetworkConfig, double_binding_fails) +{ + PubSubReader p1(TEST_TOPIC_NAME); + PubSubReader p2(TEST_TOPIC_NAME); + + // Create a participant without whitelist + p1.disable_builtin_transport().add_user_transport_to_pparams(descriptor_); + p1.init(); + ASSERT_TRUE(p1.isInitialized()); + + // Add the announced addresses to the interface whitelist + LocatorList_t locators_p1; + p1.get_native_reader().get_listening_locators(locators_p1); + for (const auto& loc : locators_p1) + { + descriptor_->interfaceWhiteList.push_back(IPLocator::ip_to_string(loc)); + } + + // Try to listen on the same locators as the first participant + p2.disable_builtin_transport().add_user_transport_to_pparams(descriptor_); + p2.set_default_unicast_locators(locators_p1); + p2.init(); + ASSERT_TRUE(p2.isInitialized()); + + // Should be listening on different locators + LocatorList_t locators_p2; + p2.get_native_reader().get_listening_locators(locators_p2); + EXPECT_FALSE(locators_p1 == locators_p2); +} + #ifdef INSTANTIATE_TEST_SUITE_P #define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) #else diff --git a/test/unittest/transport/UDPv4Tests.cpp b/test/unittest/transport/UDPv4Tests.cpp index af6c0bc4240..430e58feabf 100644 --- a/test/unittest/transport/UDPv4Tests.cpp +++ b/test/unittest/transport/UDPv4Tests.cpp @@ -704,6 +704,27 @@ TEST_F(UDPv4Tests, simple_throughput) , std::chrono::duration_cast(t1 - t0).count() / (num_samples_per_batch * 1000.0)); } +// Regression test for redmine issue #19587 +TEST_F(UDPv4Tests, double_binding_fails) +{ + auto whitelist_descriptor = descriptor; + whitelist_descriptor.interfaceWhiteList.emplace_back("127.0.0.1"); + + UDPv4Transport default_transport(descriptor); + UDPv4Transport whitelist_transport(whitelist_descriptor); + + Locator_t locator; + IPLocator::createLocator(LOCATOR_KIND_UDPv4, "127.0.0.1", g_default_port, locator); + + MockReceiverResource whitelist_receiver(whitelist_transport, locator); + EXPECT_TRUE(whitelist_receiver.is_valid()); + EXPECT_TRUE(whitelist_transport.IsInputChannelOpen(locator)); + + MockReceiverResource default_receiver(default_transport, locator); + EXPECT_FALSE(default_receiver.is_valid()); + EXPECT_FALSE(default_transport.IsInputChannelOpen(locator)); +} + void UDPv4Tests::HELPER_SetDescriptorDefaults() { descriptor.maxMessageSize = 5; diff --git a/test/unittest/transport/UDPv6Tests.cpp b/test/unittest/transport/UDPv6Tests.cpp index 6f2b11b040a..4328553e54e 100644 --- a/test/unittest/transport/UDPv6Tests.cpp +++ b/test/unittest/transport/UDPv6Tests.cpp @@ -737,6 +737,27 @@ TEST_F(UDPv6Tests, simple_throughput) , std::chrono::duration_cast(t1 - t0).count() / (num_samples_per_batch * 1000.0)); } +// Regression test for redmine issue #19587 +TEST_F(UDPv6Tests, double_binding_fails) +{ + auto whitelist_descriptor = descriptor; + whitelist_descriptor.interfaceWhiteList.emplace_back("::1"); + + UDPv6Transport default_transport(descriptor); + UDPv6Transport whitelist_transport(whitelist_descriptor); + + Locator_t locator; + IPLocator::createLocator(LOCATOR_KIND_UDPv6, "::1", g_default_port, locator); + + MockReceiverResource whitelist_receiver(whitelist_transport, locator); + EXPECT_TRUE(whitelist_receiver.is_valid()); + EXPECT_TRUE(whitelist_transport.IsInputChannelOpen(locator)); + + MockReceiverResource default_receiver(default_transport, locator); + EXPECT_FALSE(default_receiver.is_valid()); + EXPECT_FALSE(default_transport.IsInputChannelOpen(locator)); +} + void UDPv6Tests::HELPER_SetDescriptorDefaults() { descriptor.maxMessageSize = 5; diff --git a/test/unittest/transport/mock/MockReceiverResource.h b/test/unittest/transport/mock/MockReceiverResource.h index 75197b406f5..b1da38cd24a 100644 --- a/test/unittest/transport/mock/MockReceiverResource.h +++ b/test/unittest/transport/mock/MockReceiverResource.h @@ -31,6 +31,11 @@ class MockReceiverResource : public ReceiverResource { public: + bool is_valid() const + { + return mValid; + } + virtual void OnDataReceived( const octet*, const uint32_t,