Starting to handle acks
This commit is contained in:
parent
a9ba7a659e
commit
e8ba8feb92
@ -11,7 +11,8 @@
|
||||
"phpseclib/phpseclib": "^2.0",
|
||||
"paragonie/constant_time_encoding": "^1|^2",
|
||||
"paragonie/random_compat": "^2.0",
|
||||
"php": ">=5.6.0"
|
||||
"php": ">=5.6.0",
|
||||
"icicleio/icicle": "^0.9.6"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
70
composer.lock
generated
70
composer.lock
generated
@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "8d6fcaae1bc321e5d42b8b4749ea4266",
|
||||
"content-hash": "d004c37ebd93efd29d86d09824fdd71b",
|
||||
"hash": "966d0bc73f86b42249ee2a37fea56e64",
|
||||
"content-hash": "c5463d805ceb0061da4eca7c688a973e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "danog/phpstruct",
|
||||
@ -55,6 +55,72 @@
|
||||
],
|
||||
"time": "2016-08-14 17:51:55"
|
||||
},
|
||||
{
|
||||
"name": "icicleio/icicle",
|
||||
"version": "v0.9.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icicleio/icicle.git",
|
||||
"reference": "84a3cc6f7dc38500f4ed9bdae79f458d191cb119"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icicleio/icicle/zipball/84a3cc6f7dc38500f4ed9bdae79f458d191cb119",
|
||||
"reference": "84a3cc6f7dc38500f4ed9bdae79f458d191cb119",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ev": "Provides an event loop with better performance.",
|
||||
"ext-pcntl": "Enables custom signal handling."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Icicle\\": "src"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php",
|
||||
"src/Awaitable/functions.php",
|
||||
"src/Coroutine/functions.php",
|
||||
"src/Loop/functions.php",
|
||||
"src/Observable/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aaron Piotrowski",
|
||||
"email": "aaron@icicle.io"
|
||||
}
|
||||
],
|
||||
"description": "Icicle is a PHP library for writing asynchronous code using synchronous coding techniques.",
|
||||
"homepage": "http://icicle.io",
|
||||
"keywords": [
|
||||
"Socket",
|
||||
"async",
|
||||
"asynchronous",
|
||||
"awaitable",
|
||||
"coroutine",
|
||||
"event",
|
||||
"generator",
|
||||
"interruptible",
|
||||
"multitasking",
|
||||
"network",
|
||||
"promise",
|
||||
"server",
|
||||
"stream"
|
||||
],
|
||||
"time": "2016-03-31 16:34:26"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v2.0.3",
|
||||
|
@ -92,7 +92,10 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
|
||||
$this->seq_no = 0;
|
||||
$this->timedelta = 0; // time delta
|
||||
$this->message_ids = [];
|
||||
$this->incoming_message_ids = [];
|
||||
$this->outgoing_message_ids = [];
|
||||
$this->ack_incoming_message_ids = [];
|
||||
$this->ack_outgoing_message_ids = [];
|
||||
|
||||
if ($this->settings['authorization']['temp_auth_key'] == null || $this->settings['authorization']['auth_key'] == null) {
|
||||
if ($this->settings['authorization']['auth_key'] == null) {
|
||||
@ -107,7 +110,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
unset($this->sock);
|
||||
}
|
||||
|
||||
public function check_message_id($new_message_id, $from_client)
|
||||
public function check_message_id($new_message_id, $outgoing)
|
||||
{
|
||||
$new_message_id = $this->struct->unpack('<Q', $new_message_id)[0];
|
||||
if (((int) ((time() + $this->timedelta - 300) * pow(2, 30)) * 4) > $new_message_id) {
|
||||
@ -116,23 +119,57 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
if (((int) ((time() + $this->timedelta + 30) * pow(2, 30)) * 4) < $new_message_id) {
|
||||
throw new Exception('Given message id is too new.');
|
||||
}
|
||||
if ($from_client) {
|
||||
if ($outgoing) {
|
||||
if ($new_message_id % 4 != 0) {
|
||||
throw new Exception('Given message id is not divisible by 4.');
|
||||
}
|
||||
} else {
|
||||
if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) {
|
||||
throw new Exception('message id mod 4 != 1 or 3');
|
||||
}
|
||||
foreach ($this->message_ids as $message_id) {
|
||||
foreach ($this->outgoing_message_ids as $message_id) {
|
||||
if ($new_message_id <= $message_id) {
|
||||
throw new Exception('Given message id is lower than or equal than the current limit ('.$message_id.').');
|
||||
}
|
||||
}
|
||||
$this->message_ids[] = $new_message_id;
|
||||
if (count($this->message_ids) > $this->settings['authorization']['message_ids_limit']) {
|
||||
array_shift($this->message_ids);
|
||||
$this->outgoing_message_ids[] = $new_message_id;
|
||||
if (count($this->outgoing_message_ids) > $this->settings['authorization']['message_ids_limit']) {
|
||||
array_shift($this->outgoing_message_ids);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) {
|
||||
throw new Exception('message id mod 4 != 1 or 3');
|
||||
}
|
||||
foreach ($this->incoming_message_ids as $message_id) {
|
||||
if ($new_message_id <= $message_id) {
|
||||
throw new Exception('Given message id is lower than or equal than the current limit ('.$message_id.').');
|
||||
}
|
||||
}
|
||||
$this->incoming_message_ids[] = $new_message_id;
|
||||
if (count($this->incoming_message_ids) > $this->settings['authorization']['message_ids_limit']) {
|
||||
array_shift($this->incoming_message_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function ack_outgoing_message_id($message_id) {
|
||||
$message_id = $this->struct->unpack('<Q', $message_id)[0];
|
||||
// The server acknowledges that it received my message
|
||||
if (!in_array($message_id, $this->outgoing_message_ids)) {
|
||||
throw new Exception("Couldn't find message id ".$message_id." in the array of outgoing message ids. Maybe try to increase its size?");
|
||||
}
|
||||
$this->ack_outgoing_message_ids[] = $message_id;
|
||||
if (count($this->ack_outgoing_message_ids) > $this->settings['authorization']['message_ids_limit']) {
|
||||
array_shift($this->ack_outgoing_message_ids);
|
||||
}
|
||||
}
|
||||
public function ack_incoming_message_id($message_id) {
|
||||
$message_id = $this->struct->unpack('<Q', $message_id)[0];
|
||||
// I let the server know that I received its message
|
||||
if (!in_array($message_id, $this->incoming_message_ids)) {
|
||||
throw new Exception("Couldn't find message id ".$message_id." in the array of incoming message ids. Maybe try to increase its size?");
|
||||
}
|
||||
$this->object_call('msgs_ack', ['msg_ids' => [$message_id]]);
|
||||
$this->ack_incoming_message_ids[] = $message_id;
|
||||
if (count($this->ack_incoming_message_ids) > $this->settings['authorization']['message_ids_limit']) {
|
||||
array_shift($this->ack_incoming_message_ids);
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,10 +183,6 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
return ($value * 2) + $in;
|
||||
}
|
||||
|
||||
public function acknowledge($msg_id)
|
||||
{
|
||||
return $this->object_call('msgs_ack', ['msg_ids' => [$msg_id]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forming the message frame and sending message to server
|
||||
@ -161,6 +194,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
$this->check_message_id($message_id, true);
|
||||
if (($this->settings['authorization']['temp_auth_key']['auth_key'] == null) || ($this->settings['authorization']['temp_auth_key']['server_salt'] == null)) {
|
||||
$message = Tools::string2bin('\x00\x00\x00\x00\x00\x00\x00\x00').$message_id.$this->struct->pack('<I', strlen($message_data)).$message_data;
|
||||
$this->last_sent = ["message_id" => $message_id];
|
||||
} else {
|
||||
$seq_no = $this->generate_seq_no($content_related);
|
||||
$encrypted_data = $this->settings['authorization']['temp_auth_key']['server_salt'].$this->settings['authorization']['session_id'].$message_id.$this->struct->pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
@ -168,6 +202,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
$padding = \phpseclib\Crypt\Random::string(Tools::posmod(-strlen($encrypted_data), 16));
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key);
|
||||
$message = $this->settings['authorization']['temp_auth_key']['id'].$message_key.Crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv);
|
||||
$this->last_sent = ["message_id" => $message_id, "seq_no" => $seq_no];
|
||||
}
|
||||
$this->sock->send_message($message);
|
||||
}
|
||||
@ -186,6 +221,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
list($message_id, $message_length) = $this->struct->unpack('<8sI', fread($payload, 12));
|
||||
$this->check_message_id($message_id, false);
|
||||
$message_data = fread($payload, $message_length);
|
||||
$this->last_received = ["message_id" => $message_id];
|
||||
} elseif ($auth_key_id == $this->settings['authorization']['temp_auth_key']['id']) {
|
||||
$message_key = fread($payload, 16);
|
||||
$encrypted_data = stream_get_contents($payload);
|
||||
@ -230,19 +266,18 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
if ($message_key != substr(sha1(substr($decrypted_data, 0, 32 + $message_data_length), true), -16)) {
|
||||
throw new Exception('msg_key mismatch');
|
||||
}
|
||||
//$this->acknowledge($message_id);
|
||||
$this->last_received = ["message_id" => $message_id, "seq_no" => $seq_no];
|
||||
} else {
|
||||
throw new Exception('Got unknown auth_key id');
|
||||
}
|
||||
|
||||
return $message_data;
|
||||
}
|
||||
|
||||
public function method_call($method, $kwargs)
|
||||
public function method_call($method, $args)
|
||||
{
|
||||
foreach (range(1, $this->settings['max_tries']['query']) as $i) {
|
||||
try {
|
||||
$this->send_message($this->tl->serialize_method($method, $kwargs), $this->tl->content_related($method));
|
||||
$this->send_message($this->tl->serialize_method($method, $args), $this->tl->content_related($method));
|
||||
$server_answer = $this->recv_message();
|
||||
} catch (Exception $e) {
|
||||
$this->log->log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().'. Recreating connection and retrying to call method...');
|
||||
@ -254,10 +289,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
throw new Exception('An error occurred while calling method '.$method.'.');
|
||||
}
|
||||
$deserialized = $this->tl->deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $server_answer));
|
||||
switch ($deserialized["_"]) {
|
||||
|
||||
}
|
||||
return $deserialized;
|
||||
return $this->handle_response($deserialized, $method, $args);
|
||||
}
|
||||
throw new Exception('An error occurred while calling method '.$method.'.');
|
||||
}
|
||||
@ -282,6 +314,46 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
}
|
||||
throw new Exception('An error occurred while calling object '.$object.'.');
|
||||
}
|
||||
public function handle_response($response, $name, $args) {
|
||||
switch ($response["_"]) {
|
||||
case "rpc_result":
|
||||
$this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response
|
||||
$this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received my
|
||||
|
||||
return $this->handle_response($response, $name, $args);
|
||||
break;
|
||||
case "rpc_error":
|
||||
throw new Exception("Got rpc error " . $response["error_code"] . ": " . $response["error_message"]);
|
||||
break;
|
||||
case "rpc_answer_unknown":
|
||||
$this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message
|
||||
return $response; // I'm not handling this error
|
||||
break;
|
||||
case "rpc_answer_dropped_running":
|
||||
$this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response
|
||||
$this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message
|
||||
|
||||
$this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received the original query (the same one, the response to which we wish to forget)
|
||||
return $response; // I'm not handling this
|
||||
break;
|
||||
case "rpc_answer_dropped":
|
||||
$this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response
|
||||
$this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message
|
||||
|
||||
$this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received the original query (the same one, the response to which we wish to forget)
|
||||
return $response; // I'm not handling this
|
||||
break;
|
||||
case "future_salts":
|
||||
$this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message
|
||||
|
||||
break;
|
||||
default:
|
||||
$this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response
|
||||
return $response;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function create_auth_key($expires_in = -1)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user