Skip to content

Commit 07b37d5

Browse files
authored
Merge pull request #267 from clue-labs/accept-errno
2 parents bb9daad + f10e66e commit 07b37d5

File tree

5 files changed

+90
-10
lines changed

5 files changed

+90
-10
lines changed

src/SocketServer.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,44 @@ public function close()
9090
{
9191
$this->server->close();
9292
}
93+
94+
/**
95+
* [internal] Internal helper method to accept new connection from given server socket
96+
*
97+
* @param resource $socket server socket to accept connection from
98+
* @return resource new client socket if any
99+
* @throws \RuntimeException if accepting fails
100+
* @internal
101+
*/
102+
public static function accept($socket)
103+
{
104+
$newSocket = @\stream_socket_accept($socket, 0);
105+
106+
if (false === $newSocket) {
107+
// Match errstr from PHP's warning message.
108+
// stream_socket_accept(): accept failed: Connection timed out
109+
$error = \error_get_last();
110+
$errstr = \preg_replace('#.*: #', '', $error['message']);
111+
112+
// Go through list of possible error constants to find matching errno.
113+
// @codeCoverageIgnoreStart
114+
$errno = 0;
115+
if (\function_exists('socket_strerror')) {
116+
foreach (\get_defined_constants(false) as $name => $value) {
117+
if (\strpos($name, 'SOCKET_E') === 0 && \socket_strerror($value) === $errstr) {
118+
$errno = $value;
119+
break;
120+
}
121+
}
122+
}
123+
// @codeCoverageIgnoreEnd
124+
125+
throw new \RuntimeException(
126+
'Unable to accept new connection: ' . $errstr,
127+
$errno
128+
);
129+
}
130+
131+
return $newSocket;
132+
}
93133
}

src/TcpServer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ public function resume()
211211

212212
$that = $this;
213213
$this->loop->addReadStream($this->master, function ($master) use ($that) {
214-
$newSocket = @\stream_socket_accept($master, 0);
215-
if (false === $newSocket) {
216-
$that->emit('error', array(new \RuntimeException('Error accepting new connection')));
217-
214+
try {
215+
$newSocket = SocketServer::accept($master);
216+
} catch (\RuntimeException $e) {
217+
$that->emit('error', array($e));
218218
return;
219219
}
220220
$that->handleConnection($newSocket);

src/UnixServer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ public function resume()
113113

114114
$that = $this;
115115
$this->loop->addReadStream($this->master, function ($master) use ($that) {
116-
$newSocket = @\stream_socket_accept($master, 0);
117-
if (false === $newSocket) {
118-
$that->emit('error', array(new \RuntimeException('Error accepting new connection')));
119-
116+
try {
117+
$newSocket = SocketServer::accept($master);
118+
} catch (\RuntimeException $e) {
119+
$that->emit('error', array($e));
120120
return;
121121
}
122122
$that->handleConnection($newSocket);

tests/TcpServerTest.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,10 @@ public function testEmitsErrorWhenAcceptListenerFails()
287287

288288
$server = new TcpServer(0, $loop);
289289

290-
$server->on('error', $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));
290+
$exception = null;
291+
$server->on('error', function ($e) use (&$exception) {
292+
$exception = $e;
293+
});
291294

292295
$this->assertNotNull($listener);
293296
$socket = stream_socket_server('tcp://127.0.0.1:0');
@@ -297,6 +300,23 @@ public function testEmitsErrorWhenAcceptListenerFails()
297300
$time = microtime(true) - $time;
298301

299302
$this->assertLessThan(1, $time);
303+
304+
$this->assertInstanceOf('RuntimeException', $exception);
305+
assert($exception instanceof \RuntimeException);
306+
$this->assertStringStartsWith('Unable to accept new connection: ', $exception->getMessage());
307+
308+
return $exception;
309+
}
310+
311+
/**
312+
* @param \RuntimeException $e
313+
* @requires extension sockets
314+
* @depends testEmitsErrorWhenAcceptListenerFails
315+
*/
316+
public function testEmitsTimeoutErrorWhenAcceptListenerFails(\RuntimeException $exception)
317+
{
318+
$this->assertEquals('Unable to accept new connection: ' . socket_strerror(SOCKET_ETIMEDOUT), $exception->getMessage());
319+
$this->assertEquals(SOCKET_ETIMEDOUT, $exception->getCode());
300320
}
301321

302322
public function testListenOnBusyPortThrows()

tests/UnixServerTest.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,10 @@ public function testEmitsErrorWhenAcceptListenerFails()
292292

293293
$server = new UnixServer($this->getRandomSocketUri(), $loop);
294294

295-
$server->on('error', $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));
295+
$exception = null;
296+
$server->on('error', function ($e) use (&$exception) {
297+
$exception = $e;
298+
});
296299

297300
$this->assertNotNull($listener);
298301
$socket = stream_socket_server('tcp://127.0.0.1:0');
@@ -302,6 +305,23 @@ public function testEmitsErrorWhenAcceptListenerFails()
302305
$time = microtime(true) - $time;
303306

304307
$this->assertLessThan(1, $time);
308+
309+
$this->assertInstanceOf('RuntimeException', $exception);
310+
assert($exception instanceof \RuntimeException);
311+
$this->assertStringStartsWith('Unable to accept new connection: ', $exception->getMessage());
312+
313+
return $exception;
314+
}
315+
316+
/**
317+
* @param \RuntimeException $e
318+
* @requires extension sockets
319+
* @depends testEmitsErrorWhenAcceptListenerFails
320+
*/
321+
public function testEmitsTimeoutErrorWhenAcceptListenerFails(\RuntimeException $exception)
322+
{
323+
$this->assertEquals('Unable to accept new connection: ' . socket_strerror(SOCKET_ETIMEDOUT), $exception->getMessage());
324+
$this->assertEquals(SOCKET_ETIMEDOUT, $exception->getCode());
305325
}
306326

307327
public function testListenOnBusyPortThrows()

0 commit comments

Comments
 (0)