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