Refactoring

This commit is contained in:
Daniil Gentili 2020-10-26 23:13:05 +01:00
parent d0189b1ef2
commit 806f50bc2d
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
4 changed files with 143 additions and 179 deletions

5
.gitignore vendored
View File

@ -125,9 +125,4 @@ tempConv
extracted.json extracted.json
.phpunit.result.cache .phpunit.result.cache
src/danog/MadelineProto/VoIP.php
src/danog/MadelineProto/VoIP/AckHandler.php
src/danog/MadelineProto/VoIP/MessageHandler.php
src/danog/MadelineProto/OpusStream.php
ponyScripts ponyScripts

View File

@ -12,11 +12,20 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto; namespace danog\MadelineProto;
use Amp\Delayed;
use danog\MadelineProto\MTProto\PermAuthKey;
use danog\MadelineProto\Stream\Common\FileBufferedStream;
use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\Ogg\Ogg;
use danog\MadelineProto\VoIP\Endpoint;
use function Amp\File\open;
if (\extension_loaded('php-libtgvoip')) { if (\extension_loaded('php-libtgvoip')) {
return; return;
} }
class VoIP extends Tools class VoIP
{ {
use \danog\MadelineProto\VoIP\MessageHandler; use \danog\MadelineProto\VoIP\MessageHandler;
use \danog\MadelineProto\VoIP\AckHandler; use \danog\MadelineProto\VoIP\AckHandler;
@ -125,6 +134,16 @@ class VoIP extends Tools
private $outputFile; private $outputFile;
private $isPlaying = false; private $isPlaying = false;
private bool $creator;
private PermAuthKey $authKey;
private int $peerVersion;
/**
* @var Endpoint[]
*/
private array $sockets = [];
private $connection_settings = []; private $connection_settings = [];
private $dclist = []; private $dclist = [];
@ -191,13 +210,12 @@ class VoIP extends Tools
public function startTheMagic() public function startTheMagic()
{ {
while (true) { foreach ($this->sockets as $socket) {
$waiting = $this->datacenter->select(); Tools::callFork(function () use ($socket) {
foreach ($waiting as $dc) { while ($payload = $this->recv_message($socket)) {
if ($packet = $this->recv_message($dc)) { Tools::callFork($this->handlePacket($socket, $payload));
$this->handlePacket($dc, $packet);
}
} }
});
} }
return $this; return $this;
} }
@ -208,14 +226,31 @@ class VoIP extends Tools
case self::PKT_INIT: case self::PKT_INIT:
$this->voip_state = self::STATE_WAIT_INIT_ACK; $this->voip_state = self::STATE_WAIT_INIT_ACK;
$this->send_message(['_' => self::PKT_INIT_ACK, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'all_streams' => [['id' => 0, 'type' => self::STREAM_TYPE_AUDIO, 'codec' => self::CODEC_OPUS, 'frame_duration' => 60, 'enabled' => 1]]], $datacenter); $this->send_message(['_' => self::PKT_INIT_ACK, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'all_streams' => [['id' => 0, 'type' => self::STREAM_TYPE_AUDIO, 'codec' => self::CODEC_OPUS, 'frame_duration' => 60, 'enabled' => 1]]], $datacenter);
//$a = fopen('paloma.opus', 'rb');
//(new Ogg($a, [$this, 'oggCallback']))->run();
break; break;
case self::PKT_INIT_ACK: case self::PKT_INIT_ACK:
if ($this->voip_state !== self::STATE_ESTABLISHED) {
$this->voip_state = self::STATE_ESTABLISHED; $this->voip_state = self::STATE_ESTABLISHED;
$a = \fopen('paloma.opus', 'rb');
(new Ogg($a, [$this, 'oggCallback']))->run();
$ctx = new ConnectionContext;
$ctx->addStream(FileBufferedStream::class, yield open('kda.opus', 'r'));
$stream = yield from $ctx->getStream();
$ogg = yield from Ogg::init($stream, 60000);
$it = $ogg->getEmitter()->iterate();
Tools::callFork($ogg->read());
Tools::callFork(function () use ($it) {
$timestamp = 0;
$t = microtime(true);
while (yield $it->advance()) {
$elapsed = microtime(true) - $t;
$t = microtime(true);
yield new Delayed((int) (60000 - $elapsed / 1000));
yield $this->send_message(['_' => self::PKT_STREAM_DATA, 'stream_id' => 0, 'data' => $it->getCurrent(), 'timestamp' => $this->timestamp], $datacenter);
$timestamp += 60;
}
});
}
break; break;
} }
} }
@ -279,11 +314,6 @@ class VoIP extends Tools
return $this->callID; return $this->callID;
} }
public function isCreator()
{
return $this->creator;
}
public function whenCreated() public function whenCreated()
{ {
return isset($this->internalStorage['created']) ? $this->internalStorage['created'] : false; return isset($this->internalStorage['created']) ? $this->internalStorage['created'] : false;
@ -291,36 +321,16 @@ class VoIP extends Tools
public function parseConfig() public function parseConfig()
{ {
$this->authKey = new PermAuthKey();
$this->authKey->setAuthKey($this->configuration['auth_key']);
if (\count($this->configuration['endpoints'])) { if (\count($this->configuration['endpoints'])) {
$this->connection_settings['all'] = $this->MadelineProto->settings['connection_settings']['all'];
$this->connection_settings['all']['protocol'] = 'obfuscated2';
$this->connection_settings['all']['timeout'] = 1;
$this->connection_settings['all']['do_not_retry'] = true;
$test = $this->connection_settings['all']['test_mode'] ? 'test' : 'main';
foreach ($this->configuration['endpoints'] as $endpoint) { foreach ($this->configuration['endpoints'] as $endpoint) {
$this->dclist[$test]['ipv6'][$endpoint['id']] = ['ip_address' => $endpoint['ipv6'], 'port' => $endpoint['port'], 'peer_tag' => $endpoint['peer_tag']]; $this->sockets['v6 '.$endpoint['id']] = new Endpoint($endpoint['ipv6'], $endpoint['port'], $endpoint['peer_tag'], true, $this);
$this->dclist[$test]['ipv4'][$endpoint['id']] = ['ip_address' => $endpoint['ip'], 'port' => $endpoint['port'], 'peer_tag' => $endpoint['peer_tag']]; $this->sockets['v4 '.$endpoint['id']] = new Endpoint($endpoint['ip'], $endpoint['port'], $endpoint['peer_tag'], true, $this);
} }
if (!isset($this->datacenter)) { foreach ($this->sockets as $socket) {
$this->datacenter = new DataCenter($this->dclist, $this->connection_settings); yield from $socket->connect();
} }
//$this->datacenter->__construct($this->dclist, $this->connection_settings);
foreach ($this->datacenter->get_dcs() as $new_dc) {
try {
$this->datacenter->dc_connect($new_dc);
} catch (\danog\MadelineProto\Exception $e) {
}
}
$this->init_all();
foreach ($this->datacenter->get_dcs(false) as $new_dc) {
try {
$this->datacenter->dc_connect($new_dc);
} catch (\danog\MadelineProto\Exception $e) {
}
}
$this->init_all();
} }
} }
@ -328,29 +338,8 @@ class VoIP extends Tools
{ {
$test = $this->connection_settings['all']['test_mode'] ? 'test' : 'main'; $test = $this->connection_settings['all']['test_mode'] ? 'test' : 'main';
foreach ($this->datacenter->sockets as $dc_id => $socket) { foreach ($this->datacenter->sockets as $dc_id => $socket) {
if ($socket->auth_key === null) { $this->send_message(['_' => self::PKT_INIT, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'audio_streams' => [self::CODEC_OPUS], 'video_streams' => []], $socket);
$socket->auth_key = ['id' => $this->configuration['auth_key_id'], 'auth_key' => $this->configuration['auth_key'], 'connection_inited' => false];
}
if ($socket->type === Connection::API_ENDPOINT) {
$socket->type = Connection::VOIP_TCP_REFLECTOR_ENDPOINT;
}
if ($socket->peer_tag === null) {
switch ($socket->type) {
case Connection::VOIP_TCP_REFLECTOR_ENDPOINT:
case Connection::VOIP_UDP_REFLECTOR_ENDPOINT:
$socket->peer_tag = $this->dclist[$test]['ipv4'][$dc_id]['peer_tag'];
break;
default:
$socket->peer_tag = $this->configuration['call_id'];
}
}
//if ($this->voip_state === self::STATE_CREATED) {
$this->send_message(['_' => self::PKT_INIT, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'audio_streams' => [self::CODEC_OPUS], 'video_streams' => []], $dc_id);
$this->voip_state = self::STATE_WAIT_INIT; $this->voip_state = self::STATE_WAIT_INIT;
//}
if (isset($this->datacenter->sockets[$dc_id])) {
$this->send_message(['_' => self::PKT_PING], $dc_id);
}
} }
} }
@ -383,4 +372,34 @@ class VoIP extends Tools
{ {
return $this->signal; return $this->signal;
} }
/**
* Get the value of creator.
*
* @return bool
*/
public function isCreator(): bool
{
return $this->creator;
}
/**
* Get the value of authKey.
*
* @return PermAuthKey
*/
public function getAuthKey(): PermAuthKey
{
return $this->authKey;
}
/**
* Get the value of peerVersion.
*
* @return int
*/
public function getPeerVersion(): int
{
return $this->peerVersion;
}
} }

View File

@ -19,7 +19,7 @@ trait AckHandler
{ {
return $s1 > $s2; return $s1 > $s2;
} }
public function received_packet($datacenter, $last_ack_id, $packet_seq_no, $ack_mask) public function received_packet($last_ack_id, $packet_seq_no, $ack_mask)
{ {
if ($this->seqgt($packet_seq_no, $this->session_in_seq_no)) { if ($this->seqgt($packet_seq_no, $this->session_in_seq_no)) {
$diff = $packet_seq_no - $this->session_in_seq_no; $diff = $packet_seq_no - $this->session_in_seq_no;

View File

@ -13,6 +13,9 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto\VoIP; namespace danog\MadelineProto\VoIP;
use danog\MadelineProto\TL\Exception;
use danog\MadelineProto\Tools;
/** /**
* Manages packing and unpacking of messages, and the list of sent and received messages. * Manages packing and unpacking of messages, and the list of sent and received messages.
*/ */
@ -28,7 +31,7 @@ trait MessageHandler
$concat .= \pack('@'.$this->posmod(-$l - 1, 4)); $concat .= \pack('@'.$this->posmod(-$l - 1, 4));
} else { } else {
$concat .= \chr(254); $concat .= \chr(254);
$concat .= \substr($this->pack_signed_int($l), 0, 3); $concat .= \substr(Tools::packSignedInt($l), 0, 3);
$concat .= $object; $concat .= $object;
$concat .= \pack('@'.$this->posmod(-$l, 4)); $concat .= \pack('@'.$this->posmod(-$l, 4));
} }
@ -60,7 +63,7 @@ trait MessageHandler
public function send_message($args, $datacenter = null) public function send_message($args, $datacenter = null)
{ {
if ($datacenter === null) { if ($datacenter === null) {
return $this->send_message($args, \key($this->datacenter->sockets)); return $this->send_message($args, \reset($this->sockets));
} }
$message = ''; $message = '';
switch ($args['_']) { switch ($args['_']) {
@ -68,11 +71,11 @@ trait MessageHandler
// //
// packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet; // packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet;
case \danog\MadelineProto\VoIP::PKT_INIT: case \danog\MadelineProto\VoIP::PKT_INIT:
$message .= $this->pack_signed_int($args['protocol']); $message .= Tools::packSignedInt($args['protocol']);
$message .= $this->pack_signed_int($args['min_protocol']); $message .= Tools::packSignedInt($args['min_protocol']);
$flags = 0; $flags = 0;
$flags = isset($args['data_saving_enabled']) && $args['data_saving_enabled'] ? $flags | 1 : $flags & ~1; $flags = isset($args['data_saving_enabled']) && $args['data_saving_enabled'] ? $flags | 1 : $flags & ~1;
$message .= $this->pack_unsigned_int($flags); $message .= Tools::packUnsignedInt($flags);
$message .= \chr(\count($args['audio_streams'])); $message .= \chr(\count($args['audio_streams']));
foreach ($args['audio_streams'] as $codec) { foreach ($args['audio_streams'] as $codec) {
$message .= \chr($codec); $message .= \chr($codec);
@ -86,8 +89,8 @@ trait MessageHandler
// //
// packetInitAck#2 protocol:int min_protocol:int all_streams:byteVector<streamType> = Packet; // packetInitAck#2 protocol:int min_protocol:int all_streams:byteVector<streamType> = Packet;
case \danog\MadelineProto\VoIP::PKT_INIT_ACK: case \danog\MadelineProto\VoIP::PKT_INIT_ACK:
$message .= $this->pack_signed_int($args['protocol']); $message .= Tools::packSignedInt($args['protocol']);
$message .= $this->pack_signed_int($args['min_protocol']); $message .= Tools::packSignedInt($args['min_protocol']);
$message .= \chr(\count($args['all_streams'])); $message .= \chr(\count($args['all_streams']));
foreach ($args['all_streams'] as $stream) { foreach ($args['all_streams'] as $stream) {
$message .= \chr($stream['id']); $message .= \chr($stream['id']);
@ -114,7 +117,7 @@ trait MessageHandler
$flags = $flags | $args['stream_id']; $flags = $flags | $args['stream_id'];
$message .= \chr($flags); $message .= \chr($flags);
$message .= $length > 255 ? \pack('v', $length) : \chr($length); $message .= $length > 255 ? \pack('v', $length) : \chr($length);
$message .= $this->pack_unsigned_int($args['timestamp']); $message .= Tools::packUnsignedInt($args['timestamp']);
$message .= $args['data']; $message .= $args['data'];
break; break;
/*case \danog\MadelineProto\VoIP::PKT_UPDATE_STREAMS: /*case \danog\MadelineProto\VoIP::PKT_UPDATE_STREAMS:
@ -122,7 +125,7 @@ trait MessageHandler
case \danog\MadelineProto\VoIP::PKT_PING: case \danog\MadelineProto\VoIP::PKT_PING:
break;*/ break;*/
case \danog\MadelineProto\VoIP::PKT_PONG: case \danog\MadelineProto\VoIP::PKT_PONG:
$message .= $this->pack_unsigned_int($args['out_seq_no']); $message .= Tools::packUnsignedInt($args['out_seq_no']);
break; break;
case \danog\MadelineProto\VoIP::PKT_STREAM_DATA_X2: case \danog\MadelineProto\VoIP::PKT_STREAM_DATA_X2:
for ($x = 0; $x < 2; $x++) { for ($x = 0; $x < 2; $x++) {
@ -134,7 +137,7 @@ trait MessageHandler
$flags = $flags | $args[$x]['stream_id']; $flags = $flags | $args[$x]['stream_id'];
$message .= \chr($flags); $message .= \chr($flags);
$message .= $length > 255 ? \pack('v', $length) : \chr($length); $message .= $length > 255 ? \pack('v', $length) : \chr($length);
$message .= $this->pack_unsigned_int($args[$x]['timestamp']); $message .= Tools::packUnsignedInt($args[$x]['timestamp']);
$message .= $args[$x]['data']; $message .= $args[$x]['data'];
} }
break; break;
@ -148,22 +151,22 @@ trait MessageHandler
$flags = $flags | $args[$x]['stream_id']; $flags = $flags | $args[$x]['stream_id'];
$message .= \chr($flags); $message .= \chr($flags);
$message .= $length > 255 ? \pack('v', $length) : \chr($length); $message .= $length > 255 ? \pack('v', $length) : \chr($length);
$message .= $this->pack_unsigned_int($args[$x]['timestamp']); $message .= Tools::packUnsignedInt($args[$x]['timestamp']);
$message .= $args[$x]['data']; $message .= $args[$x]['data'];
} }
break; break;
// packetLanEndpoint#A address:int port:int = Packet; // packetLanEndpoint#A address:int port:int = Packet;
case \danog\MadelineProto\VoIP::PKT_LAN_ENDPOINT: case \danog\MadelineProto\VoIP::PKT_LAN_ENDPOINT:
$message .= $this->pack_signed_int($args['address']); $message .= Tools::packSignedInt($args['address']);
$message .= $this->pack_signed_int($args['port']); $message .= Tools::packSignedInt($args['port']);
break; break;
// packetNetworkChanged#B flags:# data_saving_enabled:flags.0?true = Packet; // packetNetworkChanged#B flags:# data_saving_enabled:flags.0?true = Packet;
case \danog\MadelineProto\VoIP::PKT_NETWORK_CHANGED: case \danog\MadelineProto\VoIP::PKT_NETWORK_CHANGED:
$message .= $this->pack_signed_int(isset($args['data_saving_enabled']) && $args['data_saving_enabled'] ? 1 : 0); $message .= Tools::packSignedInt(isset($args['data_saving_enabled']) && $args['data_saving_enabled'] ? 1 : 0);
break; break;
// packetSwitchPreferredRelay#C relay_id:long = Packet; // packetSwitchPreferredRelay#C relay_id:long = Packet;
case \danog\MadelineProto\VoIP::PKT_SWITCH_PREF_RELAY: case \danog\MadelineProto\VoIP::PKT_SWITCH_PREF_RELAY:
$message .= $this->pack_signed_long($args['relay_d']); $message .= Tools::packSignedLong($args['relay_d']);
break; break;
/*case \danog\MadelineProto\VoIP::PKT_SWITCH_TO_P2P: /*case \danog\MadelineProto\VoIP::PKT_SWITCH_TO_P2P:
break; break;
@ -194,11 +197,11 @@ trait MessageHandler
$flags = isset($args['extra']) ? $flags | 2 : $flags & ~2; // extra $flags = isset($args['extra']) ? $flags | 2 : $flags & ~2; // extra
$flags = \strlen($message) ? $flags | 1 : $flags & ~1; // raw_data $flags = \strlen($message) ? $flags | 1 : $flags & ~1; // raw_data
$flags = $flags | ($args['_'] << 24); $flags = $flags | ($args['_'] << 24);
$payload .= $this->pack_unsigned_int($flags); $payload .= Tools::packUnsignedInt($flags);
$payload .= $this->configuration['call_id']; $payload .= $this->configuration['call_id'];
$payload .= $this->pack_unsigned_int($this->session_in_seq_no); $payload .= Tools::packUnsignedInt($this->session_in_seq_no);
$payload .= $this->pack_unsigned_int($this->session_out_seq_no); $payload .= Tools::packUnsignedInt($this->session_out_seq_no);
$payload .= $this->pack_unsigned_int($ack_mask); $payload .= Tools::packUnsignedInt($ack_mask);
$payload .= \danog\MadelineProto\VoIP::PROTO_ID; $payload .= \danog\MadelineProto\VoIP::PROTO_ID;
if ($flags & 2) { if ($flags & 2) {
$payload .= $this->pack_string($args['extra']); $payload .= $this->pack_string($args['extra']);
@ -211,76 +214,23 @@ trait MessageHandler
$payload .= $this->random(8); $payload .= $this->random(8);
$payload .= \chr(7); $payload .= \chr(7);
$payload .= $this->random(7); $payload .= $this->random(7);
$message = \chr($args['_']).$this->pack_unsigned_int($this->session_in_seq_no).$this->pack_unsigned_int($this->session_out_seq_no).$this->pack_unsigned_int($ack_mask).$message; $message = \chr($args['_']).Tools::packUnsignedInt($this->session_in_seq_no).Tools::packUnsignedInt($this->session_out_seq_no).Tools::packUnsignedInt($ack_mask).$message;
$payload .= $this->pack_string($message); $payload .= $this->pack_string($message);
} }
$this->session_out_seq_no++; $this->session_out_seq_no++;
$payload = $this->pack_unsigned_int(\strlen($payload)).$payload; return $datacenter->write($payload);
$payload_key = \substr(\sha1($payload, true), -16);
list($aes_key, $aes_iv) = $this->old_aes_calculate($payload_key, $this->datacenter->sockets[$datacenter]->auth_key['auth_key'], $this->creator);
$payload .= $this->random($this->posmod(-\strlen($payload), 16));
$payload = $this->datacenter->sockets[$datacenter]->peer_tag.$this->datacenter->sockets[$datacenter]->auth_key['id'].$payload_key.$this->ige_encrypt($payload, $aes_key, $aes_iv);
try {
$this->datacenter->sockets[$datacenter]->send_message($payload);
} catch (\danog\MadelineProto\Exception $e) {
unset($this->datacenter->sockets[$datacenter]);
}
} }
/** /**
* Reading connection and receiving message from server. * Reading connection and receiving message from server.
*/ */
public function recv_message($datacenter) public function recv_message(Endpoint $endpoint)
{ {
$payload = \fopen('php://memory', 'rw+b'); if (!$payload = yield from $endpoint->read()) {
\fwrite($payload, $this->datacenter->sockets[$datacenter]->read_message()); return null;
\fseek($payload, 0);
if (\stream_get_contents($payload, 16) !== $this->datacenter->sockets[$datacenter]->peer_tag) {
\danog\MadelineProto\Logger::log("Received packet has wrong peer tag", \danog\MadelineProto\Logger::ERROR);
return false;
} }
if (\stream_get_contents($payload, 12) === "\0\0\0\0\0\0\0\0\0\0\0\0") {
$payload = \stream_get_contents($payload);
} else {
\fseek($payload, 16);
if (\stream_get_contents($payload, 8) !== $this->datacenter->sockets[$datacenter]->auth_key['id']) {
\danog\MadelineProto\Logger::log('Wrong auth key ID', \danog\MadelineProto\Logger::ERROR);
return false;
}
$message_key = \stream_get_contents($payload, 16);
list($aes_key, $aes_iv) = $this->old_aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->auth_key['auth_key'], !$this->creator);
$encrypted_data = \stream_get_contents($payload);
if (\strlen($encrypted_data) % 16 != 0) {
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16'], \danog\MadelineProto\Logger::ERROR);
}
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
$message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1];
$payload = \substr($decrypted_data, 4, $message_data_length);
if ($message_data_length > \strlen($decrypted_data)) {
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big'], \danog\MadelineProto\Logger::ERROR);
return false;
}
if ($message_key != \substr(\sha1(\substr($decrypted_data, 0, 4 + $message_data_length), true), -16)) {
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch'], \danog\MadelineProto\Logger::ERROR);
return false;
}
if (\strlen($decrypted_data) - 4 - $message_data_length > 15) {
\danog\MadelineProto\Logger::log('difference between message_data_length and the length of the remaining decrypted buffer is too big', \danog\MadelineProto\Logger::ERROR);
}
if (\strlen($decrypted_data) % 16 != 0) {
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['length_not_divisible_16'], \danog\MadelineProto\Logger::ERROR);
}
}
$stream = \fopen('php://memory', 'rw+b');
\fwrite($stream, $payload);
$payload = $stream;
\fseek($payload, 0);
$result = []; $result = [];
switch ($crc = \stream_get_contents($payload, 4)) { switch ($crc = \stream_get_contents($payload, 4)) {
@ -296,25 +246,25 @@ trait MessageHandler
} }
} }
if ($flags & 16) { if ($flags & 16) {
$in_seq_no = \unpack('V', \stream_get_contents($stream, 4))[1]; $in_seq_no = \unpack('V', \stream_get_contents($payload, 4))[1];
$out_seq_no = \unpack('V', \stream_get_contents($stream, 4))[1]; $out_seq_no = \unpack('V', \stream_get_contents($payload, 4))[1];
} }
if ($flags & 32) { if ($flags & 32) {
$ack_mask = \unpack('V', \stream_get_contents($stream, 4))[1]; $ack_mask = \unpack('V', \stream_get_contents($payload, 4))[1];
} }
if ($flags & 8) { if ($flags & 8) {
if (\stream_get_contents($stream, 4) !== \danog\MadelineProto\VoIP::PROTO_ID) { if (\stream_get_contents($payload, 4) !== \danog\MadelineProto\VoIP::PROTO_ID) {
\danog\MadelineProto\Logger::log('Protocol mismatch', \danog\MadelineProto\Logger::ERROR); \danog\MadelineProto\Logger::log('Protocol mismatch', \danog\MadelineProto\Logger::ERROR);
return false; return false;
} }
} }
if ($flags & 2) { if ($flags & 2) {
$result['extra'] = $this->unpack_string($stream); $result['extra'] = $this->unpack_string($payload);
} }
$message = \fopen('php://memory', 'rw+b'); $message = \fopen('php://memory', 'rw+b');
if ($flags & 1) { if ($flags & 1) {
\fwrite($message, $this->unpack_string($stream)); \fwrite($message, $this->unpack_string($payload));
\fseek($message, 0); \fseek($message, 0);
} }
break; break;
@ -324,7 +274,7 @@ trait MessageHandler
$flags = \unpack('V', \stream_get_contents($payload, 4))[1]; $flags = \unpack('V', \stream_get_contents($payload, 4))[1];
$message = \fopen('php://memory', 'rw+b'); $message = \fopen('php://memory', 'rw+b');
\fwrite($message, $this->unpack_string($stream)); \fwrite($message, $this->unpack_string($payload));
\fseek($message, 0); \fseek($message, 0);
$result['_'] = \ord(\stream_get_contents($message, 1)); $result['_'] = \ord(\stream_get_contents($message, 1));
$in_seq_no = \unpack('V', \stream_get_contents($message, 4))[1]; $in_seq_no = \unpack('V', \stream_get_contents($message, 4))[1];
@ -333,22 +283,22 @@ trait MessageHandler
break; break;
case $this->TLID_REFLECTOR_SELF_INFO: case $this->TLID_REFLECTOR_SELF_INFO:
$result['date'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['date'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
$result['query_id'] = $this->unpack_signed_long(\stream_get_contents($payload, 8)); $result['query_id'] = Tools::unpackSignedLong(\stream_get_contents($payload, 8));
$result['my_ip'] = \stream_get_contents($payload, 16); $result['my_ip'] = \stream_get_contents($payload, 16);
$result['my_port'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['my_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
return $result; return $result;
case $this->TLID_REFLECTOR_PEER_INFO: case $this->TLID_REFLECTOR_PEER_INFO:
$result['my_address'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['my_address'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
$result['my_port'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['my_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
$result['peer_address'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['peer_address'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
$result['peer_port'] = $this->unpack_signed_int(\stream_get_contents($payload, 4)); $result['peer_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
return $result; return $result;
default: default:
\danog\MadelineProto\Logger::log('Unknown packet received: '.\bin2hex($crc), \danog\MadelineProto\Logger::ERROR); \danog\MadelineProto\Logger::log('Unknown packet received: '.\bin2hex($crc), \danog\MadelineProto\Logger::ERROR);
return false; return false;
} }
if (!$this->received_packet($datacenter, $in_seq_no, $out_seq_no, $ack_mask)) { if (!$this->received_packet($in_seq_no, $out_seq_no, $ack_mask)) {
return false; return false;
} }
switch ($result['_']) { switch ($result['_']) {
@ -356,8 +306,8 @@ trait MessageHandler
// //
// packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet; // packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet;
case \danog\MadelineProto\VoIP::PKT_INIT: case \danog\MadelineProto\VoIP::PKT_INIT:
$result['protocol'] = $this->unpack_signed_int(\stream_get_contents($message, 4)); $result['protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$result['min_protocol'] = $this->unpack_signed_int(\stream_get_contents($message, 4)); $result['min_protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$flags = \unpack('V', \stream_get_contents($message, 4))[1]; $flags = \unpack('V', \stream_get_contents($message, 4))[1];
$result['data_saving_enabled'] = (bool) ($flags & 1); $result['data_saving_enabled'] = (bool) ($flags & 1);
$result['audio_streams'] = []; $result['audio_streams'] = [];
@ -375,8 +325,8 @@ trait MessageHandler
// //
// packetInitAck#2 protocol:int min_protocol:int all_streams:byteVector<streamType> = Packet; // packetInitAck#2 protocol:int min_protocol:int all_streams:byteVector<streamType> = Packet;
case \danog\MadelineProto\VoIP::PKT_INIT_ACK: case \danog\MadelineProto\VoIP::PKT_INIT_ACK:
$result['protocol'] = $this->unpack_signed_int(\stream_get_contents($message, 4)); $result['protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$result['min_protocol'] = $this->unpack_signed_int(\stream_get_contents($message, 4)); $result['min_protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$result['all_streams'] = []; $result['all_streams'] = [];
$length = \ord(\stream_get_contents($message, 1)); $length = \ord(\stream_get_contents($message, 1));
for ($x = 0; $x < $length; $x++) { for ($x = 0; $x < $length; $x++) {
@ -410,8 +360,8 @@ trait MessageHandler
case \danog\MadelineProto\VoIP::PKT_PING: case \danog\MadelineProto\VoIP::PKT_PING:
break;*/ break;*/
case \danog\MadelineProto\VoIP::PKT_PONG: case \danog\MadelineProto\VoIP::PKT_PONG:
if (\fstat($stream)['size'] - \ftell($stream)) { if (\fstat($payload)['size'] - \ftell($payload)) {
$result['out_seq_no'] = \unpack('V', \stream_get_contents($stream, 4))[1]; $result['out_seq_no'] = \unpack('V', \stream_get_contents($payload, 4))[1];
} }
break; break;
case \danog\MadelineProto\VoIP::PKT_STREAM_DATA_X2: case \danog\MadelineProto\VoIP::PKT_STREAM_DATA_X2:
@ -438,16 +388,16 @@ trait MessageHandler
break; break;
// packetLanEndpoint#A address:int port:int = Packet; // packetLanEndpoint#A address:int port:int = Packet;
case \danog\MadelineProto\VoIP::PKT_LAN_ENDPOINT: case \danog\MadelineProto\VoIP::PKT_LAN_ENDPOINT:
$result['address'] = \unpack('V', \stream_get_contents($stream, 4))[1]; $result['address'] = \unpack('V', \stream_get_contents($payload, 4))[1];
$result['port'] = \unpack('V', \stream_get_contents($stream, 4))[1]; $result['port'] = \unpack('V', \stream_get_contents($payload, 4))[1];
break; break;
// packetNetworkChanged#B flags:# data_saving_enabled:flags.0?true = Packet; // packetNetworkChanged#B flags:# data_saving_enabled:flags.0?true = Packet;
case \danog\MadelineProto\VoIP::PKT_NETWORK_CHANGED: case \danog\MadelineProto\VoIP::PKT_NETWORK_CHANGED:
$result['data_saving_enabled'] = (bool) (\unpack('V', \stream_get_contents($stream, 4))[1] & 1); $result['data_saving_enabled'] = (bool) (\unpack('V', \stream_get_contents($payload, 4))[1] & 1);
break; break;
// packetSwitchPreferredRelay#C relay_id:long = Packet; // packetSwitchPreferredRelay#C relay_id:long = Packet;
case \danog\MadelineProto\VoIP::PKT_SWITCH_PREF_RELAY: case \danog\MadelineProto\VoIP::PKT_SWITCH_PREF_RELAY:
$result['relay_id'] = $this->unpack_signed_long(\stream_get_contents($stream, 8)); $result['relay_id'] = Tools::unpackSignedLong(\stream_get_contents($payload, 8));
break; break;
/*case \danog\MadelineProto\VoIP::PKT_SWITCH_TO_P2P: /*case \danog\MadelineProto\VoIP::PKT_SWITCH_TO_P2P:
break; break;