8000 Merge pull request #171 from clue-labs/tcp-errors · reactphp/socket@1ab77ec · GitHub
[go: up one dir, main page]

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)
0