/* 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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}