php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68853 stream_select on a TLS stream does not report last chunk as readable
Submitted: 2015-01-18 15:35 UTC Modified: 2017-11-13 14:22 UTC
Votes:3
Avg. Score:5.0 ± 0.0
Reproduced:3 of 3 (100.0%)
Same Version:1 (33.3%)
Same OS:2 (66.7%)
From: boen dot robot at gmail dot com Assigned: bukka (profile)
Status: Closed Package: OpenSSL related
PHP Version: 5.6.4 OS: Windows 2008 R2
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: boen dot robot at gmail dot com
New email:
PHP Version: OS:

 

 [2015-01-18 15:35 UTC] boen dot robot at gmail dot com
Description:
------------
If one end (say, client) sends more than one chunk of data (8192 bytes) at once, the last chunk (8192 or fewer remaining bytes) is not detected as readable by the other end (say, server) with stream_select() on the connection.

Issue occurs on both ends if they do reading, so whether it's server receiving client data or client receiving server data - the same thing happens.

This issue does not occur on a plain (non-encrypted) TCP stream. Only on encrypted streams.

This is sort of related to #65137 in that it is apparently caused by stream_select() reporting the underlying TCP stream, rather than the TLS stream. By the time one calls stream_select() on the last chunk, the last chunk has already been read from the TCP layer, and is ready to be read, but there's no way to find that out from PHP userland. Not even stream_get_meta_data() helps - it reports 0 unread bytes after the last successful fread().

Test script:
---------------
Here's an echo client/server duo demonstrating the issue.

https://gist.github.com/boenrobot/f636eba79043f7303fb4

The server can be ran with the port as an argument, and an optional second argument with the protocol (tcp or tls; defaults to tcp). The client can be ran with the ip as a first argument, port as second, and optional port as third (again tcp or tls; defaults to tcp).

From the client, you write the number of bytes to be sent to the server, with PHP_EOL appended after those, after which reading is done until PHP_EOL is found.

(I also have an equivalent Java version, which I used to confirm that issue occurs on both client and server; You'll notice MakeKeys.php which generates a self signed certificate and exports it in .p12 format too - that was for the sake of Java)

Expected result:
----------------
Same as with non-encrypted sockets - you write number of bytes, you send that many (plus EOL), and get that same many back (plus EOL), after which you can ask for more.

Actual result:
--------------
Trying to send f.e. 8191 on Windows (so 8193 bytes with the EOL in there) makes the server receive only 8192 bytes, and hanging on that last one. Same with any data larger than that, except that every next 8192 bytes are received, before the last chunk.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-03-05 23:04 UTC] rdlowrey@php.net
-Assigned To: +Assigned To: rdlowrey
 [2015-03-06 01:02 UTC] rdlowrey@php.net
I have cherry-picked @DaveRandom's original SSL_pending() solution back into 5.6 and master. I'm fairly certain this commit solves the problem fully. It was unfortunately reverted due to its close proximity to some other buggy shenanigans.

This change will *not* appear in the forthcoming 5.6.7 release so that we have time to test, get feedback and verify that it works everywhere. If you're interested in this bug's resolution please build the current PHP-5.6 or master branch to verify that the issue is resolved.
 [2015-03-08 06:25 UTC] boen dot robot at gmail dot com
I can confirm that the latest 5.6.8 snapshot fixes this issue.

Thank you.
 [2015-03-08 06:38 UTC] rdlowrey@php.net
Awesome. I may be able to hassle Ferenc to cherry-pick the fix into the 5.6.7 release even though it has already been tagged and branched. If not, it will be present in 5.6.8. I'll update this report with the version number once the question is resolved and I can close this issue.

Thanks again for your *unending patience* with this bug. I've been working hard to address and close openssl issues. If you have future openssl-related problems they will hopefully be handled much quicker than this one was.
 [2015-03-08 07:52 UTC] boen dot robot at gmail dot com
In an attempt to more accurately pinpoint the new issue (summarized in bug #65137), I found this one isn't fully solved. The goal post has simply moved further away.

If you try to echo large data... say 1048576 bytes (1MB), somewhere around 0.5MB (exact byte is different every time), the client starts emitting warnings about supposedly retrying to send the data, while the server just hangs. Same with even larger pieces of data, like 3MB, so this is not exactly "last chunk".

On the other hand, an unencrypted connection outputs notices about similar failure (as expected; this is known and documented; That's why even this minimalistic code has retries as part of it)... But ultimately delivers all data, and the server thus never even freezes, let alone hang.

(Sure, it takes a while to finish the test, with 1 byte at a time being read... My original project reads more at once, but I wanted to minimize potential "side" issues here)
 [2015-03-17 12:02 UTC] boen dot robot at gmail dot com
Just FYI...

The latest commits about bug 67965 do NOT help with the "half megabyte issue" in my previous comment. I've tried the rf040b48 snapshot.

(I thought that maybe they would, but alas...)
 [2015-03-17 16:22 UTC] rdlowrey@php.net
Will keep working on it. I've been busy tidying up generator things for the php7 feature freeze lately but this is definitely still on the radar.
 [2015-04-11 22:23 UTC] nathan dot renniewaldock at gmail dot com
I'm possibly getting the same issue in 5.6.7 on Linux. I've written an IRC bot, but when I use stream_select() it never counts the most recent line as readable, it's always one line behind.
 [2017-10-24 06:20 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: rdlowrey +Assigned To:
 [2017-11-13 10:40 UTC] kelunik@php.net
I think this one has been resolved for `stream_select`, no? The large write issue has been addressed in #72333.

At one point we probably have to rewrite the OpenSSL layer to properly work with non-blocking streams.

See also https://github.com/amphp/artax/issues/138 +  https://github.com/amphp/byte-stream/commit/d60ba033c41d3329419575f2fbb02230855c258e
 [2017-11-13 14:22 UTC] bukka@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: bukka
 [2017-11-13 14:22 UTC] bukka@php.net
Yep the large data write was addressed by #72333. It's also not related to this one which has been confirmed as fixed so I'm closing it.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 15:01:30 2024 UTC