1919
2020#include " zm_comms.h"
2121#include < array>
22+ #include < cstdio>
23+
24+ namespace {
25+
26+ int reserveEphemeralPort (int socket_type) {
27+ const int sd = ::socket (AF_INET , socket_type, 0 );
28+ REQUIRE (sd >= 0 );
29+
30+ sockaddr_in addr = {};
31+ addr.sin_family = AF_INET ;
32+ addr.sin_addr .s_addr = htonl (INADDR_LOOPBACK );
33+ addr.sin_port = 0 ;
34+
35+ const int reuse_addr = 1 ;
36+ REQUIRE (::setsockopt (sd, SOL_SOCKET , SO_REUSEADDR , &reuse_addr, sizeof (reuse_addr)) == 0 );
37+ REQUIRE (::bind (sd, reinterpret_cast <const sockaddr *>(&addr), sizeof (addr)) == 0 );
38+
39+ socklen_t addr_len = sizeof (addr);
40+ REQUIRE (::getsockname (sd, reinterpret_cast <sockaddr *>(&addr), &addr_len) == 0 );
41+
42+ const int port = ntohs (addr.sin_port );
43+ REQUIRE (port > 0 );
44+ REQUIRE (::close (sd) == 0 );
45+ return port;
46+ }
47+
48+ std::string makeUnixSocketPath () {
49+ char path_template[] = " /tmp/zm.unittest.XXXXXX" ;
50+ const int fd = ::mkstemp (path_template);
51+ REQUIRE (fd >= 0 );
52+ REQUIRE (::close (fd) == 0 );
53+ REQUIRE (::unlink (path_template) == 0 );
54+ return std::string (path_template) + " .sock" ;
55+ }
56+
57+ } // namespace
2258
2359TEST_CASE (" ZM::Pipe basics" ) {
2460 zm::Pipe pipe;
@@ -126,13 +162,15 @@ TEST_CASE("ZM::SockAddrUnix") {
126162
127163TEST_CASE (" ZM::UdpInetSocket basics" ) {
128164 zm::UdpInetSocket socket;
165+ const int port = reserveEphemeralPort (SOCK_DGRAM );
166+ const std::string port_str = std::to_string (port);
129167 REQUIRE (socket.isClosed () == true );
130168 REQUIRE (socket.isOpen () == false );
131169 REQUIRE (socket.isConnected () == false );
132170 REQUIRE (socket.isDisconnected () == false );
133171
134172 SECTION (" bind with host and port" ) {
135- REQUIRE (socket.bind (nullptr , " 1234 " ) == true );
173+ REQUIRE (socket.bind (nullptr , port_str. c_str () ) == true );
136174 REQUIRE (socket.isOpen () == true );
137175 REQUIRE (socket.isDisconnected () == true );
138176 REQUIRE (socket.isClosed () == false );
@@ -148,21 +186,23 @@ TEST_CASE("ZM::UdpInetSocket basics") {
148186 }
149187
150188 SECTION (" bind with port" ) {
151- REQUIRE (socket.bind (" 1234 " ) == true );
189+ REQUIRE (socket.bind (port_str. c_str () ) == true );
152190 }
153191
154192 SECTION (" bind with host and port number" ) {
155- REQUIRE (socket.bind (nullptr , 1234 ) == true );
193+ REQUIRE (socket.bind (nullptr , port ) == true );
156194 }
157195
158196 SECTION (" bind with port number" ) {
159- REQUIRE (socket.bind (1234 ) == true );
197+ REQUIRE (socket.bind (port ) == true );
160198 }
161199}
162200
163201TEST_CASE (" ZM::UdpInetSocket send/recv" ) {
164202 zm::UdpInetSocket srv_socket;
165203 zm::UdpInetSocket client_socket;
204+ const int port = reserveEphemeralPort (SOCK_DGRAM );
205+ const std::string port_str = std::to_string (port);
166206
167207 std::array<char , 3 > msg = {' a' , ' b' , ' c' };
168208 std::array<char , msg.size ()> rcv{};
@@ -173,10 +213,10 @@ TEST_CASE("ZM::UdpInetSocket send/recv") {
173213 }
174214
175215 SECTION (" send/recv" ) {
176- REQUIRE (srv_socket.bind (" 127.0.0.1" , " 1234 " ) == true );
216+ REQUIRE (srv_socket.bind (" 127.0.0.1" , port_str. c_str () ) == true );
177217 REQUIRE (srv_socket.isOpen () == true );
178218
179- REQUIRE (client_socket.connect (" 127.0.0.1" , " 1234 " ) == true );
219+ REQUIRE (client_socket.connect (" 127.0.0.1" , port_str. c_str () ) == true );
180220 REQUIRE (client_socket.isConnected () == true );
181221
182222 REQUIRE (client_socket.send (msg.data (), msg.size ()) == msg.size ());
@@ -187,8 +227,7 @@ TEST_CASE("ZM::UdpInetSocket send/recv") {
187227}
188228
189229TEST_CASE (" ZM::UdpUnixSocket basics" ) {
190- std::string sock_path = " /tmp/zm.unittest.sock" ;
191- unlink (sock_path.c_str ()); // make sure the socket file does not exist
230+ const std::string sock_path = makeUnixSocketPath ();
192231
193232 zm::UdpUnixSocket socket;
194233 REQUIRE (socket.isClosed () == true );
@@ -218,8 +257,7 @@ TEST_CASE("ZM::UdpUnixSocket basics") {
218257}
219258
220259TEST_CASE (" ZM::UdpUnixSocket send/recv" ) {
221- std::string sock_path = " /tmp/zm.unittest.sock" ;
222- unlink (sock_path.c_str ()); // make sure the socket file does not exist
260+ const std::string sock_path = makeUnixSocketPath ();
223261
224262 zm::UdpUnixSocket srv_socket;
225263 zm::UdpUnixSocket client_socket;
@@ -281,12 +319,13 @@ TEST_CASE("ZM::TcpInetClient basics") {
281319
282320TEST_CASE (" ZM::TcpInetServer basics" , " [notCI]" ) {
283321 zm::TcpInetServer server;
322+ const int port = reserveEphemeralPort (SOCK_STREAM );
284323 REQUIRE (server.isClosed () == true );
285324 REQUIRE (server.isOpen () == false );
286325 REQUIRE (server.isConnected () == false );
287326 REQUIRE (server.isDisconnected () == false );
288327
289- REQUIRE (server.bind (1234 ) == true );
328+ REQUIRE (server.bind (port ) == true );
290329 REQUIRE (server.isOpen () == true );
291330 REQUIRE (server.isClosed () == false );
292331 REQUIRE (server.isConnected () == false );
@@ -308,6 +347,7 @@ TEST_CASE("ZM::TcpInetServer basics", "[notCI]") {
308347TEST_CASE (" ZM::TcpInetClient/Server send/recv" , " [notCI]" ) {
309348 zm::TcpInetServer server;
310349 zm::TcpInetClient client;
350+ const int port = reserveEphemeralPort (SOCK_STREAM );
311351
312352 std::array<char , 3 > msg = {' a' , ' b' , ' c' };
313353 std::array<char , msg.size ()> rcv{};
@@ -318,11 +358,11 @@ TEST_CASE("ZM::TcpInetClient/Server send/recv", "[notCI]") {
318358 }
319359
320360 SECTION (" send/recv" ) {
321- REQUIRE (server.bind (1234 ) == true );
361+ REQUIRE (server.bind (port ) == true );
322362 REQUIRE (server.isOpen () == true );
323363 REQUIRE (server.listen () == true );
324364
325- REQUIRE (client.connect (" 127.0.0.1" , 1234 ) == true );
365+ REQUIRE (client.connect (" 127.0.0.1" , port ) == true );
326366 REQUIRE (client.isConnected () == true );
327367
328368 REQUIRE (server.accept () == true );
0 commit comments