aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlevlam <levlam@telegram.org>2026-03-17 12:30:53 +0300
committerlevlam <levlam@telegram.org>2026-03-17 12:30:53 +0300
commit0ae923c493bceb75433de2682ba8ae29cc7bf88d (patch)
tree75f0d9228943f0a10e9f3eb4728b94838fbd46da
parent338e4e5e45359f9338c98d584ecb9485bf59dd1c (diff)
Add class ProxyChecker.
-rw-r--r--CMakeLists.txt2
-rw-r--r--td/telegram/Requests.cpp5
-rw-r--r--td/telegram/Td.cpp4
-rw-r--r--td/telegram/Td.h2
-rw-r--r--td/telegram/net/ConnectionCreator.cpp132
-rw-r--r--td/telegram/net/ConnectionCreator.h26
-rw-r--r--td/telegram/net/ProxyChecker.cpp161
-rw-r--r--td/telegram/net/ProxyChecker.h63
8 files changed, 237 insertions, 158 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f675365a7..f341d25b0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -541,6 +541,7 @@ set(TDLIB_SOURCE_PART2
td/telegram/net/NetQueryVerifier.cpp
td/telegram/net/NetStatsManager.cpp
td/telegram/net/Proxy.cpp
+ td/telegram/net/ProxyChecker.cpp
td/telegram/net/PublicRsaKeySharedCdn.cpp
td/telegram/net/PublicRsaKeySharedMain.cpp
td/telegram/net/PublicRsaKeyWatchdog.cpp
@@ -933,6 +934,7 @@ set(TDLIB_SOURCE_PART2
td/telegram/net/NetStatsManager.h
td/telegram/net/NetType.h
td/telegram/net/Proxy.h
+ td/telegram/net/ProxyChecker.h
td/telegram/net/PublicRsaKeySharedCdn.h
td/telegram/net/PublicRsaKeySharedMain.h
td/telegram/net/PublicRsaKeyWatchdog.h
diff --git a/td/telegram/Requests.cpp b/td/telegram/Requests.cpp
index 5979b075f..360807086 100644
--- a/td/telegram/Requests.cpp
+++ b/td/telegram/Requests.cpp
@@ -109,6 +109,7 @@
#include "td/telegram/net/NetStatsManager.h"
#include "td/telegram/net/NetType.h"
#include "td/telegram/net/Proxy.h"
+#include "td/telegram/net/ProxyChecker.h"
#include "td/telegram/NotificationGroupId.h"
#include "td/telegram/NotificationId.h"
#include "td/telegram/NotificationManager.h"
@@ -9003,8 +9004,8 @@ void Requests::on_request(uint64 id, const td_api::testProxy &request) {
return send_closure(td_actor_, &Td::send_error, id, r_proxy.move_as_error());
}
CREATE_OK_REQUEST_PROMISE();
- send_closure(G()->connection_creator(), &ConnectionCreator::test_proxy, r_proxy.move_as_ok(), request.dc_id_,
- request.timeout_, std::move(promise));
+ send_closure(td_->proxy_checker_, &ProxyChecker::test_proxy, r_proxy.move_as_ok(), request.dc_id_, request.timeout_,
+ std::move(promise));
}
void Requests::on_request(uint64 id, const td_api::testGetDifference &request) {
diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp
index 86087da25..810efbf16 100644
--- a/td/telegram/Td.cpp
+++ b/td/telegram/Td.cpp
@@ -60,6 +60,7 @@
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/net/NetStatsManager.h"
#include "td/telegram/net/Proxy.h"
+#include "td/telegram/net/ProxyChecker.h"
#include "td/telegram/net/TempAuthKeyWatchdog.h"
#include "td/telegram/NotificationManager.h"
#include "td/telegram/NotificationSettingsManager.h"
@@ -446,6 +447,7 @@ void Td::start_up() {
inc_actor_refcnt(); // guard
alarm_manager_ = create_actor<AlarmManager>("AlarmManager", create_reference());
+ proxy_checker_ = create_actor<ProxyChecker>("ProxyChecker", create_reference());
CHECK(state_ == State::WaitParameters);
for (auto &update : get_fake_current_state()) {
@@ -671,6 +673,7 @@ void Td::clear() {
reset_actor(ActorOwn<Actor>(std::move(language_pack_manager_)));
reset_actor(ActorOwn<Actor>(std::move(net_stats_manager_)));
reset_actor(ActorOwn<Actor>(std::move(password_manager_)));
+ reset_actor(ActorOwn<Actor>(std::move(proxy_checker_)));
reset_actor(ActorOwn<Actor>(std::move(secure_manager_)));
reset_actor(ActorOwn<Actor>(std::move(secret_chats_manager_)));
reset_actor(ActorOwn<Actor>(std::move(storage_manager_)));
@@ -770,6 +773,7 @@ void Td::close_impl(bool destroy_flag) {
G()->set_close_flag();
clear_requests();
alarm_manager_.reset();
+ proxy_checker_.reset();
send_update(td_api::make_object<td_api::updateAuthorizationState>(
td_api::make_object<td_api::authorizationStateClosing>()));
diff --git a/td/telegram/Td.h b/td/telegram/Td.h
index 1ad9f4b61..42b1afd4d 100644
--- a/td/telegram/Td.h
+++ b/td/telegram/Td.h
@@ -84,6 +84,7 @@ class PhoneNumberManager;
class PollManager;
class PrivacyManager;
class PromoDataManager;
+class ProxyChecker;
class QuickReplyManager;
class ReactionManager;
class ReferralProgramManager;
@@ -300,6 +301,7 @@ class Td final : public Actor {
ActorOwn<LanguagePackManager> language_pack_manager_;
ActorOwn<NetStatsManager> net_stats_manager_;
ActorOwn<PasswordManager> password_manager_;
+ ActorOwn<ProxyChecker> proxy_checker_;
ActorOwn<SecretChatsManager> secret_chats_manager_;
ActorOwn<SecureManager> secure_manager_;
ActorOwn<StateManager> state_manager_;
diff --git a/td/telegram/net/ConnectionCreator.cpp b/td/telegram/net/ConnectionCreator.cpp
index 66010b278..f029b7b32 100644
--- a/td/telegram/net/ConnectionCreator.cpp
+++ b/td/telegram/net/ConnectionCreator.cpp
@@ -371,138 +371,6 @@ void ConnectionCreator::ping_proxy_buffered_socket_fd(IPAddress ip_address, Buff
create_reference(token))};
}
-void ConnectionCreator::test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise) {
- auto start_time = Time::now();
-
- IPAddress ip_address;
- auto status = ip_address.init_host_port(proxy.server(), proxy.port());
- if (status.is_error()) {
- return promise.set_error(400, status.public_message());
- }
- auto r_socket_fd = SocketFd::open(ip_address);
- if (r_socket_fd.is_error()) {
- return promise.set_error(400, r_socket_fd.error().public_message());
- }
-
- auto dc_options = get_default_dc_options(false);
- IPAddress mtproto_ip_address;
- for (auto &dc_option : dc_options.dc_options) {
- if (dc_option.get_dc_id().get_raw_id() == dc_id) {
- mtproto_ip_address = dc_option.get_ip_address();
- break;
- }
- }
- if (!mtproto_ip_address.is_valid()) {
- return promise.set_error(400, "Invalid datacenter identifier specified");
- }
-
- auto request_id = ++test_proxy_request_id_;
- auto request = make_unique<TestProxyRequest>();
- request->proxy_ = std::move(proxy);
- request->dc_id_ = static_cast<int16>(dc_id);
- request->promise_ = std::move(promise);
-
- auto connection_promise =
- PromiseCreator::lambda([actor_id = actor_id(this), request_id](Result<ConnectionData> r_data) {
- send_closure(actor_id, &ConnectionCreator::on_test_proxy_connection_data, request_id, std::move(r_data));
- });
- request->child_ = prepare_connection(ip_address, r_socket_fd.move_as_ok(), request->proxy_, mtproto_ip_address,
- request->get_transport(), "Test", "TestPingDC2", nullptr, {}, false,
- std::move(connection_promise));
-
- test_proxy_requests_.emplace(request_id, std::move(request));
-
- create_actor<SleepActor>("TestProxyTimeoutActor", timeout + start_time - Time::now(),
- PromiseCreator::lambda([actor_id = actor_id(this), request_id](Unit) {
- send_closure(actor_id, &ConnectionCreator::on_test_proxy_timeout, request_id);
- }))
- .release();
-}
-
-void ConnectionCreator::on_test_proxy_connection_data(uint64 request_id, Result<ConnectionData> r_data) {
- auto it = test_proxy_requests_.find(request_id);
- if (it == test_proxy_requests_.end()) {
- return;
- }
- auto *request = it->second.get();
- if (r_data.is_error()) {
- auto promise = std::move(request->promise_);
- test_proxy_requests_.erase(it);
- return promise.set_error(r_data.move_as_error());
- }
-
- class HandshakeContext final : public mtproto::AuthKeyHandshakeContext {
- public:
- mtproto::DhCallback *get_dh_callback() final {
- return nullptr;
- }
- mtproto::PublicRsaKeyInterface *get_public_rsa_key_interface() final {
- return public_rsa_key_.get();
- }
-
- private:
- std::shared_ptr<mtproto::PublicRsaKeyInterface> public_rsa_key_ = PublicRsaKeySharedMain::create(false);
- };
- auto handshake = make_unique<mtproto::AuthKeyHandshake>(request->dc_id_, 3600);
- auto data = r_data.move_as_ok();
- auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.buffered_socket_fd),
- request->get_transport(), nullptr);
- request->child_ = create_actor<mtproto::HandshakeActor>(
- "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique<HandshakeContext>(), 10.0,
- PromiseCreator::lambda(
- [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::RawConnection>> raw_connection) {
- send_closure(actor_id, &ConnectionCreator::on_test_proxy_handshake_connection, request_id,
- std::move(raw_connection));
- }),
- PromiseCreator::lambda(
- [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::AuthKeyHandshake>> handshake) {
- send_closure(actor_id, &ConnectionCreator::on_test_proxy_handshake, request_id, std::move(handshake));
- }));
-}
-
-void ConnectionCreator::on_test_proxy_handshake_connection(
- uint64 request_id, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection) {
- if (r_raw_connection.is_error()) {
- auto it = test_proxy_requests_.find(request_id);
- if (it == test_proxy_requests_.end()) {
- return;
- }
- auto promise = std::move(it->second->promise_);
- test_proxy_requests_.erase(it);
- return promise.set_error(400, r_raw_connection.move_as_error().public_message());
- }
-}
-
-void ConnectionCreator::on_test_proxy_handshake(uint64 request_id,
- Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake) {
- auto it = test_proxy_requests_.find(request_id);
- if (it == test_proxy_requests_.end()) {
- return;
- }
- auto promise = std::move(it->second->promise_);
- test_proxy_requests_.erase(it);
-
- if (r_handshake.is_error()) {
- return promise.set_error(400, r_handshake.move_as_error().public_message());
- }
- auto handshake = r_handshake.move_as_ok();
- if (!handshake->is_ready_for_finish()) {
- return promise.set_error(400, "Handshake is not ready");
- }
- promise.set_value(Unit());
-}
-
-void ConnectionCreator::on_test_proxy_timeout(uint64 request_id) {
- auto it = test_proxy_requests_.find(request_id);
- if (it == test_proxy_requests_.end()) {
- return;
- }
- auto promise = std::move(it->second->promise_);
- test_proxy_requests_.erase(it);
-
- promise.set_error(400, "Timeout expired");
-}
-
void ConnectionCreator::set_active_proxy_id(int32 proxy_id, bool from_binlog) {
active_proxy_id_ = proxy_id;
if (proxy_id == 0) {
diff --git a/td/telegram/net/ConnectionCreator.h b/td/telegram/net/ConnectionCreator.h
index 222dc7841..f61af57c2 100644
--- a/td/telegram/net/ConnectionCreator.h
+++ b/td/telegram/net/ConnectionCreator.h
@@ -84,9 +84,9 @@ class ConnectionCreator final : public NetQueryCallback {
void ping_proxy(td_api::object_ptr<td_api::proxy> input_proxy, Promise<double> promise);
- void test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise);
-
private:
+ friend class ProxyChecker;
+
ActorShared<> parent_;
DcOptionsSet dc_options_set_;
bool network_flag_ = false;
@@ -182,19 +182,6 @@ class ConnectionCreator final : public NetQueryCallback {
unique_ptr<mtproto::RawConnection::StatsCallback> stats_callback;
};
- struct TestProxyRequest {
- Proxy proxy_;
- int16 dc_id_ = -1;
- ActorOwn<> child_;
- Promise<Unit> promise_;
-
- mtproto::TransportType get_transport() const {
- return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, dc_id_, proxy_.secret()};
- }
- };
- uint64 test_proxy_request_id_ = 0;
- FlatHashMap<uint64, unique_ptr<TestProxyRequest>> test_proxy_requests_;
-
uint64 next_token() {
return ++current_token_;
}
@@ -271,15 +258,6 @@ class ConnectionCreator final : public NetQueryCallback {
mtproto::TransportType transport_type, string debug_str, Promise<double> promise);
void on_ping_main_dc_result(uint64 token, Result<double> result);
-
- void on_test_proxy_connection_data(uint64 request_id, Result<ConnectionData> r_data);
-
- void on_test_proxy_handshake_connection(uint64 request_id,
- Result<unique_ptr<mtproto::RawConnection>> r_raw_connection);
-
- void on_test_proxy_handshake(uint64 request_id, Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake);
-
- void on_test_proxy_timeout(uint64 request_id);
};
} // namespace td
diff --git a/td/telegram/net/ProxyChecker.cpp b/td/telegram/net/ProxyChecker.cpp
new file mode 100644
index 000000000..1cf16a083
--- /dev/null
+++ b/td/telegram/net/ProxyChecker.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include "td/telegram/net/ProxyChecker.h"
+
+#include "td/telegram/net/PublicRsaKeySharedMain.h"
+
+#include "td/mtproto/DhCallback.h"
+#include "td/mtproto/HandshakeActor.h"
+#include "td/mtproto/RSA.h"
+#include "td/mtproto/TlsInit.h"
+
+#include "td/actor/SleepActor.h"
+
+#include "td/utils/port/IPAddress.h"
+#include "td/utils/port/SocketFd.h"
+#include "td/utils/Time.h"
+
+#include <memory>
+
+namespace td {
+
+ProxyChecker::ProxyChecker(ActorShared<> parent) : parent_(std::move(parent)) {
+}
+
+void ProxyChecker::test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise) {
+ auto start_time = Time::now();
+
+ IPAddress ip_address;
+ auto status = ip_address.init_host_port(proxy.server(), proxy.port());
+ if (status.is_error()) {
+ return promise.set_error(400, status.public_message());
+ }
+ auto r_socket_fd = SocketFd::open(ip_address);
+ if (r_socket_fd.is_error()) {
+ return promise.set_error(400, r_socket_fd.error().public_message());
+ }
+
+ auto dc_options = ConnectionCreator::get_default_dc_options(false);
+ IPAddress mtproto_ip_address;
+ for (auto &dc_option : dc_options.dc_options) {
+ if (dc_option.get_dc_id().get_raw_id() == dc_id) {
+ mtproto_ip_address = dc_option.get_ip_address();
+ break;
+ }
+ }
+ if (!mtproto_ip_address.is_valid()) {
+ return promise.set_error(400, "Invalid datacenter identifier specified");
+ }
+
+ auto request_id = ++test_proxy_request_id_;
+ auto request = make_unique<TestProxyRequest>();
+ request->proxy_ = std::move(proxy);
+ request->dc_id_ = static_cast<int16>(dc_id);
+ request->promise_ = std::move(promise);
+
+ auto connection_promise =
+ PromiseCreator::lambda([actor_id = actor_id(this), request_id](Result<ConnectionCreator::ConnectionData> r_data) {
+ send_closure(actor_id, &ProxyChecker::on_test_proxy_connection_data, request_id, std::move(r_data));
+ });
+ request->child_ = ConnectionCreator::prepare_connection(
+ ip_address, r_socket_fd.move_as_ok(), request->proxy_, mtproto_ip_address, request->get_transport(), "Test",
+ "TestPingDC2", nullptr, {}, false, std::move(connection_promise));
+
+ test_proxy_requests_.emplace(request_id, std::move(request));
+
+ create_actor<SleepActor>("TestProxyTimeoutActor", timeout + start_time - Time::now(),
+ PromiseCreator::lambda([actor_id = actor_id(this), request_id](Unit) {
+ send_closure(actor_id, &ProxyChecker::on_test_proxy_timeout, request_id);
+ }))
+ .release();
+}
+
+void ProxyChecker::on_test_proxy_connection_data(uint64 request_id, Result<ConnectionCreator::ConnectionData> r_data) {
+ auto it = test_proxy_requests_.find(request_id);
+ if (it == test_proxy_requests_.end()) {
+ return;
+ }
+ auto *request = it->second.get();
+ if (r_data.is_error()) {
+ auto promise = std::move(request->promise_);
+ test_proxy_requests_.erase(it);
+ return promise.set_error(r_data.move_as_error());
+ }
+
+ class HandshakeContext final : public mtproto::AuthKeyHandshakeContext {
+ public:
+ mtproto::DhCallback *get_dh_callback() final {
+ return nullptr;
+ }
+ mtproto::PublicRsaKeyInterface *get_public_rsa_key_interface() final {
+ return public_rsa_key_.get();
+ }
+
+ private:
+ std::shared_ptr<mtproto::PublicRsaKeyInterface> public_rsa_key_ = PublicRsaKeySharedMain::create(false);
+ };
+ auto handshake = make_unique<mtproto::AuthKeyHandshake>(request->dc_id_, 3600);
+ auto data = r_data.move_as_ok();
+ auto raw_connection = mtproto::RawConnection::create(data.ip_address, std::move(data.buffered_socket_fd),
+ request->get_transport(), nullptr);
+ request->child_ = create_actor<mtproto::HandshakeActor>(
+ "HandshakeActor", std::move(handshake), std::move(raw_connection), make_unique<HandshakeContext>(), 10.0,
+ PromiseCreator::lambda(
+ [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::RawConnection>> raw_connection) {
+ send_closure(actor_id, &ProxyChecker::on_test_proxy_handshake_connection, request_id,
+ std::move(raw_connection));
+ }),
+ PromiseCreator::lambda(
+ [actor_id = actor_id(this), request_id](Result<unique_ptr<mtproto::AuthKeyHandshake>> handshake) {
+ send_closure(actor_id, &ProxyChecker::on_test_proxy_handshake, request_id, std::move(handshake));
+ }));
+}
+
+void ProxyChecker::on_test_proxy_handshake_connection(uint64 request_id,
+ Result<unique_ptr<mtproto::RawConnection>> r_raw_connection) {
+ if (r_raw_connection.is_error()) {
+ auto it = test_proxy_requests_.find(request_id);
+ if (it == test_proxy_requests_.end()) {
+ return;
+ }
+ auto promise = std::move(it->second->promise_);
+ test_proxy_requests_.erase(it);
+ return promise.set_error(400, r_raw_connection.move_as_error().public_message());
+ }
+}
+
+void ProxyChecker::on_test_proxy_handshake(uint64 request_id,
+ Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake) {
+ auto it = test_proxy_requests_.find(request_id);
+ if (it == test_proxy_requests_.end()) {
+ return;
+ }
+ auto promise = std::move(it->second->promise_);
+ test_proxy_requests_.erase(it);
+
+ if (r_handshake.is_error()) {
+ return promise.set_error(400, r_handshake.move_as_error().public_message());
+ }
+ auto handshake = r_handshake.move_as_ok();
+ if (!handshake->is_ready_for_finish()) {
+ return promise.set_error(400, "Handshake is not ready");
+ }
+ promise.set_value(Unit());
+}
+
+void ProxyChecker::on_test_proxy_timeout(uint64 request_id) {
+ auto it = test_proxy_requests_.find(request_id);
+ if (it == test_proxy_requests_.end()) {
+ return;
+ }
+ auto promise = std::move(it->second->promise_);
+ test_proxy_requests_.erase(it);
+
+ promise.set_error(400, "Timeout expired");
+}
+
+} // namespace td
diff --git a/td/telegram/net/ProxyChecker.h b/td/telegram/net/ProxyChecker.h
new file mode 100644
index 000000000..cca8189af
--- /dev/null
+++ b/td/telegram/net/ProxyChecker.h
@@ -0,0 +1,63 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#pragma once
+
+#include "td/telegram/net/ConnectionCreator.h"
+#include "td/telegram/net/NetQuery.h"
+#include "td/telegram/net/Proxy.h"
+
+#include "td/mtproto/Handshake.h"
+#include "td/mtproto/RawConnection.h"
+#include "td/mtproto/TransportType.h"
+
+#include "td/actor/actor.h"
+
+#include "td/utils/common.h"
+#include "td/utils/FlatHashMap.h"
+#include "td/utils/Promise.h"
+#include "td/utils/Status.h"
+
+namespace td {
+
+class ProxyChecker final : public NetQueryCallback {
+ public:
+ explicit ProxyChecker(ActorShared<> parent);
+ ProxyChecker(const ProxyChecker &) = delete;
+ ProxyChecker &operator=(const ProxyChecker &) = delete;
+ ProxyChecker(ProxyChecker &&other) = delete;
+ ProxyChecker &operator=(ProxyChecker &&other) = delete;
+ ~ProxyChecker() final = default;
+
+ void test_proxy(Proxy &&proxy, int32 dc_id, double timeout, Promise<Unit> &&promise);
+
+ private:
+ ActorShared<> parent_;
+
+ struct TestProxyRequest {
+ Proxy proxy_;
+ int16 dc_id_ = -1;
+ ActorOwn<> child_;
+ Promise<Unit> promise_;
+
+ mtproto::TransportType get_transport() const {
+ return mtproto::TransportType{mtproto::TransportType::ObfuscatedTcp, dc_id_, proxy_.secret()};
+ }
+ };
+ uint64 test_proxy_request_id_ = 0;
+ FlatHashMap<uint64, unique_ptr<TestProxyRequest>> test_proxy_requests_;
+
+ void on_test_proxy_connection_data(uint64 request_id, Result<ConnectionCreator::ConnectionData> r_data);
+
+ void on_test_proxy_handshake_connection(uint64 request_id,
+ Result<unique_ptr<mtproto::RawConnection>> r_raw_connection);
+
+ void on_test_proxy_handshake(uint64 request_id, Result<unique_ptr<mtproto::AuthKeyHandshake>> r_handshake);
+
+ void on_test_proxy_timeout(uint64 request_id);
+};
+
+} // namespace td