First changes

This commit is contained in:
Shoghi Cervantes 2013-12-16 13:06:01 +01:00
parent 3248066a37
commit e0b8527560
8 changed files with 255 additions and 223 deletions

View File

@ -533,10 +533,10 @@ class PocketMinecraftServer{
case 0x05:
$version = $data[1];
$size = strlen($data[2]);
if($version !== CURRENT_STRUCTURE){
if($version !== RAKNET_STRUCTURE){
console("[DEBUG] Incorrect structure #$version from ".$packet["ip"].":".$packet["port"], true, true, 2);
$this->send(0x1a, array(
CURRENT_STRUCTURE,
RAKNET_STRUCTURE,
RAKNET_MAGIC,
$this->serverID,
), false, $packet["ip"], $packet["port"]);

View File

@ -70,7 +70,7 @@ class MinecraftInterface{
return ($pk !== false ? $pk : $this->popPacket());
}
private function parsePacket($buf, $source, $port){
private function parsePacket($buffer, $source, $port){
$pid = ord($buf{0});
$struct = $this->getStruct($pid);
if($struct === false){
@ -86,136 +86,11 @@ class MinecraftInterface{
return false;
}
$packet = new Packet($pid, $struct, $buf);
$packet = new RakNetParser($buffer);
@$packet->parse();
if($pid === 0x99){
$CID = PocketMinecraftServer::clientID($source, $port);
if(!isset($this->chunked[$CID]) and $packet->data[0] !== 0){ //Drop packet
return false;
}
switch($packet->data[0]){
case 0:
$this->initChunked($CID, $source, $port);
return false;
case 1:
$this->stopChunked($CID);
return false;
case 3:
$this->ackChunked($CID, $data[1]["id"], $data[1]["index"]);
return false;
case 4:
$this->receiveChunked($CID, $data[1]["id"], $data[1]["index"], $data[1]["count"], $data[1]["data"]);
return true;
}
}
$this->data[] = array($pid, $packet->data, $buf, $source, $port);
$this->data[] = array($pid, $packet->data, $buffer, $source, $port);
return true;
}
public function checkChunked($CID){
$time = microtime(true);
foreach($this->needCheck as $CID => $packets){
if($packets[-1] < $time){
$d = $this->chunked[$CID];
unset($packets[-1]);
foreach($packets as $packet){
$this->writePacket(0x99, $packet, true, $d[1], $d[2], true);
}
$this->needCheck[$CID][-1] = $time + 5;
}
}
foreach($this->toChunk as $CID => $packets){
$d = $this->chunked[$CID];
$raw = "";
$MTU = 512;
foreach($packets as $packet){
$raw .= $packet;
if(($len = strlen($packet)) > $MTU){
$MTU = $len;
}
}
if($MTU > $d[0][2]){
$this->chunked[$CID][0][2] = $MTU;
}else{
$MTU = $d[0][2];
}
$raw = str_split(gzdeflate($raw, DEFLATEPACKET_LEVEL), $MTU - 9); // - 1 - 2 - 2 - 2 - 2
$count = count($raw);
$messageID = $this->chunked[$CID][0][0]++;
$this->chunked[$CID][0][0] &= 0xFFFF;
if(!isset($this->needCheck[$CID])){
$this->needCheck[$CID] = array();
}
$this->needCheck[$CID][$messageID] = array(-1 => $time + 1);
foreach($raw as $index => $r){
$p = "\x99\x02".Utils::writeShort($messageID).Utils::writeShort($index).Utils::writeShort($count).Utils::writeShort(strlen($r)).$r;
$this->needCheck[$CID][$messageID][$index] = $p;
$this->writePacket(0x99, $p, true, $d[1], $d[2], true);
}
unset($this->toChunk[$CID]);
}
}
public function isChunked($CID){
return isset($this->chunked[$CID]);
}
private function initChunked($CID, $source, $port){
console("[DEBUG] Starting DEFLATEPacket for $source:$port", true, true, 2);
$this->chunked[$CID] = array(
0 => array(0, 0, 0), //index, sent/received; MTU
1 => $source,
2 => $port,
3 => array(), //Received packets
);
$this->writePacket(0x99, array(
0 => 0, //start
), false, $source, $port, true);
}
public function stopChunked($CID){
if(!isset($this->chunked[$CID])){
return false;
}
$this->writePacket(0x99, array(
0 => 1, //stop
), false, $this->chunked[$CID][1], $this->chunked[$CID][2], true);
console("[DEBUG] Stopping DEFLATEPacket for ".$this->chunked[$CID][1].":".$this->chunked[$CID][2], true, true, 2);
$this->chunked[$CID][3] = null;
$this->chunked[$CID][4] = null;
unset($this->chunked[$CID]);
unset($this->toChunk[$CID]);
unset($this->needCheck[$CID]);
}
private function ackChunked($CID, $ID, $index){
unset($this->needCheck[$CID][$ID][$index]);
if(count($this->needCheck[$CID][$ID]) <= 1){
unset($this->needCheck[$CID][$ID]);
}
}
private function receiveChunked($CID, $ID, $index, $count, $data){
if(!isset($this->chunked[$CID][3][$ID])){
$this->chunked[$CID][3][$ID] = array();
}
$this->chunked[$CID][3][$ID][$index] = $data;
if(count($this->chunked[$CID][3][$ID]) === $count){
ksort($this->chunked[$CID][3][$ID]);
$data = gzinflate(implode($this->chunked[$CID][3][$ID]), 524280);
unset($this->chunked[$CID][3][$ID]);
if($data === false or strlen($data) === 0){
console("[ERROR] Invalid DEFLATEPacket for ".$this->chunked[$CID][1].":".$this->chunked[$CID][2], true, true, 2);
}
$offset = 0;
while(($plen = Utils::readShort(substr($data, $offset, 2), false)) !== 0xFFFF or $offset >= $len){
$offset += 2;
$packet = substr($data, $offset, $plen);
$this->parsePacket($packet, $this->chunked[$CID][1], $this->chunked[$CID][2]);
}
}
}
public function popPacket(){
if(count($this->data) > 0){
@ -232,28 +107,12 @@ class MinecraftInterface{
if($raw === false){
$packet = new Packet($pid, $this->getStruct($pid));
$packet->data = $data;
@$packet->create();
if($force === false and $this->isChunked($CID)){
if(!isset($this->toChunk[$CID])){
$this->toChunk[$CID] = array();
}
$this->toChunk[$CID][] = $packet->raw;
$write = strlen($packet->raw);
}else{
$write = $this->socket->write($packet->raw, $dest, $port);
$this->bandwidth[1] += $write;
}
@$packet->create();
$write = $this->socket->write($packet->raw, $dest, $port);
$this->bandwidth[1] += $write;
}else{
if($force === false and $this->isChunked($CID)){
if(!isset($this->toChunk[$CID])){
$this->toChunk[$CID] = array();
}
$this->toChunk[$CID][] = $data;
$write = strlen($data);
}else{
$write = $this->socket->write($data, $dest, $port);
$this->bandwidth[1] += $write;
}
$write = $this->socket->write($data, $dest, $port);
$this->bandwidth[1] += $write;
}
return $write;
}

View File

@ -0,0 +1,94 @@
<?php
/**
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
define("CURRENT_PROTOCOL", 14);
define("MC_PING", 0x00);
define("MC_PONG", 0x03);
define("MC_CLIENT_CONNECT", 0x09);
define("MC_SERVER_HANDSHAKE", 0x10);
define("MC_CLIENT_HANDSHAKE", 0x13);
define("MC_SERVER_FULL", 0x14);
define("MC_DISCONNECT", 0x15);
define("MC_BANNED", 0x17);
define("MC_LOGIN", 0x82);
define("MC_LOGIN_STATUS", 0x83);
define("MC_READY", 0x84);
define("MC_CHAT", 0x85);
define("MC_SET_TIME", 0x86);
define("MC_START_GAME", 0x87);
define("MC_ADD_MOB", 0x88);
define("MC_ADD_PLAYER", 0x89);
define("MC_REMOVE_PLAYER", 0x8a);
define("MC_ADD_ENTITY", 0x8c);
define("MC_REMOVE_ENTITY", 0x8d);
define("MC_ADD_ITEM_ENTITY", 0x8e);
define("MC_TAKE_ITEM_ENTITY", 0x8f);
define("MC_MOVE_ENTITY", 0x90);
define("MC_MOVE_ENTITY_POSROT", 0x93);
define("MC_ROTATE_HEAD", 0x94);
define("MC_MOVE_PLAYER", 0x95);
define("MC_PLACE_BLOCK", 0x96);
define("MC_REMOVE_BLOCK", 0x97);
define("MC_UPDATE_BLOCK", 0x98);
define("MC_ADD_PAINTING", 0x99);
define("MC_EXPLOSION", 0x9a);
define("MC_LEVEL_EVENT", 0x9b);
define("MC_TILE_EVENT", 0x9c);
define("MC_ENTITY_EVENT", 0x9d);
define("MC_REQUEST_CHUNK", 0x9e);
define("MC_CHUNK_DATA", 0x9f);
define("MC_PLAYER_EQUIPMENT", 0xa0);
define("MC_PLAYER_ARMOR_EQUIPMENT", 0xa1);
define("MC_INTERACT", 0xa2);
define("MC_USE_ITEM", 0xa3);
define("MC_PLAYER_ACTION", 0xa4);
define("MC_HURT_ARMOR", 0xa6);
define("MC_SET_ENTITY_DATA", 0xa7);
define("MC_SET_ENTITY_MOTION", 0xa8);
//define("MC_SET_ENTITY_LINK", 0xa9);
define("MC_SET_HEALTH", 0xaa);
define("MC_SET_SPAWN_POSITION", 0xab);
define("MC_ANIMATE", 0xac);
define("MC_RESPAWN", 0xad);
define("MC_SEND_INVENTORY", 0xae);
define("MC_DROP_ITEM", 0xaf);
define("MC_CONTAINER_OPEN", 0xb0);
define("MC_CONTAINER_CLOSE", 0xb1);
define("MC_CONTAINER_SET_SLOT", 0xb2);
define("MC_CONTAINER_SET_DATA", 0xb3);
define("MC_CONTAINER_SET_CONTENT", 0xb4);
//define("MC_CONTAINER_ACK", 0xb5);
define("MC_CLIENT_MESSAGE", 0xb6);
define("MC_ADVENTURE_SETTINGS", 0xb7);
define("MC_ENTITY_DATA", 0xb8);
//define("MC_PLAYER_INPUT", 0xb9);

View File

@ -19,85 +19,41 @@
*
*/
define("DEFLATEPACKET_LEVEL", 1);
define("CURRENT_STRUCTURE", 5);
define("CURRENT_PROTOCOL", 14);
define("RAKNET_STRUCTURE", 5);
define("RAKNET_MAGIC", "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78");
define("MC_PING", 0x00);
define("RAKNET_UNCONNECTED_PING", 0x01);
define("RAKNET_UNCONNECTED_PING_OPEN_CONNECTIONS", 0x02);
define("MC_PONG", 0x03);
define("RAKNET_OPEN_CONNECTION_REQUEST_1", 0x05);
define("RAKNET_OPEN_CONNECTION_REPLY_1", 0x06);
define("RAKNET_OPEN_CONNECTION_REQUEST_2", 0x07);
define("RAKNET_OPEN_CONNECTION_REPLY_2", 0x08);
define("MC_CLIENT_CONNECT", 0x09);
define("MC_SERVER_HANDSHAKE", 0x10);
define("RAKNET_INCOMPATIBLE_PROTOCOL_VERSION", 0x1a); //CHECK THIS
define("MC_CLIENT_HANDSHAKE", 0x13);
define("RAKNET_UNCONNECTED_PONG", 0x1c);
define("RAKNET_ADVERTISE_SYSTEM", 0x1c);
define("MC_SERVER_FULL", 0x14);
define("MC_DISCONNECT", 0x15);
define("MC_BANNED", 0x17);
define("MC_LOGIN", 0x82);
define("MC_LOGIN_STATUS", 0x83);
define("MC_READY", 0x84);
define("MC_CHAT", 0x85);
define("MC_SET_TIME", 0x86);
define("MC_START_GAME", 0x87);
define("MC_ADD_MOB", 0x88);
define("MC_ADD_PLAYER", 0x89);
define("MC_REMOVE_PLAYER", 0x8a);
define("MC_ADD_ENTITY", 0x8c);
define("MC_REMOVE_ENTITY", 0x8d);
define("MC_ADD_ITEM_ENTITY", 0x8e);
define("MC_TAKE_ITEM_ENTITY", 0x8f);
define("MC_MOVE_ENTITY", 0x90);
define("MC_MOVE_ENTITY_POSROT", 0x93);
define("MC_ROTATE_HEAD", 0x94);
define("MC_MOVE_PLAYER", 0x95);
define("MC_PLACE_BLOCK", 0x96);
define("MC_REMOVE_BLOCK", 0x97);
define("MC_UPDATE_BLOCK", 0x98);
define("MC_ADD_PAINTING", 0x99);
define("MC_EXPLOSION", 0x9a);
define("MC_LEVEL_EVENT", 0x9b);
define("MC_TILE_EVENT", 0x9c);
define("MC_ENTITY_EVENT", 0x9d);
define("MC_REQUEST_CHUNK", 0x9e);
define("MC_CHUNK_DATA", 0x9f);
define("MC_PLAYER_EQUIPMENT", 0xa0);
define("MC_PLAYER_ARMOR_EQUIPMENT", 0xa1);
define("MC_INTERACT", 0xa2);
define("MC_USE_ITEM", 0xa3);
define("MC_PLAYER_ACTION", 0xa4);
define("MC_HURT_ARMOR", 0xa6);
define("MC_SET_ENTITY_DATA", 0xa7);
define("MC_SET_ENTITY_MOTION", 0xa8);
//define("MC_SET_ENTITY_LINK", 0xa9);
define("MC_SET_HEALTH", 0xaa);
define("MC_SET_SPAWN_POSITION", 0xab);
define("MC_ANIMATE", 0xac);
define("MC_RESPAWN", 0xad);
define("MC_SEND_INVENTORY", 0xae);
define("MC_DROP_ITEM", 0xaf);
define("MC_CONTAINER_OPEN", 0xb0);
define("MC_CONTAINER_CLOSE", 0xb1);
define("MC_CONTAINER_SET_SLOT", 0xb2);
define("MC_CONTAINER_SET_DATA", 0xb3);
define("MC_CONTAINER_SET_CONTENT", 0xb4);
//define("MC_CONTAINER_ACK", 0xb5);
define("MC_CLIENT_MESSAGE", 0xb6);
define("MC_ADVENTURE_SETTINGS", 0xb7);
define("MC_ENTITY_DATA", 0xb8);
//define("MC_PLAYER_INPUT", 0xb9);
define("RAKNET_DATA_PACKET_0", 0x80);
define("RAKNET_DATA_PACKET_1", 0x81);
define("RAKNET_DATA_PACKET_2", 0x82);
define("RAKNET_DATA_PACKET_3", 0x83);
define("RAKNET_DATA_PACKET_4", 0x84);
define("RAKNET_DATA_PACKET_5", 0x85);
define("RAKNET_DATA_PACKET_6", 0x86);
define("RAKNET_DATA_PACKET_7", 0x87);
define("RAKNET_DATA_PACKET_8", 0x88);
define("RAKNET_DATA_PACKET_9", 0x89);
define("RAKNET_DATA_PACKET_A", 0x8a);
define("RAKNET_DATA_PACKET_B", 0x8b);
define("RAKNET_DATA_PACKET_C", 0x8c);
define("RAKNET_DATA_PACKET_D", 0x8d);
define("RAKNET_DATA_PACKET_E", 0x8e);
define("RAKNET_DATA_PACKET_F", 0x8f);
define("RAKNET_NACK", 0xa0);
define("RAKNET_ACK", 0xc0);
class Protocol{
public static $raknet = array(

View File

@ -0,0 +1,30 @@
<?php
/**
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
class RakNetPacket extends stdClass{
public $id;
public function __construct($packetID){
$this->id = (int) $packetID;
}
public function __destruct(){}
}

View File

@ -0,0 +1,93 @@
<?php
/**
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
class RakNetParser{
private $buffer;
private $offset;
private $packet;
public function __construct($buffer){
$this->buffer = $buffer;
$this->offset = 0;
if(strlen($this->buffer) > 0){
$this->parse(ord($this->get(1)));
}else{
$this->packet = false;
}
}
private function get($len){
if($len === true){
return substr($this->buffer, $this->offset);
}
$this->offset += $len;
return substr($this->buffer, $this->offset - $len, $len);
}
private function getLong($unsigned = false){
return Utils::readLong($this->get(8), $unsigned);
}
private function getShort($unsigned = false){
return Utils::readShort($this->get(2), $unsigned);
}
private function getByte(){
return ord($this->get(1));
}
private function feof(){
return !isset($this->buffer{$this->offset});
}
private function parse($packetID){
$this->packet = new RakNetPacket($packetID);
$this->packet->length = strlen($this->buffer);
switch($packetID){
case RAKNET_UNCONNECTED_PING:
$this->packet->pingID = $this->getLong();
$this->offset += 16; //Magic
break;
case RAKNET_UNCONNECTED_PING_OPEN_CONNECTIONS:
$this->packet->pingID = $this->getLong();
$this->offset += 16; //Magic
break;
case RAKNET_OPEN_CONNECTION_REQUEST_1:
$this->offset += 16; //Magic
$this->packet->structure = $this->getByte();
$this->packet->MTU = strlen($this->get(true));
break;
case RAKNET_OPEN_CONNECTION_REQUEST_2:
$this->offset += 16; //Magic
$this->packet->securoty = $this->get(5);
$this->packet->port = $this->getShort(false);
$this->packet->MTU = $this->getShort(false);
$this->packet->clientGUID = $this->getLong();
break;
default:
$this->packet = false;
break;
}
}
}