Skip to content

Commit 4d8c41b

Browse files
committed
ConsoleReader: Use proc_open()'s socket support to send commands back to the main server process
Support for this was introduced in PHP 8.0, though not mentioned in any changelog: php/php-src#5777 This simplifies the subprocess handling considerably. However, there is a potential for problems if PHP generates any E_* errors, since these get written to STDOUT as well.
1 parent b7a241f commit 4d8c41b

File tree

2 files changed

+6
-34
lines changed

2 files changed

+6
-34
lines changed

src/console/ConsoleReaderChildProcess.php

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,13 @@
2727
use function cli_set_process_title;
2828
use function count;
2929
use function dirname;
30-
use function feof;
3130
use function fwrite;
32-
use function stream_socket_client;
3331
use const PTHREADS_INHERIT_NONE;
32+
use const STDOUT;
3433

3534
require dirname(__DIR__, 2) . '/vendor/autoload.php';
3635

37-
if(count($argv) !== 2){
38-
die("Please provide a server to connect to");
39-
}
40-
4136
@cli_set_process_title('PocketMine-MP Console Reader');
42-
$errCode = null;
43-
$errMessage = null;
44-
$socket = stream_socket_client($argv[1], $errCode, $errMessage, 15.0);
45-
if($socket === false){
46-
throw new \RuntimeException("Failed to connect to server process ($errCode): $errMessage");
47-
}
4837

4938
$channel = new \Threaded();
5039
$thread = new class($channel) extends \Thread{
@@ -70,7 +59,7 @@ public function run(){
7059
};
7160

7261
$thread->start(PTHREADS_INHERIT_NONE);
73-
while(!feof($socket)){
62+
while(true){
7463
$line = $channel->synchronized(function() use ($channel) : ?string{
7564
if(count($channel) === 0){
7665
$channel->wait(1_000_000);
@@ -79,7 +68,7 @@ public function run(){
7968
$line = $channel->shift();
8069
return $line;
8170
});
82-
if(@fwrite($socket, ($line ?? "") . "\n") === false){
71+
if(@fwrite(STDOUT, ($line ?? "") . "\n") === false){
8372
//Always send even if there's no line, to check if the parent is alive
8473
//If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return
8574
//false even though the connection is actually broken. However, fwrite() will fail.

src/console/ConsoleReaderChildProcessDaemon.php

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,8 @@
3535
use function proc_terminate;
3636
use function sprintf;
3737
use function stream_select;
38-
use function stream_socket_accept;
39-
use function stream_socket_get_name;
40-
use function stream_socket_server;
41-
use function stream_socket_shutdown;
4238
use function trim;
4339
use const PHP_BINARY;
44-
use const STREAM_SHUT_RDWR;
4540

4641
/**
4742
* This pile of shit exists because PHP on Windows is broken, and can't handle stream_select() on stdin or pipes
@@ -72,30 +67,19 @@ public function __construct(
7267
}
7368

7469
private function prepareSubprocess() : void{
75-
$server = stream_socket_server("tcp://127.0.0.1:0");
76-
if($server === false){
77-
throw new \RuntimeException("Failed to open console reader socket server");
78-
}
79-
$address = Utils::assumeNotFalse(stream_socket_get_name($server, false), "stream_socket_get_name() shouldn't return false here");
80-
8170
//Windows sucks, and likes to corrupt UTF-8 file paths when they travel to the subprocess, so we base64 encode
8271
//the path to avoid the problem. This is an abysmally shitty hack, but here we are :(
8372
$sub = Utils::assumeNotFalse(proc_open(
84-
[PHP_BINARY, '-dopcache.enable_cli=0', '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))), $address],
73+
[PHP_BINARY, '-dopcache.enable_cli=0', '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php')))],
8574
[
75+
1 => ['socket'],
8676
2 => fopen("php://stderr", "w"),
8777
],
8878
$pipes
8979
), "Something has gone horribly wrong");
9080

91-
$client = stream_socket_accept($server, 15);
92-
if($client === false){
93-
throw new AssumptionFailedError("stream_socket_accept() returned false");
94-
}
95-
stream_socket_shutdown($server, STREAM_SHUT_RDWR);
96-
9781
$this->subprocess = $sub;
98-
$this->socket = $client;
82+
$this->socket = $pipes[1];
9983
}
10084

10185
private function shutdownSubprocess() : void{
@@ -104,7 +88,6 @@ private function shutdownSubprocess() : void{
10488
//the first place).
10589
proc_terminate($this->subprocess);
10690
proc_close($this->subprocess);
107-
stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
10891
}
10992

11093
public function readLine() : ?string{

0 commit comments

Comments
 (0)