php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39571 fsockopen timeout param does not affect ssl/tls handshake
Submitted: 2006-11-21 16:23 UTC Modified: 2006-12-05 03:12 UTC
From: tim at tmcode dot com Assigned:
Status: Closed Package: Sockets related
PHP Version: 5CVS-2006-11-21 (CVS) OS: Linux
Private report: No CVE-ID:
 [2006-11-21 16:23 UTC] tim at tmcode dot com
Description:
------------
The 5th parameter of the fsockopen function does not appear to account for a webserver taking too long to complete the ssl/tls handshake.  When connecting to an extremely loaded server,  the connection might establish within the timeout but the ssl handshake could take much longer.  From what I can tell there is no way to set the read/write timeout prior to running fsockopen,  making it impossible to prevent PHP from hanging on a slow ssl server?  

(I tried to find a similar bug or a mention of this issue in the manual so I appologize if I need to go RTFM more carefully).

This problem only affects fsockopen if you use ssl://  or tls:// in the first param.   If you modifiy the code below and just remove the ssl://  the function call works fine.



Reproduce code:
---------------
// client code:
$fp = fsockopen("ssl://$server", 443, $errno, $errstr, 5); 



If you want to simulate a "hung" ssl server to verify that the timeout does not happen in 5 seconds:
// server code:

$sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if(!socket_bind($sock,$serverip,443)) die("bind\n");
if(!socket_listen($sock,25)) die("listen\n");
if(!socket_set_nonblock($sock)) die("nonblock\n");

while(1)
{
        $newfd=@socket_accept($sock);
        sleep(30);
}

Expected result:
----------------
fsockopen should timeout after 5 seconds.  

Actual result:
--------------
fsockopen times out after 58 seconds (with the test server code above).  Change sleep to something larger and the timeout will take even longer. 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-11-21 17:16 UTC] tony2001@php.net
There is no way to set a timeout on SSL operations which do not support it.
 [2006-11-21 18:04 UTC] tim at tmcode dot com
Heh, no way to support timeouts with openssl?  Now thats funny. :) 

The problem is with SSL_connect() on line 400 of ext/openssl/xp_ssl.c  All you have to do is throw the socket into nonblocking mode.  Then loop until the timeout has been reached or SSL_connect returns >0.  The socket can then be placed back in blocking mode.

I have a very quick and dirty patch that does this.  Unfortunately it relies on fcntl() so I'm not sure how well it would port off of *nix.  If it would help get the bug fixed I would be happy to provide it.
 [2006-12-02 17:04 UTC] iliaa@php.net
Sorry, but your problem does not imply a bug in PHP itself.  For a
list of more appropriate places to ask for help using PHP, please
visit http://www.php.net/support.php as this bug system is not the
appropriate forum for asking support questions.  Due to the volume
of reports we can not explain in detail here why your report is not
a bug.  The support channels will be able to provide an explanation
for you.

Thank you for your interest in PHP.

It would be one thing to use SSL function or parameter to 
enforce the timeout, but what you suggest seems like a hack 
(that may have many stability side-effects) to overcome 
limitation of the underlying library. My suggestion would be 
to make a feature request to the OpenSSL folks to add a 
timeout parameter and once it is there, PHP will certainly use 
it with the supported version of the lib.
 [2006-12-04 23:30 UTC] tim at tmcode dot com
Not to be a pain and beat a dead horse but I still think this is a PHP issue. OpenSSL is a very common SSL library.  A long list of popular packages such as Curl, wget, links, etc all use openssl.  And all of them (that I've taken the time to test) are able to timeout correctly in the situation I've described.  

Just as an example, a quick look at the libcurl source shows that they use the same technique to timeout the connection as I have described.  Granted their code is a little more polished than my patch, but the idea is the same. They put the underlying socket into non-blocking mode,  and then loop SSL_connect() until the timeout is reached.  Using non-blocking mode to enforce a timeout was how I was taught to do it ages ago in school.  If it were a "hack" than I would assume the folks at curl would have done it the right way and patched openssl.  

The reason this bug is such a problem for me is that we make heavy use of soap calls to other systems.  Combine that with heavy traffic and everything snowballs when one of these remote soap servers choke.  We can't be the only ones wanting PHP to die gracefully when things go wrong.  

Having a timeout parameter that doesn't always timeout is a bug.  And blaiming it on an underlying library does not change the fact that something that should work in PHP does not.  

Also, I wasn't clear about the scope of this bug.  It does effect *all* https stream related functionalty including file_get_contents, SoapClient, etc.  It also prevents max_execution_time from being enforced.
 [2006-12-05 01:39 UTC] iliaa@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 [2006-12-05 03:12 UTC] tim at tmcode dot com
Thank you for the quick fix, it is timing out correctly now.
 [2011-09-19 06:34 UTC] simoncpu at gmail dot com
Hi,

I'd like to report that this still occurs in PHP 5.2.17. :(  We came across this 
bug while using PEAR's XML_RPC_Client.

Thanks,

[ simon.cpu ]
 [2011-09-19 08:42 UTC] simoncpu at gmail dot com
Revision 313616 of ext/openssl/xp_ssl.c fixes the problem, although it apparently 
has some side effects. =)
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Mon Apr 21 12:02:07 2014 UTC