From 7e97348c6bc81621a2b571fe5f0fb5dc21a00e38 Mon Sep 17 00:00:00 2001 From: EugenioCollado <121509066+EugenioCollado@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:17:41 +0100 Subject: [PATCH] Handle socket buffer size setting when system's maximum exceeded (#5527) * Regression tests for asio_helpers socket buffer size Signed-off-by: Eugenio Collado * Regression tests udp & tcp Signed-off-by: Eugenio Collado * Refs #22210. Ensure that actual set value is returned by `asio_helpers::try_setting_buffer_size` Signed-off-by: Miguel Company * Fix corner case infinite loop Signed-off-by: Eugenio Collado * Uncrustify Signed-off-by: Eugenio Collado * Fix UDP tests Signed-off-by: Eugenio Collado * Fix windows compilation Signed-off-by: Eugenio Collado * Applied suggestions to regression test Signed-off-by: Eugenio Collado * Applied suggestions to udp tests Signed-off-by: Eugenio Collado * Uncrustify Signed-off-by: Eugenio Collado --------- Signed-off-by: Eugenio Collado Signed-off-by: Miguel Company Co-authored-by: Miguel Company (cherry picked from commit 5fc77861df383a7e94691295f7b07fdaa50f9402) --- src/cpp/rtps/transport/asio_helpers.hpp | 37 ++++++- test/unittest/transport/AsioHelpersTests.cpp | 104 +++++++++++++++++++ test/unittest/transport/CMakeLists.txt | 68 ++++++++++++ test/unittest/transport/UDPv4Tests.cpp | 4 +- test/unittest/transport/UDPv6Tests.cpp | 4 +- 5 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 test/unittest/transport/AsioHelpersTests.cpp diff --git a/src/cpp/rtps/transport/asio_helpers.hpp b/src/cpp/rtps/transport/asio_helpers.hpp index f9ba81b84e0..b57d23d36ad 100644 --- a/src/cpp/rtps/transport/asio_helpers.hpp +++ b/src/cpp/rtps/transport/asio_helpers.hpp @@ -51,20 +51,49 @@ struct asio_helpers asio::error_code ec; final_buffer_value = initial_buffer_value; - while (final_buffer_value >= minimum_buffer_value) + while (final_buffer_value > minimum_buffer_value) { - socket.set_option(BufferOptionType(static_cast(final_buffer_value)), ec); + int32_t value_to_set = static_cast(final_buffer_value); + socket.set_option(BufferOptionType(value_to_set), ec); if (!ec) { + BufferOptionType option; + socket.get_option(option, ec); + if (!ec) + { + if (option.value() == value_to_set) + { + // Option actually set to the desired value + return true; + } + // Try again with the value actually set + final_buffer_value = option.value(); + continue; + } + // Could not determine the actual value, but the option was set successfully. + // Assume the option was set to the desired value. return true; } final_buffer_value /= 2; } + // Perform a final attempt to set the minimum value final_buffer_value = minimum_buffer_value; - socket.set_option(BufferOptionType(final_buffer_value), ec); - return !ec; + int32_t value_to_set = static_cast(final_buffer_value); + socket.set_option(BufferOptionType(value_to_set), ec); + if (!ec) + { + // Last attempt was successful. Get the actual value set. + BufferOptionType option; + socket.get_option(option, ec); + if (!ec) + { + final_buffer_value = option.value(); + } + return true; + } + return false; } /** diff --git a/test/unittest/transport/AsioHelpersTests.cpp b/test/unittest/transport/AsioHelpersTests.cpp new file mode 100644 index 00000000000..5168f9a64a5 --- /dev/null +++ b/test/unittest/transport/AsioHelpersTests.cpp @@ -0,0 +1,104 @@ +// Copyright 2023 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. + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace eprosima::fastdds::rtps; + + +// Regression tests for redmine issue #22210 + +template +void test_buffer_setting( + int initial_buffer_value, + int minimum_buffer_value) +{ + asio::io_service io_service; + auto socket = std::make_unique(io_service); + + // Open the socket with the provided protocol + socket->open(Protocol::v4()); + + uint32_t final_buffer_value = 0; + + // Replace this with your actual implementation of try_setting_buffer_size + ASSERT_TRUE(asio_helpers::try_setting_buffer_size( + *socket, initial_buffer_value, minimum_buffer_value, final_buffer_value)); + + + + BufferOption option; + asio::error_code ec; + socket->get_option(option, ec); + if (!ec) + { + ASSERT_EQ(static_cast(option.value()), final_buffer_value); + } + else + { + throw std::runtime_error("Failed to get buffer option"); + } +} + +// Test that the UDP buffer size is set actually to the value stored as the final value +TEST(AsioHelpersTests, udp_buffer_size) +{ + uint32_t minimum_buffer_value = 0; + for (uint32_t initial_buffer_value = std::numeric_limits::max(); initial_buffer_value > 0; + initial_buffer_value /= 4) + { + test_buffer_setting( + initial_buffer_value, minimum_buffer_value); + test_buffer_setting( + initial_buffer_value, minimum_buffer_value); + } +} + +// Test that the TCP buffer size is set actually to the value stored as the final value +TEST(AsioHelpersTests, tcp_buffer_size) +{ + uint32_t minimum_buffer_value = 0; + for (uint32_t initial_buffer_value = std::numeric_limits::max(); initial_buffer_value > 0; + initial_buffer_value /= 4) + { + test_buffer_setting( + initial_buffer_value, minimum_buffer_value); + test_buffer_setting( + initial_buffer_value, minimum_buffer_value); + } +} + +int main( + int argc, + char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/unittest/transport/CMakeLists.txt b/test/unittest/transport/CMakeLists.txt index 3b45f19afdd..9e6dad22aa2 100644 --- a/test/unittest/transport/CMakeLists.txt +++ b/test/unittest/transport/CMakeLists.txt @@ -96,6 +96,39 @@ set(UDPV4TESTS_SOURCE ${TCPTransportInterface_SOURCE} ) +set(ASIOHELPERSTESTS_SOURCE + AsioHelpersTests.cpp + mock/MockReceiverResource.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/fastdds/core/Time_t.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/attributes/PropertyPolicy.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/attributes/ThreadSettings.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/GuidPrefix_t.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/LocatorWithMask.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/SerializedPayload.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/Time_t.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/messages/CDRMessage.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/network/NetworkBuffer.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/network/NetworkFactory.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/network/utils/netmask_filter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/network/utils/network.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/ChannelResource.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/network/NetmaskFilterKind.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/network/NetworkInterface.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/network/NetworkInterfaceWithFilter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/PortBasedTransportDescriptor.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/TransportInterface.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPChannelResource.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPTransportInterface.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPv4Transport.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/Host.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPFinder.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/IPLocator.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/md5.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils/SystemInfo.cpp + ${TCPTransportInterface_SOURCE} + ) + + set(UDPV6TESTS_SOURCE UDPv6Tests.cpp mock/MockReceiverResource.cpp @@ -497,3 +530,38 @@ target_link_libraries(${PORTBASED_TRANSPORTDESCRIPTOR_TESTS_TARGET} ${MOCKS}) gtest_discover_tests(${PORTBASED_TRANSPORTDESCRIPTOR_TESTS_TARGET}) + +##################################### +# AsioHelpers tests +##################################### +add_executable(AsioHelpersTests ${ASIOHELPERSTESTS_SOURCE}) +target_compile_definitions(AsioHelpersTests PRIVATE + BOOST_ASIO_STANDALONE + ASIO_STANDALONE + $<$>,$>:__DEBUG> + $<$:__INTERNALDEBUG> # Internal debug activated. + ) +target_include_directories(AsioHelpersTests PRIVATE + ${Asio_INCLUDE_DIR} + ${PROJECT_SOURCE_DIR}/test/mock/rtps/MessageReceiver + ${PROJECT_SOURCE_DIR}/test/mock/rtps/ReceiverResource + ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include + ${PROJECT_SOURCE_DIR}/src/cpp + $<$:${ANDROID_IFADDRS_INCLUDE_DIR}> + ) +target_link_libraries(AsioHelpersTests + fastcdr + fastdds::log + GTest::gtest + ${MOCKS} + $<$:OpenSSL::SSL$OpenSSL::Crypto>) +if(QNX) + target_link_libraries(AsioHelpersTests socket) +endif() +if(MSVC OR MSVC_IDE) + target_link_libraries(AsioHelpersTests ${PRIVACY} iphlpapi Shlwapi ) +endif() +if (APPLE) + target_link_libraries(AsioHelpersTests ${PRIVACY} "-framework CoreFoundation" "-framework IOKit") +endif() +gtest_discover_tests(AsioHelpersTests) diff --git a/test/unittest/transport/UDPv4Tests.cpp b/test/unittest/transport/UDPv4Tests.cpp index 22e59454c5d..a83ca81b566 100644 --- a/test/unittest/transport/UDPv4Tests.cpp +++ b/test/unittest/transport/UDPv4Tests.cpp @@ -837,8 +837,8 @@ TEST_F(UDPv4Tests, double_binding_fails) void UDPv4Tests::HELPER_SetDescriptorDefaults() { descriptor.maxMessageSize = 5; - descriptor.sendBufferSize = 5; - descriptor.receiveBufferSize = 5; + descriptor.sendBufferSize = 5000; + descriptor.receiveBufferSize = 5000; descriptor.interfaceWhiteList.clear(); } diff --git a/test/unittest/transport/UDPv6Tests.cpp b/test/unittest/transport/UDPv6Tests.cpp index 7942892716c..f6d9a12bea3 100644 --- a/test/unittest/transport/UDPv6Tests.cpp +++ b/test/unittest/transport/UDPv6Tests.cpp @@ -876,8 +876,8 @@ TEST_F(UDPv6Tests, double_binding_fails) void UDPv6Tests::HELPER_SetDescriptorDefaults() { descriptor.maxMessageSize = 5; - descriptor.sendBufferSize = 5; - descriptor.receiveBufferSize = 5; + descriptor.sendBufferSize = 5000; + descriptor.receiveBufferSize = 5000; } int main(