@ -39,6 +39,7 @@
# include <errno.h>
# include <netinet/in.h>
# include <stdbool.h>
# include <stdio.h>
# include <string.h>
# include <sys/socket.h>
@ -50,6 +51,8 @@
# include <grpc/support/string_util.h>
# include "src/core/lib/http/httpcli.h"
# include "src/core/lib/iomgr/resolve_address.h"
# include "src/core/lib/iomgr/sockaddr_utils.h"
# include "src/core/lib/support/env.h"
# include "test/core/util/port_server_client.h"
@ -115,55 +118,68 @@ static void chose_port(int port) {
chosen_ports [ num_chosen_ports - 1 ] = port ;
}
static int is_port_available ( int * port , int is_tcp ) {
const int proto = is_tcp ? IPPROTO_TCP : 0 ;
const int fd = socket ( AF_INET , is_tcp ? SOCK_STREAM : SOCK_DGRAM , proto ) ;
int one = 1 ;
struct sockaddr_in addr ;
socklen_t alen = sizeof ( addr ) ;
int actual_port ;
static bool is_port_available ( int * port , bool is_tcp ) {
GPR_ASSERT ( * port > = 0 ) ;
GPR_ASSERT ( * port < = 65535 ) ;
if ( fd < 0 ) {
gpr_log ( GPR_ERROR , " socket() failed: %s " , strerror ( errno ) ) ;
return 0 ;
}
/* Reuseaddr lets us start up a server immediately after it exits */
if ( setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , & one , sizeof ( one ) ) < 0 ) {
gpr_log ( GPR_ERROR , " setsockopt() failed: %s " , strerror ( errno ) ) ;
close ( fd ) ;
return 0 ;
}
/* For a port to be considered available, the kernel must support
at least one of ( IPv6 , IPv4 ) , and the port must be available
on each supported family . */
bool got_socket = false ;
for ( int is_ipv6 = 1 ; is_ipv6 > = 0 ; is_ipv6 - - ) {
const int fd = socket ( is_ipv6 ? AF_INET6 : AF_INET ,
is_tcp ? SOCK_STREAM : SOCK_DGRAM ,
is_tcp ? IPPROTO_TCP : 0 ) ;
if ( fd > = 0 ) {
got_socket = true ;
} else {
continue ;
}
/* Try binding to port */
addr . sin_family = AF_INET ;
addr . sin_addr . s_addr = INADDR_ANY ;
addr . sin_port = htons ( ( uint16_t ) * port ) ;
if ( bind ( fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) < 0 ) {
gpr_log ( GPR_DEBUG , " bind(port=%d) failed: %s " , * port , strerror ( errno ) ) ;
close ( fd ) ;
return 0 ;
}
/* Reuseaddr lets us start up a server immediately after it exits */
const int one = 1 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , & one , sizeof ( one ) ) < 0 ) {
gpr_log ( GPR_ERROR , " setsockopt() failed: %s " , strerror ( errno ) ) ;
close ( fd ) ;
return false ;
}
/* Try binding to port */
grpc_resolved_address addr ;
if ( is_ipv6 ) {
grpc_sockaddr_make_wildcard6 ( * port , & addr ) ; /* [::]:port */
} else {
grpc_sockaddr_make_wildcard4 ( * port , & addr ) ; /* 0.0.0.0:port */
}
if ( bind ( fd , ( struct sockaddr * ) addr . addr , ( socklen_t ) addr . len ) < 0 ) {
gpr_log ( GPR_DEBUG , " bind(port=%d) failed: %s " , * port , strerror ( errno ) ) ;
close ( fd ) ;
return false ;
}
/* Get the bound port number */
if ( getsockname ( fd , ( struct sockaddr * ) addr . addr ,
( socklen_t * ) & addr . len ) < 0 ) {
gpr_log ( GPR_ERROR , " getsockname() failed: %s " , strerror ( errno ) ) ;
close ( fd ) ;
return false ;
}
GPR_ASSERT ( addr . len < = sizeof ( addr . addr ) ) ;
const int actual_port = grpc_sockaddr_get_port ( & addr ) ;
GPR_ASSERT ( actual_port > 0 ) ;
if ( * port = = 0 ) {
* port = actual_port ;
} else {
GPR_ASSERT ( * port = = actual_port ) ;
}
/* Get the bound port number */
if ( getsockname ( fd , ( struct sockaddr * ) & addr , & alen ) < 0 ) {
gpr_log ( GPR_ERROR , " getsockname() failed: %s " , strerror ( errno ) ) ;
close ( fd ) ;
return 0 ;
}
GPR_ASSERT ( alen < = sizeof ( addr ) ) ;
actual_port = ntohs ( addr . sin_port ) ;
GPR_ASSERT ( actual_port > 0 ) ;
if ( * port = = 0 ) {
* port = actual_port ;
} else {
GPR_ASSERT ( * port = = actual_port ) ;
if ( ! got_socket ) {
gpr_log ( GPR_ERROR , " socket() failed: %s " , strerror ( errno ) ) ;
return false ;
}
close ( fd ) ;
return 1 ;
return true ;
}
int grpc_pick_unused_port ( void ) {
@ -180,7 +196,7 @@ int grpc_pick_unused_port(void) {
UDP ports and they are scarcer . */
/* Type of port to first pick in next iteration */
int is_tcp = 1 ;
bool is_tcp = true ;
int trial = 0 ;
char * env = gpr_getenv ( " GRPC_TEST_PORT_SERVER " ) ;