diff --git a/src/Server.php b/src/Server.php index e46525b4c..f40667786 100644 --- a/src/Server.php +++ b/src/Server.php @@ -537,8 +537,12 @@ class Server{ if(!$ev->isCancelled()){ Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{ $nbt = new BigEndianNbtSerializer(); + $contents = zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP); + if($contents === false){ + throw new AssumptionFailedError("zlib_encode() failed unexpectedly"); + } try{ - Filesystem::safeFilePutContents($this->getPlayerDataPath($name), zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP)); + Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents); }catch(\RuntimeException | \ErrorException $e){ $this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage()))); $this->logger->logException($e); diff --git a/tools/ping-server.php b/tools/ping-server.php new file mode 100644 index 000000000..912119d5c --- /dev/null +++ b/tools/ping-server.php @@ -0,0 +1,152 @@ +sendPingTime = hrtime_ms(); + $ping->clientId = $rakNetClientId; + $serializer = new PacketSerializer(); + $ping->encode($serializer); + if(@socket_sendto($socket, $serializer->getBuffer(), strlen($serializer->getBuffer()), MSG_DONTROUTE, $serverIp, $serverPort) === false){ + \GlobalLogger::get()->error("Failed to send ping: " . socket_strerror(socket_last_error($socket))); + return false; + } + \GlobalLogger::get()->info("Ping sent to $serverIp on port $serverPort, waiting for response (press CTRL+C to abort)"); + + $r = [$socket]; + $w = $e = null; + if(socket_select($r, $w, $e, $timeoutSeconds) === 1){ + $response = @socket_recvfrom($socket, $recvBuffer, 65535, 0, $recvAddr, $recvPort); + if($response === false){ + \GlobalLogger::get()->error("Error reading from socket: " . socket_strerror(socket_last_error($socket))); + return false; + } + if($recvAddr === $serverIp and $recvPort === $serverPort and $recvBuffer !== "" and ord($recvBuffer[0]) === MessageIdentifiers::ID_UNCONNECTED_PONG){ + $pong = new UnconnectedPong(); + $pong->decode(new PacketSerializer($recvBuffer)); + \GlobalLogger::get()->info("--- Response received ---"); + \GlobalLogger::get()->info("Payload: $pong->serverName"); + \GlobalLogger::get()->info("Response time: " . (hrtime_ms() - $pong->sendPingTime) . " ms"); + return true; + }else{ + \GlobalLogger::get()->debug("Garbage packet from $recvAddr $recvPort: " . bin2hex($recvBuffer)); + } + } + + \GlobalLogger::get()->info("No ping response after $timeoutSeconds seconds"); + return false; +} + +if(count($argv) > 3){ + echo "Usage: " . PHP_BINARY . " " . __FILE__ . " [server IP] [server port]\n"; + exit(1); +} + +if(count($argv) > 1){ + $hostName = $argv[1]; +}else{ + do{ + $hostName = read_stdin("Server address"); + }while($hostName === ""); +} + +$serverIps = gethostbynamel($hostName); +if($serverIps === false){ + \GlobalLogger::get()->critical("Unable to resolve hostname $hostName to an IP address"); + exit(1); +} +if(count($serverIps) > 1){ + \GlobalLogger::get()->warning("Multiple IP addresses found for hostname $hostName, using the first one: " . $serverIps[0]); +} +$server = $serverIps[0]; +\GlobalLogger::get()->info("Resolved hostname to $server"); + +if(count($argv) > 2){ + $port = (int) $argv[2]; +}elseif(count($argv) > 1){ + $port = 19132; +}else{ + $portRaw = read_stdin("Server port (empty for 19132)"); + $port = $portRaw === "" ? 19132 : (int) $portRaw; +} + +$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +if($sock === false) throw new AssumptionFailedError(); + +socket_bind($sock, "0.0.0.0"); +socket_getsockname($sock, $bindAddr, $bindPort); +\GlobalLogger::get()->info("Bound to $bindAddr on port $bindPort"); + +$start = time(); +while(time() < $start + 60_000 && !ping_server($sock, $server, $port, 5, mt_rand(0, PHP_INT_MAX))){ + sleep(1); +} + +socket_close($sock);