2
This file is part of TON Blockchain Library.
4
TON Blockchain Library is free software: you can redistribute it and/or modify
5
it under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation, either version 2 of the License, or
7
(at your option) any later version.
9
TON Blockchain Library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
17
Copyright 2017-2020 Telegram Systems LLP
19
#include "adnl-ext-client.hpp"
20
#include "adnl-ext-client.h"
26
void AdnlExtClientImpl::alarm() {
30
if (conn_.empty() || !conn_.is_alive()) {
31
next_create_at_ = td::Timestamp::in(10.0);
32
alarm_timestamp() = next_create_at_;
34
auto fd = td::SocketFd::open(dst_addr_);
36
LOG(INFO) << "failed to connect to " << dst_addr_ << ": " << fd.move_as_error();
40
class Cb : public AdnlExtConnection::Callback {
42
td::actor::ActorId<AdnlExtClientImpl> id_;
45
void on_ready(td::actor::ActorId<AdnlExtConnection> conn) {
46
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_ready, conn);
48
void on_close(td::actor::ActorId<AdnlExtConnection> conn) {
49
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_stopped, conn);
51
Cb(td::actor::ActorId<AdnlExtClientImpl> id) : id_(id) {
55
conn_ = td::actor::create_actor<AdnlOutboundConnection>(td::actor::ActorOptions().with_name("outconn").with_poll(),
56
fd.move_as_ok(), std::make_unique<Cb>(actor_id(this)), dst_,
57
local_id_, actor_id(this));
61
void AdnlExtClientImpl::hangup() {
65
for (auto &it : out_queries_) {
66
td::actor::ActorOwn<>(it.second); // send hangup
71
void AdnlExtClientImpl::try_stop() {
72
if (is_closing_ && ref_cnt_ == 0 && out_queries_.empty()) {
77
td::Status AdnlOutboundConnection::process_custom_packet(td::BufferSlice &data, bool &processed) {
78
if (data.size() == 12) {
79
auto F = fetch_tl_object<ton_api::tcp_pong>(data.clone(), true);
82
return td::Status::OK();
85
if (!local_id_.empty() && nonce_.size() != 0) {
86
auto F = fetch_tl_object<ton_api::tcp_authentificationNonce>(data.clone(), true);
88
auto f = F.move_as_ok();
89
if (f->nonce_.size() == 0 || f->nonce_.size() > 512) {
90
return td::Status::Error(ErrorCode::protoviolation, "bad nonce size");
92
td::SecureString ss{nonce_.size() + f->nonce_.size()};
93
ss.as_mutable_slice().copy_from(nonce_.as_slice());
94
ss.as_mutable_slice().remove_prefix(nonce_.size()).copy_from(f->nonce_.as_slice());
96
TRY_RESULT(dec, local_id_.create_decryptor());
97
TRY_RESULT(B, dec->sign(ss.as_slice()));
100
create_tl_object<ton_api::tcp_authentificationComplete>(local_id_.compute_public_key().tl(), std::move(B));
101
send(serialize_tl_object(obj, true));
106
authorization_complete_ = true;
107
return td::Status::OK();
110
return td::Status::OK();
113
void AdnlOutboundConnection::start_up() {
114
AdnlExtConnection::start_up();
115
auto X = dst_.pubkey().create_encryptor();
117
LOG(ERROR) << "failed to init encryptor: " << X.move_as_error();
121
auto enc = X.move_as_ok();
123
td::BufferSlice d{256};
124
auto id = dst_.compute_short_id();
125
auto S = d.as_slice();
126
S.copy_from(id.as_slice());
128
S.truncate(256 - 64 - 32);
129
td::Random::secure_bytes(S);
132
auto R = enc->encrypt(S);
134
LOG(ERROR) << "failed to encrypt: " << R.move_as_error();
138
auto data = R.move_as_ok();
139
LOG_CHECK(data.size() == 256 - 32) << "size=" << data.size();
142
CHECK(S.size() == data.size());
143
S.copy_from(data.as_slice());
145
send_uninit(std::move(d));
147
if (!local_id_.empty()) {
148
nonce_ = td::SecureString{32};
149
td::Random::secure_bytes(nonce_.as_mutable_slice());
150
auto obj = create_tl_object<ton_api::tcp_authentificate>(td::BufferSlice{nonce_.as_slice()});
151
send(serialize_tl_object(obj, true));
155
void AdnlExtClientImpl::check_ready(td::Promise<td::Unit> promise) {
156
if (conn_.empty() || !conn_.is_alive()) {
157
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
160
td::actor::send_closure(td::actor::ActorId<AdnlExtConnection>{conn_.get()}, &AdnlExtConnection::check_ready_async,
164
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, td::IPAddress dst_addr,
165
std::unique_ptr<AdnlExtClient::Callback> callback) {
166
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), dst_addr, std::move(callback));
169
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, PrivateKey local_id,
170
td::IPAddress dst_addr,
171
std::unique_ptr<AdnlExtClient::Callback> callback) {
172
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), std::move(local_id), dst_addr,
173
std::move(callback));
176
td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) {
177
TRY_RESULT(F, fetch_tl_object<lite_api::adnl_message_answer>(std::move(data), true));
178
td::actor::send_closure(ext_client_, &AdnlExtClientImpl::answer_query, F->query_id_, std::move(F->answer_));
179
return td::Status::OK();
182
void AdnlExtMultiClientImpl::start_up() {
183
for (auto &id : ids_) {
184
add_server(id.first, id.second, [](td::Result<td::Unit> R) {});
189
void AdnlExtMultiClientImpl::add_server(AdnlNodeIdFull dst, td::IPAddress dst_addr, td::Promise<td::Unit> promise) {
190
for (auto &c : clients_) {
191
if (c.second->addr == dst_addr) {
192
promise.set_error(td::Status::Error(ErrorCode::error, "duplicate ip"));
197
auto g = ++generation_;
198
auto cli = std::make_unique<Client>(AdnlExtClient::create(dst, dst_addr, make_callback(g)), dst, dst_addr, g);
199
clients_[g] = std::move(cli);
202
void AdnlExtMultiClientImpl::del_server(td::IPAddress dst_addr, td::Promise<td::Unit> promise) {
203
for (auto &c : clients_) {
204
if (c.second->addr == dst_addr) {
205
if (c.second->ready) {
208
callback_->on_stop_ready();
211
clients_.erase(c.first);
212
promise.set_value(td::Unit());
216
promise.set_error(td::Status::Error(ErrorCode::error, "ip not found"));
219
void AdnlExtMultiClientImpl::send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
220
td::Promise<td::BufferSlice> promise) {
221
if (total_ready_ == 0) {
222
promise.set_error(td::Status::Error(ErrorCode::notready, "conn not ready"));
226
std::vector<td::uint32> vec;
227
for (auto &c : clients_) {
228
if (c.second->ready) {
229
vec.push_back(c.first);
232
CHECK(vec.size() == total_ready_);
234
auto &c = clients_[vec[td::Random::fast(0, td::narrow_cast<td::uint32>(vec.size() - 1))]];
236
td::actor::send_closure(c->client, &AdnlExtClient::send_query, std::move(name), std::move(data), timeout,
240
void AdnlExtMultiClientImpl::client_ready(td::uint32 idx, bool value) {
241
auto it = clients_.find(idx);
242
if (it == clients_.end()) {
245
auto &c = it->second;
246
if (c->ready == value) {
252
if (total_ready_ == 1) {
253
callback_->on_ready();
257
if (total_ready_ == 0) {
258
callback_->on_stop_ready();
263
std::unique_ptr<AdnlExtClient::Callback> AdnlExtMultiClientImpl::make_callback(td::uint32 g) {
264
class Cb : public Callback {
266
Cb(td::actor::ActorId<AdnlExtMultiClientImpl> id, td::uint32 idx) : id_(id), idx_(idx) {
269
void on_ready() override {
270
td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, true);
273
void on_stop_ready() override {
274
td::actor::send_closure(id_, &AdnlExtMultiClientImpl::client_ready, idx_, false);
278
td::actor::ActorId<AdnlExtMultiClientImpl> id_;
281
return std::make_unique<Cb>(actor_id(this), g);
284
td::actor::ActorOwn<AdnlExtMultiClient> AdnlExtMultiClient::create(
285
std::vector<std::pair<AdnlNodeIdFull, td::IPAddress>> ids, std::unique_ptr<AdnlExtClient::Callback> callback) {
286
return td::actor::create_actor<AdnlExtMultiClientImpl>("extmulticlient", std::move(ids), std::move(callback));