int grpc_pick_unused_port(void) { /* We repeatedly pick a port and then see whether or not it is available for use both as a TCP socket and a UDP socket. First, we pick a random large port number. For subsequent iterations, we bind to an anonymous port and let the OS pick the port number. The random port picking reduces the probability of races with other processes on kernels that want to reuse the same port numbers over and over. */ /* In alternating iterations we try UDP ports before TCP ports UDP ports -- it could be the case that this machine has been using up UDP ports and they are scarcer. */ /* Type of port to first pick in next iteration */ int is_tcp = 1; int try = 0; for (;;) { int port; try++; if (try == 1) { port = getpid() % (65536 - 30000) + 30000; } else if (try <= NUM_RANDOM_PORTS_TO_PICK) { port = rand() % (65536 - 30000) + 30000; } else { port = 0; } if (has_port_been_chosen(port)) { continue; } if (!is_port_available(&port, is_tcp)) { continue; } GPR_ASSERT(port > 0); /* Check that the port # is free for the other type of socket also */ if (!is_port_available(&port, !is_tcp)) { /* In the next iteration try to bind to the other type first because perhaps it is more rare. */ is_tcp = !is_tcp; continue; } chose_port(port); return port; }
int grpc_pick_unused_port(void) { /* We repeatedly pick a port and then see whether or not it is available for use both as a TCP socket and a UDP socket. First, we pick a random large port number. For subsequent iterations, we bind to an anonymous port and let the OS pick the port number. The random port picking reduces the probability of races with other processes on kernels that want to reuse the same port numbers over and over. */ /* In alternating iterations we trial UDP ports before TCP ports UDP ports -- it could be the case that this machine has been using up UDP ports and they are scarcer. */ /* Type of port to first pick in next iteration */ int is_tcp = 1; int trial = 0; char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); if (env) { int port = grpc_pick_port_using_server(env); gpr_free(env); if (port != 0) { return port; } } for (;;) { int port; trial++; if (trial == 1) { port = _getpid() % (65536 - 30000) + 30000; } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) { port = rand() % (65536 - 30000) + 30000; } else { port = 0; } if (has_port_been_chosen(port)) { continue; } if (!is_port_available(&port, is_tcp)) { continue; } GPR_ASSERT(port > 0); /* Check that the port # is free for the other type of socket also */ if (!is_port_available(&port, !is_tcp)) { /* In the next iteration trial to bind to the other type first because perhaps it is more rare. */ is_tcp = !is_tcp; continue; } /* TODO(ctiller): consider caching this port in some structure, to avoid handing it out again */ chose_port(port); return port; } /* The port iterator reached the end without finding a suitable port. */ return 0; }