Edit report at https://bugs.php.net/bug.php?id=65137&edit=1

 ID:                 65137
 User updated by:    boen dot robot at gmail dot com
 Reported by:        boen dot robot at gmail dot com
 Summary:            stream_select misleads when TLS socket is used
 Status:             Open
 Type:               Bug
 Package:            Streams related
 Operating System:   Windows Server 2008 R2
 PHP Version:        5.5.0
 Block user comment: N
 Private report:     N

 New Comment:

On a quick inspection of the relevant source (and I must note I know nothing 
about PHP's internals, nor have I compiled PHP, so take this with a grain of 
salt), this seems to be the problematic part:

https://github.com/php/php-src/blob/642721b38a9c5ebf336c81027c0dafd6f9246bd6/ext/openssl/xp_ssl.c#L814

For some reason, when doing a cast for stream_select(), the actual socket is 
returned directly, as opposed to this happening after an "sslsock->ssl_active" 
check, like the other casts, which I'm guessing is causing the gap between what 
stream_select() says, and what fread() does. What's the reason for it being 
that way anyway?


Previous Comments:
------------------------------------------------------------------------
[2013-06-26 19:01:21] boen dot robot at gmail dot com

Description:
------------
When stream_select() is called on a socket stream created by 
stream_socket_client() which uses TLS (with ADH), it seems to report too early. 
That is, it would report that that the stream can be read, but then when you 
try to read it, it would block, and potentially fail.

The exact same code, if called without encryption, would always work just fine. 
Also, if right before receiving, the script is made to sleep for a while (in my 
case, about 100 miliseconds did the trick), the script is also fine.

Sample code is hard to give, as this occurs only when the server sends large 
enough data at once over the encrypted connection, and I seem to be unable to 
mock a TLS+ADH server with PHP (which is a separate issue that, at this point, 
could be just me being stupid).

I *think* the issue might be that stream_select() reports on the underlying 
socket (i.e. the data being received before decryption), rather than the 
*readable data* from the socket, while fread() blocks until there's at least 1 
byte of readable data to be read. But this shouldn't be so IMHO.

Note that this occurs not just with PHP 5.5.0, but also the latest releases of 
5.4.16 and 5.3.26, and at least as early as 5.3.8.

Test script:
---------------
NOTE: This script is an "approximation" so to speak, in that it demonstrates 
the exact settings for the client where this occurs, but due to the lack of a 
mock server, it's not confirmed to always fail.

<?php
$socket = stream_socket_client(
        'tls://example.com:8729',
        $errno,
        $errstr,
        2,
        STREAM_CLIENT_CONNECT,
        stream_context_create(
                array('ssl' => array('ciphers' => 'ADH'))
        )
);

fwrite($socket, chr(6) . '/login' . chr(0));

$r = array($socket);
$w = $e = null;

if (1 === stream_select($r, $w, $e, null)) {
    echo fread($socket, 1);
} else {
    echo 'stream_select() returned with errors';
}


Expected result:
----------------
stream_select() should only report the encrypted socket as readable if there's 
at least 1 byte of readable data in the buffer that can be read by fread().

Actual result:
--------------
stream_select() reports the encrypted socket as readable, but fread() blocks, 
and may even time out.


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=65137&edit=1

Reply via email to