Skip to content

Commit 1ab77ec

Browse files
authored
Merge pull request #171 from clue-labs/tcp-errors
Improve TCP/IP error messages
2 parents cf7c46f + fc91b94 commit 1ab77ec

File tree

2 files changed

+33
-21
lines changed

2 files changed

+33
-21
lines changed

src/TcpConnector.php

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function connect($uri)
7171
// HHVM fails to parse URIs with a query but no path, so let's simplify our URI here
7272
$remote = 'tcp://' . $parts['host'] . ':' . $parts['port'];
7373

74-
$socket = @stream_socket_client(
74+
$stream = @stream_socket_client(
7575
$remote,
7676
$errno,
7777
$errstr,
@@ -80,39 +80,30 @@ public function connect($uri)
8080
stream_context_create($context)
8181
);
8282

83-
if (false === $socket) {
83+
if (false === $stream) {
8484
return Promise\reject(new RuntimeException(
8585
sprintf("Connection to %s failed: %s", $uri, $errstr),
8686
$errno
8787
));
8888
}
8989

90-
stream_set_blocking($socket, 0);
91-
9290
// wait for connection
93-
94-
return $this->waitForStreamOnce($socket);
95-
}
96-
97-
private function waitForStreamOnce($stream)
98-
{
9991
$loop = $this->loop;
100-
101-
return new Promise\Promise(function ($resolve, $reject) use ($loop, $stream) {
102-
$loop->addWriteStream($stream, function ($stream) use ($loop, $resolve, $reject) {
92+
return new Promise\Promise(function ($resolve, $reject) use ($loop, $stream, $uri) {
93+
$loop->addWriteStream($stream, function ($stream) use ($loop, $resolve, $reject, $uri) {
10394
$loop->removeWriteStream($stream);
10495

10596
// The following hack looks like the only way to
10697
// detect connection refused errors with PHP's stream sockets.
10798
if (false === stream_socket_get_name($stream, true)) {
10899
fclose($stream);
109100

110-
$reject(new RuntimeException('Connection refused'));
101+
$reject(new RuntimeException('Connection to ' . $uri . ' failed: Connection refused'));
111102
} else {
112103
$resolve(new Connection($stream, $loop));
113104
}
114105
});
115-
}, function () use ($loop, $stream) {
106+
}, function () use ($loop, $stream, $uri) {
116107
$loop->removeWriteStream($stream);
117108
fclose($stream);
118109

@@ -123,7 +114,7 @@ private function waitForStreamOnce($stream)
123114
}
124115
// @codeCoverageIgnoreEnd
125116

126-
throw new RuntimeException('Cancelled while waiting for TCP/IP connection to be established');
117+
throw new RuntimeException('Connection to ' . $uri . ' cancelled during TCP/IP handshake');
127118
});
128119
}
129120
}

tests/TcpConnectorTest.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ class TcpConnectorTest extends TestCase
1212
{
1313
const TIMEOUT = 0.1;
1414

15-
/** @test */
15+
/**
16+
* @test
17+
* @expectedException RuntimeException
18+
* @expectedExceptionMessage Connection to tcp://127.0.0.1:9999 failed: Connection refused
19+
*/
1620
public function connectionToEmptyPortShouldFail()
1721
{
1822
$loop = Factory::create();
1923

2024
$connector = new TcpConnector($loop);
21-
$connector->connect('127.0.0.1:9999')
22-
->then($this->expectCallableNever(), $this->expectCallableOnce());
25+
$promise = $connector->connect('127.0.0.1:9999');
2326

24-
$loop->run();
27+
Block\await($promise, $loop, self::TIMEOUT);
2528
}
2629

2730
/** @test */
@@ -254,7 +257,25 @@ public function cancellingConnectionShouldRejectPromise()
254257
$promise = $connector->connect($server->getAddress());
255258
$promise->cancel();
256259

257-
$this->setExpectedException('RuntimeException', 'Cancelled');
260+
$this->setExpectedException('RuntimeException', 'Connection to ' . $server->getAddress() . ' cancelled during TCP/IP handshake');
258261
Block\await($promise, $loop);
259262
}
263+
264+
public function testCancelDuringConnectionShouldNotCreateAnyGarbageReferences()
265+
{
266+
if (class_exists('React\Promise\When')) {
267+
$this->markTestSkipped('Not supported on legacy Promise v1 API');
268+
}
269+
270+
gc_collect_cycles();
271+
272+
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
273+
$connector = new TcpConnector($loop);
274+
$promise = $connector->connect('127.0.0.1:9999');
275+
276+
$promise->cancel();
277+
unset($promise);
278+
279+
$this->assertEquals(0, gc_collect_cycles());
280+
}
260281
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy