/* Bind to "::" to get a port number not used by any address. */ static grpc_error *get_unused_port(int *port) { grpc_resolved_address wild; grpc_sockaddr_make_wildcard6(0, &wild); grpc_dualstack_mode dsmode; int fd; grpc_error *err = grpc_create_dualstack_socket(&wild, SOCK_STREAM, 0, &dsmode, &fd); if (err != GRPC_ERROR_NONE) { return err; } if (dsmode == GRPC_DSMODE_IPV4) { grpc_sockaddr_make_wildcard4(0, &wild); } if (bind(fd, (const struct sockaddr *)wild.addr, (socklen_t)wild.len) != 0) { err = GRPC_OS_ERROR(errno, "bind"); close(fd); return err; } if (getsockname(fd, (struct sockaddr *)wild.addr, (socklen_t *)&wild.len) != 0) { err = GRPC_OS_ERROR(errno, "getsockname"); close(fd); return err; } close(fd); *port = grpc_sockaddr_get_port(&wild); return *port <= 0 ? GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad port") : GRPC_ERROR_NONE; }
void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out) { grpc_sockaddr_make_wildcard4(port, wild4_out); grpc_sockaddr_make_wildcard6(port, wild6_out); }
static bool is_port_available(int *port, bool is_tcp) { GPR_ASSERT(*port >= 0); GPR_ASSERT(*port <= 65535); /* 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; } /* 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); } close(fd); } if (!got_socket) { gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno)); return false; } return true; }