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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: grzegorz129 at gmail dot com
New email:
PHP Version: OS:

 

 [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: Fri Dec 27 03:01:28 2024 UTC