<?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; } ?>