Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[22210] Handle socket buffer size setting when system's maximum exceeded (backport #5527) #5561

Open
wants to merge 1 commit into
base: 3.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -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
Expand Down Expand Up @@ -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
$<$<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
Loading