pfsockopen returns persistent connections to the wrong server

Summary: Persistent connections return the wrong socket due to ambiguous key in g_persistentObjects
Persistent connections currently return a cached connection for (key = "hostname").
Expected behaviour is to return a cached connection for (key = "hostname + port").

As a result, persistent connections write and read from the *wrong* socket if you have multiple connections to the same hostname but different port.

Redis hhvm implementation is affected by this bug (probably other modules too, but not MySQL at least, who uses its own socket cache handler).

This bug has been introduced by commit 04b77176fe0e17e4885c6465fcd98cccaf50d4a4 ("Fix sockopen_impl with IPv6 addresses")


How to reproduce:

  Run two servers:

  Server A: nc -l -p 4545
  Server B: nc -l -p 7878


  <?php
  $A = pfsockopen('127.0.0.1', 4545);
  $B = pfsockopen('127.0.0.1', 7878);

  fwrite($A, 'hello_on_socket_A' . "\n");
  fwrite($B, 'hello_on_socket_B' . "\n");

  fwrite will write both messages on socket $A instead of writing on $A and $B.

  Actual output on server A:
    hello_on_socket_A
    hello_on_socket_B

  Actual output on server B:
    <null>


Expected output:

  On port 4545:
    hello_on_socket_A

  On port 7878:
    hello_on_socket_B


Known workaround (without recompiling hhvm):

The key is derived from Util::HostURL.getHostURL so a workaround is to explicitly pass to HostURL a port, so the used key in g_persistentObjects becomes "192.168.0.20:4545" instead of "192.168.0.20".

  $A = pfsockopen('127.0.0.1:4545', 4545);
  $B = pfsockopen('127.0.0.1:7878', 7878);


Fix:

Always use port in the key used in g_persistentObjects.


Side Effects: none

Revert Plan: simple