Skip to content

Commit

Permalink
Merge 5e5b63a into ef0d70d
Browse files Browse the repository at this point in the history
  • Loading branch information
kelunik committed Nov 9, 2017
2 parents ef0d70d + 5e5b63a commit 8f47781
Showing 1 changed file with 30 additions and 8 deletions.
38 changes: 30 additions & 8 deletions lib/functions.php
Expand Up @@ -69,13 +69,14 @@ function connect(string $uri, ClientConnectContext $socketContext = null, Cancel
$token = $token ?? new NullCancellationToken;
$attempt = 0;
$uris = [];
$failures = [];

list($scheme, $host, $port) = Internal\parseUri($uri);

if ($host[0] === '[') {
$host = substr($host, 1, -1);
}

if ($port === 0 || @\inet_pton($host)) {
// Host is already an IP address or file path.
$uris = [$uri];
Expand Down Expand Up @@ -112,10 +113,11 @@ function connect(string $uri, ClientConnectContext $socketContext = null, Cancel

if (!$socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $context)) {
throw new ConnectException(\sprintf(
"Connection to %s failed: [Error #%d] %s",
"Connection to %s failed: [Error #%d] %s%s",
$uri,
$errno,
$errstr
$errstr,
$failures ? "; previous attempts: " . \implode($failures) : ""
), $errno);
}

Expand All @@ -126,30 +128,50 @@ function connect(string $uri, ClientConnectContext $socketContext = null, Cancel

try {
yield Promise\timeout($deferred->promise(), $timeout);
} catch (TimeoutException $e) {
throw new ConnectException(\sprintf(
"Connecting to %s failed: timeout exceeded (%d ms)%s",
$uri,
$timeout,
$failures ? "; previous attempts: " . \implode($failures) : ""
), 110); // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno
} finally {
Loop::cancel($watcher);
}

// The following hack looks like the only way to detect connection refused errors with PHP's stream sockets.
if (\stream_socket_get_name($socket, true) === false) {
\fclose($socket);
throw new ConnectException(\sprintf("Connection to %s refused", $uri));
throw new ConnectException(\sprintf(
"Connection to %s refused%s",
$uri,
$failures ? "; previous attempts: " . \implode($failures) : ""
), 111); // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno
}
} catch (\Exception $e) {
// Includes only error codes used in this file, as error codes on other OS families might be different.
// In fact, this might show a confusing error message on OS families that return 110 or 111 by itself.
$knownReasons = [
110 => "connection timeout",
111 => "connection refused",
];

$code = $e->getCode();
$reason = $knownReasons[$code] ?? ("Error #" . $code);

if (++$attempt === $socketContext->getMaxAttempts()) {
break;
}

$failures[] = "{$uri} ({$reason})";

continue; // Could not connect to host, try next host in the list.
}

return new ClientSocket($socket);
}

if ($e instanceof TimeoutException) {
throw new ConnectException(\sprintf("Connecting to %s failed: timeout exceeded (%d ms)", $uri, $timeout));
}

// This is reached if either all URIs failed or the maximum number of attempts is reached.
throw $e;
});
}
Expand Down

0 comments on commit 8f47781

Please sign in to comment.