/** * @param $domains * @throws AcmeException */ private function checkDnsRecords($domains) { $promises = []; foreach ($domains as $domain) { $promises[$domain] = \Amp\Dns\resolve($domain, ["types" => [Record::A], "hosts" => false]); } list($errors) = (yield \Amp\any($promises)); if (!empty($errors)) { throw new AcmeException("Couldn't resolve the following domains to an IPv4 record: " . implode(", ", array_keys($errors))); } }
function __doConnect($uri, array $options) { $contextOptions = []; if (\stripos($uri, "unix://") === 0 || \stripos($uri, "udg://") === 0) { list($scheme, $path) = explode("://", $uri, 2); $isUnixSock = true; $resolvedUri = "{$scheme}:///" . \ltrim($path, "/"); } else { $isUnixSock = false; // TCP/UDP host names are always case-insensitive if (!($uriParts = @\parse_url(strtolower($uri)))) { throw new \DomainException("Invalid URI: {$uri}"); } // $scheme, $host, $port, $path \extract($uriParts); $scheme = empty($scheme) ? "tcp" : $scheme; if (!($scheme === "tcp" || $scheme === "udp")) { throw new \DomainException("Invalid URI scheme ({$scheme}); tcp, udp, unix or udg scheme expected"); } if (empty($host) || empty($port)) { throw new \DomainException("Invalid URI ({$uri}); host and port components required"); } if (PHP_VERSION_ID < 50600 && $scheme === "tcp") { // Prior to PHP 5.6 the SNI_server_name only registers if assigned to the stream // context at the time the socket is first connected (NOT with stream_socket_enable_crypto()). // So we always add the necessary ctx option here along with our own custom SNI_nb_hack // key to communicate our intent to the CryptoBroker if it's subsequently used $contextOptions = ["ssl" => ["SNI_server_name" => $host, "SNI_nb_hack" => true]]; } if ($inAddr = @\inet_pton($host)) { $isIpv6 = isset($inAddr[15]); } else { $records = (yield \Amp\Dns\resolve($host)); list($host, $mode) = $records[0]; $isIpv6 = $mode === \Amp\Dns\Record::AAAA; } $resolvedUri = $isIpv6 ? "[{$host}]:{$port}" : "{$host}:{$port}"; } $flags = \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT; $timeout = 42; // <--- timeout not applicable for async connects $bindTo = empty($options["bind_to"]) ? "" : (string) $options["bind_to"]; if (!$isUnixSock && $bindTo) { $contextOptions["socket"]["bindto"] = $bindTo; } $ctx = \stream_context_create($contextOptions); if (!($socket = @\stream_socket_client($resolvedUri, $errno, $errstr, $timeout, $flags, $ctx))) { throw new ConnectException(\sprintf("Connection to %s failed: [Error #%d] %s", $uri, $errno, $errstr)); } \stream_set_blocking($socket, false); $promisor = new \Amp\Deferred(); $promise = $promisor->promise(); $watcherId = \Amp\onWritable($socket, [$promisor, "succeed"]); $timeout = empty($options["timeout"]) ? 30000 : $options["timeout"]; try { (yield $timeout > 0 ? \Amp\timeout($promise, $timeout) : $promise); \Amp\cancel($watcherId); (yield new \Amp\CoroutineResult($socket)); } catch (\Amp\TimeoutException $e) { \Amp\cancel($watcherId); throw new ConnectException("Connection to {$uri} failed: timeout exceeded ({$timeout} ms)", 0, $e); } }
private function checkDnsRecords($domains) { $errors = []; $domainChunks = array_chunk($domains, 10, true); foreach ($domainChunks as $domainChunk) { $promises = []; foreach ($domainChunk as $domain) { $promises[$domain] = \Amp\Dns\resolve($domain, ["types" => [Record::A, Record::AAAA], "hosts" => false]); } list($chunkErrors) = (yield \Amp\any($promises)); $errors += $chunkErrors; } if (!empty($errors)) { throw new AcmeException("Couldn't resolve the following domains to an IPv4 nor IPv6 record: " . implode(", ", array_keys($errors))); } }