Skip to content

Commit f10e66e

Browse files
committed
Refactor to reuse connection error handling for Unix domain sockets
1 parent 0eba38d commit f10e66e

File tree

4 files changed

+69
-30
lines changed

4 files changed

+69
-30
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 & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -211,31 +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-
// Match errstr from PHP's warning message.
217-
// stream_socket_accept(): accept failed: Connection timed out
218-
$error = \error_get_last();
219-
$errstr = \preg_replace('#.*: #', '', $error['message']);
220-
221-
// Go through list of possible error constants to find matching errno.
222-
// @codeCoverageIgnoreStart
223-
$errno = 0;
224-
if (\function_exists('socket_strerror')) {
225-
foreach (\get_defined_constants(false) as $name => $value) {
226-
if (\strpos($name, 'SOCKET_E') === 0 && \socket_strerror($value) === $errstr) {
227-
$errno = $value;
228-
break;
229-
}
230-
}
231-
}
232-
// @codeCoverageIgnoreEnd
233-
234-
$that->emit('error', array(new \RuntimeException(
235-
'Unable to accept new connection: ' . $errstr,
236-
$errno
237-
)));
238-
214+
try {
215+
$newSocket = SocketServer::accept($master);
216+
} catch (\RuntimeException $e) {
217+
$that->emit('error', array($e));
239218
return;
240219
}
241220
$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/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)