Skip to content

Commit

Permalink
Handle socket buffer size setting when system's maximum exceeded (#5527)
Browse files Browse the repository at this point in the history
* Regression tests for asio_helpers socket buffer size

Signed-off-by: Eugenio Collado <[email protected]>

* Regression tests udp & tcp

Signed-off-by: Eugenio Collado <[email protected]>

* Refs #22210. Ensure that actual set value is returned by `asio_helpers::try_setting_buffer_size`

Signed-off-by: Miguel Company <[email protected]>

* Fix corner case infinite loop

Signed-off-by: Eugenio Collado <[email protected]>

* Uncrustify

Signed-off-by: Eugenio Collado <[email protected]>

* Fix UDP tests

Signed-off-by: Eugenio Collado <[email protected]>

* Fix windows compilation

Signed-off-by: Eugenio Collado <[email protected]>

* Applied suggestions to regression test

Signed-off-by: Eugenio Collado <[email protected]>

* Applied suggestions to udp tests

Signed-off-by: Eugenio Collado <[email protected]>

* Uncrustify

Signed-off-by: Eugenio Collado <[email protected]>

---------

Signed-off-by: Eugenio Collado <[email protected]>
Signed-off-by: Miguel Company <[email protected]>
Co-authored-by: Miguel Company <[email protected]>
  • Loading branch information
EugenioCollado and MiguelCompany authored Jan 10, 2025
1 parent b53a389 commit 5fc7786
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 8 deletions.
37 changes: 33 additions & 4 deletions src/cpp/rtps/transport/asio_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int32_t>(final_buffer_value)), ec);
int32_t value_to_set = static_cast<int32_t>(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<int32_t>(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;
}

/**
Expand Down
104 changes: 104 additions & 0 deletions test/unittest/transport/AsioHelpersTests.cpp
Original file line number Diff line number Diff line change
@@ -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 <limits>
#include <memory>
#include <thread>

#include <asio.hpp>
#include <gtest/gtest.h>

#include <fastdds/dds/log/Log.hpp>
#include <fastdds/rtps/transport/UDPv4TransportDescriptor.hpp>
#include <fastdds/utils/IPFinder.hpp>
#include <fastdds/utils/IPLocator.hpp>

#include <utils/Semaphore.hpp>

#include <MockReceiverResource.h>
#include <rtps/transport/asio_helpers.hpp>
#include <rtps/transport/UDPv4Transport.h>

using namespace eprosima::fastdds::rtps;


// Regression tests for redmine issue #22210

template <typename BufferOption, typename SocketType, typename Protocol>
void test_buffer_setting(
int initial_buffer_value,
int minimum_buffer_value)
{
asio::io_service io_service;
auto socket = std::make_unique<SocketType>(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<BufferOption>(
*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<uint32_t>(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<uint32_t>::max(); initial_buffer_value > 0;
initial_buffer_value /= 4)
{
test_buffer_setting<asio::socket_base::send_buffer_size, asio::ip::udp::socket, asio::ip::udp>(
initial_buffer_value, minimum_buffer_value);
test_buffer_setting<asio::socket_base::receive_buffer_size, asio::ip::udp::socket, asio::ip::udp>(
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<uint32_t>::max(); initial_buffer_value > 0;
initial_buffer_value /= 4)
{
test_buffer_setting<asio::socket_base::send_buffer_size, asio::ip::tcp::socket, asio::ip::tcp>(
initial_buffer_value, minimum_buffer_value);
test_buffer_setting<asio::socket_base::receive_buffer_size, asio::ip::tcp::socket, asio::ip::tcp>(
initial_buffer_value, minimum_buffer_value);
}
}

int main(
int argc,
char** argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
68 changes: 68 additions & 0 deletions test/unittest/transport/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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
Expand Down Expand Up @@ -514,3 +547,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
$<$<AND:$<NOT:$<BOOL:${WIN32}>>,$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">>:__DEBUG>
$<$<BOOL:${INTERNAL_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
$<$<BOOL:${ANDROID}>:${ANDROID_IFADDRS_INCLUDE_DIR}>
)
target_link_libraries(AsioHelpersTests
fastcdr
fastdds::log
GTest::gtest
${MOCKS}
$<$<BOOL:${TLS_FOUND}>:OpenSSL::SSL$<SEMICOLON>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)
4 changes: 2 additions & 2 deletions test/unittest/transport/UDPv4Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
4 changes: 2 additions & 2 deletions test/unittest/transport/UDPv6Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 5fc7786

Please sign in to comment.