#!/usr/bin/php -q
<?php
include("/system/init.php");

class 
EngineConnection {
    var 
$this->socket null;
    var 
$this->num null;
    var 
$this->key null;
    var 
$this->ip null;
    var 
$this->port null;


    function 
connect() {
        
$this->socket socket_create(AF_INETSOCK_STREAM0);
        
$datasock = @socket_connect($this->socket$this->ip$this->port);

        
socket_getpeername($this->socket,&$ip);
        
$this->ip $ip;

        return 
$datasock;
    }

    function 
encrypt($input) {
       
$td mcrypt_module_open('tripledes''''ecb''');
       
$iv mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
       
mcrypt_generic_init($td$this->key$iv);
       
$encrypted_data mcrypt_generic($td$input);
       
mcrypt_generic_deinit($td);
       
mcrypt_module_close($td);

       return 
$encrypted_data;    
    }

    function 
decrypt($input) {
       
$td mcrypt_module_open('tripledes''''ecb''');
       
$iv mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
       
mcrypt_generic_init($td$this->key$iv);
       
$decrypted_data mdecrypt_generic($td$input);
       
mcrypt_generic_deinit($td);
       
mcrypt_module_close($td);

       return 
$decrypted_data;
    }

    function 
generateNum() {
                
srand ((double) microtime() * 1000000);
        
$this->num rand(1000000099999999);

        return 
$this->num;
    }

    function 
calculateKey() {
        
$this->key substr(md5(substr($this->num,6,1).substr($this->num,2,1).substr($this->num,4,1).substr($this->num,1,1).$this->clientIp.substr($this->num,3,1).substr($this->num,0,1).date('dmY').substr($this->num,5,1).substr($this->num,7,1)),0,10);

        return 
$this->key;
    }

    function 
sendReply($data) {
        
$res socket_write($this->socket,encrypt($data,$this->key)."\r\n");
        
        
$input socket_read($this->socket100000);
        return 
$this->parse($input);

    }

    function 
sendCommand($command,$data) {
        
$res socket_write($this->socket,encrypt($command." ".base64_encode($data),$this->key)."\r\n");
        
$reply $this->readReply();

        return 
$reply;
    }

    function 
readData($limit 100000) {
        
$data socket_read($this->socket100000);
        if(
$data == null) {
            
$this->disconnect();

            return 
false;
        }
        else {
            
$data decrypt($data,$this->key);
            return 
$data;
        }
    }

    function 
readReply($limit 100000) {
        
$data $this->readData($limit);
        if(!
$data) return $data;
        else 
$data ereg_replace("//[0-9]+ ","",$data);

        return 
$data;
    }

    function 
readCommand($limit 10000000) {
        
$data ereg_replace("[\t\n\r]","",$this->readData($limit));
        if(!
$data) return $data;
        else {
            
$ar1 explode(" ",$data);
            
$arr = array('command' => strtolower($ar1[0]),'data' => unserialize(base64_decode($ar1[1])));
        }

        return 
$arr;
    }

    function 
disconnect() {
        
socket_close($this->socket);
        
$this->reInit();

        return 
true;
    }

    function 
reInit() {
        
$this->socket null;
        
$this->ip null;
        
$this->port null;
        
$this->key null;
        
$this->num null;
    }
}

class 
Engine {
    var 
$address '0.0.0.0';
    var 
$port '1984';
    var 
$max_clients 5;
    var 
$clients = array();
    var 
$banned = array();

    var 
$sock

    
function init() {
        
set_time_limit (0); 

        
$this->sock socket_create(AF_INETSOCK_STREAM0); 
        if (!@
socket_setopt($this->sock,SOL_SOCKET,SO_REUSEADDR,1)) {
            echo 
"socket_setopt() failed: reason: ".socket_strerror(socket_last_error($this->sock))."\n";
            exit;
        }

        
socket_bind($this->sock$this->address$this->port) or die('Could not bind to address'); 
        
socket_listen($this->sock);

        
$this->clients[0] = new EngineConnection();
        
$this->clients[1] = new EngineConnection();
        
$this->clients[2] = new EngineConnection();
        
$this->clients[3] = new EngineConnection();
        
$this->clients[4] = new EngineConnection();
    }

    function 
main() {
        while (
$this->quit != true) { 
            
// Setup clients listen socket for reading 
            
$read[0] = $this->sock
            for (
$i 0$i $this->max_clients$i++) 
            { 
                if (
$this->clients[$i]->socket  != null
                    
$read[$i 1] = $this->clients[$i]->socket 
            } 
            
// Set up a blocking call to socket_select() 
            
$ready socket_select($read,$write null,$except null,null); 
            
/* if a new connection is being made add it to the client array */ 
            
if (in_array($this->sock$read)) { 
                for (
$i 0$i $this->max_clients$i++) 
                { 
                    if (
$this->clients[$i]->socket == null) { 
                        
$this->clients[$i]->socket socket_accept($this->sock);
                        
$this->clients[$i]->port $this->port;
                        
$this->clients[$i]->generateNum();
                        
$this->clients[$i]->calculateKey();
                        
                        if(
in_array($this->clients[$i]->ip,$this->banned)) {
                            print 
"killed ".$this->clients[$i]->ip;
                            
socket_close($this->clients[$i]->socket);
                            break;
                        }

                        
$this->clients[$i]->sendReply("//0 Central Universal Engine www.prodigygaming.co.uk");
                        
$this->clients[$i]->sendReply("//L:".$this->clients[$i]->num);

                        break; 
                    } 
                    elseif (
$i == $this->max_clients 1
                        print (
"too many clients");
                } 
                if (--
$ready <= 0
                    continue; 
            } 
// end if in_array 
             
            // If a client is trying to write - handle it now 
            
for ($i 0$i $this->max_clients$i++) // for each client 
            

                if (
in_array($this->clients[$i]->socket $read)) 
                { 
                    
$data $this->clients[$i]->readCommand();
                    if(
$input != false) {
                        
// run the command as a function in this class
                        
eval('$this->'.$data['command'].'($i,$data['data']);');
                    }
                } else { 
                    
$this->clients[$i]->reInit();
                } 
            } 
        } 
// end while 

    
}

    
//-----------------------------------------------------------------------------------------
    // add more here with the function name = the command
    //-----------------------------------------------------------------------------------------

    
function createCharacter($clientid,$data) {
        
// insert into some table the values $data[0] $data[1] $data[2] $data[3] $data[4] $data[5]
        // get the ID in $someid

        
$this->clients[$clientid]->sendReply('//OK Character ID '.$someid);
    }

    function 
quit($clientid) {
        
$this->clients[$clientid]->sendReply('//2 Bye!');
        
$this->clients[$clientid]->disconnect();

        return 
true;
    }

    function 
shutdown() {
        for (
$i 0$i $this->max_clients$i++) { 
            
$this->clients[$i]->disconnect(); 
        }

        
socket_close($this->sock); 

        exit;
    }
}

$engine = new Engine();
$engine->port 19283;
$engine->address '0.0.0.0';
$engine->init();
$engine->main();
$engine->shutdown();

?>