small fixes

This commit is contained in:
kremsy 2014-02-27 15:03:01 +01:00 committed by Steffen Schröder
parent a85f5b36fb
commit 6e77606d7e
3 changed files with 93 additions and 88 deletions

View File

@ -17,26 +17,26 @@ if (!defined('SIZE_MAX'))
define('SIZE_MAX', 4096*1024); define('SIZE_MAX', 4096*1024);
} }
class Client class Client
{ {
public $socket; public $socket;
public $message = false; public $message = false;
public $cb_message = array(); public $cb_message = array();
public $reqhandle; public $reqhandle;
public $protocol = 0; public $protocol = 0;
/** /**
* @var int Timeout in milli-seconds * @var int Timeout in milli-seconds
*/ */
public $timeout; public $timeout;
static $received; static $received;
static $sent; static $sent;
function bigEndianTest() function bigEndianTest()
{ {
list($endiantest) = array_values(unpack('L1L', pack('V', 1))); list($endiantest) = array_values(unpack('L1L', pack('V', 1)));
if ($endiantest != 1) if ($endiantest != 1)
{ {
if(!function_exists(__NAMESPACE__.'\\unpack')) if(!function_exists(__NAMESPACE__.'\\unpack'))
{ {
@ -45,30 +45,30 @@ class Client
* does not have the capability of unpacking double precision floats * does not have the capability of unpacking double precision floats
* that were packed in the opposite byte order of the current machine. * that were packed in the opposite byte order of the current machine.
*/ */
function unpack($format, $data) function unpack($format, $data)
{ {
$ar = unpack($format, $data); $ar = unpack($format, $data);
$vals = array_values($ar); $vals = array_values($ar);
$f = explode('/', $format); $f = explode('/', $format);
$i = 0; $i = 0;
foreach ($f as $f_k => $f_v) foreach ($f as $f_k => $f_v)
{ {
$repeater = intval(substr($f_v, 1)); $repeater = intval(substr($f_v, 1));
if ($repeater == 0) if ($repeater == 0)
{ {
$repeater = 1; $repeater = 1;
} }
if ($f_v{1} == '*') if ($f_v{1} == '*')
{ {
$repeater = count($ar) - $i; $repeater = count($ar) - $i;
} }
if ($f_v{0} != 'd') if ($f_v{0} != 'd')
{ {
$i += $repeater; $i += $repeater;
continue; continue;
} }
$j = $i + $repeater; $j = $i + $repeater;
for ($a = $i; $a < $j; ++$a) for ($a = $i; $a < $j; ++$a)
{ {
$p = pack('d', $vals[$i]); $p = pack('d', $vals[$i]);
$p = strrev($p); $p = strrev($p);
@ -77,7 +77,7 @@ class Client
} }
} }
$a = 0; $a = 0;
foreach ($ar as $ar_k => $ar_v) foreach ($ar as $ar_k => $ar_v)
{ {
$ar[$ar_k] = $vals[$a]; $ar[$ar_k] = $vals[$a];
++$a; ++$a;
@ -89,91 +89,91 @@ class Client
} }
/** /**
* *
* @param string $hostname * @param string $hostname
* @param int $port * @param int $port
* @param int $timeout In milliseconds * @param int $timeout In milliseconds
*/ */
function __construct($hostname, $port, $timeout = 50) function __construct($hostname, $port, $timeout = 50)
{ {
$this->socket = false; $this->socket = false;
$this->reqhandle = 0x80000000; $this->reqhandle = 0x80000000;
$this->timeout = $timeout; $this->timeout = $timeout;
$this->init($hostname, $port); $this->init($hostname, $port);
} }
function __destruct() function __destruct()
{ {
$this->terminate(); $this->terminate();
} }
protected function init($hostname, $port) protected function init($hostname, $port)
{ {
$this->bigEndianTest(); $this->bigEndianTest();
// open connection // open connection
$this->socket = @fsockopen($hostname, $port, $errno, $errstr, $this->timeout/1000); $this->socket = @fsockopen($hostname, $port, $errno, $errstr, $this->timeout * 10000);
if (!$this->socket) if (!$this->socket)
{ {
throw new FatalException("transport error - could not open socket (error: $errno, $errstr)", FatalException::NOT_INITIALIZED); throw new FatalException("transport error - could not open socket (error: $errno, $errstr)", FatalException::NOT_INITIALIZED);
} }
// handshake // handshake
$array_result = unpack('Vsize', fread($this->socket, 4)); $array_result = unpack('Vsize', fread($this->socket, 4));
$size = $array_result['size']; $size = $array_result['size'];
if ($size > 64) if ($size > 64)
{ {
throw new FatalException('transport error - wrong lowlevel protocol header', FatalException::OTHER); throw new FatalException('transport error - wrong lowlevel protocol header', FatalException::OTHER);
} }
$handshake = fread($this->socket, $size); $handshake = fread($this->socket, $size);
if ($handshake == 'GBXRemote 1') if ($handshake == 'GBXRemote 1')
{ {
$this->protocol = 1; $this->protocol = 1;
} }
elseif ($handshake == 'GBXRemote 2') elseif ($handshake == 'GBXRemote 2')
{ {
$this->protocol = 2; $this->protocol = 2;
} }
else else
{ {
throw new FatalException('transport error - wrong lowlevel protocol version', FatalException::OTHER); throw new FatalException('transport error - wrong lowlevel protocol version', FatalException::OTHER);
} }
} }
function terminate() function terminate()
{ {
if ($this->socket) if ($this->socket)
{ {
fclose($this->socket); fclose($this->socket);
$this->socket = false; $this->socket = false;
} }
} }
protected function sendRequest(Request $request) protected function sendRequest(Request $request)
{ {
$xml = $request->getXml(); $xml = $request->getXml();
@stream_set_timeout($this->socket, 0, $this->timeout * 1000 * 100); @stream_set_timeout($this->socket, 0, $this->timeout * 1000 * 5);
// send request // send request
$this->reqhandle++; $this->reqhandle++;
if ($this->protocol == 1) if ($this->protocol == 1)
{ {
$bytes = pack('Va*', strlen($xml), $xml); $bytes = pack('Va*', strlen($xml), $xml);
} }
else else
{ {
$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml); $bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);
} }
$bytes_to_write = strlen($bytes); $bytes_to_write = strlen($bytes);
// increase sent counter ... // increase sent counter ...
self::$sent += $bytes_to_write; self::$sent += $bytes_to_write;
while ($bytes_to_write > 0) while ($bytes_to_write > 0)
{ {
$r = fwrite($this->socket, $bytes); $r = fwrite($this->socket, $bytes);
if ($r === false || $r == 0) if ($r === false || $r == 0)
{ {
throw new FatalException('Connection interupted', FatalException::INTERRUPTED); throw new FatalException('Connection interupted', FatalException::INTERRUPTED);
} }
@ -188,31 +188,31 @@ class Client
} }
} }
protected function getResult() protected function getResult()
{ {
$contents = ''; $contents = '';
$contents_length = 0; $contents_length = 0;
do do
{ {
$size = 0; $size = 0;
$recvhandle = 0; $recvhandle = 0;
@stream_set_timeout($this->socket, 0, $this->timeout * 1000); @stream_set_timeout($this->socket, 0, $this->timeout * 1000 * 2);
// Get result // Get result
if ($this->protocol == 1) if ($this->protocol == 1)
{ {
$contents = fread($this->socket, 4); $contents = fread($this->socket, 4);
if (strlen($contents) == 0 || $contents === false) if (strlen($contents) == 0 || $contents === false)
{ {
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED); throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
} }
$array_result = unpack('Vsize', $contents); $array_result = unpack('Vsize', $contents);
$size = $array_result['size']; $size = $array_result['size'];
$recvhandle = $this->reqhandle; $recvhandle = $this->reqhandle;
} }
else else
{ {
$contents = fread($this->socket, 8); $contents = fread($this->socket, 8);
if (strlen($contents) == 0 || $contents === false) if (strlen($contents) == 0 || $contents === false)
{ {
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED); throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
} }
@ -221,68 +221,68 @@ class Client
$recvhandle = $array_result['handle']; $recvhandle = $array_result['handle'];
// -- amd64 support -- // -- amd64 support --
$bits = sprintf('%b', $recvhandle); $bits = sprintf('%b', $recvhandle);
if (strlen($bits) == 64) if (strlen($bits) == 64)
{ {
$recvhandle = bindec(substr($bits, 32)); $recvhandle = bindec(substr($bits, 32));
} }
} }
if ($recvhandle == 0 || $size == 0) if ($recvhandle == 0 || $size == 0)
{ {
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED); throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
} }
if ($size > SIZE_MAX) if ($size > SIZE_MAX)
{ {
throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG); throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG);
} }
self::$received += $size; self::$received += $size;
$contents = ''; $contents = '';
$contents_length = 0; $contents_length = 0;
@stream_set_timeout($this->socket, 0, $this->timeout * 1000); @stream_set_timeout($this->socket, 0, $this->timeout * 1000);
while ($contents_length < $size) while ($contents_length < $size)
{ {
$contents .= fread($this->socket, $size-$contents_length); $contents .= fread($this->socket, $size-$contents_length);
$contents_length = strlen($contents); $contents_length = strlen($contents);
} }
if (($recvhandle & 0x80000000) == 0) if (($recvhandle & 0x80000000) == 0)
{ {
// this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents // this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents
// just add it to the message list for the user to read // just add it to the message list for the user to read
$new_cb_message = new Message($contents); $new_cb_message = new Message($contents);
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault')
{ {
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params)); array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
} }
} }
} }
while ((int)$recvhandle != (int)$this->reqhandle); while ((int)$recvhandle != (int)$this->reqhandle);
$this->message = new Message($contents); $this->message = new Message($contents);
if (!$this->message->parse()) if (!$this->message->parse())
{ {
// XML error // XML error
throw new Exception('parse error. not well formed', Exception::OTHER); throw new Exception('parse error. not well formed', Exception::OTHER);
} }
// Is the message a fault? // Is the message a fault?
if ($this->message->messageType == 'fault') if ($this->message->messageType == 'fault')
{ {
throw new Exception($this->message->faultString, $this->message->faultCode); throw new Exception($this->message->faultString, $this->message->faultCode);
} }
return $this->message; return $this->message;
} }
function query() function query()
{ {
$args = func_get_args(); $args = func_get_args();
$method = array_shift($args); $method = array_shift($args);
if (!$this->socket || $this->protocol == 0) if (!$this->socket || $this->protocol == 0)
{ {
throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED); throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED);
} }
@ -290,7 +290,7 @@ class Client
$request = new Request($method, $args); $request = new Request($method, $args);
// Check if request is larger than 1024 Kbytes // Check if request is larger than 1024 Kbytes
if ($request->getLength() > 1024*1024-8) if ($request->getLength() > 1024*1024-8)
{ {
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG); throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
} }
@ -300,12 +300,12 @@ class Client
} }
// Non-blocking query method: doesn't read the response // Non-blocking query method: doesn't read the response
function queryIgnoreResult() function queryIgnoreResult()
{ {
$args = func_get_args(); $args = func_get_args();
$method = array_shift($args); $method = array_shift($args);
if (!$this->socket || $this->protocol == 0) if (!$this->socket || $this->protocol == 0)
{ {
throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED); throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED);
} }
@ -314,13 +314,13 @@ class Client
// Check if the request is greater than 512 Kbytes to avoid errors // Check if the request is greater than 512 Kbytes to avoid errors
// If the method is system.multicall, make two calls (possibly recursively) // If the method is system.multicall, make two calls (possibly recursively)
if ($request->getLength() > 1024*1024-8) if ($request->getLength() > 1024*1024-8)
{ {
if ($method == 'system.multicall' && isset($args[0])) if ($method == 'system.multicall' && isset($args[0]))
{ {
$count = count($args[0]); $count = count($args[0]);
// If count is 1, query cannot be reduced // If count is 1, query cannot be reduced
if ($count < 2) if ($count < 2)
{ {
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG); throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
} }
@ -334,7 +334,7 @@ class Client
return ($res1 && $res2); return ($res1 && $res2);
} }
// If the method is not a multicall, just stop // If the method is not a multicall, just stop
else else
{ {
throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG); throw new Exception('transport error - request too large!', Exception::REQUEST_TOO_BIG);
} }
@ -342,16 +342,16 @@ class Client
$this->sendRequest($request); $this->sendRequest($request);
} }
function getResponse() function getResponse()
{ {
// methodResponses can only have one param - return that // methodResponses can only have one param - return that
return $this->message->params[0]; return $this->message->params[0];
} }
function readCallbacks() function readCallbacks()
{ {
if (!$this->socket || $this->protocol == 0) if (!$this->socket || $this->protocol == 0)
throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED); throw new FatalException('transport error - Client not initialized', FatalException::NOT_INITIALIZED);
if ($this->protocol == 1) if ($this->protocol == 1)
return false; return false;
@ -361,16 +361,16 @@ class Client
$contents = ''; $contents = '';
$contents_length = 0; $contents_length = 0;
@stream_set_timeout($this->socket, 0, $this->timeout * 1000); // timeout 10 ms (to read available data) @stream_set_timeout($this->socket, 0, $this->timeout * 100); // timeout 10 ms (to read available data)
// (assignment in arguments is forbidden since php 5.1.1) // (assignment in arguments is forbidden since php 5.1.1)
$read = array($this->socket); $read = array($this->socket);
$write = NULL; $write = NULL;
$except = NULL; $except = NULL;
$nb = false; $nb = false;
try try
{ {
$nb = @stream_select($read, $write, $except, 0, $this->timeout * 1000); $nb = @stream_select($read, $write, $except, 0, $this->timeout * 100);
} }
catch (\Exception $e) catch (\Exception $e)
{ {
@ -387,20 +387,20 @@ class Client
throw $e; throw $e;
} }
} }
// workaround for stream_select bug with amd64 // workaround for stream_select bug with amd64
if ($nb !== false) if ($nb !== false)
{ {
$nb = count($read); $nb = count($read);
} }
while ($nb !== false && $nb > 0) while ($nb !== false && $nb > 0)
{ {
$size = 0; $size = 0;
$recvhandle = 0; $recvhandle = 0;
// Get result // Get result
$contents = fread($this->socket, 8); $contents = fread($this->socket, 8);
if (strlen($contents) == 0 || $contents === false) if (strlen($contents) == 0 || $contents === false)
{ {
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED); throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
} }
@ -408,31 +408,31 @@ class Client
$size = $array_result['size']; $size = $array_result['size'];
$recvhandle = $array_result['handle']; $recvhandle = $array_result['handle'];
if ($recvhandle == 0 || $size == 0) if ($recvhandle == 0 || $size == 0)
{ {
throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED); throw new FatalException('transport error - connection interrupted!', FatalException::INTERRUPTED);
} }
if ($size > SIZE_MAX) if ($size > SIZE_MAX)
{ {
throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG); throw new Exception("transport error - answer too big ($size)", Exception::ANWSER_TOO_BIG);
} }
self::$received += $size; self::$received += $size;
$contents = ''; $contents = '';
$contents_length = 0; $contents_length = 0;
while ($contents_length < $size) while ($contents_length < $size)
{ {
$contents .= fread($this->socket, $size-$contents_length); $contents .= fread($this->socket, $size-$contents_length);
$contents_length = strlen($contents); $contents_length = strlen($contents);
} }
if (($recvhandle & 0x80000000) == 0) if (($recvhandle & 0x80000000) == 0)
{ {
// this is a callback. handle= $recvhandle, xml-rpc= $contents // this is a callback. handle= $recvhandle, xml-rpc= $contents
//echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF; //echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF;
$new_cb_message = new Message($contents); $new_cb_message = new Message($contents);
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault')
{ {
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params)); array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
} }
@ -444,7 +444,7 @@ class Client
$read = array($this->socket); $read = array($this->socket);
$write = NULL; $write = NULL;
$except = NULL; $except = NULL;
try try
{ {
$nb = @stream_select($read, $write, $except, 0, 0); // Notimeout, just flush the data $nb = @stream_select($read, $write, $except, 0, 0); // Notimeout, just flush the data
@ -460,7 +460,7 @@ class Client
throw $e; throw $e;
} }
} }
// workaround for stream_select bug with amd64 // workaround for stream_select bug with amd64
if ($nb !== false) if ($nb !== false)
{ {
@ -470,7 +470,7 @@ class Client
return !empty($this->cb_message); return !empty($this->cb_message);
} }
function getCallbackResponses() function getCallbackResponses()
{ {
// (look at the end of basic.php for an example) // (look at the end of basic.php for an example)
$messages = $this->cb_message; $messages = $this->cb_message;

View File

@ -48,7 +48,7 @@ class ManiaControl implements CommandListener, TimerListener {
const API_VERSION = '2013-04-16'; const API_VERSION = '2013-04-16';
const OS_UNIX = 'Unix'; const OS_UNIX = 'Unix';
const OS_WIN = 'Windows'; const OS_WIN = 'Windows';
const CONNECT_TIMEOUT = 20000; const CONNECT_TIMEOUT = 50;
const SCRIPT_TIMEOUT = 20; const SCRIPT_TIMEOUT = 20;
const URL_WEBSERVICE = 'http://ws.maniacontrol.com/'; const URL_WEBSERVICE = 'http://ws.maniacontrol.com/';
const SETTING_PERMISSION_SHUTDOWN = 'Shutdown ManiaControl'; const SETTING_PERMISSION_SHUTDOWN = 'Shutdown ManiaControl';
@ -211,6 +211,7 @@ class ManiaControl implements CommandListener, TimerListener {
if ($message) { if ($message) {
$this->log($message); $this->log($message);
} }
exit(); exit();
} }
@ -225,10 +226,14 @@ class ManiaControl implements CommandListener, TimerListener {
$this->chat->sendInformation('ManiaControl shutting down.'); $this->chat->sendInformation('ManiaControl shutting down.');
if($this->client){ if($this->client){
try{
// Hide manialinks // Hide manialinks
$this->client->sendHideManialinkPage(); $this->client->sendHideManialinkPage();
// Close the client connection // Close the client connection
$this->client->delete($this->server->ip, $this->server->port); $this->client->delete($this->server->ip, $this->server->port);
} catch(FatalException $e){
$this->errorHandler->triggerDebugNotice($e->getMessage() ." File: " . $e->getFile() . " Line: " . $e->getLine());
}
} }
//Check and Trigger Fatal Errors //Check and Trigger Fatal Errors

View File

@ -323,7 +323,7 @@ class Server implements CallbackListener {
} }
// Server not yet in given status - Wait for it... // Server not yet in given status - Wait for it...
$waitBegin = time(); $waitBegin = time();
$maxWaitTime = 30; $maxWaitTime = 50;
$lastStatus = $response->name; $lastStatus = $response->name;
$this->maniaControl->log("Waiting for server to reach status {$statusCode}..."); $this->maniaControl->log("Waiting for server to reach status {$statusCode}...");
$this->maniaControl->log("Current Status: {$lastStatus}"); $this->maniaControl->log("Current Status: {$lastStatus}");