[php-src] Issue #13887: stream_select fails on blocking sockets except for incoming connections

From: Date: Fri, 05 Apr 2024 07:39:17 +0000
Subject: [php-src] Issue #13887: stream_select fails on blocking sockets except for incoming connections
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-246705@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/13887 Author: R3kyr ### Description Passing blocking sockets created with stream_socket_server() and stream_socket_client() to stream_select() throws a ValueError except for blocking sockets created with stream_socket_accept(). Tested with PHP 8.3.0 and 8.3.4, both ZTS on Win 10 x64 latest build and Ubuntu 22.04 LTS x64. Example code that demonstrates the issue: server.php ```php <?php $server = stream_socket_server("127.0.0.1:0", $c, $e); [, $port] = explode(":", stream_socket_get_name($server, false)); $process = proc_open( "\"" . PHP_BINARY . "\" " . __DIR__ . DIRECTORY_SEPARATOR . "client.php --port=$port", [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]], $Pipes ); $client = stream_socket_accept($server); var_dump(stream_get_meta_data($client)["blocked"]); //true $_ = null; $read = [$client]; //Select on inbound blocking client socket works. while(!stream_select($read, $_, $_, 0)) { usleep(1000); } $line = fgets($client); echo $line; fwrite($client, "Hello from server!" . PHP_EOL); //Select on blocking server socket fails. $read = [$server]; while(!stream_select($read, $read, $read, 0)) { usleep(1000); } ``` client.php ```php <?php $port = getopt("", ["port::"])["port"]; $client = stream_socket_client("127.0.0.1:$port", $c, $e); $written = fwrite($client, "Hello from client!" . PHP_EOL); try { $_ = null; $read = [$client]; //Select on outbound blocking client socket fails. while(!stream_select($read, $_, $_, 0)) { usleep(1000); } $line = fgets($client); file_put_contents("child.txt", $line); } catch(ValueError $e) { file_put_contents("child.txt", (string)$e); } ``` This is kinda inconvenient if using a wrapper-class that provides async blocking read/write operations as it requires temporarily switching the socket to non-blocking mode. ```php class Socket { public function __set(...) { stream_set_blocking($this->handle, $this->blocking = $value); } public function read(int $amount) { return fread($this->handle, $amount); } public function readAsync(int $amount) { Fiber::suspend(); if(!$this->blocking) { return fread($this->handle, $amount); } stream_set_blocking($this->handle, false); $_ = null; $read = [$this->handle]; while(!stream_select($read, $_, $_, 0)) { Fiber::suspend(); } stream_set_blocking($this->handle, true); return fread($this->handle, $amount); } } ``` ### PHP Version PHP 8.3.4 ### Operating System _No response_

« previous php.bugs (#246705) next »