php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #71951 stream_socket_shutdown(..., STREAM_SHUT_RD) will not shutdown read on Linux
Submitted: 2016-04-04 03:32 UTC Modified: 2016-04-04 08:59 UTC
From: grzegorz129 at gmail dot com Assigned: krakjoe (profile)
Status: Closed Package: Streams related
PHP Version: 7.0.5 OS: Linux
Private report: No CVE-ID: None
 [2016-04-04 03:32 UTC] grzegorz129 at gmail dot com
Description:
------------
Following test script works as expected on OS X, but not on Linux.


System details:
 - Linux X 4.3.0-1-amd64 #1 SMP Debian 4.3.5-1 (2016-02-06) x86_64 GNU/Linux
 - Debian stretch/sid


Test script:
---------------
<?php

$server = stream_socket_server('tcp://127.0.0.1:9999');
$clientOnClient = stream_socket_client('tcp://127.0.0.1:9999');

$clientOnServer = stream_socket_accept($server, 0.5);
var_dump(stream_set_chunk_size($clientOnServer, 1));
var_dump(stream_set_read_buffer($clientOnServer, 1));
fwrite($clientOnClient, 'ping');

var_dump(fread($clientOnServer, 2));
stream_socket_shutdown($clientOnServer, STREAM_SHUT_RD);
var_dump(fread($clientOnServer, 2));

Expected result:
----------------
int(----)
int(0)
string(2) "pi"
string(2) "ng"

Actual result:
--------------
int(8192)
int(0)
string(2) "pi"
string(0) ""

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-04-04 03:34 UTC] grzegorz129 at gmail dot com
Edit: "Expected result" was accidentally switched with "Actual result".
 [2016-04-04 07:36 UTC] krakjoe@php.net
-Status: Open +Status: Verified
 [2016-04-04 07:53 UTC] krakjoe@php.net
-Status: Verified +Status: Open -Type: Bug +Type: Documentation Problem
 [2016-04-04 07:53 UTC] krakjoe@php.net
On OSX (BSD) the kernel space read buffer is emptied when the socket is shutdown.

On Linux, it only rejects further packets (so the other side cannot write).

A note in the documentation would be nice.
 [2016-04-04 08:58 UTC] krakjoe@php.net
Automatic comment from SVN on behalf of krakjoe
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=338908
Log: Fix #71951: shutdown behaviour note
 [2016-04-04 08:59 UTC] krakjoe@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: krakjoe
 [2016-04-04 08:59 UTC] krakjoe@php.net
The fix for this bug has been committed.

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/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 [2016-04-08 02:22 UTC] grzegorz129 at gmail dot com
This documentation not is quite nice, maybe not 100% clear for beginners but anyway - it's somewhat weird how it's actually working.
Let's take a look at this code:

<?php

$server = stream_socket_server('tcp://127.0.0.1:9999');
$clientOnClient = stream_socket_client('tcp://127.0.0.1:9999');

$clientOnServer = stream_socket_accept($server, 0.5);
var_dump(stream_set_chunk_size($clientOnServer, 1));
var_dump(stream_set_read_buffer($clientOnServer, 1));
fwrite($clientOnClient, 'ping');

//This now works as defined in documentation
var_dump(fread($clientOnServer, 2));
stream_socket_shutdown($clientOnServer, STREAM_SHUT_RD);
var_dump(fread($clientOnServer, 3));

//This should not work since buffer is empty at call
stream_socket_shutdown($clientOnServer, STREAM_SHUT_RD);
fwrite($clientOnClient, 'still-broken');
var_dump(fread($clientOnServer, 12));

//...and iterestingly it works as expected if you use RDWR or WR
stream_socket_shutdown($clientOnServer, STREAM_SHUT_WR);
fwrite($clientOnClient, 'or-is-it');
var_dump(fread($clientOnServer, 8));


Since buffer is closed and in fact event emptied why it's still receiving data on Linux? ;)

To be entirely sure I've also tested it using PHP server on the one side and telnet at the other - stream still receives data. This behavior is also present while using sockets.
<?php
$server = stream_socket_server('tcp://127.0.0.1:9999');
$clientOnServer = stream_socket_accept($server, 10);
stream_socket_shutdown($clientOnServer, STREAM_SHUT_RD);

while(1) {
  sleep(1);
  var_dump(fread($clientOnServer, 1));
}
 [2016-04-08 03:08 UTC] grzegorz129 at gmail dot com
After digging in old Linux list archives I found the suspect - in fact it's how Linux handles (or actually not handles at all) shutdown(sock, SHUT_RD): http://oss.sgi.com/archives/netdev/2003-07/msg00692.html - it's a pretty interesting discussion about this particular issue.

Maybe, since PHP is trying to be platform-independent, interpreter can unify this behavior and discard data on recv() when socket/stream was closed for reading?
 [2020-02-07 06:07 UTC] phpdocbot@php.net
Automatic comment on behalf of krakjoe
Revision: http://git.php.net/?p=doc/en.git;a=commit;h=77386c9ed685b4dac0ade2184b2d4e5d9dc54868
Log: Fix #71951: shutdown behaviour note
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 13:01:30 2024 UTC