I'm working with blocking sockets in PHP and I'm experiencing a weird issue.
Recently, few users had their websocket server hanging randomly. I managed to find out that it was caused by a bad network (either overloaded/unstable or just crappy computer) on the client side.
I was finally able to reproduce the bug with Clumsy, simulating packet drops, lag, throttle and such, forcing the client to reconnect randomly. Hours of log investigation later, the line taking forever seems to be this one :
// Note : $this->socket is a blocking TLS socket (resource type : stream)
$new = stream_socket_accept( $this->socket, 2 );
Socket metadata (as returned by stream_get_meta_data( $this->socket ) ) :
array(
'stream_type' => 'tcp_socket/ssl',
'mode' => 'r+',
'unread_bytes' => 0,
'seekable' => false,
'timed_out' => false,
'blocked' => true,
'eof' => true,
)
This line is in processMasterSocket(), called here :
stream_select( $read, $w = null, $e = null, $this->options['timeout_select'], $this->options['timeout_select_microsec'] );
foreach( $read as $socket )
{
if( $socket == $this->socket->getResource() )
$this->processMasterSocket();
else
$this->processClientSocket( $socket );
}
The issue is that stream_socket_accept() is either taking 0.0003s, 200.0s or forever !
I've already read about blocking socket weird behaviour, but as of now, we're unable to switch to non-blocking mode (as it would require a complete rewrite of our TLS/secured code). Again, there's no issue without crappy networking simulator enabled.
So here's my questions :
Why does stream_socket_accept() sometimes takes forever, completely ignoring the 2s timeout given in parameter ?
If it's waiting for data (because of blocking mode), why stream_select() told me there was something to read ?
Does stream_select() works correctly with blocking sockets when there's some packet loss ?
Is there a way for stream_socket_accept() to timeout with blocking sockets ?
Found out that the issue is related to PHP itself. I forgot to mention that I'm running PHP 5.3.3, and I just ran into this https://bugs.php.net/bug.php?id=41631
The issue about SSL blocking sockets not timing out was fixed in PHP 5.4.33
I just tried my code on PHP 7.x and it runs smoothly, timing out after 60s (which is default_socket_timeout value).
Really hope this will be helpful, even if most people should have upgraded to PHP 7.x already ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With