facebook/hiphop-php — pull request #511 by serphen (2012-05-14 08:26:01+00:00)
Title: Fix bug with (p)fsockopen() returning invalid sockets

Summary: If the peer doesn't close the connection properly or under high-load
situations (or tcp_tw_recycle=1), Hiphop-php can return invalid sockets
because it didn't detect the socket is not valid anymore.

This affects fsockopen and pfsockopen.

This is the state of socket_get_metadata during the problem:
array (\n 'wrapper_type' => 'Socket',\n 'stream_type' => '',\n
'mode' => '',\n 'unread_bytes' => 0,\n 'seekable' => false,\n
'uri' => '',\n 'timed_out' => false,\n 'blocked' => false,\n
'eof' => false,\n)

Hiphop-php can also return timed_out sockets with pfsockopen().
\n 'wrapper_type' => 'Socket',\n 'stream_type' => '',\n
'mode' => '',\n 'unread_bytes' => 0,\n 'seekable' => false,\n
'uri' => '',\n 'timed_out' => true,\n 'blocked' => false,\n
'eof' => false,\n

How to reproduce:
- Start a daemon (e.g. nc -l)
- Open a connection with pfsockopen to localhost
- pfsockopen returns a resource #A
- fwrite(#A, $foo); => OK
- Close the daemon
- Open a connection with pfsockopen to localhost
=> pfsockopen() returns the same resource #A and $errno == 0 (Success)

- fwrite($resource, $foo); => "Not a valid stream resource"

Expected output:
- pfsockopen() should establish a new connection and drop the old one.

Fix:
Hiphop-php shouldn't return invalid sockets. This is default
PHP behaviour.

What is the fix:
Testing if the socket is still alive using poll() and MSG_PEEK.
Perf looks ok.

Test Plan:
Checked connections were kept permanent (tcpdump).
Tested on 100'000'000 queries in production.

Revert Plan: easy