532 lines
12 KiB
PHP
532 lines
12 KiB
PHP
<?php
|
|
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
class CMemStream
|
|
{
|
|
var $Buffer;
|
|
var $InputStream;
|
|
var $Pos;
|
|
|
|
function CMemStream ()
|
|
{
|
|
$this->InputStream = false;
|
|
$this->Pos = 0;
|
|
}
|
|
|
|
function setBuffer ($buffer)
|
|
{
|
|
$this->InputStream = true;
|
|
$this->Buffer = $buffer;
|
|
$this->Pos = 0;
|
|
}
|
|
|
|
function isReading () { return $this->InputStream; }
|
|
|
|
/*
|
|
function serialuint8 (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
$val = ord($this->Buffer{$this->Pos++});
|
|
//printf ("read uint8 '%d'<br>", $val);
|
|
}
|
|
else
|
|
{
|
|
$this->Buffer .= chr($val & 0xFF);
|
|
$this->Pos++;
|
|
//printf ("write uint8 '%d' %d<br>", $val, $this->Pos);
|
|
}
|
|
}
|
|
|
|
function serialuint32 (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
$val = ord($this->Buffer{$this->Pos++});
|
|
$val += ord($this->Buffer{$this->Pos++})<<8;
|
|
$val += ord($this->Buffer{$this->Pos++})<<16;
|
|
$val += ord($this->Buffer{$this->Pos++})<<32;
|
|
//printf ("read uint32 '%d'<br>", $val);
|
|
}
|
|
else
|
|
{
|
|
$this->Buffer .= chr($val & 0xFF);
|
|
$this->Buffer .= chr(($val>>8) & 0xFF);
|
|
$this->Buffer .= chr(($val>>16) & 0xFF);
|
|
$this->Buffer .= chr(($val>>24) & 0xFF);
|
|
$this->Pos += 4;
|
|
//printf ("write uint32 '%d' %d<br>", $val, $this->Pos);
|
|
}
|
|
}
|
|
|
|
function serialstring (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
$this->serialuint32($size);
|
|
$val = substr ($this->Buffer, $this->Pos, $size);
|
|
//printf ("read string '%s'<br>", $val);
|
|
$this->Pos += strlen($val);
|
|
}
|
|
else
|
|
{
|
|
$this->serialuint32(strlen($val));
|
|
$this->Buffer .= $val;
|
|
$this->Pos += strlen($val);
|
|
//printf ("write string '%s' %d<br>", $val, $this->Pos);
|
|
}
|
|
}
|
|
*/
|
|
|
|
function serialuint8 (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
if ($this->Pos+1 > strlen($this->Buffer))
|
|
return false;
|
|
|
|
$val = ord($this->Buffer{$this->Pos++});
|
|
//printf ("read uint8 '%d'<br>", $val);
|
|
}
|
|
else
|
|
{
|
|
$this->Buffer .= chr($val & 0xFF);
|
|
$this->Pos++;
|
|
//printf ("write uint8 '%d' %d<br>", $val, $this->Pos);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function serialuint32 (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
if ($this->Pos+4 > strlen($this->Buffer))
|
|
return false;
|
|
|
|
$val = ord($this->Buffer{$this->Pos++});
|
|
$val += ord($this->Buffer{$this->Pos++})<<8;
|
|
$val += ord($this->Buffer{$this->Pos++})<<16;
|
|
$val += ord($this->Buffer{$this->Pos++})<<32;
|
|
//printf ("read uint32 '%d'<br>", $val);
|
|
}
|
|
else
|
|
{
|
|
$this->Buffer .= chr($val & 0xFF);
|
|
$this->Buffer .= chr(($val>>8) & 0xFF);
|
|
$this->Buffer .= chr(($val>>16) & 0xFF);
|
|
$this->Buffer .= chr(($val>>24) & 0xFF);
|
|
$this->Pos += 4;
|
|
//printf ("write uint32 '%d' %d<br>", $val, $this->Pos);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function serialstring (&$val)
|
|
{
|
|
if ($this->isReading())
|
|
{
|
|
if (!$this->serialuint32($size))
|
|
return false;
|
|
|
|
if ($this->Pos+$size > strlen($this->Buffer))
|
|
return false;
|
|
|
|
$val = substr ($this->Buffer, $this->Pos, $size);
|
|
//printf ("read string '%s'<br>", $val);
|
|
$this->Pos += strlen($val);
|
|
}
|
|
else
|
|
{
|
|
$this->serialuint32(strlen($val));
|
|
$this->Buffer .= $val;
|
|
$this->Pos += strlen($val);
|
|
//printf ("write string '%s' %d<br>", $val, $this->Pos);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
// This function connect to the AS.
|
|
// If true, $res contains the url to connect.
|
|
// If false, $res contains the reason why it s not okay.
|
|
|
|
function connectToAS(&$fp, &$res, $asHost, $asPort)
|
|
{
|
|
// connect to the login service that must be $ASHost:$ASPort
|
|
$fp = fsockopen ($asHost, $asPort, $errno, $errstr, 30);
|
|
if (!$fp)
|
|
{
|
|
$res = "Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)";
|
|
}
|
|
else
|
|
{
|
|
$res = "";
|
|
}
|
|
}
|
|
|
|
function disconnectFromAS(&$fp)
|
|
{
|
|
fclose($fp);
|
|
}
|
|
|
|
function sendMessage ($fp, $msgout)
|
|
{
|
|
$size = $msgout->Pos;
|
|
$buffer = chr(($size>>24)&0xFF);
|
|
$buffer .= chr(($size>>16)&0xFF);
|
|
$buffer .= chr(($size>>8)&0xFF);
|
|
$buffer .= chr($size&0xFF);
|
|
$buffer .= $msgout->Buffer;
|
|
|
|
fwrite ($fp, $buffer);
|
|
|
|
fflush ($fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
function logToFile($msg)
|
|
{
|
|
$f = fopen("../log_admin_tool.txt", "a");
|
|
if ($f)
|
|
{
|
|
fwrite($f, "$msg\n");
|
|
fflush($f);
|
|
fclose($f);
|
|
}
|
|
}
|
|
/*
|
|
function waitMessage ($fp, &$msgin)
|
|
{
|
|
$size = 0;
|
|
$val = fread ($fp, 1);
|
|
$size = ord($val) << 24;
|
|
$val = fread ($fp, 1);
|
|
$size = ord($val) << 16;
|
|
$val = fread ($fp, 1);
|
|
$size += ord($val) << 8;
|
|
$val = fread ($fp, 1);
|
|
$size += ord($val);
|
|
$fake = fread ($fp, 4);
|
|
$size -= 4; // remove the fake
|
|
|
|
$buffer = '';
|
|
do
|
|
{
|
|
$buffer .= fread ($fp, $size);
|
|
//logToFile("read ".strlen($buffer)." bytes...");
|
|
if (feof($fp))
|
|
break;
|
|
}
|
|
while (strlen($buffer) != $size);
|
|
|
|
//logToFile("finished read ".strlen($buffer)." bytes!!");
|
|
|
|
$msgin = new CMemStream;
|
|
$msgin->setBuffer ($buffer);
|
|
|
|
//logToFile("leave wait message");
|
|
return true;
|
|
}
|
|
*/
|
|
function waitMessage ($fp, &$msgin)
|
|
{
|
|
//echo "waiting a message";
|
|
$size = 0;
|
|
$val = fread ($fp, 1);
|
|
if (feof ($fp)) return false;
|
|
$size = ord($val) << 24;
|
|
$val = fread ($fp, 1);
|
|
if (feof ($fp)) return false;
|
|
$size = ord($val) << 16;
|
|
$val = fread ($fp, 1);
|
|
if (feof ($fp)) return false;
|
|
$size += ord($val) << 8;
|
|
$val = fread ($fp, 1);
|
|
if (feof ($fp)) return false;
|
|
$size += ord($val);
|
|
//printf ("receive packet size '%d'<br>", $size);
|
|
$fake = fread ($fp, 4);
|
|
if (feof ($fp)) return false;
|
|
$size -= 4; // remove the fake
|
|
|
|
$buffer = '';
|
|
while (($stillNotRead = $size-strlen($buffer)) > 0)
|
|
{
|
|
$buffer .= fread ($fp, $stillNotRead);
|
|
if (feof ($fp)) return false;
|
|
}
|
|
|
|
$msgin = new CMemStream;
|
|
$msgin->setBuffer ($buffer);
|
|
|
|
return true;
|
|
}
|
|
|
|
function logNelQuery($query)
|
|
{
|
|
global $uid;
|
|
/*
|
|
$f = fopen("./nel_queries.log", "a");
|
|
fwrite($f, date("Y/m/d H:i:s")." ".sprintf("%-16s", $admlogin)." $query\n");
|
|
fclose($f);
|
|
*/
|
|
logUser($uid, "QUERY=".$query);
|
|
}
|
|
|
|
|
|
function queryToAS($rawvarpath, &$result, $asAddr, $asPort)
|
|
{
|
|
global $nel_queries;
|
|
|
|
$nel_queries[] = $rawvarpath;
|
|
$ok = false;
|
|
|
|
connectToAS($fp, $result, $asAddr, $asPort);
|
|
if(strlen($result) != 0)
|
|
return $ok;
|
|
|
|
// send the message that say that we want to add a user
|
|
$msgout = new CMemStream;
|
|
$fake = 0;
|
|
$msgout->serialuint32 ($fake); // fake used to number the packet
|
|
$messageType = 0;
|
|
$msgout->serialuint8 ($messageType);
|
|
$msgout->serialstring ($rawvarpath);
|
|
|
|
sendMessage ($fp, $msgout);
|
|
|
|
waitMessage ($fp, $msgin);
|
|
|
|
$msgin->serialstring($result);
|
|
|
|
if(strlen($result) == 0)
|
|
{
|
|
// it failed
|
|
}
|
|
else
|
|
{
|
|
// it's ok
|
|
$ok = true;
|
|
}
|
|
|
|
disconnectFromAS(&$fp);
|
|
|
|
return $ok;
|
|
}
|
|
|
|
|
|
function nel_query($rawvarpath, &$result)
|
|
{
|
|
global $ASHost, $ASPort;
|
|
|
|
$shards = getShardListFromQuery($rawvarpath);
|
|
$as = getASList($shards);
|
|
|
|
if (count($as) <= 1)
|
|
{
|
|
$asHost = $ASHost;
|
|
$asPort = $ASPort;
|
|
|
|
if (count($as) > 0)
|
|
{
|
|
foreach ($as as $asHost)
|
|
{
|
|
$pos = strpos($asHost, ':');
|
|
if (pos != FALSE)
|
|
{
|
|
$asPort = substr($asHost, $pos+1);
|
|
$asHost = substr($asHost, 0, $pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
$res = queryToAS($rawvarpath, $result, $asHost, $asPort);
|
|
}
|
|
else
|
|
{
|
|
$resCols = array();
|
|
$resArray = array();
|
|
|
|
$res = false;
|
|
|
|
foreach ($as as $asHost)
|
|
{
|
|
$asPort = $ASPort;
|
|
$pos = strpos($asHost, ':');
|
|
if (pos != FALSE)
|
|
{
|
|
$asPort = substr($asHost, $pos+1);
|
|
$asHost = substr($asHost, 0, $pos);
|
|
}
|
|
|
|
$tmp = queryToAS($rawvarpath, $qres, $asHost, $asPort);
|
|
if ($tmp)
|
|
{
|
|
$res = true;
|
|
mergeResult($qres, $resCols, $resArray);
|
|
}
|
|
}
|
|
|
|
//print_r($resCols);echo '<br>';
|
|
//print_r($resArray);echo '<br>';
|
|
$result = rebuildResult($resCols, $resArray);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
function getShardFromSimpleQuery($query, $startpos=0)
|
|
{
|
|
$pos = $startpos;
|
|
while ($pos < strlen($query) && $query[$pos] != '.' && $query[$pos] != ']' && $query[$pos] != ',')
|
|
++$pos;
|
|
//echo 'getShardFromSimpleQuery: '.substr($query, $startpos, $pos-$startpos).'<br>';
|
|
return substr($query, $startpos, $pos-$startpos);
|
|
}
|
|
|
|
function getShardListFromQuery($query, $startpos=0)
|
|
{
|
|
$shards = array();
|
|
|
|
if ($query[$startpos] != '[')
|
|
{
|
|
$shards[] = getShardFromSimpleQuery($query, $startpos);
|
|
return $shards;
|
|
}
|
|
|
|
$pos = $startpos+1;
|
|
$lvl = 0;
|
|
|
|
while (true)
|
|
{
|
|
//echo 'getShardListFromQuery in '.substr($query, $pos).'<br>';
|
|
$shards = array_merge($shards, getShardListFromQuery($query, $pos));
|
|
|
|
while ($pos<strlen($query) && ($query[$pos]!=',' || $lvl>0))
|
|
{
|
|
if ($query[$pos] == '[') ++$lvl;
|
|
if ($query[$pos] == ']') --$lvl;
|
|
++$pos;
|
|
}
|
|
|
|
if ($query[$pos] != ',')
|
|
break;
|
|
|
|
++$pos;
|
|
}
|
|
|
|
return array_unique($shards);
|
|
}
|
|
|
|
function selectAllAS()
|
|
{
|
|
global $ASHost, $ASPort;
|
|
|
|
$as[] = $ASHost.':'.$ASPort;
|
|
|
|
foreach($shardLockState as $shard)
|
|
if ($shard['ASAddr'] != '')
|
|
$as[] = $shard[ASAddr];
|
|
|
|
return array_unique($as);
|
|
}
|
|
|
|
function getASList($shards)
|
|
{
|
|
global $ASHost, $ASPort, $shardLockState;
|
|
|
|
if (count($shards) == 0)
|
|
return;
|
|
|
|
if (array_search('*', $shards) != FALSE)
|
|
return selectAllAS();
|
|
|
|
foreach($shards as $shard)
|
|
if ($shardLockState[$shard]['ASAddr'] != '')
|
|
$as[$shard] = $shardLockState[$shard]['ASAddr'];
|
|
else
|
|
$as[$shard] = $ASHost.':'.$ASPort;
|
|
|
|
return array_unique($as);
|
|
}
|
|
|
|
function mergeResult(&$res, &$resCols, &$resArray)
|
|
{
|
|
$resV = explode(' ', $res);
|
|
|
|
$i = 0;
|
|
$numCols = $resV[$i++];
|
|
for ($i=1; $i<=$numCols; ++$i)
|
|
if (!isset($resCols[$resV[$i]]))
|
|
$resCols[$resV[$i]] = count($resCols);
|
|
|
|
while ($i < count($resV))
|
|
{
|
|
//echo 'examine i='.$i.', resv='.count($resV).'<br>';
|
|
|
|
$line = array();
|
|
for ($j=0; $j<$numCols; ++$j)
|
|
{
|
|
$line[ $resCols[$resV[$j+1]] ] = $resV[$i++];
|
|
|
|
if ($i > count($resV))
|
|
break;
|
|
}
|
|
if ($j>=$numCols)
|
|
$resArray[] = $line;
|
|
}
|
|
}
|
|
|
|
function rebuildResult(&$resCols, &$resArray)
|
|
{
|
|
$numCols = count($resCols);
|
|
|
|
$res = $numCols;
|
|
|
|
foreach($resCols as $col => $id)
|
|
$res .= ' '.$col;
|
|
|
|
//$res .= join(' ', $resCols);
|
|
|
|
$numRows = count($resArray);
|
|
if ($numRows == 0)
|
|
return $res;
|
|
|
|
for ($i=0; $i<$numRows; ++$i)
|
|
{
|
|
$line = &$resArray[$i];
|
|
//print_r($line); echo '<br>';
|
|
if (count($line) == 0)
|
|
continue;
|
|
|
|
foreach ($resCols as $col => $id)
|
|
{
|
|
$v = &$line[$id];
|
|
if (!isset($v) || $v == '')
|
|
$res .= ' ???';
|
|
else
|
|
$res .= ' '.$v;
|
|
}
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
?>
|