/** * deserialize * * This method deserializes a request. It requires an SabreAMF_InputStream with valid AMF data. After * deserialization the contents of the request can be found through the getBodies and getHeaders methods * * @param SabreAMF_InputStream $stream * @return void */ public function deserialize(SabreAMF_InputStream $stream) { $this->headers = array(); $this->bodies = array(); $this->InputStream = $stream; $stream->readByte(); $this->clientType = $stream->readByte(); $deserializer = new SabreAMF_AMF0_Deserializer($stream); $totalHeaders = $stream->readInt(); for ($i = 0; $i < $totalHeaders; $i++) { $header = array('name' => $deserializer->readString(), 'required' => $stream->readByte() == true); $stream->readLong(); $header['data'] = $deserializer->readAMFData(null, true); $this->headers[] = $header; } $totalBodies = $stream->readInt(); for ($i = 0; $i < $totalBodies; $i++) { try { $target = $deserializer->readString(); } catch (Exception $e) { // Could not fetch next body.. this happens with some versions of AMFPHP where the body // count isn't properly set. If this happens we simply stop decoding break; } $body = array('target' => $target, 'response' => $deserializer->readString(), 'length' => $stream->readLong(), 'data' => $deserializer->readAMFData(null, true)); if (is_object($body['data']) && $body['data'] instanceof SabreAMF_AMF3_Wrapper) { $body['data'] = $body['data']->getData(); $this->encoding = SabreAMF_Const::AMF3; } else { if (is_array($body['data']) && isset($body['data'][0]) && is_object($body['data'][0]) && $body['data'][0] instanceof SabreAMF_AMF3_Wrapper) { $body['data'] = $body['data'][0]->getData(); $this->encoding = SabreAMF_Const::AMF3; } } $this->bodies[] = $body; } }
/** * @return array * * @throws PacketException * @throws ClientKickedException */ protected function parsePacket() { $packets = array(); while (true) { $headerBasic = ord($this->socket->read(1)); $channel = $headerBasic & 0x2f; $headerType = $headerBasic & 0xc0; $headerSize = 0; switch ($headerType) { case 0x0: $headerSize = 12; break; case 0x40: $headerSize = 8; break; case 0x80: $headerSize = 4; break; case 0xc0: $headerSize = 1; break; } if (!isset($packets[$channel])) { $packets[$channel] = array('data' => ''); } $packet =& $packets[$channel]; // Parse the header if ($headerSize > 1) { $header = $this->socket->read($headerSize - 1); if ($headerSize >= 8) { $size = 0; for ($i = 3; $i < 6; $i++) { $size *= 256; $size += ord(substr($header, $i, 1)) & 0xff; } $packet['size'] = $size; $packet['type'] = ord($header[6]); } } // Parse the content for ($i = 0; $i < 128; $i++) { if (!feof($this->socket->getSocket())) { $packet['data'] .= $this->socket->read(1); } if (strlen($packet['data']) == $packet['size']) { break; } } if (!(strlen($packet['data']) == $packet['size'])) { continue; } // Remove the read packet unset($packets[$channel]); $result = array(); $input = new \SabreAMF_InputStream($packet['data']); switch ($packet['type']) { case 0x14: // decode connect $decoder = new \SabreAMF_AMF0_Deserializer($input); $result['result'] = $decoder->readAMFData(); $result['invokeId'] = $decoder->readAMFData(); $result['serviceCall'] = $decoder->readAMFData(); $result['data'] = $decoder->readAMFData(); try { $input->readByte(); throw new PacketException('id not consume entire buffer'); } catch (\Exception $e) { // good } break; case 0x11: if ($input->readByte() == 0x0) { $packet['data'] = substr($packet['data'], 1); $result['version'] = 0x0; } $decoder = new \SabreAMF_AMF0_Deserializer($input); $result['result'] = $decoder->readAMFData(); $result['invokeId'] = $decoder->readAMFData(); $result['serviceCall'] = $decoder->readAMFData(); $result['data'] = $decoder->readAMFData(); try { $input->readByte(); throw new PacketException('id not consume entire buffer'); } catch (\Exception $e) { // good } break; case 0x3: // ack // ack case 0x6: // bandwidth continue 2; default: throw new PacketException('Unknown message type'); } if (!isset($result['invokeId'])) { // The client has been kicked, someone connect to the same account with another API instance or from the desktop launcher if ('receive' == $result['result'] && 'com.riotgames.platform.messaging.ClientLoginKickNotification' == $result['data']->getData()->getAMFData()['body']->getAMFClassName()) { throw new ClientKickedException('Someone is connected with the same account, only one instance can running. Restarting client...'); } throw new PacketException("Error after decoding packet"); } $invokeId = $result['invokeId']; if ($invokeId == null || $invokeId == 0) { throw new PacketException('Unknown invokeId: ' . $invokeId); } return $result; } }
private function readResponse() { $packets = array(); while (true) { $headerBasic = ord($this->read(1)); $channel = $headerBasic & 0x2f; $headerType = $headerBasic & 0xc0; $headerSize = 0; switch ($headerType) { case 0x0: $headerSize = 12; break; case 0x40: $headerSize = 8; break; case 0x80: $headerSize = 4; break; case 0xc0: $headerSize = 1; break; } if (!array_key_exists($channel, $packets)) { $packets[$channel] = array('data' => ''); } $packet =& $packets[$channel]; if ($headerSize > 1) { $header = $this->read($headerSize - 1); if ($headerSize >= 8) { $size = 0; for ($i = 3; $i < 6; $i++) { $size *= 256; $size += ord(substr($header, $i, 1)) & 0xff; } $packet['size'] = $size; $packet['type'] = ord($header[6]); } } for ($i = 0; $i < 128; $i++) { if (!feof($this->socket)) { $packet['data'] .= $this->read(1); } if (strlen($packet['data']) == $packet['size']) { break; } } $len = strlen($packet['data']); if (!(strlen($packet['data']) == $packet['size'])) { continue; } unset($packets[$channel]); $result = null; if ($packet['type'] == 0x3 || $packet['type'] == 0x6) { continue; } elseif ($packet['type'] == 0x11) { $result = array(); $stream = new \SabreAMF_InputStream($packet['data']); if ($stream->readByte() == 0x0) { $result['version'] = 0x0; $packet['data'] = substr($packet['data'], 1, strlen($packet['data'])); } $deserializer = new \SabreAMF_AMF0_Deserializer($stream); $result['result'] = $deserializer->readAMFData(); $result['invokeId'] = $deserializer->readAMFData(); $result['serviceCall'] = $deserializer->readAMFData(); $result['data'] = $deserializer->readAMFData(); } elseif ($packet['type'] == 0x14) { $result = array(); $stream = new \SabreAMF_InputStream($packet['data']); $deserializer = new \SabreAMF_AMF0_Deserializer($stream); $result['result'] = $deserializer->readAMFData(); $result['invokeId'] = $deserializer->readAMFData(); $result['serviceCall'] = $deserializer->readAMFData(); $result['data'] = $deserializer->readAMFData(); } else { //Unhandled Packet } if (!isset($result)) { throw new \Exception("Error after decoding packet"); } $id = $result['invokeId']; if ($id == null || $id == 0) { //CALLBACK } elseif (false) { //CALLBACK2 } else { return $result; } } }