/** * Query DNS server for A / AAAA records in batches of 2. * * @param string $host Host name to be resolved. * @return array Resolved address and expiration time. * * @throws MultiReasonException When no IP address could be resolved. */ protected function resolveHost(string $host) : \Generator { $errors = []; foreach (\array_chunk($this->servers, 2) as $servers) { $ipv4 = []; $ipv6 = []; foreach ($servers as $server) { if (Socket::isIPv6Supported()) { $ipv6[] = new Coroutine($this->lookupAddress($server, $errors, $host, Request::TYPE_AAAA)); } $ipv4[] = new Coroutine($this->lookupAddress($server, $errors, $host, Request::TYPE_A)); } list($ipv4, $ipv6) = (yield new AwaitAll([$this->awaitFirstResult($ipv6, $errors), $this->awaitFirstResult($ipv4, $errors)])); if (empty($ipv4) && empty($ipv6)) { continue; } $ttl = min($ipv4['ttl'] ?? PHP_INT_MAX, $ipv6['ttl'] ?? PHP_INT_MAX); $ttl = max(1, min(300, $ttl)); $address = null; foreach (\array_merge((array) $ipv4['ips'], (array) $ipv6['ips']) as $ip) { try { $address = $address ? $address->mergeWith(new Address($ip)) : new Address($ip); } catch (\Throwable $e) { $errors[] = $e; } } if ($address && \count($address)) { return ['address' => $address, 'expires' => \time() + $ttl]; } } $error = ''; foreach ($errors as $e) { $error .= \sprintf("\n+ [%s] %s", \get_class($e), $e->getMessage()); } if (!empty($errors)) { $error .= "\n"; } throw new MultiReasonException($errors, \sprintf('Unable to resolve host "%s" into an IP address%s', $host, $error)); }