Skip to content

Commit 0b5dde4

Browse files
committed
Fix tcp_server test port race on Windows CI
Add tcp_server::local_endpoint() and use ephemeral port binding (port 0) instead of TOCTOU port-probing in testStopWithActiveConnection and testRestart.
1 parent d9f2057 commit 0b5dde4

File tree

3 files changed

+21
-35
lines changed

3 files changed

+21
-35
lines changed

include/boost/corosio/tcp_server.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,15 @@ class BOOST_COROSIO_DECL tcp_server
712712
*/
713713
void start();
714714

715+
/** Return the local endpoint for the i-th bound port.
716+
717+
@param index Zero-based index into the list of bound ports.
718+
719+
@return The local endpoint, or a default-constructed endpoint
720+
if @p index is out of range or the acceptor is not open.
721+
*/
722+
endpoint local_endpoint(std::size_t index = 0) const noexcept;
723+
715724
/** Stop accepting connections.
716725
717726
Signals all listening ports to stop accepting new connections

src/corosio/src/tcp_server.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ tcp_server::bind(endpoint ep)
105105
}
106106
}
107107

108+
endpoint
109+
tcp_server::local_endpoint(std::size_t index) const noexcept
110+
{
111+
if (index >= impl_->ports.size())
112+
return endpoint{};
113+
return impl_->ports[index].local_endpoint();
114+
}
115+
108116
void
109117
tcp_server::start()
110118
{

test/unit/tcp_server.cpp

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -116,26 +116,10 @@ struct tcp_server_test
116116
{
117117
io_context ioc;
118118

119-
// Find an available port
120-
tcp_acceptor acc(ioc);
121-
std::uint16_t port = 0;
122-
for (int attempt = 0; attempt < 20; ++attempt)
123-
{
124-
port = static_cast<std::uint16_t>(49152 + (attempt * 7) % 16383);
125-
acc.open();
126-
acc.set_option(socket_option::reuse_address(true));
127-
if (!acc.bind(endpoint(ipv4_address::loopback(), port)) &&
128-
!acc.listen())
129-
break;
130-
acc.close();
131-
acc = tcp_acceptor(ioc);
132-
}
133-
acc.close();
134-
135-
// Create server and bind to found port
136119
test_server srv(ioc);
137-
auto ec = srv.bind(endpoint(ipv4_address::loopback(), port));
120+
auto ec = srv.bind(endpoint(ipv4_address::loopback(), 0));
138121
BOOST_TEST(!ec);
122+
auto port = srv.local_endpoint().port();
139123

140124
std::atomic<bool> connection_handled{false};
141125
std::atomic<bool> stop_requested{false};
@@ -251,25 +235,10 @@ struct tcp_server_test
251235

252236
io_context ioc;
253237

254-
// Find an available port
255-
tcp_acceptor acc(ioc);
256-
std::uint16_t port = 0;
257-
for (int attempt = 0; attempt < 20; ++attempt)
258-
{
259-
port = static_cast<std::uint16_t>(49152 + (attempt * 7) % 16383);
260-
acc.open();
261-
acc.set_option(socket_option::reuse_address(true));
262-
if (!acc.bind(endpoint(ipv4_address::loopback(), port)) &&
263-
!acc.listen())
264-
break;
265-
acc.close();
266-
acc = tcp_acceptor(ioc);
267-
}
268-
acc.close();
269-
270238
test_server srv(ioc);
271-
auto ec = srv.bind(endpoint(ipv4_address::loopback(), port));
239+
auto ec = srv.bind(endpoint(ipv4_address::loopback(), 0));
272240
BOOST_TEST(!ec);
241+
auto port = srv.local_endpoint().port();
273242

274243
int connections_handled = 0;
275244

0 commit comments

Comments
 (0)