Skip to content

Commit 32ee586

Browse files
Handle socket buffer size setting when system's maximum exceeded (#5527)
* Regression tests for asio_helpers socket buffer size Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Regression tests udp & tcp Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Refs #22210. Ensure that actual set value is returned by `asio_helpers::try_setting_buffer_size` Signed-off-by: Miguel Company <miguelcompany@eprosima.com> * Fix corner case infinite loop Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Uncrustify Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Fix UDP tests Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Fix windows compilation Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Applied suggestions to regression test Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Applied suggestions to udp tests Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> * Uncrustify Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> --------- Signed-off-by: Eugenio Collado <eugeniocollado@eprosima.com> Signed-off-by: Miguel Company <miguelcompany@eprosima.com> Co-authored-by: Miguel Company <miguelcompany@eprosima.com>
1 parent 2148998 commit 32ee586

File tree

5 files changed

+198
-8
lines changed

5 files changed

+198
-8
lines changed

src/cpp/rtps/transport/asio_helpers.hpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,49 @@ struct asio_helpers
5151
asio::error_code ec;
5252

5353
final_buffer_value = initial_buffer_value;
54-
while (final_buffer_value >= minimum_buffer_value)
54+
while (final_buffer_value > minimum_buffer_value)
5555
{
56-
socket.set_option(BufferOptionType(static_cast<int32_t>(final_buffer_value)), ec);
56+
int32_t value_to_set = static_cast<int32_t>(final_buffer_value);
57+
socket.set_option(BufferOptionType(value_to_set), ec);
5758
if (!ec)
5859
{
60+
BufferOptionType option;
61+
socket.get_option(option, ec);
62+
if (!ec)
63+
{
64+
if (option.value() == value_to_set)
65+
{
66+
// Option actually set to the desired value
67+
return true;
68+
}
69+
// Try again with the value actually set
70+
final_buffer_value = option.value();
71+
continue;
72+
}
73+
// Could not determine the actual value, but the option was set successfully.
74+
// Assume the option was set to the desired value.
5975
return true;
6076
}
6177

6278
final_buffer_value /= 2;
6379
}
6480

81+
// Perform a final attempt to set the minimum value
6582
final_buffer_value = minimum_buffer_value;
66-
socket.set_option(BufferOptionType(final_buffer_value), ec);
67-
return !ec;
83+
int32_t value_to_set = static_cast<int32_t>(final_buffer_value);
84+
socket.set_option(BufferOptionType(value_to_set), ec);
85+
if (!ec)
86+
{
87+
// Last attempt was successful. Get the actual value set.
88+
BufferOptionType option;
89+
socket.get_option(option, ec);
90+
if (!ec)
91+
{
92+
final_buffer_value = option.value();
93+
}
94+
return true;
95+
}
96+
return false;
6897
}
6998

7099
/**
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <limits>
16+
#include <memory>
17+
#include <thread>
18+
19+
#include <asio.hpp>
20+
#include <gtest/gtest.h>
21+
22+
#include <fastdds/dds/log/Log.hpp>
23+
#include <fastdds/rtps/transport/UDPv4TransportDescriptor.hpp>
24+
#include <fastdds/utils/IPFinder.hpp>
25+
#include <fastdds/utils/IPLocator.hpp>
26+
27+
#include <utils/Semaphore.hpp>
28+
29+
#include <MockReceiverResource.h>
30+
#include <rtps/transport/asio_helpers.hpp>
31+
#include <rtps/transport/UDPv4Transport.h>
32+
33+
using namespace eprosima::fastdds::rtps;
34+
35+
36+
// Regression tests for redmine issue #22210
37+
38+
template <typename BufferOption, typename SocketType, typename Protocol>
39+
void test_buffer_setting(
40+
int initial_buffer_value,
41+
int minimum_buffer_value)
42+
{
43+
asio::io_service io_service;
44+
auto socket = std::make_unique<SocketType>(io_service);
45+
46+
// Open the socket with the provided protocol
47+
socket->open(Protocol::v4());
48+
49+
uint32_t final_buffer_value = 0;
50+
51+
// Replace this with your actual implementation of try_setting_buffer_size
52+
ASSERT_TRUE(asio_helpers::try_setting_buffer_size<BufferOption>(
53+
*socket, initial_buffer_value, minimum_buffer_value, final_buffer_value));
54+
55+
56+
57+
BufferOption option;
58+
asio::error_code ec;
59+
socket->get_option(option, ec);
60+
if (!ec)
61+
{
62+
ASSERT_EQ(static_cast<uint32_t>(option.value()), final_buffer_value);
63+
}
64+
else
65+
{
66+
throw std::runtime_error("Failed to get buffer option");
67+
}
68+
}
69+
70+
// Test that the UDP buffer size is set actually to the value stored as the final value
71+
TEST(AsioHelpersTests, udp_buffer_size)
72+
{
73+
uint32_t minimum_buffer_value = 0;
74+
for (uint32_t initial_buffer_value = std::numeric_limits<uint32_t>::max(); initial_buffer_value > 0;
75+
initial_buffer_value /= 4)
76+
{
77+
test_buffer_setting<asio::socket_base::send_buffer_size, asio::ip::udp::socket, asio::ip::udp>(
78+
initial_buffer_value, minimum_buffer_value);
79+
test_buffer_setting<asio::socket_base::receive_buffer_size, asio::ip::udp::socket, asio::ip::udp>(
80+
initial_buffer_value, minimum_buffer_value);
81+
}
82+
}
83+
84+
// Test that the TCP buffer size is set actually to the value stored as the final value
85+
TEST(AsioHelpersTests, tcp_buffer_size)
86+
{
87+
uint32_t minimum_buffer_value = 0;
88+
for (uint32_t initial_buffer_value = std::numeric_limits<uint32_t>::max(); initial_buffer_value > 0;
89+
initial_buffer_value /= 4)
90+
{
91+
test_buffer_setting<asio::socket_base::send_buffer_size, asio::ip::tcp::socket, asio::ip::tcp>(
92+
initial_buffer_value, minimum_buffer_value);
93+
test_buffer_setting<asio::socket_base::receive_buffer_size, asio::ip::tcp::socket, asio::ip::tcp>(
94+
initial_buffer_value, minimum_buffer_value);
95+
}
96+
}
97+
98+
int main(
99+
int argc,
100+
char** argv)
101+
{
102+
testing::InitGoogleTest(&argc, argv);
103+
return RUN_ALL_TESTS();
104+
}

test/unittest/transport/CMakeLists.txt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,28 @@ set(UDPV4TESTS_SOURCE
8585
${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/Time_t.cpp
8686
)
8787

88+
set(ASIOHELPERSTESTS_SOURCE
89+
AsioHelpersTests.cpp
90+
mock/MockReceiverResource.cpp
91+
${PROJECT_SOURCE_DIR}/src/cpp/utils/IPFinder.cpp
92+
${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/Log.cpp
93+
${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/OStreamConsumer.cpp
94+
${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/StdoutConsumer.cpp
95+
${PROJECT_SOURCE_DIR}/src/cpp/fastdds/log/StdoutErrConsumer.cpp
96+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/attributes/PropertyPolicy.cpp
97+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/flowcontrol/ThroughputControllerDescriptor.cpp
98+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPv4Transport.cpp
99+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPTransportInterface.cpp
100+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/ChannelResource.cpp
101+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/transport/UDPChannelResource.cpp
102+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/network/NetworkFactory.cpp
103+
${TCPTransportInterface_SOURCE}
104+
${PROJECT_SOURCE_DIR}/src/cpp/utils/IPLocator.cpp
105+
${PROJECT_SOURCE_DIR}/src/cpp/utils/SystemInfo.cpp
106+
${PROJECT_SOURCE_DIR}/src/cpp/rtps/common/Time_t.cpp
107+
)
108+
109+
88110
set(UDPV6TESTS_SOURCE
89111
UDPv6Tests.cpp
90112
mock/MockReceiverResource.cpp
@@ -225,6 +247,9 @@ if(ANDROID)
225247
list(APPEND UDPV4TESTS_SOURCE
226248
${ANDROID_IFADDRS_SOURCE_DIR}/ifaddrs.c
227249
)
250+
list(APPEND ASIOHELPERSTESTS_SOURCE
251+
${ANDROID_IFADDRS_SOURCE_DIR}/ifaddrs.c
252+
)
228253
list(APPEND SHAREDMEMTESTS_SOURCE
229254
${ANDROID_IFADDRS_SOURCE_DIR}/ifaddrs.c
230255
)
@@ -399,11 +424,43 @@ foreach(TRANSPORT_XFAIL_TEST ${TRANSPORT_XFAIL_LIST})
399424
add_xfail_label(${CMAKE_CURRENT_SOURCE_DIR}/${TRANSPORT_XFAIL_TEST}.list)
400425
endforeach()
401426

427+
#####################################
428+
# AsioHelpers tests
429+
#####################################
430+
add_executable(AsioHelpersTests ${ASIOHELPERSTESTS_SOURCE})
431+
target_compile_definitions(AsioHelpersTests PRIVATE
432+
BOOST_ASIO_STANDALONE
433+
ASIO_STANDALONE
434+
$<$<AND:$<NOT:$<BOOL:${WIN32}>>,$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">>:__DEBUG>
435+
$<$<BOOL:${INTERNAL_DEBUG}>:__INTERNALDEBUG> # Internal debug activated.
436+
)
437+
target_include_directories(AsioHelpersTests PRIVATE
438+
${Asio_INCLUDE_DIR}
439+
${PROJECT_SOURCE_DIR}/test/mock/rtps/MessageReceiver
440+
${PROJECT_SOURCE_DIR}/test/mock/rtps/ReceiverResource
441+
${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include
442+
${PROJECT_SOURCE_DIR}/src/cpp
443+
$<$<BOOL:${ANDROID}>:${ANDROID_IFADDRS_INCLUDE_DIR}>
444+
)
445+
target_link_libraries(AsioHelpersTests GTest::gtest ${MOCKS}
446+
$<$<BOOL:${TLS_FOUND}>:OpenSSL::SSL$<SEMICOLON>OpenSSL::Crypto>)
447+
if(QNX)
448+
target_link_libraries(AsioHelpersTests socket)
449+
endif()
450+
if(MSVC OR MSVC_IDE)
451+
target_link_libraries(AsioHelpersTests ${PRIVACY} fastcdr iphlpapi Shlwapi)
452+
else()
453+
target_link_libraries(AsioHelpersTests ${PRIVACY} fastcdr)
454+
endif()
455+
add_gtest(AsioHelpersTests SOURCES ${ASIOHELPERSTESTS_SOURCE})
456+
402457
if(ANDROID)
403458
set_property(TARGET UDPv4Tests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
404459
set_property(TARGET UDPv6Tests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
405460
set_property(TARGET TCPv4Tests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
406461
set_property(TARGET TCPv6Tests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
407462
set_property(TARGET SharedMemTests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
408463
set_property(TARGET test_UDPv4Tests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
464+
set_property(TARGET AsioHelpersTests PROPERTY CROSSCOMPILING_EMULATOR "adb;shell;cd;${CMAKE_CURRENT_BINARY_DIR};&&")
409465
endif()
466+

test/unittest/transport/UDPv4Tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,8 @@ TEST_F(UDPv4Tests, double_binding_fails)
794794
void UDPv4Tests::HELPER_SetDescriptorDefaults()
795795
{
796796
descriptor.maxMessageSize = 5;
797-
descriptor.sendBufferSize = 5;
798-
descriptor.receiveBufferSize = 5;
797+
descriptor.sendBufferSize = 5000;
798+
descriptor.receiveBufferSize = 5000;
799799
descriptor.interfaceWhiteList.clear();
800800
}
801801

test/unittest/transport/UDPv6Tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,8 @@ TEST_F(UDPv6Tests, double_binding_fails)
826826
void UDPv6Tests::HELPER_SetDescriptorDefaults()
827827
{
828828
descriptor.maxMessageSize = 5;
829-
descriptor.sendBufferSize = 5;
830-
descriptor.receiveBufferSize = 5;
829+
descriptor.sendBufferSize = 5000;
830+
descriptor.receiveBufferSize = 5000;
831831
}
832832

833833
int main(

0 commit comments

Comments
 (0)