2 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
3 // Copyright (C) 2010 Winch Gate Property Limited
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 function CMemStream ()
26 $this->InputStream
= false;
30 function setBuffer ($buffer)
32 $this->InputStream
= true;
33 $this->Buffer
= $buffer;
37 function isReading () { return $this->InputStream
; }
40 function serialuint8 (&$val)
42 if ($this->isReading())
44 $val = ord($this->Buffer{$this->Pos++});
45 //printf ("read uint8 '%d'<br>", $val);
49 $this->Buffer .= chr($val & 0xFF);
51 //printf ("write uint8 '%d' %d<br>", $val, $this->Pos);
55 function serialuint32 (&$val)
57 if ($this->isReading())
59 $val = ord($this->Buffer{$this->Pos++});
60 $val += ord($this->Buffer{$this->Pos++})<<8;
61 $val += ord($this->Buffer{$this->Pos++})<<16;
62 $val += ord($this->Buffer{$this->Pos++})<<32;
63 //printf ("read uint32 '%d'<br>", $val);
67 $this->Buffer .= chr($val & 0xFF);
68 $this->Buffer .= chr(($val>>8) & 0xFF);
69 $this->Buffer .= chr(($val>>16) & 0xFF);
70 $this->Buffer .= chr(($val>>24) & 0xFF);
72 //printf ("write uint32 '%d' %d<br>", $val, $this->Pos);
76 function serialstring (&$val)
78 if ($this->isReading())
80 $this->serialuint32($size);
81 $val = substr ($this->Buffer, $this->Pos, $size);
82 //printf ("read string '%s'<br>", $val);
83 $this->Pos += strlen($val);
87 $this->serialuint32(strlen($val));
88 $this->Buffer .= $val;
89 $this->Pos += strlen($val);
90 //printf ("write string '%s' %d<br>", $val, $this->Pos);
95 function serialuint8 (&$val)
97 if ($this->isReading())
99 if ($this->Pos+
1 > strlen($this->Buffer
))
102 $val = ord($this->Buffer
{$this->Pos++
});
103 //printf ("read uint8 '%d'<br>", $val);
107 $this->Buffer
.= chr($val & 0xFF);
109 //printf ("write uint8 '%d' %d<br>", $val, $this->Pos);
114 function serialuint32 (&$val)
116 if ($this->isReading())
118 if ($this->Pos+
4 > strlen($this->Buffer
))
121 $val = ord($this->Buffer
{$this->Pos++
});
122 $val +
= ord($this->Buffer
{$this->Pos++
})<<8;
123 $val +
= ord($this->Buffer
{$this->Pos++
})<<16;
124 $val +
= ord($this->Buffer
{$this->Pos++
})<<32;
125 //printf ("read uint32 '%d'<br>", $val);
129 $this->Buffer
.= chr($val & 0xFF);
130 $this->Buffer
.= chr(($val>>8) & 0xFF);
131 $this->Buffer
.= chr(($val>>16) & 0xFF);
132 $this->Buffer
.= chr(($val>>24) & 0xFF);
134 //printf ("write uint32 '%d' %d<br>", $val, $this->Pos);
139 function serialstring (&$val)
141 if ($this->isReading())
143 if (!$this->serialuint32($size))
146 if ($this->Pos+
$size > strlen($this->Buffer
))
149 $val = substr ($this->Buffer
, $this->Pos
, $size);
150 //printf ("read string '%s'<br>", $val);
151 $this->Pos +
= strlen($val);
155 $this->serialuint32(strlen($val));
156 $this->Buffer
.= $val;
157 $this->Pos +
= strlen($val);
158 //printf ("write string '%s' %d<br>", $val, $this->Pos);
165 // This function connect to the AS.
166 // If true, $res contains the url to connect.
167 // If false, $res contains the reason why it s not okay.
169 function connectToAS(&$fp, &$res, $asHost, $asPort)
171 // connect to the login service that must be $ASHost:$ASPort
172 $fp = fsockopen ($asHost, $asPort, $errno, $errstr, 30);
175 $res = "Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)";
183 function disconnectFromAS(&$fp)
188 function sendMessage ($fp, $msgout)
190 $size = $msgout->Pos
;
191 $buffer = chr(($size>>24)&0xFF);
192 $buffer .= chr(($size>>16)&0xFF);
193 $buffer .= chr(($size>>8)&0xFF);
194 $buffer .= chr($size&0xFF);
195 $buffer .= $msgout->Buffer
;
197 fwrite ($fp, $buffer);
204 function logToFile($msg)
206 $f = fopen("../log_admin_tool.txt", "a");
209 fwrite($f, "$msg\n");
215 function waitMessage ($fp, &$msgin)
218 $val = fread ($fp, 1);
219 $size = ord($val) << 24;
220 $val = fread ($fp, 1);
221 $size = ord($val) << 16;
222 $val = fread ($fp, 1);
223 $size += ord($val) << 8;
224 $val = fread ($fp, 1);
226 $fake = fread ($fp, 4);
227 $size -= 4; // remove the fake
232 $buffer .= fread ($fp, $size);
233 //logToFile("read ".strlen($buffer)." bytes...");
237 while (strlen($buffer) != $size);
239 //logToFile("finished read ".strlen($buffer)." bytes!!");
241 $msgin = new CMemStream;
242 $msgin->setBuffer ($buffer);
244 //logToFile("leave wait message");
248 function waitMessage ($fp, &$msgin)
250 //echo "waiting a message";
252 $val = fread ($fp, 1);
253 if (feof ($fp)) return false;
254 $size = ord($val) << 24;
255 $val = fread ($fp, 1);
256 if (feof ($fp)) return false;
257 $size = ord($val) << 16;
258 $val = fread ($fp, 1);
259 if (feof ($fp)) return false;
260 $size +
= ord($val) << 8;
261 $val = fread ($fp, 1);
262 if (feof ($fp)) return false;
264 //printf ("receive packet size '%d'<br>", $size);
265 $fake = fread ($fp, 4);
266 if (feof ($fp)) return false;
267 $size -= 4; // remove the fake
270 while (($stillNotRead = $size-strlen($buffer)) > 0)
272 $buffer .= fread ($fp, $stillNotRead);
273 if (feof ($fp)) return false;
276 $msgin = new CMemStream
;
277 $msgin->setBuffer ($buffer);
282 function logNelQuery($query)
286 $f = fopen("./nel_queries.log", "a");
287 fwrite($f, date("Y/m/d H:i:s")." ".sprintf("%-16s", $admlogin)." $query\n");
290 logUser($uid, "QUERY=".$query);
294 function queryToAS($rawvarpath, &$result, $asAddr, $asPort)
298 $nel_queries[] = $rawvarpath;
301 connectToAS($fp, $result, $asAddr, $asPort);
302 if(strlen($result) != 0)
305 // send the message that say that we want to add a user
306 $msgout = new CMemStream
;
308 $msgout->serialuint32 ($fake); // fake used to number the packet
310 $msgout->serialuint8 ($messageType);
311 $msgout->serialstring ($rawvarpath);
313 sendMessage ($fp, $msgout);
315 waitMessage ($fp, $msgin);
317 $msgin->serialstring($result);
319 if(strlen($result) == 0)
329 disconnectFromAS(&$fp);
335 function nel_query($rawvarpath, &$result)
337 global $ASHost, $ASPort;
339 $shards = getShardListFromQuery($rawvarpath);
340 $as = getASList($shards);
349 foreach ($as as $asHost)
351 $pos = strpos($asHost, ':');
354 $asPort = substr($asHost, $pos+
1);
355 $asHost = substr($asHost, 0, $pos);
360 $res = queryToAS($rawvarpath, $result, $asHost, $asPort);
369 foreach ($as as $asHost)
372 $pos = strpos($asHost, ':');
375 $asPort = substr($asHost, $pos+
1);
376 $asHost = substr($asHost, 0, $pos);
379 $tmp = queryToAS($rawvarpath, $qres, $asHost, $asPort);
383 mergeResult($qres, $resCols, $resArray);
387 //print_r($resCols);echo '<br>';
388 //print_r($resArray);echo '<br>';
389 $result = rebuildResult($resCols, $resArray);
396 function getShardFromSimpleQuery($query, $startpos=0)
399 while ($pos < strlen($query) && $query[$pos] != '.' && $query[$pos] != ']' && $query[$pos] != ',')
401 //echo 'getShardFromSimpleQuery: '.substr($query, $startpos, $pos-$startpos).'<br>';
402 return substr($query, $startpos, $pos-$startpos);
405 function getShardListFromQuery($query, $startpos=0)
409 if ($query[$startpos] != '[')
411 $shards[] = getShardFromSimpleQuery($query, $startpos);
420 //echo 'getShardListFromQuery in '.substr($query, $pos).'<br>';
421 $shards = array_merge($shards, getShardListFromQuery($query, $pos));
423 while ($pos<strlen($query) && ($query[$pos]!=',' ||
$lvl>0))
425 if ($query[$pos] == '[') ++
$lvl;
426 if ($query[$pos] == ']') --$lvl;
430 if ($query[$pos] != ',')
436 return array_unique($shards);
439 function selectAllAS()
441 global $ASHost, $ASPort;
443 $as[] = $ASHost.':'.$ASPort;
445 foreach($shardLockState as $shard)
446 if ($shard['ASAddr'] != '')
447 $as[] = $shard[ASAddr
];
449 return array_unique($as);
452 function getASList($shards)
454 global $ASHost, $ASPort, $shardLockState;
456 if (count($shards) == 0)
459 if (array_search('*', $shards) != FALSE)
460 return selectAllAS();
462 foreach($shards as $shard)
463 if ($shardLockState[$shard]['ASAddr'] != '')
464 $as[$shard] = $shardLockState[$shard]['ASAddr'];
466 $as[$shard] = $ASHost.':'.$ASPort;
468 return array_unique($as);
471 function mergeResult(&$res, &$resCols, &$resArray)
473 $resV = explode(' ', $res);
476 $numCols = $resV[$i++
];
477 for ($i=1; $i<=$numCols; ++
$i)
478 if (!isset($resCols[$resV[$i]]))
479 $resCols[$resV[$i]] = count($resCols);
481 while ($i < count($resV))
483 //echo 'examine i='.$i.', resv='.count($resV).'<br>';
486 for ($j=0; $j<$numCols; ++
$j)
488 $line[ $resCols[$resV[$j+
1]] ] = $resV[$i++
];
490 if ($i > count($resV))
498 function rebuildResult(&$resCols, &$resArray)
500 $numCols = count($resCols);
504 foreach($resCols as $col => $id)
507 //$res .= join(' ', $resCols);
509 $numRows = count($resArray);
513 for ($i=0; $i<$numRows; ++
$i)
515 $line = &$resArray[$i];
516 //print_r($line); echo '<br>';
517 if (count($line) == 0)
520 foreach ($resCols as $col => $id)
523 if (!isset($v) ||
$v == '')