----- Original Message -----
> From: "Alan Conway" <[email protected]>
> To: "dev" <[email protected]>
> Sent: Monday, February 20, 2017 4:23:50 PM
> Subject: Picking temporary ports for tests
> 
> Our code bases have a motley collection of  attempts to pick safe ports
>  for short-lived tests, most of which have race conditions that can
> result in sporadic bogus "address in use" test failures.
> 
> Here's an approach that seems to work: Bind a socket with bind(0) and
> SO_REUSEADDR - guaranteed by the OS to get you a port. Now leave that
> socket open while you start your server on that port.  Our servers also
> set SO_REUSEADDR for other reasons, this means the server can bind to
> the same port even though we have a socket bound already. The test code
> only binds, it doesn't listen, so the server is can listen as usual.
> Now you can close the test socket and you're off to the races!
> 
> Am I only dreaming? Here's the code (proton/proton-c/src/test_tools.h)
> 
> /* Create a socket and bind(LOOPBACK:0) to get a free port.
>    Use SO_REUSEADDR so other processes can bind and listen on this port.
>    Close the returned fd when the other process is listening.
>    Fail on error.
> */
> static sock_t sock_bind0(void) {
>   int sock =  socket(AF_INET, SOCK_STREAM, 0);
>   TEST_ASSERT_ERRNO(sock >= 0, errno);
>   int on = 1;
>   TEST_ASSERT_ERRNO(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const
>   char*)&on, sizeof(on)) == 0, errno);
>   struct sockaddr_in addr = {0};
>   addr.sin_family = AF_INET;    /* set the type of connection to TCP/IP */
>   addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
>   addr.sin_port = 0;            /* bind to port 0 */
>   TEST_ASSERT_ERRNO(bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0,
>   errno);
>   return sock;
> }
> 
> /* Get the real port number allocated to a socket created with sock_bind0 */
> static int sock_port(sock_t sock) {
>   struct sockaddr addr = {0};
>   socklen_t len = sizeof(addr);
>   TEST_ASSERT_ERRNO(getsockname(sock, &addr, &len) == 0, errno);
>   int port = -1;
>   switch (addr.sa_family) {
>    case AF_INET: port = ((struct sockaddr_in*)&addr)->sin_port; break;
>    case AF_INET6: port = ((struct sockaddr_in6*)&addr)->sin6_port; break;
>    default: TEST_ASSERTF(false, "unknown protocol type %d\n",
>    addr.sa_family); break;
>   }
>   return ntohs(port);
> }
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
> 
> 

Looks like you already have this code in the (proton) code base. 
* Does it work?
* Are there issues with using INADDR_LOOPBACK vs INADDR_ANY?
* It looks like it opens a port on one sa_family only (IPv4 or IPv6).
  I remember one of the problems with temp ports as the port being
  available on IPv4 but not on IPv6. Getting them both open was
  necessary. This may not be an issue for your use case.

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to