1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

98
adnl/CMakeLists.txt Normal file
View file

@ -0,0 +1,98 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
#BEGIN internal
set(ADNL_HEADERS
adnl-address-list.h
adnl-address-list.hpp
adnl-db.h
adnl-db.hpp
adnl-channel.h
adnl-channel.hpp
adnl-ext-client.h
adnl-ext-client.hpp
adnl-ext-connection.hpp
adnl-ext-server.h
adnl-ext-server.hpp
adnl-local-id.h
adnl-message.h
adnl-network-manager.h
adnl-network-manager.hpp
adnl-node.h
adnl-packet.h
adnl-peer-table.h
adnl-peer-table.hpp
adnl-peer.h
adnl-peer.hpp
adnl-query.h
adnl-static-nodes.h
adnl-static-nodes.hpp
adnl-proxy-types.h
adnl-proxy-types.hpp
adnl.h
utils.hpp
)
set(ADNL_SOURCE
adnl-address-list.cpp
adnl-db.cpp
adnl-ext-client.cpp
adnl-ext-server.cpp
adnl-ext-connection.cpp
adnl-local-id.cpp
adnl-message.cpp
adnl-network-manager.cpp
adnl-node.cpp
adnl-packet.cpp
adnl-peer-table.cpp
adnl-peer.cpp
adnl-query.cpp
adnl-channel.cpp
adnl-static-nodes.cpp
adnl-proxy-types.cpp
utils.cpp
${ADNL_HEADERS}
)
set(ADNL_TEST_SOURCE
adnl-test-loopback-implementation.h
adnl-test-loopback-implementation.cpp
)
set(ADNL_PROXY_SOURCE
adnl-proxy.cpp
adnl-proxy-types.h
adnl-proxy-types.hpp
adnl-proxy-types.cpp
)
#FIXME
set(ADNL_LITE_HEADERS ${ADNL_HEADERS})
#END internal
set(ADNL_LITE_SOURCE
adnl-ext-client.cpp
adnl-ext-connection.cpp
adnl-query.cpp
${ADNL_LITE_HEADERS}
)
#BEGIN internal
add_library(adnl STATIC ${ADNL_SOURCE})
target_include_directories(adnl PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnl PUBLIC tdactor ton_crypto tl_api tdnet tddb keys keyring )
add_executable(adnl-proxy ${ADNL_PROXY_SOURCE})
target_include_directories(adnl-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnl-proxy PUBLIC tdactor ton_crypto tl_api tdnet common
tl-utils)
add_library(adnltest STATIC ${ADNL_TEST_SOURCE})
target_include_directories(adnltest PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnltest PUBLIC adnl )
#END internal
add_library(adnllite STATIC ${ADNL_LITE_SOURCE})
target_include_directories(adnllite PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(adnllite PUBLIC tdactor ton_crypto tl_lite_api tdnet keys )

160
adnl/adnl-address-list.cpp Normal file
View file

@ -0,0 +1,160 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-address-list.hpp"
#include "adnl-peer-table.h"
#include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
#include "td/net/UdpServer.h"
namespace ton {
namespace adnl {
class AdnlNetworkConnectionUdp : public AdnlNetworkConnection {
public:
void send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority, td::BufferSlice message) override;
bool is_alive() const override {
return true;
}
bool is_active() const override {
return true;
}
void start_up() override {
callback_->on_change_state(true);
}
AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager, td::uint32 ip, td::uint16 port,
std::unique_ptr<AdnlNetworkConnection::Callback> callback);
AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager, td::Bits128 ip, td::uint16 port,
std::unique_ptr<AdnlNetworkConnection::Callback> callback);
private:
td::actor::ActorId<AdnlNetworkManager> network_manager_;
td::IPAddress addr_;
std::unique_ptr<AdnlNetworkConnection::Callback> callback_;
};
void AdnlNetworkConnectionUdp::send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority,
td::BufferSlice message) {
LOG_CHECK(message.size() <= AdnlNetworkManager::get_mtu()) << "dst=" << addr_ << " size=" << message.size();
td::actor::send_closure(network_manager_, &AdnlNetworkManager::send_udp_packet, src, dst, addr_, priority,
std::move(message));
}
AdnlNetworkConnectionUdp::AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::uint32 ip, td::uint16 port,
std::unique_ptr<AdnlNetworkConnection::Callback> callback)
: network_manager_(network_manager), callback_(std::move(callback)) {
addr_.init_host_port(td::IPAddress::ipv4_to_str(ip), port).ensure();
}
AdnlNetworkConnectionUdp::AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::Bits128 ip, td::uint16 port,
std::unique_ptr<AdnlNetworkConnection::Callback> callback)
: network_manager_(network_manager), callback_(std::move(callback)) {
addr_.init_host_port(td::IPAddress::ipv6_to_str(ip.as_slice()), port).ensure();
}
AdnlAddressImpl::Hash AdnlAddressImpl::get_hash() const {
return get_tl_object_sha_bits256(tl());
}
td::actor::ActorOwn<AdnlNetworkConnection> AdnlAddressUdp::create_connection(
td::actor::ActorId<AdnlNetworkManager> network_manager,
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const {
return td::actor::create_actor<AdnlNetworkConnectionUdp>("udpconn", network_manager, ip_, port_, std::move(callback));
}
AdnlAddressUdp::AdnlAddressUdp(const ton_api::adnl_address_udp &obj) {
ip_ = obj.ip_;
port_ = static_cast<td::uint16>(obj.port_);
}
td::actor::ActorOwn<AdnlNetworkConnection> AdnlAddressUdp6::create_connection(
td::actor::ActorId<AdnlNetworkManager> network_manager,
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const {
return td::actor::create_actor<AdnlNetworkConnectionUdp>("udpconn", network_manager, ip_, port_, std::move(callback));
}
AdnlAddressUdp6::AdnlAddressUdp6(const ton_api::adnl_address_udp6 &obj) {
ip_ = obj.ip_;
port_ = static_cast<td::uint16>(obj.port_);
}
td::Ref<AdnlAddressImpl> AdnlAddressImpl::create(const tl_object_ptr<ton_api::adnl_Address> &addr) {
td::Ref<AdnlAddressImpl> res = td::Ref<AdnlAddressImpl>{};
ton_api::downcast_call(*const_cast<ton_api::adnl_Address *>(addr.get()),
td::overloaded(
[&](const ton_api::adnl_address_udp &obj) {
res = td::Ref<AdnlAddressUdp>{true, obj};
},
[&](const ton_api::adnl_address_udp6 &obj) {
res = td::Ref<AdnlAddressUdp6>{true, obj};
}));
return res;
}
bool AdnlAddressList::public_only() const {
for (auto &addr : addrs_) {
if (!addr->is_public()) {
return false;
}
}
return true;
}
AdnlAddressList::AdnlAddressList(const tl_object_ptr<ton_api::adnl_addressList> &addrs) {
version_ = static_cast<td::uint32>(addrs->version_);
std::vector<td::Ref<AdnlAddressImpl>> vec;
for (auto &addr : addrs->addrs_) {
vec.push_back(AdnlAddressImpl::create(addr));
}
addrs_ = std::move(vec);
reinit_date_ = addrs->reinit_date_;
priority_ = addrs->priority_;
expire_at_ = addrs->expire_at_;
}
tl_object_ptr<ton_api::adnl_addressList> AdnlAddressList::tl() const {
std::vector<tl_object_ptr<ton_api::adnl_Address>> addrs;
for (auto &v : addrs_) {
addrs.emplace_back(v->tl());
}
return create_tl_object<ton_api::adnl_addressList>(std::move(addrs), version_, reinit_date_, priority_, expire_at_);
}
td::uint32 AdnlAddressList::serialized_size() const {
td::uint32 res = 24;
for (auto &addr : addrs_) {
res += addr->serialized_size();
}
return res;
}
td::Result<AdnlAddressList> AdnlAddressList::create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list) {
auto A = AdnlAddressList{addr_list};
if (A.serialized_size() > max_serialized_size()) {
return td::Status::Error(ErrorCode::protoviolation, PSTRING() << "too big addr list: size=" << A.serialized_size());
}
return A;
}
} // namespace adnl
} // namespace ton

105
adnl/adnl-address-list.h Normal file
View file

@ -0,0 +1,105 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-network-manager.h"
#include "crypto/common/refcnt.hpp"
namespace ton {
namespace adnl {
class AdnlAddressImpl : public td::CntObject {
public:
using Hash = td::Bits256;
virtual ~AdnlAddressImpl() = default;
virtual Hash get_hash() const;
virtual bool is_public() const = 0;
virtual td::uint32 serialized_size() const = 0;
virtual tl_object_ptr<ton_api::adnl_Address> tl() const = 0;
virtual td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
td::actor::ActorId<AdnlNetworkManager> network_manager,
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const = 0;
static td::Ref<AdnlAddressImpl> create(const tl_object_ptr<ton_api::adnl_Address> &addr);
};
using AdnlAddress = td::Ref<AdnlAddressImpl>;
class AdnlAddressList {
private:
AdnlAddressList(const tl_object_ptr<ton_api::adnl_addressList> &addrs);
td::int32 version_;
td::int32 reinit_date_;
td::int32 priority_;
td::int32 expire_at_;
std::vector<AdnlAddress> addrs_;
public:
static constexpr td::uint32 max_serialized_size() {
return 128;
}
const auto &addrs() const {
return addrs_;
}
auto version() const {
return version_;
}
auto reinit_date() const {
return reinit_date_;
}
auto priority() const {
return priority_;
}
auto expire_at() const {
return expire_at_;
}
void set_version(td::uint32 version) {
version_ = version;
}
void set_reinit_date(td::int32 date) {
reinit_date_ = date;
}
void set_expire_at(td::int32 date) {
expire_at_ = date;
}
bool empty() const {
return version_ == -1;
}
void add_addr(AdnlAddress addr) {
addrs_.push_back(addr);
}
bool public_only() const;
td::uint32 size() const {
return static_cast<td::uint32>(addrs_.size());
}
td::uint32 serialized_size() const;
tl_object_ptr<ton_api::adnl_addressList> tl() const;
AdnlAddressList() : version_{-1}, reinit_date_{0}, priority_{0}, expire_at_{0} {
}
static td::Result<AdnlAddressList> create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list);
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,90 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-node-id.hpp"
#include "adnl-address-list.h"
namespace ton {
namespace adnl {
class AdnlAddressUdp : public AdnlAddressImpl {
private:
td::uint32 ip_;
td::uint16 port_;
public:
explicit AdnlAddressUdp(const ton_api::adnl_address_udp &obj);
AdnlAddressUdp(td::uint32 ip, td::uint16 port) : ip_(ip), port_(port) {
}
AdnlAddressUdp *make_copy() const override {
return new AdnlAddressUdp{ip_, port_};
}
bool is_public() const override {
return true;
}
td::uint32 serialized_size() const override {
return 12;
}
tl_object_ptr<ton_api::adnl_Address> tl() const override {
return create_tl_object<ton_api::adnl_address_udp>(ip_, port_);
}
td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
td::actor::ActorId<AdnlNetworkManager> network_manager,
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const override;
};
class AdnlAddressUdp6 : public AdnlAddressImpl {
private:
td::Bits128 ip_;
td::uint16 port_;
public:
explicit AdnlAddressUdp6(const ton_api::adnl_address_udp6 &obj);
AdnlAddressUdp6(td::Bits128 ip, td::uint16 port) : ip_(ip), port_(port) {
}
AdnlAddressUdp6 *make_copy() const override {
return new AdnlAddressUdp6{ip_, port_};
}
bool is_public() const override {
return true;
}
td::uint32 serialized_size() const override {
return 12;
}
tl_object_ptr<ton_api::adnl_Address> tl() const override {
return create_tl_object<ton_api::adnl_address_udp6>(ip_, port_);
}
td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
td::actor::ActorId<AdnlNetworkManager> network_manager,
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const override;
};
} // namespace adnl
} // namespace ton

129
adnl/adnl-channel.cpp Normal file
View file

@ -0,0 +1,129 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-channel.hpp"
#include "adnl-peer.h"
#include "adnl-peer-table.h"
#include "td/utils/crypto.h"
#include "crypto/Ed25519.h"
namespace ton {
namespace adnl {
td::Result<td::actor::ActorOwn<AdnlChannel>> AdnlChannel::create(privkeys::Ed25519 pk_data, pubkeys::Ed25519 pub_data,
AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
td::actor::ActorId<AdnlPeerPair> peer_pair) {
td::Ed25519::PublicKey pub_k = pub_data.export_key();
td::Ed25519::PrivateKey priv_k = pk_data.export_key();
TRY_RESULT_PREFIX(shared_secret, td::Ed25519::compute_shared_secret(pub_k, priv_k),
"failed to compute channel shared secret: ");
CHECK(shared_secret.length() == 32);
td::SecureString rev_secret{32};
for (td::uint32 i = 0; i < 32; i++) {
rev_secret.as_mutable_slice()[i] = shared_secret[31 - i];
}
auto R = [&]() -> std::pair<PrivateKey, PublicKey> {
if (local_id < peer_id) {
return {privkeys::AES{std::move(shared_secret)}, pubkeys::AES{std::move(rev_secret)}};
} else if (peer_id < local_id) {
return {privkeys::AES{std::move(rev_secret)}, pubkeys::AES{std::move(shared_secret)}};
} else {
auto c = shared_secret.copy();
return {privkeys::AES{std::move(c)}, pubkeys::AES{std::move(shared_secret)}};
}
}();
in_id = AdnlChannelIdShort{R.first.compute_short_id()};
out_id = AdnlChannelIdShort{R.second.compute_short_id()};
TRY_RESULT_PREFIX(encryptor, R.second.create_encryptor(), "failed to init channel encryptor: ");
TRY_RESULT_PREFIX(decryptor, R.first.create_decryptor(), "failed to init channel decryptor: ");
return td::actor::create_actor<AdnlChannelImpl>("channel", local_id, peer_id, peer_pair, in_id, out_id,
std::move(encryptor), std::move(decryptor));
}
AdnlChannelImpl::AdnlChannelImpl(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
td::actor::ActorId<AdnlPeerPair> peer_pair, AdnlChannelIdShort in_id,
AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
std::unique_ptr<Decryptor> decryptor) {
local_id_ = local_id;
peer_id_ = peer_id;
encryptor_ = std::move(encryptor);
decryptor_ = std::move(decryptor);
channel_in_id_ = in_id;
channel_out_id_ = out_id;
peer_pair_ = peer_pair;
VLOG(ADNL_INFO) << this << ": created";
}
void AdnlChannelImpl::decrypt(td::BufferSlice raw_data, td::Promise<AdnlPacket> promise) {
TRY_RESULT_PROMISE_PREFIX(promise, data, decryptor_->decrypt(raw_data.as_slice()),
"failed to decrypt channel message: ");
TRY_RESULT_PROMISE_PREFIX(promise, tl_packet, fetch_tl_object<ton_api::adnl_packetContents>(std::move(data), true),
"decrypted channel packet contains invalid TL scheme: ");
TRY_RESULT_PROMISE_PREFIX(promise, packet, AdnlPacket::create(std::move(tl_packet)), "received bad packet: ");
if (packet.inited_from_short() && packet.from_short() != peer_id_) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad channel packet destination"));
return;
}
promise.set_value(std::move(packet));
}
void AdnlChannelImpl::send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
td::BufferSlice data) {
auto E = encryptor_->encrypt(data.as_slice());
if (E.is_error()) {
VLOG(ADNL_ERROR) << this << ": dropping OUT message: can not encrypt: " << E.move_as_error();
return;
}
auto enc = E.move_as_ok();
auto B = td::BufferSlice(enc.size() + 32);
td::MutableSlice S = B.as_slice();
S.copy_from(channel_out_id_.as_slice());
S.remove_prefix(32);
S.copy_from(enc.as_slice());
td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_, priority, std::move(B));
}
void AdnlChannelImpl::receive(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda(
[peer = peer_pair_, channel_id = channel_in_id_, id = print_id()](td::Result<AdnlPacket> R) {
if (R.is_error()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error();
} else {
td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, R.move_as_ok());
}
});
decrypt(std::move(data), std::move(P));
}
} // namespace adnl
} // namespace ton

46
adnl/adnl-channel.h Normal file
View file

@ -0,0 +1,46 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-local-id.h"
#include "adnl-peer.h"
#include "adnl-peer-table.h"
#include "adnl-network-manager.h"
namespace ton {
namespace adnl {
class AdnlPeerPair;
class AdnlChannel : public td::actor::Actor {
public:
static td::Result<td::actor::ActorOwn<AdnlChannel>> create(privkeys::Ed25519 pk, pubkeys::Ed25519 pub,
AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
td::actor::ActorId<AdnlPeerPair> peer_pair);
virtual void receive(td::BufferSlice data) = 0;
virtual void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
td::BufferSlice data) = 0;
virtual ~AdnlChannel() = default;
};
} // namespace adnl
} // namespace ton

82
adnl/adnl-channel.hpp Normal file
View file

@ -0,0 +1,82 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-channel.h"
#include "keys/encryptor.h"
namespace ton {
namespace adnl {
class AdnlPeerPair;
class AdnlChannelImpl : public AdnlChannel {
public:
AdnlChannelImpl(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::actor::ActorId<AdnlPeerPair> peer_pair,
AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
std::unique_ptr<Decryptor> decryptor);
void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
void receive(td::BufferSlice data) override;
void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, td::BufferSlice data) override;
struct AdnlChannelPrintId {
AdnlChannelIdShort channel_out_id_;
AdnlChannelIdShort channel_in_id_;
AdnlNodeIdShort local_id_;
AdnlNodeIdShort peer_id_;
};
AdnlChannelPrintId print_id() const {
return AdnlChannelPrintId{channel_out_id_, channel_in_id_, local_id_, peer_id_};
}
private:
AdnlChannelIdShort channel_out_id_;
AdnlChannelIdShort channel_in_id_;
AdnlNodeIdShort local_id_;
AdnlNodeIdShort peer_id_;
std::unique_ptr<Encryptor> encryptor_;
std::unique_ptr<Decryptor> decryptor_;
td::actor::ActorId<AdnlPeerPair> peer_pair_;
};
} // namespace adnl
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl::AdnlChannelPrintId &id) {
sb << "[channel " << id.peer_id_ << "-" << id.local_id_ << " " << id.channel_out_id_ << "-" << id.channel_in_id_
<< "]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl &channel) {
sb << channel.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl *channel) {
sb << channel->print_id();
return sb;
}
} // namespace td

82
adnl/adnl-db.cpp Normal file
View file

@ -0,0 +1,82 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-db.hpp"
#include "td/db/RocksDb.h"
namespace ton {
namespace adnl {
void AdnlDbImpl::update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
td::Promise<td::Unit> promise) {
td::BufferSlice b{64};
auto S = b.as_slice();
S.copy_from(local_id.as_slice());
S.remove_prefix(32);
S.copy_from(peer_id.as_slice());
auto obj = create_tl_object<ton_api::adnl_db_node_value>(static_cast<td::int32>(td::Clocks::system()), item.id.tl(),
item.addr_list.tl(), item.priority_addr_list.tl());
kv_->begin_transaction().ensure();
kv_->set(b.as_slice(), serialize_tl_object(obj, true).as_slice()).ensure();
kv_->commit_transaction().ensure();
}
void AdnlDbImpl::get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) {
td::BufferSlice b{64};
auto S = b.as_slice();
S.copy_from(local_id.as_slice());
S.remove_prefix(32);
S.copy_from(peer_id.as_slice());
std::string value;
auto R = kv_->get(b.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
return;
}
auto F = fetch_tl_object<ton_api::adnl_db_node_value>(td::BufferSlice{value}, true);
F.ensure();
auto f = F.move_as_ok();
AdnlDbItem n;
auto id = AdnlNodeIdFull::create(f->id_);
id.ensure();
n.id = id.move_as_ok();
auto addr_list = AdnlAddressList::create(std::move(f->addr_list_));
addr_list.ensure();
n.addr_list = addr_list.move_as_ok();
auto priority_addr_list = AdnlAddressList::create(std::move(f->priority_addr_list_));
priority_addr_list.ensure();
n.priority_addr_list = priority_addr_list.move_as_ok();
promise.set_value(std::move(n));
}
void AdnlDbImpl::start_up() {
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_).move_as_ok());
}
td::actor::ActorOwn<AdnlDb> AdnlDb::create(std::string path) {
return td::actor::create_actor<AdnlDbImpl>("adnldb", path);
}
} // namespace adnl
} // namespace ton

47
adnl/adnl-db.h Normal file
View file

@ -0,0 +1,47 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "adnl.h"
namespace ton {
namespace adnl {
struct AdnlDbItem {
AdnlNodeIdFull id;
AdnlAddressList addr_list;
AdnlAddressList priority_addr_list;
};
class AdnlDb : public td::actor::Actor {
public:
virtual ~AdnlDb() = default;
virtual void update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
td::Promise<td::Unit> promise) = 0;
virtual void get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) = 0;
static td::actor::ActorOwn<AdnlDb> create(std::string path);
};
} // namespace adnl
} // namespace ton

47
adnl/adnl-db.hpp Normal file
View file

@ -0,0 +1,47 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-db.h"
#include "td/db/KeyValue.h"
namespace ton {
namespace adnl {
class AdnlDbImpl : public AdnlDb {
public:
void update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
td::Promise<td::Unit> promise) override;
void get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) override;
void start_up() override;
AdnlDbImpl(std::string path) : path_(path) {
}
private:
std::string path_;
std::shared_ptr<td::KeyValue> kv_;
};
} // namespace adnl
} // namespace ton

181
adnl/adnl-ext-client.cpp Normal file
View file

@ -0,0 +1,181 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-ext-client.hpp"
#include "adnl-ext-client.h"
namespace ton {
namespace adnl {
void AdnlExtClientImpl::alarm() {
if (is_closing_) {
return;
}
if (conn_.empty() || !conn_.is_alive()) {
next_create_at_ = td::Timestamp::in(10.0);
alarm_timestamp() = next_create_at_;
auto fd = td::SocketFd::open(dst_addr_);
if (fd.is_error()) {
LOG(INFO) << "failed to connect to " << dst_addr_ << ": " << fd.move_as_error();
return;
}
class Cb : public AdnlExtConnection::Callback {
private:
td::actor::ActorId<AdnlExtClientImpl> id_;
public:
void on_ready(td::actor::ActorId<AdnlExtConnection> conn) {
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_ready, conn);
}
void on_close(td::actor::ActorId<AdnlExtConnection> conn) {
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_stopped, conn);
}
Cb(td::actor::ActorId<AdnlExtClientImpl> id) : id_(id) {
}
};
conn_ = td::actor::create_actor<AdnlOutboundConnection>(td::actor::ActorOptions().with_name("outconn").with_poll(),
fd.move_as_ok(), std::make_unique<Cb>(actor_id(this)), dst_,
local_id_, actor_id(this));
}
}
void AdnlExtClientImpl::hangup() {
conn_ = {};
is_closing_ = true;
ref_cnt_--;
try_stop();
}
void AdnlExtClientImpl::try_stop() {
if (is_closing_ && ref_cnt_ == 0 && out_queries_.empty()) {
stop();
}
}
td::Status AdnlOutboundConnection::process_custom_packet(td::BufferSlice &data, bool &processed) {
if (data.size() == 12) {
auto F = fetch_tl_object<ton_api::tcp_pong>(data.clone(), true);
if (F.is_ok()) {
processed = true;
return td::Status::OK();
}
}
if (!local_id_.empty() && nonce_.size() != 0) {
auto F = fetch_tl_object<ton_api::tcp_authentificationNonce>(data.clone(), true);
if (F.is_ok()) {
auto f = F.move_as_ok();
if (f->nonce_.size() == 0 || f->nonce_.size() > 512) {
return td::Status::Error(ErrorCode::protoviolation, "bad nonce size");
}
td::SecureString ss{nonce_.size() + f->nonce_.size()};
ss.as_mutable_slice().copy_from(nonce_.as_slice());
ss.as_mutable_slice().remove_prefix(nonce_.size()).copy_from(f->nonce_.as_slice());
TRY_RESULT(dec, local_id_.create_decryptor());
TRY_RESULT(B, dec->sign(ss.as_slice()));
auto obj =
create_tl_object<ton_api::tcp_authentificationComplete>(local_id_.compute_public_key().tl(), std::move(B));
send(serialize_tl_object(obj, true));
nonce_.clear();
processed = true;
authorization_complete_ = true;
return td::Status::OK();
}
}
return td::Status::OK();
}
void AdnlOutboundConnection::start_up() {
AdnlExtConnection::start_up();
auto X = dst_.pubkey().create_encryptor();
if (X.is_error()) {
LOG(ERROR) << "failed to init encryptor: " << X.move_as_error();
stop();
return;
}
auto enc = X.move_as_ok();
td::BufferSlice d{256};
auto id = dst_.compute_short_id();
auto S = d.as_slice();
S.copy_from(id.as_slice());
S.remove_prefix(32);
S.truncate(256 - 64 - 32);
td::Random::secure_bytes(S);
init_crypto(S);
auto R = enc->encrypt(S);
if (R.is_error()) {
LOG(ERROR) << "failed to encrypt: " << R.move_as_error();
stop();
return;
}
auto data = R.move_as_ok();
LOG_CHECK(data.size() == 256 - 32) << "size=" << data.size();
S = d.as_slice();
S.remove_prefix(32);
CHECK(S.size() == data.size());
S.copy_from(data.as_slice());
send_uninit(std::move(d));
if (!local_id_.empty()) {
nonce_ = td::SecureString{32};
td::Random::secure_bytes(nonce_.as_mutable_slice());
auto obj = create_tl_object<ton_api::tcp_authentificate>(td::BufferSlice{nonce_.as_slice()});
send(serialize_tl_object(obj, true));
}
}
void AdnlExtClientImpl::check_ready(td::Promise<td::Unit> promise) {
if (conn_.empty() || !conn_.is_alive()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
return;
}
td::actor::send_closure(td::actor::ActorId<AdnlExtConnection>{conn_.get()}, &AdnlExtConnection::check_ready_async,
std::move(promise));
}
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, td::IPAddress dst_addr,
std::unique_ptr<AdnlExtClient::Callback> callback) {
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), dst_addr, std::move(callback));
}
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, PrivateKey local_id,
td::IPAddress dst_addr,
std::unique_ptr<AdnlExtClient::Callback> callback) {
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), std::move(local_id), dst_addr,
std::move(callback));
}
td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) {
TRY_RESULT(F, fetch_tl_object<lite_api::adnl_message_answer>(std::move(data), true));
td::actor::send_closure(ext_client_, &AdnlExtClientImpl::answer_query, F->query_id_, std::move(F->answer_));
return td::Status::OK();
}
} // namespace adnl
} // namespace ton

48
adnl/adnl-ext-client.h Normal file
View file

@ -0,0 +1,48 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-node-id.hpp"
#include "td/utils/port/IPAddress.h"
namespace ton {
namespace adnl {
class AdnlExtClient : public td::actor::Actor {
public:
class Callback {
public:
virtual ~Callback() = default;
virtual void on_ready() = 0;
virtual void on_stop_ready() = 0;
};
virtual ~AdnlExtClient() = default;
virtual void check_ready(td::Promise<td::Unit> promise) = 0;
virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) = 0;
static td::actor::ActorOwn<AdnlExtClient> create(AdnlNodeIdFull dst, td::IPAddress dst_addr,
std::unique_ptr<AdnlExtClient::Callback> callback);
static td::actor::ActorOwn<AdnlExtClient> create(AdnlNodeIdFull dst, PrivateKey local_id, td::IPAddress dst_addr,
std::unique_ptr<AdnlExtClient::Callback> callback);
};
} // namespace adnl
} // namespace ton

145
adnl/adnl-ext-client.hpp Normal file
View file

@ -0,0 +1,145 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "auto/tl/lite_api.h"
#include "adnl-ext-connection.hpp"
#include "tl-utils/lite-utils.hpp"
#include "td/utils/Random.h"
#include "adnl-query.h"
#include "keys/encryptor.h"
#include "adnl-ext-client.h"
namespace ton {
namespace adnl {
class AdnlExtClientImpl;
class AdnlOutboundConnection : public AdnlExtConnection {
private:
AdnlNodeIdFull dst_;
PrivateKey local_id_;
td::actor::ActorId<AdnlExtClientImpl> ext_client_;
td::SecureString nonce_;
bool authorization_complete_ = false;
public:
AdnlOutboundConnection(td::SocketFd fd, std::unique_ptr<AdnlExtConnection::Callback> callback, AdnlNodeIdFull dst,
td::actor::ActorId<AdnlExtClientImpl> ext_client)
: AdnlExtConnection(std::move(fd), std::move(callback), true), dst_(std::move(dst)), ext_client_(ext_client) {
}
AdnlOutboundConnection(td::SocketFd fd, std::unique_ptr<AdnlExtConnection::Callback> callback, AdnlNodeIdFull dst,
PrivateKey local_id, td::actor::ActorId<AdnlExtClientImpl> ext_client)
: AdnlExtConnection(std::move(fd), std::move(callback), true)
, dst_(std::move(dst))
, local_id_(local_id)
, ext_client_(ext_client) {
}
td::Status process_packet(td::BufferSlice data) override;
td::Status process_init_packet(td::BufferSlice data) override {
UNREACHABLE();
}
td::Status process_custom_packet(td::BufferSlice &data, bool &processed) override;
void start_up() override;
bool authorized() const override {
return local_id_.empty() ? true : authorization_complete_;
}
};
class AdnlExtClientImpl : public AdnlExtClient {
public:
AdnlExtClientImpl(AdnlNodeIdFull dst_id, td::IPAddress dst_addr, std::unique_ptr<Callback> callback)
: dst_(std::move(dst_id)), dst_addr_(dst_addr), callback_(std::move(callback)) {
}
AdnlExtClientImpl(AdnlNodeIdFull dst_id, PrivateKey local_id, td::IPAddress dst_addr,
std::unique_ptr<Callback> callback)
: dst_(std::move(dst_id)), local_id_(local_id), dst_addr_(dst_addr), callback_(std::move(callback)) {
}
void start_up() override {
alarm_timestamp() = next_create_at_;
}
void conn_stopped(td::actor::ActorId<AdnlExtConnection> conn) {
if (!conn_.empty() && conn_.get() == conn) {
callback_->on_stop_ready();
conn_ = {};
alarm_timestamp() = next_create_at_;
try_stop();
}
}
void conn_ready(td::actor::ActorId<AdnlExtConnection> conn) {
if (!conn_.empty() && conn_.get() == conn) {
callback_->on_ready();
}
}
void check_ready(td::Promise<td::Unit> promise) override;
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
auto P = [SelfId = actor_id(this)](AdnlQueryId id) {
td::actor::send_closure(SelfId, &AdnlExtClientImpl::destroy_query, id);
};
auto q_id = generate_next_query_id();
out_queries_.emplace(q_id, AdnlQuery::create(std::move(promise), std::move(P), name, timeout, q_id));
if (!conn_.empty()) {
auto obj = create_tl_object<lite_api::adnl_message_query>(q_id, std::move(data));
td::actor::send_closure(conn_, &AdnlOutboundConnection::send, serialize_tl_object(obj, true));
}
}
void destroy_query(AdnlQueryId id) {
out_queries_.erase(id);
try_stop();
}
void answer_query(AdnlQueryId id, td::BufferSlice data) {
auto it = out_queries_.find(id);
if (it != out_queries_.end()) {
td::actor::send_closure(it->second, &AdnlQuery::result, std::move(data));
}
}
void alarm() override;
void hangup() override;
AdnlQueryId generate_next_query_id() {
while (true) {
AdnlQueryId q_id = AdnlQuery::random_query_id();
if (out_queries_.count(q_id) == 0) {
return q_id;
}
}
}
private:
AdnlNodeIdFull dst_;
PrivateKey local_id_;
td::IPAddress dst_addr_;
std::unique_ptr<Callback> callback_;
td::actor::ActorOwn<AdnlOutboundConnection> conn_;
td::Timestamp next_create_at_ = td::Timestamp::now_cached();
std::map<AdnlQueryId, td::actor::ActorId<AdnlQuery>> out_queries_;
bool is_closing_{false};
td::uint32 ref_cnt_{1};
void try_stop();
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,192 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-ext-connection.hpp"
namespace ton {
namespace adnl {
void AdnlExtConnection::send_uninit(td::BufferSlice data) {
buffered_fd_.output_buffer().append(std::move(data));
loop();
}
void AdnlExtConnection::send(td::BufferSlice data) {
LOG(DEBUG) << "sending packet of size " << data.size();
auto data_size = td::narrow_cast<td::uint32>(data.size()) + 32 + 32;
if (data_size < 32 || data_size > (1 << 24)) {
LOG(WARNING) << "bad packet size " << data_size;
return;
}
td::BufferSlice d{data.size() + 4 + 32 + 32};
auto S = d.as_slice();
S.copy_from(td::Slice(reinterpret_cast<const td::uint8 *>(&data_size), 4));
S.remove_prefix(4);
auto Sc = S;
td::Random::secure_bytes(S.copy().truncate(32));
S.remove_prefix(32);
S.copy_from(data.as_slice());
S.remove_prefix(data.size());
td::sha256(Sc.truncate(32 + data.size()), S);
td::BufferSlice e{d.size()};
out_ctr_.encrypt(d.as_slice(), e.as_slice());
buffered_fd_.output_buffer().append(std::move(e));
loop();
}
td::Status AdnlExtConnection::receive(td::ChainBufferReader &input, bool &exit_loop) {
if (stop_read_) {
exit_loop = true;
return td::Status::OK();
}
if (input.size() > 0) {
received_bytes_ = 1;
}
if (inited_) {
if (!read_len_) {
if (input.size() < 4) {
exit_loop = true;
return td::Status::OK();
}
char x[4];
td::MutableSlice s{x, 4};
input.advance(4, s);
td::MutableSlice e{reinterpret_cast<td::uint8 *>(&len_), 4};
in_ctr_.encrypt(s, e);
LOG(DEBUG) << "len=" << len_;
if (len_ > (1 << 24) || len_ < 32) {
return td::Status::Error("Too big packet");
}
read_len_ = true;
}
if (input.size() < len_) {
exit_loop = true;
return td::Status::OK();
}
auto data = input.cut_head(len_).move_as_buffer_slice();
update_timer();
td::BufferSlice dec_data{data.size()};
in_ctr_.encrypt(data.as_slice(), dec_data.as_slice());
exit_loop = false;
read_len_ = false;
len_ = 0;
return receive_packet(std::move(dec_data));
} else {
if (input.size() < 256) {
exit_loop = true;
return td::Status::OK();
}
auto data = input.cut_head(256).move_as_buffer_slice();
update_timer();
exit_loop = false;
return process_init_packet(std::move(data));
}
}
void AdnlExtConnection::loop() {
auto status = [&] {
TRY_STATUS(buffered_fd_.flush_read());
auto &input = buffered_fd_.input_buffer();
bool exit_loop = false;
while (!exit_loop) {
TRY_STATUS(receive(input, exit_loop));
}
TRY_STATUS(buffered_fd_.flush_write());
if (td::can_close(buffered_fd_)) {
stop();
}
return td::Status::OK();
}();
if (status.is_error()) {
LOG(ERROR) << "Client got error " << status;
stop();
} else {
send_ready();
}
}
td::Status AdnlExtConnection::init_crypto(td::Slice S) {
if (S.size() < 96) {
return td::Status::Error(ErrorCode::protoviolation, "too small enc data");
}
CHECK(S.size() >= 96);
td::SecureString s1(32), s2(32);
td::SecureString v1(16), v2(16);
s1.as_mutable_slice().copy_from(S.copy().truncate(32));
S.remove_prefix(32);
s2.as_mutable_slice().copy_from(S.copy().truncate(32));
S.remove_prefix(32);
v1.as_mutable_slice().copy_from(S.copy().truncate(16));
S.remove_prefix(16);
v2.as_mutable_slice().copy_from(S.copy().truncate(16));
S.remove_prefix(16);
if (is_client_) {
in_ctr_.init(s1, v1);
out_ctr_.init(s2, v2);
} else {
in_ctr_.init(s2, v2);
out_ctr_.init(s1, v1);
}
inited_ = true;
return td::Status::OK();
}
td::Status AdnlExtConnection::receive_packet(td::BufferSlice data) {
LOG(DEBUG) << "received packet of size " << data.size();
auto S = data.as_slice();
S.truncate(data.size() - 32);
auto D = data.as_slice();
D.remove_prefix(data.size() - 32);
if (td::sha256(S) != D) {
return td::Status::Error(ErrorCode::protoviolation, "sha256 mismatch");
}
data.truncate(data.size() - 32);
data.confirm_read(32);
if (data.size() == 0) {
// keepalive
return td::Status::OK();
}
bool processed = false;
TRY_STATUS(process_custom_packet(data, processed));
if (processed) {
return td::Status::OK();
}
return process_packet(std::move(data));
}
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,163 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/net/TcpListener.h"
#include "td/utils/crypto.h"
#include "td/utils/BufferedFd.h"
#include "tl-utils/tl-utils.hpp"
#include "td/utils/Random.h"
#include "common/errorcode.h"
#include <map>
#include <set>
namespace ton {
namespace adnl {
class AdnlExtConnection : public td::actor::Actor, public td::ObserverBase {
public:
class Callback {
public:
virtual ~Callback() = default;
virtual void on_close(td::actor::ActorId<AdnlExtConnection> conn) = 0;
virtual void on_ready(td::actor::ActorId<AdnlExtConnection> conn) = 0;
};
double timeout() {
return is_client_ ? 20.0 : 60.0;
}
AdnlExtConnection(td::SocketFd fd, std::unique_ptr<Callback> callback, bool is_client)
: buffered_fd_(std::move(fd)), callback_(std::move(callback)), is_client_(is_client) {
}
void send(td::BufferSlice data);
void send_uninit(td::BufferSlice data);
td::Status receive(td::ChainBufferReader &input, bool &exit_loop);
virtual td::Status process_packet(td::BufferSlice data) = 0;
td::Status receive_packet(td::BufferSlice data);
virtual td::Status process_custom_packet(td::BufferSlice &data, bool &processed) = 0;
virtual td::Status process_init_packet(td::BufferSlice data) = 0;
virtual bool authorized() const {
return false;
}
td::Status init_crypto(td::Slice data);
void stop_read() {
stop_read_ = true;
}
void resume_read() {
stop_read_ = false;
}
bool check_ready() const {
return received_bytes_ && inited_ && authorized() && !td::can_close(buffered_fd_);
}
void check_ready_async(td::Promise<td::Unit> promise) {
if (check_ready()) {
promise.set_value(td::Unit());
} else {
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
}
}
void send_ready() {
if (check_ready() && !sent_ready_ && callback_) {
callback_->on_ready(actor_id(this));
sent_ready_ = true;
}
}
protected:
td::BufferedFd<td::SocketFd> buffered_fd_;
td::actor::ActorId<AdnlExtConnection> self_;
std::unique_ptr<Callback> callback_;
bool sent_ready_ = false;
bool is_client_;
void notify() override {
// NB: Interface will be changed
td::actor::send_closure_later(self_, &AdnlExtConnection::on_net);
}
void start_up() override {
self_ = actor_id(this);
// Subscribe for socket updates
// NB: Interface will be changed
td::actor::SchedulerContext::get()->get_poll().subscribe(buffered_fd_.get_poll_info().extract_pollable_fd(this),
td::PollFlags::ReadWrite());
update_timer();
notify();
}
private:
td::AesCtrState in_ctr_;
td::AesCtrState out_ctr_;
bool inited_ = false;
bool stop_read_ = false;
bool read_len_ = false;
td::uint32 len_;
td::uint32 received_bytes_ = 0;
td::Timestamp fail_at_;
td::Timestamp send_ping_at_;
bool ping_sent_ = false;
void on_net() {
loop();
}
void tear_down() override {
if (callback_) {
callback_->on_close(actor_id(this));
callback_ = nullptr;
}
// unsubscribe from socket updates
// nb: interface will be changed
td::actor::SchedulerContext::get()->get_poll().unsubscribe(buffered_fd_.get_poll_info().get_pollable_fd_ref());
}
void update_timer() {
fail_at_ = td::Timestamp::in(timeout());
alarm_timestamp() = fail_at_;
if (is_client_) {
ping_sent_ = false;
send_ping_at_ = td::Timestamp::in(timeout() / 2);
alarm_timestamp().relax(send_ping_at_);
}
}
void loop() override;
void alarm() override {
alarm_timestamp() = fail_at_;
if (fail_at_.is_in_past()) {
stop();
} else if (is_client_ && !ping_sent_) {
if (send_ping_at_.is_in_past()) {
auto obj = create_tl_object<ton_api::tcp_ping>(td::Random::fast_uint64());
send(serialize_tl_object(obj, true));
ping_sent_ = true;
} else {
alarm_timestamp().relax(send_ping_at_);
}
}
}
};
} // namespace adnl
} // namespace ton

182
adnl/adnl-ext-server.cpp Normal file
View file

@ -0,0 +1,182 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-ext-server.hpp"
#include "keys/encryptor.h"
#include "utils.hpp"
namespace ton {
namespace adnl {
td::Status AdnlInboundConnection::process_packet(td::BufferSlice data) {
TRY_RESULT(f, fetch_tl_object<ton_api::adnl_message_query>(std::move(data), true));
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this), query_id = f->query_id_](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
auto S = R.move_as_error();
LOG(WARNING) << "failed ext query: " << S;
} else {
auto B = create_tl_object<ton_api::adnl_message_answer>(query_id, R.move_as_ok());
td::actor::send_closure(SelfId, &AdnlInboundConnection::send, serialize_tl_object(B, true));
}
});
td::actor::send_closure(peer_table_, &AdnlPeerTable::deliver_query, remote_id_, local_id_, std::move(f->query_),
std::move(P));
return td::Status::OK();
}
td::Status AdnlInboundConnection::process_init_packet(td::BufferSlice data) {
if (data.size() < 32) {
return td::Status::Error(ErrorCode::protoviolation, "too small init packet");
}
local_id_ = AdnlNodeIdShort{data.as_slice().truncate(32)};
data.confirm_read(32);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &AdnlInboundConnection::inited_crypto, std::move(R));
});
td::actor::send_closure(ext_server_, &AdnlExtServerImpl::decrypt_init_packet, local_id_, std::move(data),
std::move(P));
stop_read();
return td::Status::OK();
}
void AdnlInboundConnection::inited_crypto(td::Result<td::BufferSlice> R) {
if (R.is_error()) {
LOG(ERROR) << "failed to init crypto: " << R.move_as_error();
stop();
return;
}
auto S = init_crypto(R.move_as_ok().as_slice());
if (S.is_error()) {
LOG(ERROR) << "failed to init crypto (2): " << R.move_as_error();
stop();
return;
}
send(td::BufferSlice());
resume_read();
notify();
}
td::Status AdnlInboundConnection::process_custom_packet(td::BufferSlice &data, bool &processed) {
if (data.size() == 12) {
auto F = fetch_tl_object<ton_api::tcp_ping>(data.clone(), true);
if (F.is_ok()) {
auto f = F.move_as_ok();
auto obj = create_tl_object<ton_api::tcp_pong>(f->random_id_);
send(serialize_tl_object(obj, true));
processed = true;
return td::Status::OK();
}
}
if (1) {
auto F = fetch_tl_object<ton_api::tcp_authentificate>(data.clone(), true);
if (F.is_ok()) {
if (nonce_.size() > 0 || !remote_id_.is_zero()) {
return td::Status::Error(ErrorCode::protoviolation, "duplicate authentificate");
}
auto f = F.move_as_ok();
nonce_ = td::SecureString{f->nonce_.size() + 256};
nonce_.as_mutable_slice().truncate(f->nonce_.size()).copy_from(f->nonce_.as_slice());
td::Random::secure_bytes(nonce_.as_mutable_slice().remove_prefix(f->nonce_.size()));
auto obj = create_tl_object<ton_api::tcp_authentificationNonce>(
td::BufferSlice{nonce_.as_slice().remove_prefix(f->nonce_.size())});
send(serialize_tl_object(obj, true));
processed = true;
return td::Status::OK();
}
}
if (nonce_.size() != 0) {
auto F = fetch_tl_object<ton_api::tcp_authentificationComplete>(data.clone(), true);
if (F.is_ok()) {
auto f = F.move_as_ok();
if (nonce_.size() == 0 || !remote_id_.is_zero()) {
return td::Status::Error(ErrorCode::protoviolation, "duplicate authentificate");
}
auto pub_key = PublicKey{f->key_};
TRY_RESULT(enc, pub_key.create_encryptor());
TRY_STATUS(enc->check_signature(nonce_.as_slice(), f->signature_.as_slice()));
remote_id_ = AdnlNodeIdShort{pub_key.compute_short_id()};
nonce_.clear();
processed = true;
return td::Status::OK();
}
}
return td::Status::OK();
}
void AdnlExtServerImpl::add_tcp_port(td::uint16 port) {
auto it = listeners_.find(port);
if (it != listeners_.end()) {
return;
}
class Callback : public td::TcpListener::Callback {
private:
td::actor::ActorId<AdnlExtServerImpl> id_;
public:
Callback(td::actor::ActorId<AdnlExtServerImpl> id) : id_(id) {
}
void accept(td::SocketFd fd) override {
td::actor::send_closure(id_, &AdnlExtServerImpl::accepted, std::move(fd));
}
};
auto act = td::actor::create_actor<td::TcpListener>(td::actor::ActorOptions().with_name("listener").with_poll(), port,
std::make_unique<Callback>(actor_id(this)));
listeners_.emplace(port, std::move(act));
}
void AdnlExtServerImpl::add_local_id(AdnlNodeIdShort id) {
local_ids_.insert(id);
}
void AdnlExtServerImpl::accepted(td::SocketFd fd) {
td::actor::create_actor<AdnlInboundConnection>(td::actor::ActorOptions().with_name("inconn").with_poll(),
std::move(fd), peer_table_, actor_id(this))
.release();
}
void AdnlExtServerImpl::decrypt_init_packet(AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto it = local_ids_.find(dst);
if (it != local_ids_.end()) {
td::actor::send_closure(peer_table_, &AdnlPeerTable::decrypt_message, dst, std::move(data), std::move(promise));
} else {
promise.set_error(td::Status::Error());
}
}
td::actor::ActorOwn<AdnlExtServer> AdnlExtServerCreator::create(td::actor::ActorId<AdnlPeerTable> adnl,
std::vector<AdnlNodeIdShort> ids,
std::vector<td::uint16> ports) {
return td::actor::create_actor<AdnlExtServerImpl>("extserver", adnl, std::move(ids), std::move(ports));
}
} // namespace adnl
} // namespace ton

35
adnl/adnl-ext-server.h Normal file
View file

@ -0,0 +1,35 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-peer-table.h"
namespace ton {
namespace adnl {
class AdnlExtServerCreator {
public:
static td::actor::ActorOwn<AdnlExtServer> create(td::actor::ActorId<AdnlPeerTable> adnl,
std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports);
};
} // namespace adnl
} // namespace ton

92
adnl/adnl-ext-server.hpp Normal file
View file

@ -0,0 +1,92 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-peer-table.h"
#include "td/net/TcpListener.h"
#include "td/utils/crypto.h"
#include "td/utils/BufferedFd.h"
#include "adnl-ext-connection.hpp"
#include "adnl-ext-server.h"
#include <map>
#include <set>
namespace ton {
namespace adnl {
class AdnlExtServerImpl;
class AdnlInboundConnection : public AdnlExtConnection {
public:
AdnlInboundConnection(td::SocketFd fd, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlExtServerImpl> ext_server)
: AdnlExtConnection(std::move(fd), nullptr, false), peer_table_(peer_table), ext_server_(ext_server) {
}
td::Status process_packet(td::BufferSlice data) override;
td::Status process_init_packet(td::BufferSlice data) override;
td::Status process_custom_packet(td::BufferSlice &data, bool &processed) override;
void inited_crypto(td::Result<td::BufferSlice> R);
private:
td::actor::ActorId<AdnlPeerTable> peer_table_;
td::actor::ActorId<AdnlExtServerImpl> ext_server_;
AdnlNodeIdShort local_id_;
td::SecureString nonce_;
AdnlNodeIdShort remote_id_ = AdnlNodeIdShort::zero();
};
class AdnlExtServerImpl : public AdnlExtServer {
public:
void add_tcp_port(td::uint16 port) override;
void add_local_id(AdnlNodeIdShort id) override;
void accepted(td::SocketFd fd);
void decrypt_init_packet(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void start_up() override {
for (auto &port : ports_) {
add_tcp_port(port);
}
ports_.clear();
}
AdnlExtServerImpl(td::actor::ActorId<AdnlPeerTable> adnl, std::vector<AdnlNodeIdShort> ids,
std::vector<td::uint16> ports)
: peer_table_(adnl) {
for (auto &id : ids) {
add_local_id(id);
}
for (auto &port : ports) {
ports_.insert(port);
}
}
private:
td::actor::ActorId<AdnlPeerTable> peer_table_;
std::set<AdnlNodeIdShort> local_ids_;
std::set<td::uint16> ports_;
std::map<td::uint16, td::actor::ActorOwn<td::TcpListener>> listeners_;
};
} // namespace adnl
} // namespace ton

279
adnl/adnl-local-id.cpp Normal file
View file

@ -0,0 +1,279 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/utils/crypto.h"
#include "td/utils/Random.h"
#include "adnl-local-id.h"
#include "keys/encryptor.h"
#include "utils.hpp"
namespace ton {
namespace adnl {
AdnlNodeIdFull AdnlLocalId::get_id() const {
return id_;
}
AdnlNodeIdShort AdnlLocalId::get_short_id() const {
return short_id_;
}
AdnlAddressList AdnlLocalId::get_addr_list() const {
CHECK(!addr_list_.empty());
return addr_list_;
}
void AdnlLocalId::receive(td::BufferSlice data) {
auto P = td::PromiseCreator::lambda(
[peer_table = peer_table_, dst = short_id_, id = print_id()](td::Result<AdnlPacket> R) {
if (R.is_error()) {
VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error();
} else {
td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, R.move_as_ok());
}
});
decrypt(std::move(data), std::move(P));
}
void AdnlLocalId::deliver(AdnlNodeIdShort src, td::BufferSlice data) {
auto s = std::move(data);
for (auto &cb : cb_) {
auto f = cb.first;
if (f.length() <= s.length() && s.as_slice().substr(0, f.length()) == f) {
cb.second->receive_message(src, short_id_, std::move(s));
return;
}
}
VLOG(ADNL_INFO) << this << ": dropping IN message from " << src
<< ": no callbacks for custom message. firstint=" << td::TlParser(s.as_slice()).fetch_int();
}
void AdnlLocalId::deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
auto s = std::move(data);
for (auto &cb : cb_) {
auto f = cb.first;
if (f.length() <= s.length() && s.as_slice().substr(0, f.length()) == f) {
cb.second->receive_query(src, short_id_, std::move(s), std::move(promise));
return;
}
}
VLOG(ADNL_INFO) << this << ": dropping IN message from " << src
<< ": no callbacks for custom query. firstint=" << td::TlParser(s.as_slice()).fetch_int();
promise.set_error(td::Status::Error(ErrorCode::warning, "no callbacks for query"));
}
void AdnlLocalId::subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback) {
auto S = td::Slice(prefix);
for (auto &cb : cb_) {
auto G = td::Slice(cb.first);
if (S.size() < G.size()) {
LOG_CHECK(G.substr(0, S.size()) != S) << this << ": duplicate subscribe prefix";
} else {
LOG_CHECK(S.substr(0, G.size()) != G) << this << ": duplicate subscribe prefix";
}
}
cb_.emplace_back(prefix, std::move(callback));
}
void AdnlLocalId::unsubscribe(std::string prefix) {
bool deleted = false;
for (auto it = cb_.begin(); it != cb_.end();) {
if (it->first == prefix) {
it = cb_.erase(it);
deleted = true;
} else {
it++;
}
}
LOG_CHECK(deleted) << this << ": cannot unsubscribe: prefix not found";
}
void AdnlLocalId::update_address_list(AdnlAddressList addr_list) {
addr_list_ = std::move(addr_list);
addr_list_.set_reinit_date(Adnl::adnl_start_time());
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
VLOG(ADNL_INFO) << this << ": updated addr list. New version set to " << addr_list_.version();
publish_address_list();
}
void AdnlLocalId::publish_address_list() {
if (dht_node_.empty() || addr_list_.empty()) {
VLOG(ADNL_NOTICE) << this << ": skipping public addr list, because localid (or dht node) not fully initialized";
return;
}
dht::DhtKey dht_key{short_id_.pubkey_hash(), "address", 0};
auto dht_update_rule = dht::DhtUpdateRuleSignature::create().move_as_ok();
dht::DhtKeyDescription dht_key_description{std::move(dht_key), id_.pubkey(), std::move(dht_update_rule),
td::BufferSlice()};
auto B = serialize_tl_object(dht_key_description.tl(), true);
auto P = td::PromiseCreator::lambda([dht_node = dht_node_, SelfId = actor_id(this), addr_list = addr_list_.tl(),
dht_key_description = std::move(dht_key_description),
print_id = print_id()](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
LOG(ERROR) << print_id << ": cannot sign: " << R.move_as_error();
return;
}
dht_key_description.update_signature(R.move_as_ok());
dht_key_description.check().ensure();
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
dht::DhtValue dht_value{std::move(dht_key_description), serialize_tl_object(addr_list, true), ttl,
td::BufferSlice("")};
auto B = serialize_tl_object(dht_value.tl(), true);
auto Q = td::PromiseCreator::lambda(
[dht_node, dht_value = std::move(dht_value), print_id](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
LOG(ERROR) << print_id << ": cannot sign: " << R.move_as_error();
return;
}
dht_value.update_signature(R.move_as_ok());
dht_value.check().ensure();
auto E = td::PromiseCreator::lambda([print_id](td::Result<td::Unit> R) {
if (R.is_error()) {
VLOG(ADNL_NOTICE) << print_id << ": failed to update addr list in DHT: " << R.move_as_error();
} else {
VLOG(ADNL_INFO) << print_id << ": updated dht addr list";
}
});
td::actor::send_closure(dht_node, &dht::Dht::set_value, std::move(dht_value), std::move(E));
});
td::actor::send_closure(SelfId, &AdnlLocalId::sign_async, std::move(B), std::move(Q));
});
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(B),
std::move(P));
}
AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node) {
id_ = std::move(id);
short_id_ = id_.compute_short_id();
addr_list_ = std::move(addr_list);
if (addr_list_.addrs().size() > 0) {
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
}
peer_table_ = peer_table;
keyring_ = keyring;
dht_node_ = dht_node;
VLOG(ADNL_INFO) << this << ": created local id " << short_id_;
}
void AdnlLocalId::get_self_node(td::Promise<AdnlNode> promise) {
//addr_list_->version_ = static_cast<td::int32>(td::Clocks::system());
promise.set_value(AdnlNode{id_, addr_list_});
}
void AdnlLocalId::decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(keyring_, &keyring::Keyring::decrypt_message, short_id_.pubkey_hash(), std::move(data),
std::move(promise));
}
void AdnlLocalId::decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), p = std::move(promise)](td::Result<td::BufferSlice> res) mutable {
if (res.is_error()) {
p.set_error(res.move_as_error());
} else {
td::actor::send_closure_later(SelfId, &AdnlLocalId::decrypt_continue, res.move_as_ok(), std::move(p));
}
});
td::actor::send_closure(keyring_, &keyring::Keyring::decrypt_message, short_id_.pubkey_hash(), std::move(data),
std::move(P));
}
void AdnlLocalId::decrypt_continue(td::BufferSlice data, td::Promise<AdnlPacket> promise) {
auto R = fetch_tl_object<ton_api::adnl_packetContents>(std::move(data), true);
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
auto packetR = AdnlPacket::create(R.move_as_ok());
if (packetR.is_error()) {
promise.set_error(packetR.move_as_error());
return;
}
promise.set_value(packetR.move_as_ok());
}
void AdnlLocalId::sign_async(td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(data),
std::move(promise));
}
void AdnlLocalId::sign_batch_async(std::vector<td::BufferSlice> data,
td::Promise<std::vector<td::Result<td::BufferSlice>>> promise) {
td::actor::send_closure(keyring_, &keyring::Keyring::sign_messages, short_id_.pubkey_hash(), std::move(data),
std::move(promise));
}
void AdnlLocalId::start_up() {
publish_address_list();
alarm_timestamp() = td::Timestamp::in(AdnlPeerTable::republish_addr_list_timeout() * td::Random::fast(1.0, 2.0));
}
void AdnlLocalId::alarm() {
publish_address_list();
alarm_timestamp() = td::Timestamp::in(AdnlPeerTable::republish_addr_list_timeout() * td::Random::fast(1.0, 2.0));
}
void AdnlLocalId::update_packet(AdnlPacket packet, bool update_id, bool sign, td::int32 update_addr_list_if,
td::int32 update_priority_addr_list_if, td::Promise<AdnlPacket> promise) {
packet.init_random();
if (update_id) {
packet.set_source(id_);
}
if (!addr_list_.empty() && update_addr_list_if < addr_list_.version()) {
packet.set_addr_list(addr_list_);
}
if (!sign) {
promise.set_result(std::move(packet));
} else {
auto to_sign = packet.to_sign();
auto P = td::PromiseCreator::lambda(
[packet = std::move(packet), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
packet.set_signature(R.move_as_ok());
promise.set_value(std::move(packet));
}
});
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(to_sign),
std::move(P));
}
}
} // namespace adnl
} // namespace ton

117
adnl/adnl-local-id.h Normal file
View file

@ -0,0 +1,117 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <map>
#include "td/actor/actor.h"
#include "td/utils/BufferedUdp.h"
#include "auto/tl/ton_api.h"
#include "keys/encryptor.h"
#include "adnl-peer-table.h"
#include "dht/dht.h"
#include "adnl-peer-table.h"
#include "utils.hpp"
namespace ton {
namespace adnl {
class AdnlLocalId : public td::actor::Actor {
public:
AdnlNodeIdFull get_id() const;
AdnlNodeIdShort get_short_id() const;
AdnlAddressList get_addr_list() const;
void get_addr_list_async(td::Promise<AdnlAddressList> P) {
P.set_value(get_addr_list());
}
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
dht_node_ = dht_node;
publish_address_list();
}
void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
void decrypt_continue(td::BufferSlice data, td::Promise<AdnlPacket> promise);
void decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void deliver(AdnlNodeIdShort src, td::BufferSlice data);
void deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void receive(td::BufferSlice data);
void subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback);
void unsubscribe(std::string prefix);
void update_address_list(AdnlAddressList addr_list);
void get_self_node(td::Promise<AdnlNode> promise);
void sign_async(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void sign_batch_async(std::vector<td::BufferSlice> data,
td::Promise<std::vector<td::Result<td::BufferSlice>>> promise);
AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node);
void start_up() override;
void alarm() override;
void update_packet(AdnlPacket packet, bool update_id, bool sign, td::int32 update_addr_list_if,
td::int32 update_priority_addr_list_if, td::Promise<AdnlPacket> promise);
struct PrintId {
AdnlNodeIdShort id;
};
PrintId print_id() const {
return PrintId{short_id_};
}
private:
td::actor::ActorId<AdnlPeerTable> peer_table_;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<dht::Dht> dht_node_;
std::vector<std::pair<std::string, std::unique_ptr<AdnlPeerTable::Callback>>> cb_;
AdnlAddressList addr_list_;
AdnlNodeIdFull id_;
AdnlNodeIdShort short_id_;
void publish_address_list();
};
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId::PrintId &id) {
sb << "[localid " << id.id << "]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId &localid) {
sb << localid.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId *localid) {
sb << localid->print_id();
return sb;
}
} // namespace adnl
} // namespace ton

54
adnl/adnl-message.cpp Normal file
View file

@ -0,0 +1,54 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl-message.h"
#include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
namespace ton {
namespace adnl {
AdnlMessage::AdnlMessage(tl_object_ptr<ton_api::adnl_Message> message) {
ton_api::downcast_call(
*message.get(),
td::overloaded(
[&](ton_api::adnl_message_createChannel &msg) {
message_ = adnlmessage::AdnlMessageCreateChannel{msg.key_, msg.date_};
},
[&](ton_api::adnl_message_confirmChannel &msg) {
message_ = adnlmessage::AdnlMessageConfirmChannel{msg.key_, msg.peer_key_, msg.date_};
},
[&](ton_api::adnl_message_custom &msg) { message_ = adnlmessage::AdnlMessageCustom{std::move(msg.data_)}; },
[&](ton_api::adnl_message_nop &msg) { message_ = adnlmessage::AdnlMessageNop{}; },
[&](ton_api::adnl_message_reinit &msg) { message_ = adnlmessage::AdnlMessageReinit{msg.date_}; },
[&](ton_api::adnl_message_query &msg) {
message_ = adnlmessage::AdnlMessageQuery{msg.query_id_, std::move(msg.query_)};
},
[&](ton_api::adnl_message_answer &msg) {
message_ = adnlmessage::AdnlMessageAnswer{msg.query_id_, std::move(msg.answer_)};
},
[&](ton_api::adnl_message_part &msg) {
message_ = adnlmessage::AdnlMessagePart{msg.hash_, static_cast<td::uint32>(msg.total_size_),
static_cast<td::uint32>(msg.offset_), std::move(msg.data_)};
}));
}
} // namespace adnl
} // namespace ton

296
adnl/adnl-message.h Normal file
View file

@ -0,0 +1,296 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl/adnl.h"
#include "adnl/adnl-query.h"
namespace ton {
namespace adnl {
namespace adnlmessage {
class AdnlMessageCreateChannel {
public:
AdnlMessageCreateChannel(pubkeys::Ed25519 key, td::int32 date) : key_(key), date_(date) {
}
const auto &key() const {
return key_;
}
auto date() const {
return date_;
}
td::uint32 size() const {
return 40;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_createChannel>(key_.raw(), date_);
}
private:
pubkeys::Ed25519 key_;
td::int32 date_;
};
class AdnlMessageConfirmChannel {
public:
AdnlMessageConfirmChannel(pubkeys::Ed25519 key, pubkeys::Ed25519 peer_key, td::int32 date)
: key_(key), peer_key_(peer_key), date_(date) {
}
const auto &key() const {
return key_;
}
const auto &peer_key() const {
return peer_key_;
}
auto date() const {
return date_;
}
td::uint32 size() const {
return 72;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_confirmChannel>(key_.raw(), peer_key_.raw(), date_);
}
private:
pubkeys::Ed25519 key_;
pubkeys::Ed25519 peer_key_;
td::int32 date_;
};
class AdnlMessageCustom {
public:
AdnlMessageCustom(td::BufferSlice data) : data_(std::move(data)) {
}
auto data() const {
return data_.clone();
}
td::uint32 size() const {
return static_cast<td::uint32>(data_.size()) + 12;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_custom>(data_.clone());
}
private:
td::BufferSlice data_;
};
class AdnlMessageNop {
public:
AdnlMessageNop() {
}
td::uint32 size() const {
return 4;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_nop>();
}
private:
};
class AdnlMessageReinit {
public:
AdnlMessageReinit(td::int32 date) : date_(date) {
}
auto date() const {
return date_;
}
td::uint32 size() const {
return 8;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_reinit>(date_);
}
private:
td::int32 date_;
};
class AdnlMessageQuery {
public:
AdnlMessageQuery(AdnlQueryId query_id, td::BufferSlice data) : query_id_(query_id), data_(std::move(data)) {
}
const auto &query_id() const {
return query_id_;
}
auto data() const {
return data_.clone();
}
td::uint32 size() const {
return static_cast<td::uint32>(data_.size()) + 44;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_query>(query_id_, data_.clone());
}
private:
AdnlQueryId query_id_;
td::BufferSlice data_;
};
class AdnlMessageAnswer {
public:
AdnlMessageAnswer(AdnlQueryId query_id, td::BufferSlice data) : query_id_(query_id), data_(std::move(data)) {
}
const auto &query_id() const {
return query_id_;
}
auto data() const {
return data_.clone();
}
td::uint32 size() const {
return static_cast<td::uint32>(data_.size()) + 44;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_answer>(query_id_, data_.clone());
}
private:
AdnlQueryId query_id_;
td::BufferSlice data_;
};
class AdnlMessagePart {
public:
AdnlMessagePart(td::Bits256 hash, td::uint32 total_size, td::uint32 offset, td::BufferSlice data)
: hash_(hash), total_size_(total_size), offset_(offset), data_(std::move(data)) {
}
const auto &hash() const {
return hash_;
}
auto offset() const {
return offset_;
}
auto total_size() const {
return total_size_;
}
auto data() const {
return data_.clone();
}
td::uint32 size() const {
return static_cast<td::uint32>(data_.size()) + 48;
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
return create_tl_object<ton_api::adnl_message_part>(hash_, total_size_, offset_, data_.clone());
}
private:
td::Bits256 hash_;
td::uint32 total_size_;
td::uint32 offset_;
td::BufferSlice data_;
};
} // namespace adnlmessage
class AdnlMessage {
public:
class Empty {
public:
Empty() {
}
td::uint32 size() const {
UNREACHABLE();
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
UNREACHABLE();
}
};
private:
td::Variant<Empty, adnlmessage::AdnlMessageCreateChannel, adnlmessage::AdnlMessageConfirmChannel,
adnlmessage::AdnlMessageCustom, adnlmessage::AdnlMessageNop, adnlmessage::AdnlMessageReinit,
adnlmessage::AdnlMessageQuery, adnlmessage::AdnlMessageAnswer, adnlmessage::AdnlMessagePart>
message_{Empty{}};
public:
explicit AdnlMessage(tl_object_ptr<ton_api::adnl_Message> message);
template <class T>
AdnlMessage(T m) : message_(std::move(m)) {
}
tl_object_ptr<ton_api::adnl_Message> tl() const {
tl_object_ptr<ton_api::adnl_Message> res;
message_.visit([&](const auto &obj) { res = obj.tl(); });
return res;
}
td::uint32 size() const {
td::uint32 res;
message_.visit([&](const auto &obj) { res = obj.size(); });
return res;
}
template <class F>
void visit(F &&f) {
message_.visit(std::move(f));
}
template <class F>
void visit(F &&f) const {
message_.visit(std::move(f));
}
};
class AdnlMessageList {
public:
AdnlMessageList() {
}
AdnlMessageList(tl_object_ptr<ton_api::adnl_Message> message) {
auto msg = AdnlMessage{std::move(message)};
messages_.emplace_back(std::move(msg));
}
AdnlMessageList(std::vector<tl_object_ptr<ton_api::adnl_Message>> messages) {
for (auto &message : messages) {
messages_.push_back(AdnlMessage{std::move(message)});
}
}
void push_back(AdnlMessage message) {
messages_.push_back(std::move(message));
}
td::uint32 size() const {
return static_cast<td::uint32>(messages_.size());
}
tl_object_ptr<ton_api::adnl_Message> one_message() const {
CHECK(size() == 1);
return messages_[0].tl();
}
std::vector<tl_object_ptr<ton_api::adnl_Message>> mult_messages() const {
std::vector<tl_object_ptr<ton_api::adnl_Message>> vec;
for (auto &m : messages_) {
vec.emplace_back(m.tl());
}
return vec;
}
static std::vector<tl_object_ptr<ton_api::adnl_Message>> empty_vector() {
return std::vector<tl_object_ptr<ton_api::adnl_Message>>{};
}
auto &vector() {
return messages_;
}
private:
std::vector<AdnlMessage> messages_;
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,114 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-network-manager.hpp"
#include "adnl-peer-table.h"
namespace ton {
namespace adnl {
td::actor::ActorOwn<AdnlNetworkManager> AdnlNetworkManager::create(td::uint16 port) {
return td::actor::create_actor<AdnlNetworkManagerImpl>("NetworkManager", port);
}
void AdnlNetworkManagerImpl::add_listening_udp_port(td::uint16 port) {
class Callback : public td::UdpServer::Callback {
public:
Callback(td::actor::ActorShared<AdnlNetworkManagerImpl> manager) : manager_(std::move(manager)) {
}
private:
td::actor::ActorShared<AdnlNetworkManagerImpl> manager_;
void on_udp_message(td::UdpMessage udp_message) override {
td::actor::send_closure_later(manager_, &AdnlNetworkManagerImpl::receive_udp_message, std::move(udp_message));
}
};
auto X = td::UdpServer::create("udp server", port, std::make_unique<Callback>(actor_shared(this)));
X.ensure();
udp_servers_.emplace(port, X.move_as_ok());
}
void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
if (!callback_) {
LOG(ERROR) << this << ": dropping IN message [?->?]: peer table unitialized";
return;
}
if (message.error.is_error()) {
VLOG(ADNL_WARNING) << this << ": dropping ERROR message: " << message.error;
return;
}
if (message.data.size() >= get_mtu()) {
VLOG(ADNL_NOTICE) << this << ": received huge packet of size " << message.data.size();
}
received_messages_++;
if (received_messages_ % 64 == 0) {
VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << "udp messages";
}
VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size();
callback_->receive_packet(message.address, std::move(message.data));
}
void AdnlNetworkManagerImpl::send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) {
auto randseed = 1; // use DST?
while (priority > 0) {
if (out_desc_[priority].size() > 0) {
break;
}
priority--;
}
if (out_desc_[priority].size() == 0) {
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: no out desc";
return;
}
auto &dv = out_desc_[priority];
auto &v = dv[randseed % dv.size()];
if (!v.is_proxy()) {
auto it = udp_servers_.find(static_cast<td::uint16>(v.addr.get_port()));
CHECK(it != udp_servers_.end());
td::UdpMessage M;
M.address = dst_addr;
M.data = std::move(data);
CHECK(M.data.size() <= get_mtu());
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M));
} else {
auto it = udp_servers_.find(out_udp_port_);
CHECK(it != udp_servers_.end());
auto enc = v.proxy->encrypt(
AdnlProxy::Packet{dst_addr.get_ipv4(), static_cast<td::uint16>(dst_addr.get_port()), std::move(data)});
td::UdpMessage M;
M.address = v.addr;
M.data = std::move(enc);
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M));
}
}
} // namespace adnl
} // namespace ton

107
adnl/adnl-network-manager.h Normal file
View file

@ -0,0 +1,107 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/port/IPAddress.h"
#include "adnl-node-id.hpp"
#include "adnl-proxy-types.h"
namespace td {
class UdpServer;
}
namespace ton {
namespace adnl {
class AdnlPeerTable;
class AdnlNetworkConnection : public td::actor::Actor {
public:
class Callback {
public:
virtual void on_change_state(bool ready) = 0;
virtual ~Callback() = default;
};
virtual void send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority, td::BufferSlice message) = 0;
virtual bool is_alive() const = 0;
virtual bool is_active() const = 0;
virtual ~AdnlNetworkConnection() = default;
};
class AdnlNetworkManager : public td::actor::Actor {
public:
//using ConnHandle = td::uint64;
class Callback {
public:
virtual ~Callback() = default;
//virtual void receive_packet(td::IPAddress addr, ConnHandle conn_handle, td::BufferSlice data) = 0;
virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0;
};
static td::actor::ActorOwn<AdnlNetworkManager> create(td::uint16 out_port);
virtual ~AdnlNetworkManager() = default;
virtual void install_callback(std::unique_ptr<Callback> callback) = 0;
virtual void add_self_addr(td::IPAddress addr, td::uint32 priority) = 0;
virtual void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) = 0;
virtual void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) = 0;
//virtual void send_tcp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
// td::uint32 priority, td::BufferSlice data) = 0;
//virtual void send_answer_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
// ConnHandle conn_handle, td::uint32 priority, td::BufferSlice data) = 0;
static constexpr td::uint32 get_mtu() {
return 1440;
}
struct PrintId {};
PrintId print_id() const {
return PrintId{};
}
};
} // namespace adnl
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager::PrintId &id) {
sb << "[networkmanager]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager &manager) {
sb << manager.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager *manager) {
sb << manager->print_id();
return sb;
}
} // namespace td

View file

@ -0,0 +1,121 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "td/utils/BufferedUdp.h"
#include "td/net/UdpServer.h"
#include "td/net/TcpListener.h"
#include "td/actor/PromiseFuture.h"
#include "adnl-network-manager.h"
#include <map>
namespace td {
class UdpServer;
}
namespace ton {
namespace adnl {
class AdnlPeerTable;
class AdnlNetworkManagerImpl : public AdnlNetworkManager {
public:
struct OutDesc {
td::IPAddress addr;
std::shared_ptr<AdnlProxy> proxy;
bool is_proxy() const {
return proxy != nullptr;
}
bool operator==(const OutDesc &with) const {
return addr == with.addr && is_proxy() == with.is_proxy();
}
};
AdnlNetworkManagerImpl(td::uint16 out_udp_port) : out_udp_port_(out_udp_port) {
}
void install_callback(std::unique_ptr<Callback> callback) override {
callback_ = std::move(callback);
}
void add_self_addr(td::IPAddress addr, td::uint32 priority) override {
auto x = OutDesc{addr, nullptr};
auto &v = out_desc_[priority];
for (auto &y : v) {
if (x == y) {
return;
}
}
out_desc_[priority].push_back(std::move(x));
add_listening_udp_port(static_cast<td::uint16>(addr.get_port()));
}
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override {
auto x = OutDesc{addr, std::move(proxy)};
auto &v = out_desc_[priority];
for (auto &y : v) {
if (x == y) {
return;
}
}
out_desc_[priority].push_back(std::move(x));
if (!udp_servers_.count(out_udp_port_)) {
add_listening_udp_port(out_udp_port_);
}
}
void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32 priority,
td::BufferSlice data) override;
void add_listening_udp_port(td::uint16 port);
void receive_udp_message(td::UdpMessage message);
private:
std::unique_ptr<Callback> callback_;
std::map<td::uint32, std::vector<OutDesc>> out_desc_;
td::uint64 received_messages_ = 0;
td::uint64 sent_messages_ = 0;
std::map<td::uint16, td::actor::ActorOwn<td::UdpServer>> udp_servers_;
td::uint16 out_udp_port_;
};
} // namespace adnl
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManagerImpl &manager) {
sb << manager.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManagerImpl *manager) {
sb << manager->print_id();
return sb;
}
} // namespace td

130
adnl/adnl-node-id.hpp Normal file
View file

@ -0,0 +1,130 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "keys/keys.hpp"
#include "common/io.hpp"
namespace ton {
namespace adnl {
class AdnlNodeIdShort {
public:
explicit AdnlNodeIdShort(const PublicKeyHash &hash) : hash_(hash) {
}
explicit AdnlNodeIdShort(PublicKeyHash &&hash) : hash_(std::move(hash)) {
}
AdnlNodeIdShort() {
}
explicit AdnlNodeIdShort(td::Slice data) : hash_(data) {
}
explicit AdnlNodeIdShort(td::Bits256 value) : hash_(value) {
}
explicit AdnlNodeIdShort(tl_object_ptr<ton_api::adnl_id_short> obj) : hash_(obj->id_) {
}
const auto &pubkey_hash() const {
return hash_;
}
bool operator==(const AdnlNodeIdShort &with) const {
return hash_ == with.hash_;
}
bool operator!=(const AdnlNodeIdShort &with) const {
return hash_ != with.hash_;
}
bool operator<(const AdnlNodeIdShort &with) const {
return hash_ < with.hash_;
}
tl_object_ptr<ton_api::adnl_id_short> tl() const {
return create_tl_object<ton_api::adnl_id_short>(hash_.tl());
}
auto as_slice() {
return hash_.as_slice();
}
auto as_slice() const {
return hash_.as_slice();
}
auto uint256_value() const {
return hash_.uint256_value();
}
auto bits256_value() const {
return hash_.bits256_value();
}
static AdnlNodeIdShort zero() {
return AdnlNodeIdShort{PublicKeyHash::zero()};
}
bool is_zero() const {
return hash_.is_zero();
}
private:
PublicKeyHash hash_;
};
class AdnlNodeIdFull {
private:
explicit AdnlNodeIdFull(const tl_object_ptr<ton_api::PublicKey> &pub) : pub_(pub) {
}
public:
explicit AdnlNodeIdFull(const PublicKey &pub) : pub_(pub) {
}
explicit AdnlNodeIdFull(PublicKey &&pub) : pub_(std::move(pub)) {
}
static td::Result<AdnlNodeIdFull> create(const tl_object_ptr<ton_api::PublicKey> &pub) {
return AdnlNodeIdFull{pub};
}
AdnlNodeIdFull() {
}
const auto &pubkey() const {
return pub_;
}
bool empty() const {
return pub_.empty();
}
bool operator==(const AdnlNodeIdFull &with) const {
return pub_ == with.pub_;
}
bool operator!=(const AdnlNodeIdFull &with) const {
return pub_ != with.pub_;
}
auto tl() const {
return pub_.tl();
}
AdnlNodeIdShort compute_short_id() const {
return AdnlNodeIdShort{pub_.compute_short_id()};
}
private:
PublicKey pub_;
};
} // namespace adnl
} // namespace ton
namespace td {
inline StringBuilder &operator<<(StringBuilder &stream, const ton::adnl::AdnlNodeIdShort &value) {
return stream << value.bits256_value();
}
} // namespace td

50
adnl/adnl-node.cpp Normal file
View file

@ -0,0 +1,50 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-node.h"
namespace ton {
namespace adnl {
td::Result<AdnlNode> AdnlNode::create(const tl_object_ptr<ton_api::adnl_node> &obj) {
TRY_RESULT(id, AdnlNodeIdFull::create(obj->id_));
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(obj->addr_list_)));
return AdnlNode{std::move(id), std::move(addr_list)};
}
tl_object_ptr<ton_api::adnl_nodes> AdnlNodesList::tl() const {
std::vector<tl_object_ptr<ton_api::adnl_node>> vec;
for (auto &node : nodes_) {
vec.emplace_back(node.tl());
}
return create_tl_object<ton_api::adnl_nodes>(std::move(vec));
}
td::Result<AdnlNodesList> AdnlNodesList::create(const tl_object_ptr<ton_api::adnl_nodes> &nodes) {
AdnlNodesList res{};
for (auto &node : nodes->nodes_) {
TRY_RESULT(N, AdnlNode::create(node));
res.push(std::move(N));
}
return res;
}
} // namespace adnl
} // namespace ton

74
adnl/adnl-node.h Normal file
View file

@ -0,0 +1,74 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "auto/tl/ton_api.h"
#include "adnl-node-id.hpp"
#include "adnl-address-list.h"
namespace ton {
namespace adnl {
class AdnlNode {
private:
AdnlNodeIdFull pub_;
AdnlAddressList addr_list_;
public:
AdnlNode(AdnlNodeIdFull pub, AdnlAddressList addr_list) : pub_(std::move(pub)), addr_list_(std::move(addr_list)) {
}
AdnlNode(const AdnlNode& from) : pub_(from.pub_), addr_list_(from.addr_list_) {
}
static td::Result<AdnlNode> create(const tl_object_ptr<ton_api::adnl_node>& obj);
tl_object_ptr<ton_api::adnl_node> tl() const {
return create_tl_object<ton_api::adnl_node>(pub_.tl(), addr_list_.tl());
}
AdnlNodeIdFull pub_id() const {
return pub_;
}
AdnlNodeIdShort compute_short_id() const {
return pub_.compute_short_id();
}
const AdnlAddressList& addr_list() const {
return addr_list_;
}
};
class AdnlNodesList {
private:
std::vector<AdnlNode> nodes_;
public:
const auto& nodes() const {
return nodes_;
}
AdnlNodesList() {
}
void push(AdnlNode node) {
nodes_.push_back(std::move(node));
}
tl_object_ptr<ton_api::adnl_nodes> tl() const;
static td::Result<AdnlNodesList> create(const tl_object_ptr<ton_api::adnl_nodes>& nodes);
};
} // namespace adnl
} // namespace ton

135
adnl/adnl-packet.cpp Normal file
View file

@ -0,0 +1,135 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-packet.h"
#include "td/utils/Random.h"
namespace ton {
namespace adnl {
/*adnl.packetContents rand1:bytes flags:# from:flags.0?PublicKey from_short:flags.1?adnl.id.short
message:flags.2?adnl.Message messages:flags.3?(vector adnl.Message)
address:flags.6?adnl.addressList seqno:flags.8?long recv_addr_list_version:flags.9?int
confirm_seqno:flags.10?long reinit_date:flags.11?int dst_reinit_date:flags.11?int
signature:flags.7?bytes rand2:bytes = adnl.PacketContents;*/
td::Result<AdnlPacket> AdnlPacket::create(tl_object_ptr<ton_api::adnl_packetContents> packet) {
AdnlPacket R;
R.rand1_ = std::move(packet->rand1_);
R.flags_ = packet->flags_;
if (R.flags_ & Flags::f_from) {
TRY_RESULT(F, AdnlNodeIdFull::create(packet->from_));
R.from_ = std::move(F);
}
if (R.flags_ & Flags::f_from_short) {
R.from_short_ = AdnlNodeIdShort{packet->from_short_->id_};
} else if (packet->flags_ & Flags::f_from) {
R.from_short_ = R.from_.compute_short_id();
}
if (R.flags_ & Flags::f_one_message) {
R.messages_ = AdnlMessageList{std::move(packet->message_)};
}
if (R.flags_ & Flags::f_mult_messages) {
// may override messages_ if (flags & 0x4)
// but this message will fail in run_basic_checks()
// so it doesn't matter
R.messages_ = AdnlMessageList{std::move(packet->messages_)};
}
if (R.flags_ & Flags::f_address) {
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(packet->address_)));
R.addr_ = std::move(addr_list);
}
if (R.flags_ & Flags::f_priority_address) {
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(packet->address_)));
R.priority_addr_ = std::move(addr_list);
}
if (R.flags_ & Flags::f_seqno) {
R.seqno_ = packet->seqno_;
}
if (R.flags_ & Flags::f_confirm_seqno) {
R.confirm_seqno_ = packet->confirm_seqno_;
}
if (R.flags_ & Flags::f_recv_addr_version) {
R.recv_addr_list_version_ = packet->recv_addr_list_version_;
}
if (R.flags_ & Flags::f_recv_priority_addr_version) {
R.recv_priority_addr_list_version_ = packet->recv_priority_addr_list_version_;
}
if (R.flags_ & Flags::f_reinit_date) {
R.reinit_date_ = packet->reinit_date_;
R.dst_reinit_date_ = packet->dst_reinit_date_;
}
if (R.flags_ & Flags::f_signature) {
R.signature_ = std::move(packet->signature_);
}
R.rand2_ = std::move(packet->rand2_);
TRY_STATUS(R.run_basic_checks());
return std::move(R);
}
td::Status AdnlPacket::run_basic_checks() const {
if ((flags_ & Flags::f_all) != flags_) {
return td::Status::Error(ErrorCode::protoviolation, "bad flags");
}
if ((flags_ & Flags::f_one_message) && (flags_ & Flags::f_mult_messages)) {
return td::Status::Error(ErrorCode::protoviolation, "both flags 0x4 and 0x8 set");
}
if ((flags_ & Flags::f_from) && (flags_ & Flags::f_from_short) && from_.compute_short_id() != from_short_) {
return td::Status::Error(ErrorCode::protoviolation, "source and short source mismatch");
}
if ((flags_ & Flags::f_address) && addr_.empty()) {
return td::Status::Error(ErrorCode::protoviolation, "bad addr list");
}
if ((flags_ & Flags::f_priority_address) && priority_addr_.empty()) {
return td::Status::Error(ErrorCode::protoviolation, "bad addr list");
}
return td::Status::OK();
}
tl_object_ptr<ton_api::adnl_packetContents> AdnlPacket::tl() const {
return create_tl_object<ton_api::adnl_packetContents>(
rand1_.clone(), flags_ & ~Flags::f_priority, (flags_ & Flags::f_from) ? from_.tl() : nullptr,
(flags_ & Flags::f_from_short) ? from_short_.tl() : nullptr,
(flags_ & Flags::f_one_message) ? messages_.one_message() : nullptr,
(flags_ & Flags::f_mult_messages) ? messages_.mult_messages() : messages_.empty_vector(),
(flags_ & Flags::f_address) ? addr_.tl() : nullptr,
(flags_ & Flags::f_priority_address) ? priority_addr_.tl() : nullptr, seqno_, confirm_seqno_,
recv_addr_list_version_, recv_priority_addr_list_version_, reinit_date_, dst_reinit_date_, signature_.clone(),
rand2_.clone());
}
td::BufferSlice AdnlPacket::to_sign() const {
auto obj = tl();
obj->signature_.clear();
obj->flags_ &= ~Flags::f_signature;
CHECK(obj->signature_.size() == 0);
return serialize_tl_object(obj, true);
}
void AdnlPacket::init_random() {
rand1_ = td::BufferSlice{(td::Random::fast_uint32() & 1) ? 7u : 15u};
rand2_ = td::BufferSlice{(td::Random::fast_uint32() & 1) ? 7u : 15u};
td::Random::secure_bytes(rand1_.as_slice());
td::Random::secure_bytes(rand2_.as_slice());
}
} // namespace adnl
} // namespace ton

211
adnl/adnl-packet.h Normal file
View file

@ -0,0 +1,211 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl/adnl.h"
#include "adnl/adnl-message.h"
namespace ton {
namespace adnl {
/*
from:flags.0?PublicKey
from_short:flags.1?adnl.id.short
message:flags.2?adnl.Message
messages:flags.3?(vector adnl.Message)
address:flags.4?adnl.addressList
priority_address:flags.5?adnl.addressList
seqno:flags.6?long
confirm_seqno:flags.7?long
recv_addr_list_version:flags.8?int
recv_priority_addr_list_version:flags.9?int
reinit_date:flags.10?int
dst_reinit_date:flags.10?int
signature:flags.11?bytes
*/
// total packet length:
// for full packet:
// 32 (dst) + 64 (encryption overhead) + 4 (magic) + 36 (pubkey) + 4 + M (sum of messages) +
// + A1 + A2 + 8 + 8 + 4 + 4 + 4 + 4 + 68 (signature) + 16 (r1) + 16 (r2) =
// = 272 + M + A1 + A2
// for channel:
// 32 (channel id) + 32 (encryption overhead) + 4 (magic) + 4 + M (sum of messages) +
// + A1 + A2 + 8 + 8 + 4 + 4 + 16(r1) + 16(r2) = 128 + M + A1 + A2
class AdnlPacket {
private:
enum Flags : td::uint32 {
f_from = 0x1,
f_from_short = 0x2,
f_one_message = 0x4,
f_mult_messages = 0x8,
f_address = 0x10,
f_priority_address = 0x20,
f_seqno = 0x40,
f_confirm_seqno = 0x80,
f_recv_addr_version = 0x100,
f_recv_priority_addr_version = 0x200,
f_reinit_date = 0x400,
f_signature = 0x800,
f_priority = 0x1000,
f_all = 0x1fff
};
public:
AdnlPacket() {
}
static td::Result<AdnlPacket> create(tl_object_ptr<ton_api::adnl_packetContents> packet);
tl_object_ptr<ton_api::adnl_packetContents> tl() const;
td::BufferSlice to_sign() const;
td::Status run_basic_checks() const;
auto flags() const {
return flags_;
}
bool priority() const {
return flags_ & f_priority;
}
bool inited_from_short() const {
return flags_ & (Flags::f_from | Flags::f_from_short);
}
bool inited_from() const {
return flags_ & Flags::f_from;
}
auto from() const {
return from_;
}
auto from_short() const {
return from_short_;
}
const auto &messages() const {
return messages_;
}
auto &messages() {
return messages_;
}
bool inited_addr_list() const {
return flags_ & Flags::f_address;
}
auto addr_list() const {
return addr_;
}
auto priority_addr_list() const {
return priority_addr_;
}
auto seqno() const {
return seqno_;
}
auto confirm_seqno() const {
return confirm_seqno_;
}
auto recv_addr_list_version() const {
return recv_addr_list_version_;
}
auto recv_priority_addr_list_version() const {
return recv_priority_addr_list_version_;
}
auto reinit_date() const {
return reinit_date_;
}
auto dst_reinit_date() const {
return dst_reinit_date_;
}
auto signature() const {
return signature_.clone();
}
void init_random();
void set_signature(td::BufferSlice signature) {
signature_ = std::move(signature);
flags_ |= Flags::f_signature;
}
void set_source(AdnlNodeIdFull src) {
from_ = src;
from_short_ = src.compute_short_id();
flags_ = (flags_ | Flags::f_from) & ~Flags::f_from_short;
}
void set_source(AdnlNodeIdShort src) {
if (!(flags_ & Flags::f_from)) {
from_short_ = src;
flags_ |= Flags::f_from_short;
}
}
void add_message(AdnlMessage message) {
messages_.push_back(std::move(message));
if (messages_.size() == 1) {
flags_ = (flags_ | Flags::f_one_message) & ~Flags::f_mult_messages;
} else {
flags_ = (flags_ | Flags::f_mult_messages) & ~Flags::f_one_message;
}
}
void set_addr_list(AdnlAddressList addr_list) {
addr_ = std::move(addr_list);
flags_ |= Flags::f_address;
}
void set_priority_addr_list(AdnlAddressList addr_list) {
priority_addr_ = std::move(addr_list);
flags_ |= Flags::f_priority_address;
}
void set_seqno(td::uint64 seqno) {
seqno_ = seqno;
flags_ |= Flags::f_seqno;
}
void set_confirm_seqno(td::uint64 seqno) {
confirm_seqno_ = seqno;
flags_ |= Flags::f_confirm_seqno;
}
void set_received_addr_list_version(td::int32 version) {
recv_addr_list_version_ = version;
flags_ |= Flags::f_recv_addr_version;
}
void set_received_priority_addr_list_version(td::int32 version) {
recv_priority_addr_list_version_ = version;
flags_ |= Flags::f_recv_priority_addr_version;
}
void set_reinit_date(td::int32 date, td::int32 dst_reinit_date) {
reinit_date_ = date;
dst_reinit_date_ = dst_reinit_date;
flags_ |= Flags::f_reinit_date;
}
private:
td::BufferSlice rand1_;
td::uint32 flags_{0};
AdnlNodeIdFull from_;
AdnlNodeIdShort from_short_;
AdnlMessageList messages_;
AdnlAddressList addr_;
AdnlAddressList priority_addr_;
td::uint64 seqno_{0};
td::uint64 confirm_seqno_{0};
td::int32 recv_addr_list_version_{0};
td::int32 recv_priority_addr_list_version_{0};
td::int32 reinit_date_{0};
td::int32 dst_reinit_date_{0};
td::BufferSlice signature_;
td::BufferSlice rand2_;
};
} // namespace adnl
} // namespace ton

336
adnl/adnl-peer-table.cpp Normal file
View file

@ -0,0 +1,336 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-peer-table.hpp"
#include "adnl-peer.h"
#include "adnl-channel.h"
#include "utils.hpp"
#include "td/utils/tl_storers.h"
#include "td/utils/crypto.h"
#include "td/utils/tl_parsers.h"
#include "td/utils/Random.h"
#include "td/db/RocksDb.h"
#include "utils.hpp"
#include "adnl-query.h"
#include "adnl-ext-client.h"
namespace ton {
namespace adnl {
td::int32 Adnl::adnl_start_time() {
static td::int32 start_time = [] {
auto init_start_time = static_cast<td::int32>(td::Clocks::system());
CHECK(init_start_time > 0);
return init_start_time;
}();
return start_time;
}
td::actor::ActorOwn<Adnl> Adnl::create(std::string db, td::actor::ActorId<keyring::Keyring> keyring) {
adnl_start_time();
return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring));
}
void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
if (data.size() < 32) {
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
return;
}
AdnlNodeIdShort dst{data.as_slice().truncate(32)};
data.confirm_read(32);
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::receive, std::move(data));
return;
}
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
auto it2 = channels_.find(dst_chan_id);
if (it2 != channels_.end()) {
td::actor::send_closure(it2->second, &AdnlChannel::receive, std::move(data));
return;
}
VLOG(ADNL_DEBUG) << this << ": dropping IN message [?->" << dst << "]: unknown dst " << dst
<< " (len=" << (data.size() + 32) << ")";
}
void AdnlPeerTableImpl::receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) {
packet.run_basic_checks().ensure();
if (!packet.inited_from_short()) {
VLOG(ADNL_INFO) << this << ": dropping IN message [?->" << dst << "]: destination not set";
return;
}
auto it = peers_.find(packet.from_short());
if (it == peers_.end()) {
if (!packet.inited_from()) {
VLOG(ADNL_NOTICE) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
<< "]: unknown peer and no full src in packet";
return;
}
if (network_manager_.empty()) {
VLOG(ADNL_NOTICE) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
<< "]: unknown peer and network manager uninitialized";
return;
}
it = peers_
.emplace(packet.from_short(),
AdnlPeer::create(network_manager_, actor_id(this), dht_node_, packet.from_short()))
.first;
CHECK(it != peers_.end());
}
auto it2 = local_ids_own_.find(dst);
if (it2 == local_ids_own_.end()) {
VLOG(ADNL_ERROR) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
<< "]: unknown dst (but how did we decrypt message?)";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.get(), std::move(packet));
}
void AdnlPeerTableImpl::add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) {
auto id_short = id.compute_short_id();
VLOG(ADNL_DEBUG) << this << ": adding peer " << id_short << " for local id " << local_id;
auto it2 = local_ids_own_.find(local_id);
CHECK(it2 != local_ids_own_.end());
auto it = peers_.find(id_short);
if (it == peers_.end()) {
it = peers_.emplace(id_short, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, id_short)).first;
CHECK(it != peers_.end());
}
td::actor::send_closure(it->second, &AdnlPeer::update_id, std::move(id));
if (!addr_list.empty()) {
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.get(), std::move(addr_list));
}
}
void AdnlPeerTableImpl::add_static_nodes_from_config(AdnlNodesList nodes) {
for (auto &it : nodes.nodes()) {
add_static_node(it);
}
}
void AdnlPeerTableImpl::send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) {
auto it = peers_.find(dst);
if (it == peers_.end()) {
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
}
auto it2 = local_ids_own_.find(src);
if (it2 == local_ids_own_.end()) {
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.get(), std::move(message));
}
void AdnlPeerTableImpl::answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id,
td::BufferSlice data) {
if (data.size() > get_mtu()) {
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst
<< "]: message too big: size=" << data.size();
return;
}
send_message_in(src, dst, adnlmessage::AdnlMessageAnswer{query_id, std::move(data)});
}
void AdnlPeerTableImpl::send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) {
if (data.size() > huge_packet_max_size()) {
VLOG(ADNL_WARNING) << "dropping too big packet [" << src << "->" << dst << "]: size=" << data.size();
VLOG(ADNL_WARNING) << "DUMP: " << td::buffer_to_hex(data.as_slice().truncate(128));
return;
}
auto it = peers_.find(dst);
if (it == peers_.end()) {
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
}
auto it2 = local_ids_own_.find(src);
if (it2 == local_ids_own_.end()) {
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
return;
}
td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.get(), name, std::move(promise), timeout,
std::move(data));
}
void AdnlPeerTableImpl::add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) {
auto a = id.compute_short_id();
VLOG(ADNL_INFO) << "adnl: adding local id " << a;
auto it = local_ids_own_.find(a);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::update_address_list, std::move(addr_list));
} else {
local_ids_own_[a] = td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list),
actor_id(this), keyring_, dht_node_);
}
}
void AdnlPeerTableImpl::del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) {
VLOG(ADNL_INFO) << "adnl: deleting local id " << id;
local_ids_own_.erase(id);
promise.set_value(td::Unit());
}
void AdnlPeerTableImpl::subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) {
auto it = local_ids_own_.find(dst);
LOG_CHECK(it != local_ids_own_.end()) << "dst=" << dst;
td::actor::send_closure(it->second, &AdnlLocalId::subscribe, prefix, std::move(callback));
}
void AdnlPeerTableImpl::unsubscribe(AdnlNodeIdShort dst, std::string prefix) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::unsubscribe, prefix);
}
}
void AdnlPeerTableImpl::register_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
dht_node_ = dht_node;
for (auto it = peers_.begin(); it != peers_.end(); it++) {
td::actor::send_closure(it->second, &AdnlPeer::update_dht_node, dht_node_);
}
for (auto it = local_ids_own_.begin(); it != local_ids_own_.end(); it++) {
td::actor::send_closure(it->second, &AdnlLocalId::update_dht_node, dht_node_);
}
}
void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) {
network_manager_ = std::move(network_manager);
class Cb : public AdnlNetworkManager::Callback {
public:
void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, std::move(data));
}
Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) {
}
private:
td::actor::ActorId<AdnlPeerTableImpl> id_;
};
auto cb = std::make_unique<Cb>(actor_id(this));
td::actor::send_closure(network_manager_, &AdnlNetworkManager::install_callback, std::move(cb));
}
void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) {
auto it = local_ids_own_.find(id);
if (it == local_ids_own_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready));
return;
}
td::actor::send_closure(it->second, &AdnlLocalId::get_addr_list_async, std::move(promise));
}
void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) {
auto it = local_ids_own_.find(id);
if (it == local_ids_own_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready));
return;
}
td::actor::send_closure(it->second, &AdnlLocalId::get_self_node, std::move(promise));
}
void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) {
auto success = channels_.emplace(id, channel).second;
CHECK(success);
}
void AdnlPeerTableImpl::unregister_channel(AdnlChannelIdShort id) {
auto erased = channels_.erase(id);
CHECK(erased == 1);
}
void AdnlPeerTableImpl::start_up() {
}
void AdnlPeerTableImpl::write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
td::Promise<td::Unit> promise) {
td::actor::send_closure(db_, &AdnlDb::update, local_id, peer_id, std::move(node), std::move(promise));
}
void AdnlPeerTableImpl::get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
td::Promise<AdnlDbItem> promise) {
td::actor::send_closure(db_, &AdnlDb::get, local_id, peer_id, std::move(promise));
}
AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring) {
keyring_ = keyring;
static_nodes_manager_ = AdnlStaticNodesManager::create();
db_ = AdnlDb::create(db_root + "/adnl");
}
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::deliver, src, std::move(data));
}
}
void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise));
} else {
LOG(WARNING) << "deliver query: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot deliver: unknown DST"));
}
}
void AdnlPeerTableImpl::decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
auto it = local_ids_own_.find(dst);
if (it != local_ids_own_.end()) {
td::actor::send_closure(it->second, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise));
} else {
LOG(WARNING) << "decrypt message: unknown dst " << dst;
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot decrypt: unknown DST"));
}
}
void AdnlPeerTableImpl::create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) {
promise.set_value(AdnlExtServerCreator::create(actor_id(this), std::move(ids), std::move(ports)));
}
} // namespace adnl
} // namespace ton

124
adnl/adnl-peer-table.h Normal file
View file

@ -0,0 +1,124 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "td/utils/BufferedUdp.h"
#include "adnl.h"
#include "utils.hpp"
#include "adnl/adnl-query.h"
#include "adnl/adnl-db.h"
#include "common/io.hpp"
#include "adnl-packet.h"
#include "auto/tl/ton_api.h"
namespace ton {
namespace adnl {
constexpr int VERBOSITY_NAME(ADNL_ERROR) = verbosity_WARNING;
constexpr int VERBOSITY_NAME(ADNL_WARNING) = verbosity_INFO;
constexpr int VERBOSITY_NAME(ADNL_NOTICE) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(ADNL_INFO) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(ADNL_DEBUG) = verbosity_DEBUG + 1;
constexpr int VERBOSITY_NAME(ADNL_EXTRA_DEBUG) = verbosity_DEBUG + 10;
class AdnlChannelIdShortImpl {
public:
explicit AdnlChannelIdShortImpl(PublicKeyHash value) {
value_ = value.bits256_value();
}
explicit AdnlChannelIdShortImpl(td::Bits256 value) {
value_ = value;
}
AdnlChannelIdShortImpl() {
}
td::Bits256 bits256_value() const {
return value_;
}
auto tl() const {
return value_;
}
bool operator<(const AdnlChannelIdShortImpl &with) const {
return value_ < with.value_;
}
bool operator==(const AdnlChannelIdShortImpl &with) const {
return value_ == with.value_;
}
bool operator!=(const AdnlChannelIdShortImpl &with) const {
return value_ != with.value_;
}
td::Slice as_slice() const {
return td::as_slice(value_);
}
private:
td::Bits256 value_;
};
using AdnlChannelIdShort = AdnlChannelIdShortImpl;
class AdnlLocalId;
class AdnlChannel;
class AdnlPeerTable : public Adnl {
public:
static constexpr double republish_addr_list_timeout() {
return 60.0;
}
virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0;
virtual void receive_packet(td::BufferSlice data) = 0;
virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0;
virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) = 0;
virtual void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) = 0;
virtual void unregister_channel(AdnlChannelIdShort id) = 0;
virtual void add_static_node(AdnlNode node) = 0;
virtual void del_static_node(AdnlNodeIdShort id) = 0;
virtual void get_static_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) = 0;
virtual void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
td::Promise<td::Unit> promise) = 0;
virtual void get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
td::Promise<AdnlDbItem> promise) = 0;
virtual void deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
virtual void deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) = 0;
virtual void decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
};
} // namespace adnl
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &stream, const ton::adnl::AdnlChannelIdShort &value) {
return stream << value.bits256_value();
}
} // namespace td

137
adnl/adnl-peer-table.hpp Normal file
View file

@ -0,0 +1,137 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <map>
#include <set>
#include "adnl-peer-table.h"
#include "adnl-peer.h"
#include "keys/encryptor.h"
//#include "adnl-decryptor.h"
#include "adnl-local-id.h"
#include "adnl-query.h"
#include "utils.hpp"
#include "adnl-static-nodes.h"
#include "adnl-ext-server.h"
#include "adnl-address-list.h"
namespace ton {
namespace adnl {
class AdnlPeerTableImpl : public AdnlPeerTable {
public:
AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring);
void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override;
void add_static_nodes_from_config(AdnlNodesList nodes) override;
void receive_packet(td::BufferSlice data) override;
void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override;
void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) override;
void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {
if (data.size() > huge_packet_max_size()) {
VLOG(ADNL_WARNING) << "dropping too big packet [" << src << "->" << dst << "]: size=" << data.size();
VLOG(ADNL_WARNING) << "DUMP: " << td::buffer_to_hex(data.as_slice().truncate(128));
return;
}
send_message_in(src, dst, AdnlMessage{adnlmessage::AdnlMessageCustom{std::move(data)}});
}
void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) override;
void send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice data) override;
void send_query_ex(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice data, td::uint64 max_answer_size) override {
send_query(src, dst, name, std::move(promise), timeout, std::move(data));
}
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) override;
void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) override;
void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) override;
void unsubscribe(AdnlNodeIdShort dst, std::string prefix) override;
void register_dht_node(td::actor::ActorId<dht::Dht> dht_node) override;
void register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) override;
void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) override;
void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override;
void start_up() override;
void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) override;
void unregister_channel(AdnlChannelIdShort id) override;
void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
td::Promise<td::Unit> promise) override;
void get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
td::Promise<AdnlDbItem> promise) override;
void add_static_node(AdnlNode node) override {
CHECK(!static_nodes_manager_.empty());
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::add_node, std::move(node));
}
void del_static_node(AdnlNodeIdShort id) override {
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::del_node, id);
}
void get_static_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override {
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::get_node, id, std::move(promise));
}
void deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override;
void deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override;
void decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) override;
struct PrintId {};
PrintId print_id() const {
return PrintId{};
}
private:
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<AdnlNetworkManager> network_manager_;
td::actor::ActorId<dht::Dht> dht_node_;
td::actor::ActorOwn<AdnlStaticNodesManager> static_nodes_manager_;
void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message);
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_;
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlLocalId>> local_ids_own_;
std::map<AdnlChannelIdShort, td::actor::ActorId<AdnlChannel>> channels_;
td::actor::ActorOwn<AdnlDb> db_;
td::actor::ActorOwn<AdnlExtServer> ext_server_;
//std::map<td::uint64, td::actor::ActorId<AdnlQuery>> out_queries_;
//td::uint64 last_query_id_ = 1;
};
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlPeerTableImpl::PrintId &id) {
sb << "[peertable]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlPeerTableImpl &manager) {
sb << manager.print_id();
return sb;
}
} // namespace adnl
} // namespace ton

878
adnl/adnl-peer.cpp Normal file
View file

@ -0,0 +1,878 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-peer.h"
#include "adnl-peer.hpp"
#include "adnl-local-id.h"
#include "utils.hpp"
#include "td/actor/PromiseFuture.h"
#include "td/utils/base64.h"
#include "td/utils/Random.h"
#include "auto/tl/ton_api.h"
namespace ton {
namespace adnl {
static_assert(AdnlPeerPairImpl::get_mtu() + AdnlPeerPairImpl::packet_header_max_size() <= AdnlNetworkManager::get_mtu(),
"wrong mtu configuration");
void AdnlPeerPairImpl::start_up() {
auto P1 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<AdnlDbItem> R) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_db, std::move(R));
});
td::actor::send_closure(peer_table_, &AdnlPeerTable::get_addr_list_from_db, local_id_, peer_id_short_, std::move(P1));
auto P2 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<AdnlNode> R) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_static_nodes, std::move(R));
});
td::actor::send_closure(peer_table_, &AdnlPeerTable::get_static_node, peer_id_short_, std::move(P2));
if (!dht_node_.empty()) {
discover();
}
}
void AdnlPeerPairImpl::alarm() {
if (next_dht_query_at_ && next_dht_query_at_.is_in_past()) {
next_dht_query_at_ = td::Timestamp::never();
discover();
}
if (next_db_update_at_ && next_db_update_at_.is_in_past()) {
if (received_from_db_ && received_from_static_nodes_ && !peer_id_.empty()) {
AdnlDbItem item;
item.id = peer_id_;
item.addr_list = addr_list_;
item.priority_addr_list = priority_addr_list_;
td::actor::send_closure(peer_table_, &AdnlPeerTable::write_new_addr_list_to_db, local_id_, peer_id_short_,
std::move(item), [](td::Unit) {});
}
next_db_update_at_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
}
if (retry_send_at_ && retry_send_at_.is_in_past()) {
retry_send_at_ = td::Timestamp::never();
send_messages_in(std::move(pending_messages_), false);
}
alarm_timestamp().relax(next_dht_query_at_);
alarm_timestamp().relax(next_db_update_at_);
alarm_timestamp().relax(retry_send_at_);
}
void AdnlPeerPairImpl::discover() {
CHECK(!dht_query_active_);
CHECK(!dht_node_.empty());
dht_query_active_ = true;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = print_id(),
peer_id = peer_id_short_](td::Result<dht::DhtValue> kv) {
if (kv.is_error()) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht,
kv.move_as_error_prefix("failed to get from dht: "));
return;
}
auto k = kv.move_as_ok();
auto pub = AdnlNodeIdFull{k.key().public_key()};
CHECK(pub.compute_short_id() == peer_id);
auto addr_list = fetch_tl_object<ton_api::adnl_addressList>(k.value().clone(), true);
if (addr_list.is_error()) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht,
addr_list.move_as_error_prefix("bad dht value: "));
return;
}
auto F = AdnlAddressList::create(addr_list.move_as_ok());
if (F.is_error()) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht, F.move_as_error_prefix("bad dht value: "));
return;
}
AdnlNode node{pub, F.move_as_ok()};
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht, std::move(node));
});
td::actor::send_closure(dht_node_, &dht::Dht::get_value, dht::DhtKey{peer_id_short_.pubkey_hash(), "address", 0},
std::move(P));
}
void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
auto d = Adnl::adnl_start_time();
if (packet.dst_reinit_date() > d) {
VLOG(ADNL_WARNING) << this << ": dropping IN message: too new our reinit date " << packet.dst_reinit_date();
return;
}
if (packet.reinit_date() > td::Clocks::system() + 60) {
VLOG(ADNL_NOTICE) << this << ": dropping IN message: too new peer reinit date " << packet.reinit_date();
return;
}
if (packet.reinit_date() > reinit_date_) {
reinit(packet.reinit_date());
}
if (packet.reinit_date() > 0 && packet.reinit_date() < reinit_date_) {
VLOG(ADNL_NOTICE) << this << ": dropping IN message: old peer reinit date " << packet.reinit_date();
return;
}
if (packet.dst_reinit_date() > 0 && packet.dst_reinit_date() < d) {
if (!packet.addr_list().empty()) {
update_addr_list(packet.addr_list());
}
if (!packet.priority_addr_list().empty()) {
update_addr_list(packet.priority_addr_list());
}
VLOG(ADNL_NOTICE) << this << ": dropping IN message old our reinit date " << packet.reinit_date() << " date=" << d;
auto M = AdnlMessage{adnlmessage::AdnlMessageNop{}};
send_message(std::move(M));
return;
}
if (packet.seqno() > 0) {
if (received_packet(static_cast<td::uint32>(packet.seqno()))) {
VLOG(ADNL_INFO) << this << ": dropping IN message: old seqno: " << packet.seqno() << " (current max " << in_seqno_
<< ")";
return;
}
}
if (packet.confirm_seqno() > 0) {
if (packet.confirm_seqno() > out_seqno_) {
VLOG(ADNL_WARNING) << this << ": dropping IN message: new ack seqno: " << packet.confirm_seqno()
<< " (current max sent " << out_seqno_ << ")";
return;
}
}
// accepted
// delivering
add_received_packet(static_cast<td::uint32>(packet.seqno()));
if (packet.confirm_seqno() > ack_seqno_) {
ack_seqno_ = packet.confirm_seqno();
}
if (packet.recv_addr_list_version() > peer_recv_addr_list_version_) {
peer_recv_addr_list_version_ = packet.recv_addr_list_version();
}
if (packet.recv_priority_addr_list_version() > peer_recv_priority_addr_list_version_) {
peer_recv_priority_addr_list_version_ = packet.recv_priority_addr_list_version();
}
if (!packet.addr_list().empty()) {
update_addr_list(packet.addr_list());
}
if (!packet.priority_addr_list().empty()) {
update_addr_list(packet.priority_addr_list());
}
received_messages_++;
if (received_messages_ % 64 == 0) {
VLOG(ADNL_INFO) << this << ": received " << received_messages_ << " messages";
}
for (auto &M : packet.messages().vector()) {
deliver_message(std::move(M));
}
}
void AdnlPeerPairImpl::receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) {
if (id != channel_in_id_) {
VLOG(ADNL_NOTICE) << this << ": dropping IN message: outdated channel id" << id;
return;
}
channel_ready_ = true;
receive_packet_checked(std::move(packet));
}
void AdnlPeerPairImpl::receive_packet(AdnlPacket packet) {
packet.run_basic_checks().ensure();
if (!encryptor_) {
VLOG(ADNL_NOTICE) << this << "dropping IN message: unitialized id";
return;
}
auto S = encryptor_->check_signature(packet.to_sign().as_slice(), packet.signature().as_slice());
if (S.is_error()) {
VLOG(ADNL_NOTICE) << this << "dropping IN message: bad signature: " << S;
return;
}
receive_packet_checked(std::move(packet));
}
void AdnlPeerPairImpl::deliver_message(AdnlMessage message) {
message.visit([&](const auto &obj) { this->process_message(obj); });
}
void AdnlPeerPairImpl::send_messages_in(std::vector<AdnlMessage> messages, bool allow_postpone) {
auto connR = get_conn();
if (connR.is_error()) {
if (!allow_postpone) {
VLOG(ADNL_NOTICE) << this << ": dropping OUT messages: cannot get conn: " << connR.move_as_error();
return;
}
VLOG(ADNL_INFO) << this << ": delaying OUT messages: cannot get conn: " << connR.move_as_error();
if (!retry_send_at_) {
retry_send_at_.relax(td::Timestamp::in(10.0));
alarm_timestamp().relax(retry_send_at_);
}
for (auto &m : messages) {
pending_messages_.push_back(std::move(m));
}
return;
}
auto conn = connR.move_as_ok();
size_t ptr = 0;
bool first = true;
do {
size_t s = (channel_ready_ ? channel_packet_header_max_size() : packet_header_max_size());
if (first) {
s += 2 * addr_list_max_size();
}
AdnlPacket packet;
packet.set_seqno(++out_seqno_);
packet.set_confirm_seqno(in_seqno_);
if (first) {
if (!channel_inited_) {
auto M = adnlmessage::AdnlMessageCreateChannel{channel_pub_, channel_pk_date_};
s += M.size();
packet.add_message(std::move(M));
} else if (!channel_ready_) {
auto M = adnlmessage::AdnlMessageConfirmChannel{channel_pub_, peer_channel_pub_, channel_pk_date_};
s += M.size();
packet.add_message(std::move(M));
}
}
if (!addr_list_.empty()) {
packet.set_received_addr_list_version(addr_list_.version());
}
if (!priority_addr_list_.empty()) {
packet.set_received_priority_addr_list_version(priority_addr_list_.version());
}
while (ptr < messages.size()) {
auto &M = messages[ptr];
CHECK(M.size() <= get_mtu());
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
s += M.size();
packet.add_message(std::move(M));
ptr++;
} else {
break;
}
}
if (!channel_ready_) {
packet.set_reinit_date(Adnl::adnl_start_time(), reinit_date_);
packet.set_source(local_id_);
}
if (!first) {
if (!channel_inited_) {
auto M = adnlmessage::AdnlMessageCreateChannel{channel_pub_, channel_pk_date_};
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
s += M.size();
packet.add_message(std::move(M));
}
} else if (!channel_ready_) {
auto M = adnlmessage::AdnlMessageConfirmChannel{channel_pub_, peer_channel_pub_, channel_pk_date_};
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
s += M.size();
packet.add_message(std::move(M));
}
}
}
packet.run_basic_checks().ensure();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), conn, id = print_id(),
via_channel = channel_ready_](td::Result<AdnlPacket> res) {
if (res.is_error()) {
LOG(ERROR) << id << ": dropping OUT message: error while creating packet: " << res.move_as_error();
} else {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::send_packet_continue, res.move_as_ok(), conn, via_channel);
}
});
td::actor::send_closure(
local_actor_, &AdnlLocalId::update_packet, std::move(packet),
!channel_ready_ && ack_seqno_ == 0 && in_seqno_ == 0, !channel_ready_,
(first || s + addr_list_max_size() <= AdnlNetworkManager::get_mtu()) ? peer_recv_addr_list_version_
: 0x7fffffff,
(first || s + 2 * addr_list_max_size() <= AdnlNetworkManager::get_mtu()) ? peer_recv_priority_addr_list_version_
: 0x7fffffff,
std::move(P));
first = false;
} while (ptr < messages.size());
}
void AdnlPeerPairImpl::send_messages(std::vector<AdnlMessage> messages) {
std::vector<AdnlMessage> new_vec;
for (auto &M : messages) {
if (M.size() <= get_mtu()) {
new_vec.push_back(std::move(M));
} else {
auto B = serialize_tl_object(M.tl(), true);
CHECK(B.size() <= huge_packet_max_size());
auto hash = sha256_bits256(B.as_slice());
auto size = static_cast<td::uint32>(B.size());
td::uint32 offset = 0;
td::uint32 part_size = Adnl::get_mtu();
while (offset < size) {
auto data = B.clone();
if (data.size() > part_size) {
data.truncate(part_size);
}
B.confirm_read(data.size());
new_vec.push_back(AdnlMessage{adnlmessage::AdnlMessagePart{hash, size, offset, std::move(data)}});
offset += part_size;
}
}
}
send_messages_in(std::move(new_vec), true);
}
void AdnlPeerPairImpl::send_packet_continue(AdnlPacket packet, td::actor::ActorId<AdnlNetworkConnection> conn,
bool via_channel) {
packet.run_basic_checks().ensure();
auto B = serialize_tl_object(packet.tl(), true);
if (via_channel) {
if (channel_ready_) {
td::actor::send_closure(channel_, &AdnlChannel::send_message, priority_, conn, std::move(B));
} else {
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
<< "]: channel destroyed in process";
}
return;
}
if (!encryptor_) {
VLOG(ADNL_INFO) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
<< "]: empty encryptor";
return;
}
auto res = encryptor_->encrypt(B.as_slice());
if (res.is_error()) {
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
<< "]: failed to encrypt: " << res.move_as_error();
return;
}
auto X = res.move_as_ok();
auto enc = td::BufferSlice(X.size() + 32);
td::MutableSlice S = enc.as_slice();
S.copy_from(peer_id_short_.as_slice());
S.remove_prefix(32);
S.copy_from(X.as_slice());
td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_short_, priority_, std::move(enc));
}
void AdnlPeerPairImpl::send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice data) {
AdnlQueryId id = AdnlQuery::random_query_id();
CHECK(out_queries_.count(id) == 0);
auto P = [SelfId = actor_id(this)](AdnlQueryId id) {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::delete_query, id);
};
out_queries_[id] = AdnlQuery::create(std::move(promise), std::move(P), name, timeout, id);
send_message(adnlmessage::AdnlMessageQuery{id, std::move(data)});
}
void AdnlPeerPairImpl::alarm_query(AdnlQueryId id) {
out_queries_.erase(id);
}
AdnlPeerPairImpl::AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id) {
network_manager_ = network_manager;
peer_table_ = peer_table;
local_actor_ = local_actor;
peer_ = peer;
dht_node_ = dht_node;
local_id_ = local_id;
peer_id_short_ = peer_id;
channel_pk_ = privkeys::Ed25519::random();
channel_pub_ = channel_pk_.pub();
channel_pk_date_ = static_cast<td::int32>(td::Clocks::system());
}
void AdnlPeerPairImpl::create_channel(pubkeys::Ed25519 pub, td::uint32 date) {
if (channel_inited_ && peer_channel_pub_ == pub) {
return;
}
if (channel_inited_ && date <= peer_channel_date_) {
return;
}
if (channel_inited_) {
td::actor::send_closure(peer_table_, &AdnlPeerTable::unregister_channel, channel_in_id_);
channel_.reset();
channel_inited_ = false;
channel_ready_ = false;
}
CHECK(!channel_ready_);
peer_channel_pub_ = pub;
peer_channel_date_ = date;
auto R = AdnlChannel::create(channel_pk_, peer_channel_pub_, local_id_, peer_id_short_, channel_out_id_,
channel_in_id_, actor_id(this));
if (R.is_ok()) {
channel_ = R.move_as_ok();
channel_inited_ = true;
td::actor::send_closure_later(peer_table_, &AdnlPeerTable::register_channel, channel_in_id_, channel_.get());
} else {
VLOG(ADNL_WARNING) << this << ": failed to create channel: " << R.move_as_error();
}
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageCreateChannel &message) {
create_channel(message.key(), message.date());
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageConfirmChannel &message) {
if (message.peer_key() != channel_pub_) {
VLOG(ADNL_NOTICE) << this << ": received adnl.message.confirmChannel with bad peer_key";
return;
}
create_channel(message.key(), message.date());
if (!channel_inited_ || peer_channel_pub_ != message.key()) {
VLOG(ADNL_NOTICE) << this << ": received adnl.message.confirmChannel with old key";
return;
}
channel_ready_ = true;
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageCustom &message) {
td::actor::send_closure(local_actor_, &AdnlLocalId::deliver, peer_id_short_, message.data());
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageNop &message) {
// nop
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageReinit &message) {
reinit(message.date());
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageQuery &message) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), query_id = message.query_id()](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
LOG(WARNING) << "failed to answer query: " << R.move_as_error();
} else {
auto data = R.move_as_ok();
if (data.size() > Adnl::huge_packet_max_size()) {
LOG(WARNING) << "dropping too big answer query: size=" << data.size();
} else {
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::send_message,
AdnlMessage{adnlmessage::AdnlMessageAnswer{query_id, std::move(data)}});
}
}
});
td::actor::send_closure(local_actor_, &AdnlLocalId::deliver_query, peer_id_short_, message.data(), std::move(P));
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageAnswer &message) {
auto Q = out_queries_.find(message.query_id());
if (Q == out_queries_.end()) {
VLOG(ADNL_NOTICE) << this << ": dropping IN answer: unknown query id " << message.query_id();
return;
}
if (message.data().size() > Adnl::huge_packet_max_size()) {
VLOG(ADNL_NOTICE) << this << ": dropping IN answer: too big answer size";
return;
}
td::actor::send_closure_later(Q->second, &AdnlQuery::result, message.data());
out_queries_.erase(Q);
}
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessagePart &message) {
auto size = message.total_size();
if (size > huge_packet_max_size()) {
VLOG(ADNL_WARNING) << this << ": dropping too big huge message: size=" << size;
return;
}
if (message.hash().is_zero()) {
VLOG(ADNL_WARNING) << this << ": dropping huge message with zero hash";
return;
}
if (message.hash() != huge_message_hash_) {
huge_message_hash_.set_zero();
huge_message_.clear();
huge_message_offset_ = 0;
if (message.offset() == 0) {
huge_message_hash_ = message.hash();
huge_message_ = td::BufferSlice{size};
} else {
return;
}
}
auto data = message.data();
if (data.size() + message.offset() > size) {
VLOG(ADNL_WARNING) << this << ": dropping huge message with bad part";
return;
}
if (size != huge_message_.size()) {
VLOG(ADNL_WARNING) << this << ": dropping huge message part with inconsistent size";
return;
}
if (message.offset() == huge_message_offset_) {
auto S = huge_message_.as_slice();
S.remove_prefix(huge_message_offset_);
S.copy_from(data.as_slice());
huge_message_offset_ += static_cast<td::uint32>(data.size());
if (huge_message_offset_ == huge_message_.size()) {
//td::actor::send_closure(local_actor_, &AdnlLocalId::deliver, peer_id_short_, std::move(huge_message_));
if (sha256_bits256(huge_message_.as_slice()) != huge_message_hash_) {
VLOG(ADNL_WARNING) << this << ": dropping huge message: hash mismatch";
return;
}
huge_message_hash_.set_zero();
huge_message_offset_ = 0;
auto MR = fetch_tl_object<ton_api::adnl_Message>(std::move(huge_message_), true);
if (MR.is_error()) {
VLOG(ADNL_WARNING) << this << ": dropping huge message part with bad data";
return;
}
auto M = AdnlMessage{MR.move_as_ok()};
deliver_message(std::move(M));
}
}
}
void AdnlPeerPairImpl::delete_query(AdnlQueryId id) {
auto Q = out_queries_.find(id);
if (Q != out_queries_.end()) {
out_queries_.erase(Q);
}
}
void AdnlPeerPairImpl::reinit(td::int32 date) {
if (reinit_date_ == 0) {
reinit_date_ = date;
}
if (reinit_date_ < date) {
if (channel_inited_) {
td::actor::send_closure(peer_table_, &AdnlPeerTable::unregister_channel, channel_in_id_);
}
in_seqno_ = 0;
out_seqno_ = 0;
ack_seqno_ = 0;
recv_seqno_mask_ = 0;
channel_ready_ = false;
channel_inited_ = false;
peer_recv_addr_list_version_ = 0;
huge_message_offset_ = 0;
huge_message_hash_.set_zero();
huge_message_.clear();
channel_.release();
reinit_date_ = date;
}
}
td::Result<td::actor::ActorId<AdnlNetworkConnection>> AdnlPeerPairImpl::get_conn() {
if (!priority_addr_list_.empty() && priority_addr_list_.expire_at() < td::Clocks::system()) {
priority_addr_list_ = AdnlAddressList{};
priority_conns_.clear();
}
if (conns_.size() == 0 && priority_conns_.size() == 0) {
return td::Status::Error(ErrorCode::notready, PSTRING()
<< "empty network information: version=" << addr_list_.version()
<< " reinit_date=" << addr_list_.reinit_date()
<< " real_reinit_date=" << reinit_date_);
}
for (auto &conn : priority_conns_) {
if (conn.ready()) {
return conn.conn.get();
}
}
for (auto &conn : conns_) {
if (conn.ready()) {
return conn.conn.get();
}
}
return td::Status::Error(ErrorCode::notready, "no active connections");
}
void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
if (addr_list.empty()) {
return;
}
CHECK(addr_list.size() > 0);
if (addr_list.reinit_date() > td::Clocks::system() + 60) {
VLOG(ADNL_WARNING) << "dropping addr list with too new reinit date";
return;
}
if (addr_list.reinit_date() > reinit_date_) {
reinit(addr_list.reinit_date());
} else if (addr_list.reinit_date() < reinit_date_) {
return;
}
bool priority = addr_list.priority() > 0;
if ((priority ? priority_addr_list_ : addr_list_).version() >= addr_list.version()) {
if (priority && priority_addr_list_.version() == addr_list.version()) {
auto expire_at = addr_list.expire_at();
if (expire_at > priority_addr_list_.expire_at()) {
priority_addr_list_.set_expire_at(expire_at);
}
}
return;
}
VLOG(ADNL_INFO) << this << ": updating addr list to version " << addr_list.version() << " size=" << addr_list.size();
const auto addrs = addr_list.addrs();
std::vector<Conn> conns;
conns.resize(std::min(addr_list.size(), 3u));
auto &old_conns = priority ? priority_conns_ : conns_;
for (size_t i = 0; i < conns.size(); i++) {
auto &addr = addrs[i];
auto hash = addr->get_hash();
if (i < old_conns.size() && old_conns[i].addr->get_hash() == hash) {
conns[i] = std::move(old_conns[i]);
} else {
conns[i] = Conn{addr, actor_id(this), network_manager_};
}
}
old_conns = std::move(conns);
(priority ? priority_addr_list_ : addr_list_) = addr_list;
}
void AdnlPeerImpl::update_id(AdnlNodeIdFull id) {
CHECK(id.compute_short_id() == peer_id_short_);
if (!peer_id_.empty()) {
return;
}
peer_id_ = std::move(id);
for (auto &it : peer_pairs_) {
td::actor::send_closure(it.second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
}
}
void AdnlPeerPairImpl::Conn::create_conn(td::actor::ActorId<AdnlPeerPairImpl> peer,
td::actor::ActorId<AdnlNetworkManager> network_manager) {
auto id = addr->get_hash();
conn = addr->create_connection(network_manager, std::make_unique<ConnCallback>(peer, id));
}
void AdnlPeerPairImpl::conn_change_state(AdnlConnectionIdShort id, bool ready) {
if (ready) {
if (pending_messages_.size() > 0) {
send_messages_in(std::move(pending_messages_), true);
}
}
}
td::actor::ActorOwn<AdnlPeerPair> AdnlPeerPair::create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor,
td::actor::ActorId<AdnlPeer> peer_actor,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id) {
auto X = td::actor::create_actor<AdnlPeerPairImpl>("peerpair", network_manager, peer_table, local_actor, peer_actor,
dht_node, local_id, peer_id);
return td::actor::ActorOwn<AdnlPeerPair>(std::move(X));
}
td::actor::ActorOwn<AdnlPeer> AdnlPeer::create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id) {
auto X = td::actor::create_actor<AdnlPeerImpl>("peer", network_manager, peer_table, dht_node, peer_id);
return td::actor::ActorOwn<AdnlPeer>(std::move(X));
}
void AdnlPeerImpl::receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) {
if (packet.inited_from()) {
update_id(packet.from());
}
auto it = peer_pairs_.find(dst);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, dst_actor, actor_id(this), dht_node_, dst, peer_id_short_);
peer_pairs_.emplace(dst, std::move(X));
it = peer_pairs_.find(dst);
CHECK(it != peer_pairs_.end());
if (!peer_id_.empty()) {
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
}
}
td::actor::send_closure(it->second.get(), &AdnlPeerPair::receive_packet_checked, std::move(packet));
}
void AdnlPeerImpl::send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) {
auto it = peer_pairs_.find(src);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
peer_pairs_.emplace(src, std::move(X));
it = peer_pairs_.find(src);
CHECK(it != peer_pairs_.end());
if (!peer_id_.empty()) {
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
}
}
td::actor::send_closure(it->second, &AdnlPeerPair::send_messages, std::move(messages));
}
void AdnlPeerImpl::send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) {
auto it = peer_pairs_.find(src);
if (it == peer_pairs_.end()) {
auto X =
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
peer_pairs_.emplace(src, std::move(X));
it = peer_pairs_.find(src);
CHECK(it != peer_pairs_.end());
if (!peer_id_.empty()) {
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
}
}
td::actor::send_closure(it->second, &AdnlPeerPair::send_query, name, std::move(promise), timeout, std::move(data));
}
void AdnlPeerImpl::del_local_id(AdnlNodeIdShort local_id) {
peer_pairs_.erase(local_id);
}
void AdnlPeerImpl::update_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
dht_node_ = dht_node;
for (auto it = peer_pairs_.begin(); it != peer_pairs_.end(); it++) {
td::actor::send_closure(it->second, &AdnlPeerPair::update_dht_node, dht_node_);
}
}
void AdnlPeerImpl::update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) {
auto it = peer_pairs_.find(local_id);
if (it == peer_pairs_.end()) {
auto X = AdnlPeerPair::create(network_manager_, peer_table_, local_actor, actor_id(this), dht_node_, local_id,
peer_id_short_);
peer_pairs_.emplace(local_id, std::move(X));
it = peer_pairs_.find(local_id);
CHECK(it != peer_pairs_.end());
if (!peer_id_.empty()) {
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
}
}
td::actor::send_closure(it->second, &AdnlPeerPair::update_addr_list, std::move(addr_list));
}
void AdnlPeerPairImpl::got_data_from_db(td::Result<AdnlDbItem> R) {
received_from_db_ = false;
if (R.is_error()) {
return;
}
auto value = R.move_as_ok();
if (!value.id.empty()) {
update_peer_id(value.id);
}
update_addr_list(value.addr_list);
update_addr_list(value.priority_addr_list);
}
void AdnlPeerPairImpl::got_data_from_static_nodes(td::Result<AdnlNode> R) {
received_from_static_nodes_ = false;
if (R.is_error()) {
return;
}
auto value = R.move_as_ok();
if (!value.pub_id().empty()) {
update_peer_id(value.pub_id());
}
update_addr_list(value.addr_list());
}
void AdnlPeerPairImpl::got_data_from_dht(td::Result<AdnlNode> R) {
CHECK(dht_query_active_);
dht_query_active_ = false;
next_dht_query_at_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
if (R.is_error()) {
VLOG(ADNL_INFO) << this << ": dht query failed: " << R.move_as_error();
return;
}
auto value = R.move_as_ok();
if (!value.pub_id().empty()) {
update_peer_id(value.pub_id());
}
update_addr_list(value.addr_list());
}
void AdnlPeerPairImpl::update_peer_id(AdnlNodeIdFull id) {
if (peer_id_.empty()) {
peer_id_ = std::move(id);
auto R = peer_id_.pubkey().create_encryptor();
if (R.is_ok()) {
encryptor_ = R.move_as_ok();
} else {
VLOG(ADNL_WARNING) << this << ": failed to create encryptor: " << R.move_as_error();
}
}
CHECK(!peer_id_.empty());
}
} // namespace adnl
} // namespace ton

101
adnl/adnl-peer.h Normal file
View file

@ -0,0 +1,101 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "td/utils/BufferedUdp.h"
#include "dht/dht.h"
#include "adnl-peer-table.h"
#include "utils.hpp"
#include "auto/tl/ton_api.h"
namespace ton {
namespace adnl {
class AdnlPeerTable;
class AdnlNetworkManager;
class AdnlLocalId;
class AdnlNetworkConnection;
class AdnlPeer;
class AdnlPeerPair : public td::actor::Actor {
public:
virtual void receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) = 0;
virtual void receive_packet_checked(AdnlPacket packet) = 0;
virtual void receive_packet(AdnlPacket packet) = 0;
virtual void send_messages(std::vector<AdnlMessage> message) = 0;
inline void send_message(AdnlMessage message) {
std::vector<AdnlMessage> vec;
vec.push_back(std::move(message));
send_messages(std::move(vec));
}
static constexpr td::uint32 get_mtu() {
return Adnl::get_mtu() + 128;
}
virtual void send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice data) = 0;
virtual void alarm_query(AdnlQueryId query_id) = 0;
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
virtual void update_peer_id(AdnlNodeIdFull id) = 0;
virtual void update_addr_list(AdnlAddressList addr_list) = 0;
static td::actor::ActorOwn<AdnlPeerPair> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor,
td::actor::ActorId<AdnlPeer> peer_actor,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
AdnlNodeIdShort peer_id);
};
class AdnlPeer : public td::actor::Actor {
public:
virtual void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket message) = 0;
virtual void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) = 0;
virtual void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) = 0;
void send_one_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, AdnlMessage message) {
std::vector<AdnlMessage> vec;
vec.push_back(std::move(message));
send_messages(src, src_actor, std::move(vec));
}
void send_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, td::BufferSlice data) {
auto M = AdnlMessage{adnlmessage::AdnlMessageCustom{std::move(data)}};
send_one_message(src, src_actor, std::move(M));
}
static td::actor::ActorOwn<AdnlPeer> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id);
virtual void del_local_id(AdnlNodeIdShort local_id) = 0;
virtual void update_id(AdnlNodeIdFull id) = 0;
virtual void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) = 0;
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
};
} // namespace adnl
} // namespace ton

318
adnl/adnl-peer.hpp Normal file
View file

@ -0,0 +1,318 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <vector>
#include <map>
#include "adnl-peer.h"
#include "adnl-peer-table.h"
#include "adnl-network-manager.h"
#include "keys/encryptor.h"
#include "adnl-channel.h"
#include "adnl-query.h"
#include "crypto/Ed25519.h"
#include "td/utils/DecTree.h"
#include "utils.hpp"
namespace ton {
namespace adnl {
using AdnlConnectionIdShort = AdnlAddressImpl::Hash;
class AdnlPeerPairImpl : public AdnlPeerPair {
public:
static constexpr td::uint32 packet_header_max_size() {
return 272;
}
static constexpr td::uint32 channel_packet_header_max_size() {
return 128;
}
static constexpr td::uint32 addr_list_max_size() {
return 128;
}
static constexpr td::uint32 get_mtu() {
return Adnl::get_mtu() + 128;
}
static constexpr td::uint32 huge_packet_max_size() {
return Adnl::huge_packet_max_size() + 128;
}
AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id);
void start_up() override;
void alarm() override;
void discover();
void receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) override;
void receive_packet_checked(AdnlPacket packet) override;
void receive_packet(AdnlPacket packet) override;
void deliver_message(AdnlMessage message);
void send_messages_in(std::vector<AdnlMessage> messages, bool allow_postpone);
void send_messages(std::vector<AdnlMessage> messages) override;
void send_packet_continue(AdnlPacket packet, td::actor::ActorId<AdnlNetworkConnection> conn, bool via_channel);
void send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice data) override;
void alarm_query(AdnlQueryId id) override;
void discover_query_result(td::Result<dht::DhtValue> B, bool dummy);
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) override {
dht_node_ = dht_node;
}
void update_addr_list(AdnlAddressList addr_list) override;
void update_peer_id(AdnlNodeIdFull id) override;
void got_data_from_db(td::Result<AdnlDbItem> R);
void got_data_from_static_nodes(td::Result<AdnlNode> R);
void got_data_from_dht(td::Result<AdnlNode> R);
//void conn_ready(AdnlConnectionIdShort id, td::Result<td::actor::ActorOwn<AdnlNetworkConnection>> R);
void process_message(const adnlmessage::AdnlMessageCreateChannel &message);
void process_message(const adnlmessage::AdnlMessageConfirmChannel &message);
void process_message(const adnlmessage::AdnlMessageCustom &message);
void process_message(const adnlmessage::AdnlMessageNop &message);
void process_message(const adnlmessage::AdnlMessageReinit &message);
void process_message(const adnlmessage::AdnlMessageQuery &message);
void process_message(const adnlmessage::AdnlMessageAnswer &message);
void process_message(const adnlmessage::AdnlMessagePart &message);
void process_message(const AdnlMessage::Empty &message) {
UNREACHABLE();
}
void conn_change_state(AdnlConnectionIdShort conn_id, bool ready);
void delete_query(AdnlQueryId id);
struct PrintId {
AdnlNodeIdShort peer_id;
AdnlNodeIdShort local_id;
};
PrintId print_id() const {
return PrintId{peer_id_short_, local_id_};
}
private:
void reinit(td::int32 date);
td::Result<td::actor::ActorId<AdnlNetworkConnection>> get_conn();
void create_channel(pubkeys::Ed25519 pub, td::uint32 date);
bool received_packet(td::uint32 seqno) const {
CHECK(seqno > 0);
if (seqno + 64 <= in_seqno_) {
return true;
}
if (seqno > in_seqno_) {
return false;
}
return recv_seqno_mask_ & (1ull << (in_seqno_ - seqno));
}
void add_received_packet(td::uint32 seqno) {
CHECK(!received_packet(seqno));
if (seqno <= in_seqno_) {
recv_seqno_mask_ |= (1ull << (in_seqno_ - seqno));
} else {
auto old = in_seqno_;
in_seqno_ = seqno;
if (in_seqno_ - old >= 64) {
recv_seqno_mask_ = 1;
} else {
recv_seqno_mask_ = recv_seqno_mask_ << (in_seqno_ - old);
recv_seqno_mask_ |= 1;
}
}
}
struct Conn {
class ConnCallback : public AdnlNetworkConnection::Callback {
public:
void on_change_state(bool ready) override {
td::actor::send_closure(root_, &AdnlPeerPairImpl::conn_change_state, conn_id_, ready);
}
ConnCallback(td::actor::ActorId<AdnlPeerPairImpl> root, AdnlConnectionIdShort conn_id)
: root_(root), conn_id_(conn_id) {
}
private:
td::actor::ActorId<AdnlPeerPairImpl> root_;
AdnlConnectionIdShort conn_id_;
};
AdnlAddress addr;
td::actor::ActorOwn<AdnlNetworkConnection> conn;
Conn(AdnlAddress addr, td::actor::ActorId<AdnlPeerPairImpl> peer,
td::actor::ActorId<AdnlNetworkManager> network_manager)
: addr(std::move(addr)) {
create_conn(peer, network_manager);
}
Conn() {
}
bool ready() {
return !conn.empty() && conn.get_actor_unsafe().is_active();
}
void create_conn(td::actor::ActorId<AdnlPeerPairImpl> peer, td::actor::ActorId<AdnlNetworkManager> network_manager);
};
std::vector<AdnlMessage> pending_messages_;
td::actor::ActorId<AdnlNetworkManager> network_manager_;
td::actor::ActorId<AdnlPeerTable> peer_table_;
td::actor::ActorId<AdnlLocalId> local_actor_;
td::actor::ActorId<AdnlPeer> peer_;
td::actor::ActorId<dht::Dht> dht_node_;
td::uint32 priority_ = 0;
td::int32 reinit_date_ = 0;
bool channel_ready_ = false;
bool channel_inited_ = false;
AdnlChannelIdShort channel_in_id_;
AdnlChannelIdShort channel_out_id_;
privkeys::Ed25519 channel_pk_;
pubkeys::Ed25519 channel_pub_;
td::int32 channel_pk_date_;
td::actor::ActorOwn<AdnlChannel> channel_;
td::uint64 in_seqno_ = 0;
td::uint64 out_seqno_ = 0;
td::uint64 ack_seqno_ = 0;
td::uint64 recv_seqno_mask_ = 0;
td::uint32 peer_channel_date_ = 0;
pubkeys::Ed25519 peer_channel_pub_;
td::int32 peer_recv_addr_list_version_ = -1;
td::int32 peer_recv_priority_addr_list_version_ = -1;
td::Bits256 huge_message_hash_ = td::Bits256::zero();
td::BufferSlice huge_message_;
td::uint32 huge_message_offset_ = 0;
AdnlAddressList addr_list_;
AdnlAddressList priority_addr_list_;
std::vector<Conn> conns_;
std::vector<Conn> priority_conns_;
AdnlNodeIdFull peer_id_;
AdnlNodeIdShort peer_id_short_;
AdnlNodeIdShort local_id_;
std::unique_ptr<Encryptor> encryptor_;
std::map<AdnlQueryId, td::actor::ActorId<AdnlQuery>> out_queries_;
td::uint32 received_messages_ = 0;
bool received_from_db_ = false;
bool received_from_static_nodes_ = false;
bool dht_query_active_ = false;
td::Timestamp next_dht_query_at_ = td::Timestamp::never();
td::Timestamp next_db_update_at_ = td::Timestamp::never();
td::Timestamp retry_send_at_ = td::Timestamp::never();
};
class AdnlPeerImpl : public AdnlPeer {
public:
void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) override;
void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
std::vector<AdnlMessage> messages) override;
void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) override;
void del_local_id(AdnlNodeIdShort local_id) override;
void update_id(AdnlNodeIdFull id) override;
void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
AdnlAddressList addr_list) override;
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) override;
//void check_signature(td::BufferSlice data, td::BufferSlice signature, td::Promise<td::Unit> promise) override;
AdnlPeerImpl(td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id)
: peer_id_short_(peer_id), dht_node_(dht_node), peer_table_(peer_table), network_manager_(network_manager) {
}
struct PrintId {
AdnlNodeIdShort peer_id;
};
PrintId print_id() const {
return PrintId{peer_id_short_};
}
private:
AdnlNodeIdShort peer_id_short_;
AdnlNodeIdFull peer_id_;
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeerPair>> peer_pairs_;
td::actor::ActorId<dht::Dht> dht_node_;
td::actor::ActorId<AdnlPeerTable> peer_table_;
td::actor::ActorId<AdnlNetworkManager> network_manager_;
};
} // namespace adnl
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl::PrintId &id) {
sb << "[peer " << id.peer_id << "]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl &peer) {
sb << peer.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl *peer) {
sb << peer->print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl::PrintId &id) {
sb << "[peerpair " << id.peer_id << "-" << id.local_id << "]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl &peer) {
sb << peer.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl *peer) {
sb << peer->print_id();
return sb;
}
} // namespace td

87
adnl/adnl-proxy-types.cpp Normal file
View file

@ -0,0 +1,87 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-proxy-types.hpp"
#include "tl-utils/tl-utils.hpp"
#include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
#include "td/utils/Time.h"
#include "common/errorcode.h"
namespace ton {
namespace adnl {
td::BufferSlice AdnlProxyFast::encrypt(Packet packet) const {
auto date = static_cast<td::uint32>(td::Clocks::system());
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
packet.ip, packet.port, date, sha256_bits256(packet.data.as_slice()), shared_secret_);
auto obj = create_serialize_tl_object<ton_api::adnl_proxyToFast>(packet.ip, packet.port, date, signature);
td::BufferSlice res{32 + obj.size() + packet.data.size()};
auto S = res.as_slice();
S.copy_from(td::Bits256::zero().as_slice());
S.remove_prefix(32);
S.copy_from(obj.as_slice());
S.remove_prefix(obj.size());
S.copy_from(packet.data.as_slice());
return res;
}
td::Result<AdnlProxy::Packet> AdnlProxyFast::decrypt(td::BufferSlice packet) const {
if (packet.size() < 36) {
return td::Status::Error(ErrorCode::protoviolation, "too short packet");
}
td::Bits256 v;
v.as_slice().copy_from(packet.as_slice().truncate(32));
if (!v.is_zero()) {
return td::Status::Error(ErrorCode::protoviolation, "non-zero DST");
}
packet.confirm_read(32);
TRY_RESULT(R, fetch_tl_prefix<ton_api::adnl_proxyToFast>(packet, true));
if (R->date_ < td::Clocks::system() - 8) {
return td::Status::Error(ErrorCode::protoviolation, "too old date");
}
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
R->ip_, R->port_, R->date_, sha256_bits256(packet.as_slice()), shared_secret_);
if (signature != R->signature_) {
return td::Status::Error(ErrorCode::protoviolation, "bad signature");
}
return Packet{static_cast<td::uint32>(R->ip_), static_cast<td::uint16>(R->port_), std::move(packet)};
}
td::Result<std::shared_ptr<AdnlProxy>> AdnlProxy::create(const ton_api::adnl_Proxy &proxy_type) {
std::shared_ptr<AdnlProxy> R;
ton_api::downcast_call(
const_cast<ton_api::adnl_Proxy &>(proxy_type),
td::overloaded([&](const ton_api::adnl_proxy_none &x) { R = std::make_shared<AdnlProxyNone>(); },
[&](const ton_api::adnl_proxy_fast &x) {
R = std::make_shared<AdnlProxyFast>(x.shared_secret_.as_slice());
}));
return R;
}
} // namespace adnl
} // namespace ton

45
adnl/adnl-proxy-types.h Normal file
View file

@ -0,0 +1,45 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/buffer.h"
#include "auto/tl/ton_api.h"
namespace ton {
namespace adnl {
class AdnlProxy {
public:
struct Packet {
td::uint32 ip;
td::uint16 port;
td::BufferSlice data;
};
virtual ~AdnlProxy() = default;
virtual td::BufferSlice encrypt(Packet packet) const = 0;
virtual td::Result<Packet> decrypt(td::BufferSlice packet) const = 0;
virtual tl_object_ptr<ton_api::adnl_Proxy> tl() const = 0;
static td::Result<std::shared_ptr<AdnlProxy>> create(const ton_api::adnl_Proxy &proxy_type);
};
} // namespace adnl
} // namespace ton

62
adnl/adnl-proxy-types.hpp Normal file
View file

@ -0,0 +1,62 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl-proxy-types.h"
#include "common/checksum.h"
namespace ton {
namespace adnl {
class AdnlProxyNone : public AdnlProxy {
public:
AdnlProxyNone() {
}
td::BufferSlice encrypt(Packet packet) const override {
return std::move(packet.data);
}
td::Result<Packet> decrypt(td::BufferSlice packet) const override {
return Packet{0, 0, std::move(packet)};
}
tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
return create_tl_object<ton_api::adnl_proxy_none>();
}
};
class AdnlProxyFast : public AdnlProxy {
public:
AdnlProxyFast(td::Slice shared_secret)
: shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) {
}
td::BufferSlice encrypt(Packet packet) const override;
td::Result<Packet> decrypt(td::BufferSlice packet) const override;
tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
return create_tl_object<ton_api::adnl_proxy_fast>(shared_secret_raw_.clone_as_buffer_slice());
}
private:
td::Bits256 shared_secret_;
td::SharedSlice shared_secret_raw_;
};
} // namespace adnl
} // namespace ton

265
adnl/adnl-proxy.cpp Normal file
View file

@ -0,0 +1,265 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/actor/actor.h"
#include "td/utils/buffer.h"
#include "td/utils/port/IPAddress.h"
#include "td/net/UdpServer.h"
#include "td/utils/port/signals.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/FileLog.h"
#include "td/utils/port/path.h"
#include "td/utils/port/user.h"
#include "td/utils/filesystem.h"
#include "common/checksum.h"
#include "common/errorcode.h"
#include "tl-utils/tl-utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "adnl-proxy-types.h"
#include <map>
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
namespace ton {
namespace adnl {
class Receiver : public td::actor::Actor {
public:
void start_up() override;
void receive_common(td::BufferSlice data);
void receive_from_client(td::BufferSlice data);
void receive_to_client(td::BufferSlice data);
Receiver(td::uint16 in_port, td::uint16 out_port, std::shared_ptr<AdnlProxy> proxy, td::IPAddress client_addr)
: in_port_(in_port), out_port_(out_port), proxy_(std::move(proxy)), addr_(client_addr) {
}
private:
td::uint16 in_port_;
td::uint16 out_port_;
std::shared_ptr<ton::adnl::AdnlProxy> proxy_;
td::IPAddress addr_;
td::actor::ActorOwn<td::UdpServer> out_udp_server_;
td::actor::ActorOwn<td::UdpServer> in_udp_server_;
};
void Receiver::start_up() {
class Callback : public td::UdpServer::Callback {
public:
Callback(td::actor::ActorId<Receiver> manager, td::uint32 mode) : manager_(std::move(manager)), mode_(mode) {
}
private:
td::actor::ActorId<Receiver> manager_;
const td::uint32 mode_;
void on_udp_message(td::UdpMessage udp_message) override {
if (udp_message.error.is_error()) {
LOG(DEBUG) << udp_message.error;
return;
}
if (mode_ == 0) {
td::actor::send_closure_later(manager_, &Receiver::receive_common, std::move(udp_message.data));
} else if (mode_ == 1) {
td::actor::send_closure_later(manager_, &Receiver::receive_from_client, std::move(udp_message.data));
} else {
td::actor::send_closure_later(manager_, &Receiver::receive_to_client, std::move(udp_message.data));
}
}
};
if (in_port_ == out_port_) {
auto X = td::UdpServer::create("udp server", in_port_, std::make_unique<Callback>(actor_id(this), 0));
X.ensure();
in_udp_server_ = X.move_as_ok();
} else {
auto X = td::UdpServer::create("udp server", in_port_, std::make_unique<Callback>(actor_id(this), 1));
X.ensure();
in_udp_server_ = X.move_as_ok();
X = td::UdpServer::create("udp server", out_port_, std::make_unique<Callback>(actor_id(this), 2));
X.ensure();
out_udp_server_ = X.move_as_ok();
}
}
void Receiver::receive_common(td::BufferSlice data) {
if (data.size() <= 32) {
return;
}
td::Bits256 id;
id.as_slice().copy_from(data.as_slice().truncate(32));
if (id.is_zero()) {
receive_from_client(std::move(data));
} else {
receive_to_client(std::move(data));
}
}
void Receiver::receive_from_client(td::BufferSlice data) {
auto F = proxy_->decrypt(std::move(data));
if (F.is_error()) {
return;
}
auto f = F.move_as_ok();
td::IPAddress a;
if (a.init_ipv4_port(td::IPAddress::ipv4_to_str(f.ip), f.port).is_error()) {
return;
}
td::UdpMessage M;
M.address = a;
M.data = std::move(f.data);
td::actor::send_closure(out_udp_server_.empty() ? in_udp_server_.get() : out_udp_server_.get(), &td::UdpServer::send,
std::move(M));
}
void Receiver::receive_to_client(td::BufferSlice data) {
LOG(DEBUG) << "proxying to " << addr_;
td::UdpMessage M;
M.address = addr_;
M.data = std::move(data);
td::actor::send_closure(in_udp_server_.empty() ? out_udp_server_.get() : in_udp_server_.get(), &td::UdpServer::send,
std::move(M));
}
} // namespace adnl
} // namespace ton
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
std::vector<td::actor::ActorOwn<ton::adnl::Receiver>> x;
std::unique_ptr<td::LogInterface> logger_;
SCOPE_EXIT {
td::log_interface = td::default_log_interface;
};
std::string config = "/var/ton-work/etc/adnl-proxy.conf.json";
td::OptionsParser p;
p.set_description("validator or full node for TON network");
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
SET_VERBOSITY_LEVEL(v);
return td::Status::OK();
});
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('c', "config", "config file", [&](td::Slice arg) {
config = arg.str();
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto F = std::make_unique<td::FileLog>();
TRY_STATUS(F->init(fname.str()));
logger_ = std::move(F);
td::log_interface = logger_.get();
return td::Status::OK();
});
#endif
td::uint32 threads = 7;
p.add_option('t', "threads", PSTRING() << "number of threads (default=" << threads << ")", [&](td::Slice fname) {
td::int32 v;
try {
v = std::stoi(fname.str());
} catch (...) {
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: not a number");
}
if (v < 1 || v > 256) {
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: should be in range [1..256]");
}
threads = v;
return td::Status::OK();
});
p.add_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user); });
p.run(argc, argv).ensure();
td::actor::Scheduler scheduler({threads});
auto R = [&]() -> td::Status {
TRY_RESULT_PREFIX(conf_data, td::read_file(config), "failed to read: ");
TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
ton::ton_api::engine_adnlProxy_config conf;
TRY_STATUS_PREFIX(ton::ton_api::from_json(conf, conf_json.get_object()), "json does not fit TL scheme: ");
if (!conf.ports_.size()) {
return td::Status::Error("empty config");
}
for (auto &y : conf.ports_) {
auto in_port = static_cast<td::uint16>(y->in_port_);
auto out_port = static_cast<td::uint16>(y->out_port_);
if (!y->proxy_type_) {
return td::Status::Error("empty proxy type");
}
TRY_RESULT(proxy, ton::adnl::AdnlProxy::create(*y->proxy_type_.get()));
td::IPAddress a;
a.init_ipv4_port(td::IPAddress::ipv4_to_str(y->dst_ip_), static_cast<td::uint16>(y->dst_port_)).ensure();
scheduler.run_in_context([&] {
x.push_back(td::actor::create_actor<ton::adnl::Receiver>("adnl-proxy", in_port, out_port, std::move(proxy), a));
});
}
return td::Status::OK();
}();
if (R.is_error()) {
LOG(FATAL) << "bad config: " << R.move_as_error();
}
while (scheduler.run(1)) {
}
}

44
adnl/adnl-query.cpp Normal file
View file

@ -0,0 +1,44 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-query.h"
#include "common/errorcode.h"
#include "td/utils/Random.h"
namespace ton {
namespace adnl {
void AdnlQuery::alarm() {
promise_.set_error(td::Status::Error(ErrorCode::timeout, "adnl query timeout"));
stop();
}
void AdnlQuery::result(td::BufferSlice data) {
promise_.set_value(std::move(data));
stop();
}
AdnlQueryId AdnlQuery::random_query_id() {
AdnlQueryId q_id;
td::Random::secure_bytes(q_id.as_slice());
return q_id;
}
} // namespace adnl
} // namespace ton

67
adnl/adnl-query.h Normal file
View file

@ -0,0 +1,67 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "common/bitstring.h"
#include "td/utils/buffer.h"
#include <functional>
namespace ton {
namespace adnl {
class AdnlPeerPair;
using AdnlQueryId = td::Bits256;
class AdnlQuery : public td::actor::Actor {
public:
static td::actor::ActorId<AdnlQuery> create(td::Promise<td::BufferSlice> promise,
std::function<void(AdnlQueryId)> destroy, std::string name,
td::Timestamp timeout, AdnlQueryId id) {
return td::actor::create_actor<AdnlQuery>("query", name, std::move(promise), std::move(destroy), timeout, id)
.release();
}
static AdnlQueryId random_query_id();
AdnlQuery(std::string name, td::Promise<td::BufferSlice> promise, std::function<void(AdnlQueryId)> destroy,
td::Timestamp timeout, AdnlQueryId id)
: name_(std::move(name)), timeout_(timeout), promise_(std::move(promise)), destroy_(std::move(destroy)), id_(id) {
}
void alarm() override;
void result(td::BufferSlice data);
void start_up() override {
alarm_timestamp() = timeout_;
}
void tear_down() override {
destroy_(id_);
}
private:
std::string name_;
td::Timestamp timeout_;
td::Promise<td::BufferSlice> promise_;
std::function<void(AdnlQueryId)> destroy_;
AdnlQueryId id_;
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,55 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-static-nodes.h"
#include "adnl-static-nodes.hpp"
#include "utils.hpp"
namespace ton {
namespace adnl {
void AdnlStaticNodesManagerImpl::add_node(AdnlNode node) {
auto id_short = node.compute_short_id();
VLOG(ADNL_INFO) << "[staticnodes] adding static node " << id_short;
nodes_.emplace(id_short, std::move(node));
}
void AdnlStaticNodesManagerImpl::del_node(AdnlNodeIdShort id) {
nodes_.erase(id);
}
td::Result<AdnlNode> AdnlStaticNodesManagerImpl::get_node(AdnlNodeIdShort id) {
auto it = nodes_.find(id);
if (it == nodes_.end()) {
return td::Status::Error(ErrorCode::notready, "static node not found");
}
return it->second;
}
td::actor::ActorOwn<AdnlStaticNodesManager> AdnlStaticNodesManager::create() {
auto X = td::actor::create_actor<AdnlStaticNodesManagerImpl>("staticnodesmanager");
return td::actor::ActorOwn<AdnlStaticNodesManager>(std::move(X));
}
} // namespace adnl
} // namespace ton

43
adnl/adnl-static-nodes.h Normal file
View file

@ -0,0 +1,43 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "td/utils/Status.h"
#include "td/actor/PromiseFuture.h"
#include "auto/tl/ton_api.h"
#include "adnl-peer-table.h"
namespace ton {
namespace adnl {
class AdnlStaticNodesManager : public td::actor::Actor {
public:
virtual void add_node(AdnlNode node) = 0;
virtual void del_node(AdnlNodeIdShort id) = 0;
virtual td::Result<AdnlNode> get_node(AdnlNodeIdShort id) = 0;
static td::actor::ActorOwn<AdnlStaticNodesManager> create();
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,42 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <map>
#include "adnl-static-nodes.h"
namespace ton {
namespace adnl {
class AdnlStaticNodesManagerImpl : public AdnlStaticNodesManager {
public:
void add_node(AdnlNode node) override;
void del_node(AdnlNodeIdShort id) override;
td::Result<AdnlNode> get_node(AdnlNodeIdShort id) override;
AdnlStaticNodesManagerImpl() {
}
private:
std::map<AdnlNodeIdShort, AdnlNode> nodes_;
};
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,38 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl-test-loopback-implementation.h"
namespace ton {
namespace adnl {
AdnlAddressList TestLoopbackNetworkManager::generate_dummy_addr_list(bool empty) {
auto obj = ton::create_tl_object<ton::ton_api::adnl_address_udp>(1, 1);
auto objv = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
objv.push_back(std::move(obj));
td::uint32 now = Adnl::adnl_start_time();
auto addrR = ton::adnl::AdnlAddressList::create(
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(objv), empty ? 0 : now, empty ? 0 : now, 0, 0));
addrR.ensure();
return addrR.move_as_ok();
}
} // namespace adnl
} // namespace ton

View file

@ -0,0 +1,86 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl/adnl.h"
#include "td/utils/Random.h"
#include <set>
namespace ton {
namespace adnl {
class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
public:
void install_callback(std::unique_ptr<Callback> callback) override {
CHECK(!callback_);
callback_ = std::move(callback);
}
void add_self_addr(td::IPAddress addr, td::uint32 priority) override {
}
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override {
}
void send_udp_packet(ton::adnl::AdnlNodeIdShort src_id, ton::adnl::AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
td::uint32 priority, td::BufferSlice data) override {
if (allowed_sources_.count(src_id) == 0 || allowed_destinations_.count(dst_id) == 0) {
// just drop
return;
}
if (loss_probability_ > 0 && td::Random::fast(0, 10000) < loss_probability_ * 10000) {
return;
}
CHECK(callback_);
callback_->receive_packet(dst_addr, std::move(data));
}
void add_node_id(AdnlNodeIdShort id, bool allow_send, bool allow_receive) {
if (allow_send) {
allowed_sources_.insert(id);
} else {
allowed_sources_.erase(id);
}
if (allow_receive) {
allowed_destinations_.insert(id);
} else {
allowed_destinations_.erase(id);
}
}
void set_loss_probability(double p) {
CHECK(p >= 0 && p <= 1);
loss_probability_ = p;
}
TestLoopbackNetworkManager() {
}
static AdnlAddressList generate_dummy_addr_list(bool empty = false);
private:
std::set<AdnlNodeIdShort> allowed_sources_;
std::set<AdnlNodeIdShort> allowed_destinations_;
std::unique_ptr<Callback> callback_;
double loss_probability_ = 0.0;
};
} // namespace adnl
} // namespace ton

120
adnl/adnl.h Normal file
View file

@ -0,0 +1,120 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/actor/actor.h"
#include "auto/tl/ton_api.h"
#include "td/utils/port/IPAddress.h"
#include "adnl-node-id.hpp"
#include "adnl-node.h"
#include "common/errorcode.h"
#include "keyring/keyring.h"
namespace ton {
namespace dht {
class Dht;
}
namespace adnl {
class AdnlNetworkManager;
class AdnlExtServer : public td::actor::Actor {
public:
virtual void add_local_id(AdnlNodeIdShort id) = 0;
virtual void add_tcp_port(td::uint16 port) = 0;
virtual ~AdnlExtServer() = default;
};
class AdnlSenderInterface : public td::actor::Actor {
public:
virtual ~AdnlSenderInterface() = default;
virtual void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
virtual void send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) = 0;
virtual void send_query_ex(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data,
td::uint64 max_answer_size) = 0;
};
class Adnl : public AdnlSenderInterface {
public:
class Callback {
public:
virtual void receive_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
virtual void receive_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) = 0;
virtual ~Callback() = default;
};
static constexpr td::uint32 get_mtu() {
return 1024;
}
static constexpr td::uint32 huge_packet_max_size() {
return 1024 * 8;
}
// adds node to peer table
// used mostly from DHT to avoid loops
virtual void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) = 0;
// adds address list for nodes from config
virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0;
// adds local id. After that you can send/receive messages from/to this id
virtual void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) = 0;
virtual void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) = 0;
// subscribe to (some) messages(+queries) to this local id
virtual void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) = 0;
virtual void unsubscribe(AdnlNodeIdShort dst, std::string prefix) = 0;
// register (main) dht node
// it will be used to send queries to DHT from adnl
// there are two types of queries:
// - discover node addr list for unknown node
// - update local node information
virtual void register_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
virtual void register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) = 0;
// get local id information
// for example when you need to sent it further
virtual void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) = 0;
virtual void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) = 0;
virtual void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) = 0;
static td::actor::ActorOwn<Adnl> create(std::string db, td::actor::ActorId<keyring::Keyring> keyring);
static std::string int_to_bytestring(td::int32 id) {
return std::string(reinterpret_cast<char *>(&id), 4);
}
static td::int32 adnl_start_time();
};
} // namespace adnl
using Adnl = adnl::Adnl;
} // namespace ton

View file

@ -0,0 +1,240 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl-network-manager.h"
#include "adnl/adnl-peer-table.h"
#include "adnl/utils.hpp"
#include "keys/encryptor.h"
#include "td/utils/Time.h"
#include "td/utils/format.h"
#include "td/utils/OptionsParser.h"
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class AdnlNode : public td::actor::Actor {
private:
std::vector<td::UInt256> ping_ids_;
td::actor::ActorOwn<ton::AdnlNetworkManager> network_manager_;
td::actor::ActorOwn<ton::AdnlPeerTable> peer_table_;
td::UInt256 local_id_;
bool local_id_set_ = false;
std::string host_ = "127.0.0.1";
td::uint32 ip_ = 0x7f000001;
td::uint16 port_ = 2380;
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) {
std::cout << "MESSAGE FROM " << src << " to " << dst << " of size " << std::to_string(data.size()) << "\n";
}
void receive_query(td::UInt256 src, td::UInt256 dst, td::uint64 query_id, td::BufferSlice data) {
std::cout << "QUERY " << std::to_string(query_id) << " FROM " << src << " to " << dst << " of size "
<< std::to_string(data.size()) << "\n";
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::answer_query, dst, src, query_id,
ton::create_tl_object<ton::ton_api::testObject>());
}
std::unique_ptr<ton::AdnlPeerTable::Callback> make_callback() {
class Callback : public ton::AdnlPeerTable::Callback {
public:
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlNode::receive_message, src, dst, std::move(data));
}
void receive_query(td::UInt256 src, td::UInt256 dst, td::uint64 query_id, td::BufferSlice data) override {
td::actor::send_closure(id_, &AdnlNode::receive_query, src, dst, query_id, std::move(data));
}
Callback(td::actor::ActorId<AdnlNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<AdnlNode> id_;
};
return std::make_unique<Callback>(td::actor::actor_id(this));
}
public:
void start_up() override {
alarm_timestamp() = td::Timestamp::in(1);
}
AdnlNode() {
network_manager_ = ton::AdnlNetworkManager::create();
peer_table_ = ton::AdnlPeerTable::create();
td::actor::send_closure(network_manager_, &ton::AdnlNetworkManager::register_peer_table, peer_table_.get());
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::register_network_manager, network_manager_.get());
}
void listen_udp(td::uint16 port) {
td::actor::send_closure(network_manager_, &ton::AdnlNetworkManager::add_listening_udp_port, "0.0.0.0", port);
port_ = port;
}
void set_host(td::IPAddress ip, std::string host) {
ip_ = ip.get_ipv4();
host_ = host;
}
void send_pings_to(td::UInt256 id) {
std::cout << "send pings to " << id << "\n";
ping_ids_.push_back(id);
}
void add_local_id(ton::tl_object_ptr<ton::ton_api::adnl_id_Pk> pk_) {
auto pub_ = ton::get_public_key(pk_);
local_id_ = ton::adnl_short_id(pub_);
std::cout << "local_id = '" << local_id_ << "'\n";
auto x = ton::create_tl_object<ton::ton_api::adnl_address_udp>(ip_, port_);
auto v = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
v.push_back(ton::move_tl_object_as<ton::ton_api::adnl_Address>(x));
auto y =
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(v), static_cast<td::int32>(td::Time::now()));
LOG(INFO) << "local_addr_list: " << ton::ton_api::to_string(y);
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::add_id, std::move(pk_), std::move(y));
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::subscribe, local_id_, "", make_callback());
local_id_set_ = true;
}
void add_foreign(ton::tl_object_ptr<ton::ton_api::adnl_id_Full> id,
ton::tl_object_ptr<ton::ton_api::adnl_addressList> addr_list) {
std::cout << ton::adnl_short_id(id) << "\n";
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::add_peer, std::move(id), std::move(addr_list));
}
void alarm() override {
std::cout << "alarm\n";
if (local_id_set_) {
for (auto it = ping_ids_.begin(); it != ping_ids_.end(); it++) {
auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> result) {
if (result.is_error()) {
std::cout << "received error " << result.move_as_error().to_string() << "\n";
} else {
auto message = result.move_as_ok();
std::cout << "received answer to query\n";
}
});
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::send_query, local_id_, *it, std::move(P),
td::Timestamp::in(5), ton::create_tl_object<ton::ton_api::getTestObject>());
}
}
alarm_timestamp() = td::Timestamp::in(1);
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
td::actor::ActorOwn<AdnlNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb({b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('p', "port", "sets udp port", [&](td::Slice port) {
td::actor::send_closure(x, &AdnlNode::listen_udp, static_cast<td::uint16>(std::stoi(port.str())));
return td::Status::OK();
});
p.add_option('a', "host", "sets local ip", [&](td::Slice ip) {
td::IPAddress addr;
auto R = addr.init_host_port(ip.str(), 0);
if (R.is_error()) {
return R;
}
td::actor::send_closure(x, &AdnlNode::set_host, addr, ip.str());
return td::Status::OK();
});
p.add_option('i', "id", "sets local id", [&](td::Slice id) {
td::actor::send_closure(x, &AdnlNode::add_local_id,
ton::create_tl_object<ton::ton_api::adnl_id_pk_unenc>(id.str()));
return td::Status::OK();
});
p.add_option('P', "peer", "adds peer id@host:port", [&](td::Slice id) {
auto pos = id.rfind('@');
if (pos == static_cast<size_t>(-1)) {
return td::Status::Error("--peer expected randomtag@host:port as argument");
}
auto s1 = id.substr(0, pos);
auto f_id = ton::create_tl_object<ton::ton_api::adnl_id_unenc>(s1.str());
td::IPAddress addr;
auto R = addr.init_host_port(td::CSlice(id.substr(pos + 1).str()));
if (R.is_error()) {
return R.move_as_error();
}
auto f_addr = ton::create_tl_object<ton::ton_api::adnl_address_udp>(addr.get_ipv4(), addr.get_port());
std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>> vv;
vv.push_back(ton::move_tl_object_as<ton::ton_api::adnl_Address>(f_addr));
auto f_addr_list =
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(vv), static_cast<int>(td::Time::now()));
td::actor::send_closure(x, &AdnlNode::add_foreign, ton::move_tl_object_as<ton::ton_api::adnl_id_Full>(f_id),
std::move(f_addr_list));
return td::Status::OK();
});
p.add_option('n', "node", "node to send pings to", [&](td::Slice node) {
auto R = get_uint256(node.str());
if (R.is_error()) {
return R.move_as_error();
}
td::actor::send_closure(x, &AdnlNode::send_pings_to, R.move_as_ok());
return td::Status::OK();
});
td::actor::Scheduler scheduler({2});
scheduler.run_in_context([&] {
x = td::actor::create_actor<AdnlNode>(td::actor::ActorInfoCreator::Options().with_name("A").with_poll());
});
scheudler.run();
return 0;
}

27
adnl/utils.cpp Normal file
View file

@ -0,0 +1,27 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "utils.hpp"
#include "tl/tl_object_store.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "keys/encryptor.h"
#include "auto/tl/ton_api.hpp"
#include "adnl-node-id.hpp"
namespace ton {} // namespace ton

45
adnl/utils.hpp Normal file
View file

@ -0,0 +1,45 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library 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 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/buffer.h"
#include "td/utils/misc.h"
#include "td/utils/crypto.h"
#include "td/utils/format.h"
#include "td/utils/base64.h"
#include "tl-utils/tl-utils.hpp"
#include "common/errorcode.h"
#include "common/checksum.h"
#include "adnl-node-id.hpp"
#include "common/status.h"
#include "adnl-node.h"
#include "adnl-address-list.hpp"
namespace ton {
namespace adnl {
inline bool adnl_node_is_older(AdnlNode &a, AdnlNode &b) {
return a.addr_list().version() < b.addr_list().version();
}
} // namespace adnl
} // namespace ton