Edit report at http://bugs.php.net/bug.php?id=51056&edit=1
ID: 51056 Updated by: magical...@php.net Reported by: magical...@php.net Summary: fread() on blocking stream will block even if data is available Status: Open Type: Bug Package: Streams related Operating System: Linux Gentoo 2.6.32 PHP Version: 5.3.1 New Comment: Hi, I know about fread() returning less data than asked for, however I could not modify this behaviour without passing some kind of value to lower-level read operation, which will call poll() if socket is blocking. When data is already available in buffer, an information should be passed to the lower-level read() to let it know it should not block. The only non-intrusive solution to fix this would be to temporarly pass socket in non-blocking mode if data was found in PHP buffer. Considering any application handling data from network should handle cases when received data is not complete, I believe it was best to return immediatly if data is found and let the application call fread() again rather than trying to workaround this problem with a dirty solution like passing temporarly in non- blocking mode. Another solution would be to add an argument to the internal read call ("do not block") however it would change the API for the internal stream api, and would require the argument to be handled into each stream wrapper. Previous Comments: ------------------------------------------------------------------------ [2010-03-11 02:05:59] lbarn...@php.net Hi, I made a test case for this ( 51056.phpt.txt ) fread() in C has exactly the same behavior, it will block if you try to read more bytes than available. Your patch correctly avoids this, however it introduces an other issue: fread() will return less data than asked for, even if enough data is available ( 51056-2.phpt.txt ). ------------------------------------------------------------------------ [2010-02-17 16:00:07] j...@php.net btw. If you really want someone to do something about this, post the patch to intern...@lists.php.net as well. :) ------------------------------------------------------------------------ [2010-02-17 05:39:56] magical...@php.net While for file sockets it makes sense when reading data to make sure a buffer gets completly filled until EOF is reached, this is not true for sockets. There is already a condition for "greedy read", but it does not apply when we first restore data from the read buffer. Here is a diff (PHP_5_3) that solves the issue: Index: main/streams/streams.c =================================================================== --- main/streams/streams.c (révision 295152) +++ main/streams/streams.c (copie de travail) @@ -592,6 +592,10 @@ size -= toread; buf += toread; didread += toread; + + /* avoid trying to read if we already have data to pass */ + if (stream->wrapper != &php_plain_files_wrapper) + break; } /* ignore eof here; the underlying state might have changed */ Test script output: Testing PHP version: 5.3.3-dev fread took 0.07ms to read 8 bytes fread took 5.07ms to read 256 bytes fread took 0.00ms to read 45 bytes fread took 1000.11ms to read 8 bytes fread took 5.02ms to read 256 bytes fread took 0.00ms to read 45 bytes fread took 1000.13ms to read 8 bytes fread took 5.04ms to read 256 bytes ------------------------------------------------------------------------ [2010-02-16 13:06:45] magical...@php.net I tried to switch to non-blocking mode. This solves this issue with most sockets, except for SSL sockets when transmitting a lot of data. This bug is blocking in my case (socket communication transmitting a lot of data). ------------------------------------------------------------------------ [2010-02-16 12:19:38] fel...@php.net Testing PHP version: 5.2.13RC3-dev fread took 0.04ms to read 8 bytes fread took 4.88ms to read 256 bytes fread took 1000.04ms to read 53 bytes fread took 4.96ms to read 256 bytes fread took 1000.06ms to read 53 bytes fread took 4.97ms to read 256 bytes fread took 1000.06ms to read 53 bytes (etc) ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/bug.php?id=51056 -- Edit this bug report at http://bugs.php.net/bug.php?id=51056&edit=1