Skip to content

Commit 4ea75eb

Browse files
authored
Merge pull request #265 from clue-labs/errno
Improve error messages for failed TCP/IP connections with errno/errstr
2 parents aa6e3f8 + 5beea91 commit 4ea75eb

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

src/TcpConnector.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,20 @@ public function connect($uri)
9999
// The following hack looks like the only way to
100100
// detect connection refused errors with PHP's stream sockets.
101101
if (false === \stream_socket_get_name($stream, true)) {
102-
\fclose($stream);
102+
// actual socket errno and errstr can only be retrieved when ext-sockets is available (see tests)
103+
// @codeCoverageIgnoreStart
104+
if (\function_exists('socket_import_stream')) {
105+
$socket = \socket_import_stream($stream);
106+
$errno = \socket_get_option($socket, \SOL_SOCKET, \SO_ERROR);
107+
$errstr = \socket_strerror($errno);
108+
} else {
109+
$errno = \defined('SOCKET_ECONNREFUSED') ? \SOCKET_ECONNRESET : 111;
110+
$errstr = 'Connection refused?';
111+
}
112+
// @codeCoverageIgnoreEnd
103113

104-
$reject(new \RuntimeException('Connection to ' . $uri . ' failed: Connection refused'));
114+
\fclose($stream);
115+
$reject(new \RuntimeException('Connection to ' . $uri . ' failed: ' . $errstr, $errno));
105116
} else {
106117
$resolve(new Connection($stream, $loop));
107118
}

tests/TcpConnectorTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,39 @@ public function connectionToTcpServerShouldFailIfFileDescriptorsAreExceeded()
100100
Block\await($connector->connect('127.0.0.1:9999'), $loop, self::TIMEOUT);
101101
}
102102

103+
/** @test */
104+
public function connectionToInvalidNetworkShouldFailWithUnreachableError()
105+
{
106+
if (!defined('SOCKET_ENETUNREACH') || !function_exists('socket_import_stream')) {
107+
$this->markTestSkipped('Test requires ext-socket on PHP 5.4+');
108+
}
109+
110+
// try to find an unreachable network by trying a couple of private network addresses
111+
$errno = 0; $errstr = '';
112+
for ($i = 0; $i < 20; ++$i) {
113+
$address = 'tcp://192.168.' . mt_rand(0, 255) . '.' . mt_rand(1, 254) . ':8123';
114+
$client = @stream_socket_client($address, $errno, $errstr, 0.1 * $i);
115+
if ($errno === SOCKET_ENETUNREACH) {
116+
break;
117+
}
118+
}
119+
if ($client || $errno !== SOCKET_ENETUNREACH) {
120+
$this->markTestSkipped('Expected error ' . SOCKET_ENETUNREACH . ' but got ' . $errno . ' (' . $errstr . ') for ' . $address);
121+
}
122+
123+
$loop = Factory::create();
124+
$connector = new TcpConnector($loop);
125+
126+
$promise = $connector->connect($address);
127+
128+
$this->setExpectedException(
129+
'RuntimeException',
130+
'Connection to ' . $address . ' failed: ' . socket_strerror(SOCKET_ENETUNREACH),
131+
SOCKET_ENETUNREACH
132+
);
133+
Block\await($promise, $loop, self::TIMEOUT);
134+
}
135+
103136
/** @test */
104137
public function connectionToTcpServerShouldSucceedWithRemoteAdressSameAsTarget()
105138
{

0 commit comments

Comments
 (0)