This repository has been archived on 2020-05-25. You can view files and clone it, but cannot push or open issues or pull requests.
tdlib-fork/td/mtproto/RawConnection.cpp
Arseny Smirnov c02d4505e4 0xdd transport
GitOrigin-RevId: 241c2fcea3ebaac20fc68531692cbd299a9de95a
2018-06-15 21:54:22 +03:00

134 lines
4.3 KiB
C++

//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/mtproto/RawConnection.h"
#include "td/mtproto/AuthKey.h"
#include "td/mtproto/Transport.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <utility>
namespace td {
namespace mtproto {
void RawConnection::send_crypto(const Storer &storer, int64 session_id, int64 salt, const AuthKey &auth_key,
uint64 quick_ack_token) {
mtproto::PacketInfo info;
info.version = 2;
info.no_crypto_flag = false;
info.salt = salt;
info.session_id = session_id;
auto packet = BufferWriter{mtproto::Transport::write(storer, auth_key, &info), transport_->max_prepend_size(),
transport_->max_append_size()};
mtproto::Transport::write(storer, auth_key, &info, packet.as_slice());
bool use_quick_ack = false;
if (quick_ack_token != 0 && transport_->support_quick_ack()) {
auto tmp = quick_ack_to_token_.insert(std::make_pair(info.message_ack, quick_ack_token));
if (tmp.second) {
use_quick_ack = true;
} else {
LOG(ERROR) << "quick_ack collision " << tag("quick_ack", info.message_ack);
}
}
transport_->write(std::move(packet), use_quick_ack);
}
uint64 RawConnection::send_no_crypto(const Storer &storer) {
mtproto::PacketInfo info;
info.no_crypto_flag = true;
auto packet = BufferWriter{mtproto::Transport::write(storer, mtproto::AuthKey(), &info),
transport_->max_prepend_size(), transport_->max_append_size()};
mtproto::Transport::write(storer, mtproto::AuthKey(), &info, packet.as_slice());
LOG(INFO) << "Send handshake packet: " << format::as_hex_dump<4>(packet.as_slice());
transport_->write(std::move(packet), false);
return info.message_id;
}
Status RawConnection::flush_read(const AuthKey &auth_key, Callback &callback) {
auto r = socket_fd_.flush_read();
if (r.is_ok() && stats_callback_) {
stats_callback_->on_read(r.ok());
}
while (transport_->can_read()) {
BufferSlice packet;
uint32 quick_ack = 0;
TRY_RESULT(wait_size, transport_->read_next(&packet, &quick_ack));
if (!is_aligned_pointer<4>(packet.as_slice().ubegin())) {
BufferSlice new_packet(packet.size());
new_packet.as_slice().copy_from(packet.as_slice());
packet = std::move(new_packet);
}
CHECK(is_aligned_pointer<4>(packet.as_slice().ubegin()));
if (wait_size != 0) {
break;
}
if (quick_ack != 0) {
auto it = quick_ack_to_token_.find(quick_ack);
if (it == quick_ack_to_token_.end()) {
LOG(WARNING) << Status::Error(PSLICE() << "Unknown " << tag("quick_ack", quick_ack));
continue;
// TODO: return Status::Error(PSLICE() << "Unknown " << tag("quick_ack", quick_ack));
}
auto token = it->second;
quick_ack_to_token_.erase(it);
callback.on_quick_ack(token);
continue;
}
MutableSlice data = packet.as_slice();
PacketInfo info;
info.version = 2;
int32 error_code = 0;
TRY_STATUS(mtproto::Transport::read(data, auth_key, &info, &data, &error_code));
if (error_code) {
if (error_code == -429) {
if (stats_callback_) {
stats_callback_->on_mtproto_error();
}
return Status::Error(500, PSLICE() << "Mtproto error: " << error_code);
}
if (error_code == -404) {
return Status::Error(-404, PSLICE() << "Mtproto error: " << error_code);
}
return Status::Error(PSLICE() << "Mtproto error: " << error_code);
}
// If a packet was successfully decrypted, then it is ok to assume that the connection is alive
if (!auth_key.empty()) {
if (stats_callback_) {
stats_callback_->on_pong();
}
}
TRY_STATUS(callback.on_raw_packet(info, packet.from_slice(data)));
}
TRY_STATUS(std::move(r));
return Status::OK();
}
Status RawConnection::flush_write() {
TRY_RESULT(size, socket_fd_.flush_write());
if (size > 0 && stats_callback_) {
stats_callback_->on_write(size);
}
return Status::OK();
}
} // namespace mtproto
} // namespace td