2018-12-31 20:04:05 +01:00
|
|
|
//
|
2018-01-02 14:42:31 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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/telegram_api.h"
|
|
|
|
|
|
|
|
#include "td/telegram/net/DcId.h"
|
|
|
|
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/format.h"
|
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/port/IPAddress.h"
|
|
|
|
#include "td/utils/Slice.h"
|
|
|
|
#include "td/utils/StringBuilder.h"
|
|
|
|
#include "td/utils/tl_helpers.h"
|
|
|
|
|
|
|
|
namespace td {
|
2018-04-24 18:21:47 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class DcOption {
|
|
|
|
// do not forget to update PrintFlags
|
2018-04-24 20:17:21 +02:00
|
|
|
enum Flags : int32 { IPv6 = 1, MediaOnly = 2, ObfuscatedTcpOnly = 4, Cdn = 8, Static = 16, HasSecret = 32 };
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-04-24 20:17:21 +02:00
|
|
|
int32 flags_ = 0;
|
|
|
|
DcId dc_id_;
|
|
|
|
IPAddress ip_address_;
|
|
|
|
string secret_;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
struct PrintFlags {
|
|
|
|
int32 flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool is_ipv6() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return (flags_ & Flags::IPv6) != 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
DcOption() = default;
|
|
|
|
|
|
|
|
DcOption(DcId dc_id, const IPAddress &ip_address)
|
2018-04-24 20:17:21 +02:00
|
|
|
: flags_(ip_address.is_ipv4() ? 0 : IPv6), dc_id_(dc_id), ip_address_(ip_address) {
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
explicit DcOption(const telegram_api::dcOption &option) {
|
|
|
|
auto ip = option.ip_address_;
|
|
|
|
auto port = option.port_;
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
if (!DcId::is_valid(option.id_)) {
|
2018-04-24 20:17:21 +02:00
|
|
|
dc_id_ = DcId::invalid();
|
2018-12-31 20:04:05 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (option.cdn_) {
|
2018-04-24 20:17:21 +02:00
|
|
|
dc_id_ = DcId::external(option.id_);
|
|
|
|
flags_ |= Flags::Cdn;
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2018-04-24 20:17:21 +02:00
|
|
|
dc_id_ = DcId::internal(option.id_);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (option.ipv6_) {
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ |= Flags::IPv6;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (option.media_only_) {
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ |= Flags::MediaOnly;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (option.tcpo_only_) {
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ |= Flags::ObfuscatedTcpOnly;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (option.static_) {
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ |= Flags::Static;
|
|
|
|
}
|
|
|
|
if (!option.secret_.empty()) {
|
|
|
|
flags_ |= Flags::HasSecret;
|
|
|
|
if (option.secret_.size() != 16u) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
secret_ = option.secret_.as_slice().str();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
init_ip_address(ip, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
DcOption(DcId new_dc_id, const telegram_api::ipPort &ip_port) {
|
2018-04-24 20:17:21 +02:00
|
|
|
dc_id_ = new_dc_id;
|
2018-12-31 20:04:05 +01:00
|
|
|
init_ip_address(IPAddress::ipv4_to_str(ip_port.ipv4_), ip_port.port_);
|
|
|
|
}
|
|
|
|
|
|
|
|
DcId get_dc_id() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return dc_id_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const IPAddress &get_ip_address() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return ip_address_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_media_only() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return (flags_ & Flags::MediaOnly) != 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_obfuscated_tcp_only() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return (flags_ & Flags::ObfuscatedTcpOnly) != 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_static() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return (flags_ & Flags::Static) != 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_valid() const {
|
2018-04-24 20:17:21 +02:00
|
|
|
return ip_address_.is_valid() && dc_id_.is_exact();
|
|
|
|
}
|
|
|
|
|
|
|
|
Slice get_secret() const {
|
|
|
|
return secret_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class StorerT>
|
|
|
|
void store(StorerT &storer) const {
|
2018-04-24 20:17:21 +02:00
|
|
|
storer.store_int(flags_);
|
|
|
|
storer.store_int(dc_id_.get_raw_id());
|
|
|
|
CHECK(ip_address_.is_valid());
|
|
|
|
storer.store_string(ip_address_.get_ip_str());
|
|
|
|
storer.store_int(ip_address_.get_port());
|
|
|
|
if ((flags_ & Flags::HasSecret) != 0) {
|
|
|
|
storer.store_string(secret_);
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void parse(ParserT &parser) {
|
2018-04-24 20:17:21 +02:00
|
|
|
flags_ = parser.fetch_int();
|
2018-12-31 20:04:05 +01:00
|
|
|
auto raw_dc_id = parser.fetch_int();
|
2018-04-24 20:17:21 +02:00
|
|
|
if ((flags_ & Flags::Cdn) != 0) {
|
|
|
|
dc_id_ = DcId::external(raw_dc_id);
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2018-04-24 20:17:21 +02:00
|
|
|
dc_id_ = DcId::internal(raw_dc_id);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
auto ip = parser.template fetch_string<std::string>();
|
|
|
|
auto port = parser.fetch_int();
|
|
|
|
init_ip_address(ip, port);
|
2018-04-24 20:17:21 +02:00
|
|
|
if ((flags_ & Flags::HasSecret) != 0) {
|
|
|
|
secret_ = parser.template fetch_string<std::string>();
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
friend bool operator==(const DcOption &lhs, const DcOption &rhs);
|
|
|
|
|
|
|
|
friend StringBuilder &operator<<(StringBuilder &sb, const DcOption::PrintFlags &flags);
|
|
|
|
|
|
|
|
friend StringBuilder &operator<<(StringBuilder &sb, const DcOption &dc_option);
|
|
|
|
|
|
|
|
private:
|
|
|
|
void init_ip_address(CSlice ip, int32 port) {
|
|
|
|
if (is_ipv6()) {
|
2018-04-24 20:17:21 +02:00
|
|
|
ip_address_.init_ipv6_port(ip, port).ignore();
|
2018-12-31 20:04:05 +01:00
|
|
|
} else {
|
2018-04-24 20:17:21 +02:00
|
|
|
ip_address_.init_ipv4_port(ip, port).ignore();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool operator==(const DcOption &lhs, const DcOption &rhs) {
|
2018-04-24 20:17:21 +02:00
|
|
|
return lhs.dc_id_ == rhs.dc_id_ && lhs.ip_address_ == rhs.ip_address_ && lhs.flags_ == rhs.flags_ &&
|
|
|
|
lhs.secret_ == rhs.secret_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
inline StringBuilder &operator<<(StringBuilder &sb, const DcOption::PrintFlags &flags) {
|
|
|
|
if ((flags.flags & DcOption::Flags::ObfuscatedTcpOnly) != 0) {
|
|
|
|
sb << "(ObfuscatedTcpOnly)";
|
|
|
|
}
|
|
|
|
if ((flags.flags & DcOption::Flags::MediaOnly) != 0) {
|
|
|
|
sb << "(MediaOnly)";
|
|
|
|
}
|
|
|
|
if ((flags.flags & DcOption::Flags::IPv6) != 0) {
|
|
|
|
sb << "(IPv6)";
|
|
|
|
}
|
|
|
|
if ((flags.flags & DcOption::Flags::Cdn) != 0) {
|
|
|
|
sb << "(Cdn)";
|
|
|
|
}
|
|
|
|
if ((flags.flags & DcOption::Flags::Static) != 0) {
|
|
|
|
sb << "(Static)";
|
|
|
|
}
|
2018-04-24 20:17:21 +02:00
|
|
|
if ((flags.flags & DcOption::Flags::HasSecret) != 0) {
|
|
|
|
sb << "(HasSecret)";
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
return sb;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline StringBuilder &operator<<(StringBuilder &sb, const DcOption &dc_option) {
|
2018-04-24 20:17:21 +02:00
|
|
|
return sb << tag("DcOption", format::concat(dc_option.dc_id_, tag("ip", dc_option.ip_address_.get_ip_str()),
|
|
|
|
tag("port", dc_option.ip_address_.get_port()),
|
|
|
|
tag("secret_len", dc_option.secret_.size()),
|
|
|
|
tag("flags", DcOption::PrintFlags{dc_option.flags_})));
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class DcOptions {
|
|
|
|
public:
|
|
|
|
DcOptions() = default;
|
|
|
|
explicit DcOptions(const std::vector<tl_object_ptr<telegram_api::dcOption>> &server_dc_options) {
|
|
|
|
for (auto &dc_option : server_dc_options) {
|
|
|
|
DcOption option(*dc_option);
|
|
|
|
if (option.is_valid()) {
|
|
|
|
dc_options.push_back(std::move(option));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
explicit DcOptions(const telegram_api::help_configSimple &config_simple) {
|
|
|
|
auto dc_id = DcId::is_valid(config_simple.dc_id_) ? DcId::internal(config_simple.dc_id_) : DcId();
|
|
|
|
for (auto &ip_port : config_simple.ip_port_list_) {
|
|
|
|
DcOption option(dc_id, *ip_port);
|
|
|
|
if (option.is_valid()) {
|
|
|
|
dc_options.push_back(std::move(option));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template <class StorerT>
|
|
|
|
void store(StorerT &storer) const {
|
|
|
|
::td::store(dc_options, storer);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void parse(ParserT &parser) {
|
|
|
|
::td::parse(dc_options, parser);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<DcOption> dc_options;
|
|
|
|
};
|
2018-04-24 18:21:47 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
inline StringBuilder &operator<<(StringBuilder &sb, const DcOptions &dc_options) {
|
|
|
|
return sb << "DcOptions" << format::as_array(dc_options.dc_options);
|
|
|
|
}
|
2018-04-24 18:21:47 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
}; // namespace td
|