async function connect_async()

in src/tcp/connect.php [21:94]


async function connect_async(
  string $host,
  int $port,
  ConnectOptions $opts = shape(),
): Awaitable<CloseableSocket> {
  $ipver = $opts['ip_version'] ?? Network\IPProtocolBehavior::PREFER_IPV6;
  $timeout_ns = $opts['timeout_ns'] ?? 0;
  switch ($ipver) {
    case Network\IPProtocolBehavior::PREFER_IPV6:
      $sds = vec[OS\SocketDomain::PF_INET6, OS\SocketDomain::PF_INET];
      break;
    case Network\IPProtocolBehavior::FORCE_IPV6:
      $sds = vec[OS\SocketDomain::PF_INET6];
      break;
    case Network\IPProtocolBehavior::FORCE_IPV4:
      $sds = vec[OS\SocketDomain::PF_INET];
      break;
  }

  $ex = null;
  foreach ($sds as $sd) {
    $sock = OS\socket($sd, OS\SocketType::SOCK_STREAM, 0);
    $sa = null;
    switch ($sd) {
      case OS\SocketDomain::PF_INET:
        $ipv4_host = _Network\resolve_hostname(
          OS\AddressFamily::AF_INET,
          $host,
        );
        if ($ipv4_host is nonnull) {
          $sa = new OS\sockaddr_in(
            $port,
            OS\inet_pton_inet($ipv4_host),
          );
        }
        break;
      case OS\SocketDomain::PF_INET6:
        $ipv6_host = _Network\resolve_hostname(
          OS\AddressFamily::AF_INET6,
          $host,
        );

        if ($ipv6_host !== null) {
          $sa = new OS\sockaddr_in6(
            $port,
            /* flowinfo = */ 0,
            OS\inet_pton_inet6($ipv6_host),
            /* scope id = */ 0,
          );
        }
        break;
      case OS\SocketDomain::PF_UNIX:
        invariant_violation('unreachable');
    }

    if ($sa === null) {
      continue;
    }

    try {
      await _Network\socket_connect_async($sock, $sa, $timeout_ns);
      return new _TCP\CloseableTCPSocket($sock);
    } catch (OS\ErrnoException $this_sd_ex) {
      $ex = $this_sd_ex;
    }
  }
  if ($ex === null) {
    _OS\throw_errno(
      OS\Errno::EINVAL,
      "Failed to create a sockaddr for any domain",
    );
  }
  throw $ex;
}