1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "base/observer.h"
11 #include "base/bytes.h"
12 
13 #include <QtCore/QReadWriteLock>
14 #include <string>
15 #include <vector>
16 #include <map>
17 #include <set>
18 
19 namespace MTP {
20 namespace details {
21 class RSAPublicKey;
22 } // namespace details
23 
24 enum class DcType {
25 	Regular,
26 	Temporary,
27 	MediaCluster,
28 	Cdn,
29 };
30 
31 enum class Environment : uchar {
32 	Production,
33 	Test,
34 };
35 
36 class DcOptions {
37 public:
38 	using Flag = MTPDdcOption::Flag;
39 	using Flags = MTPDdcOption::Flags;
40 	struct Endpoint {
EndpointEndpoint41 		Endpoint(
42 			DcId id,
43 			Flags flags,
44 			const std::string &ip,
45 			int port,
46 			const bytes::vector &secret)
47 			: id(id)
48 			, flags(flags)
49 			, ip(ip)
50 			, port(port)
51 			, secret(secret) {
52 		}
53 
54 		DcId id;
55 		Flags flags;
56 		std::string ip;
57 		int port;
58 		bytes::vector secret;
59 
60 	};
61 
62 	explicit DcOptions(Environment environment);
63 	DcOptions(const DcOptions &other);
64 	~DcOptions();
65 
66 	[[nodiscard]] static bool ValidateSecret(bytes::const_span secret);
67 
68 	[[nodiscard]] Environment environment() const;
69 	[[nodiscard]] bool isTestMode() const;
70 
71 	// construct methods don't notify "changed" subscribers.
72 	bool constructFromSerialized(const QByteArray &serialized);
73 	void constructFromBuiltIn();
74 	void constructAddOne(
75 		int id,
76 		Flags flags,
77 		const std::string &ip,
78 		int port,
79 		const bytes::vector &secret);
80 	QByteArray serialize() const;
81 
82 	[[nodiscard]] rpl::producer<DcId> changed() const;
83 	[[nodiscard]] rpl::producer<> cdnConfigChanged() const;
84 	void setFromList(const MTPVector<MTPDcOption> &options);
85 	void addFromList(const MTPVector<MTPDcOption> &options);
86 	void addFromOther(DcOptions &&options);
87 
88 	[[nodiscard]] std::vector<DcId> configEnumDcIds() const;
89 
90 	struct Variants {
91 		enum Address {
92 			IPv4 = 0,
93 			IPv6 = 1,
94 			AddressTypeCount = 2,
95 		};
96 		enum Protocol {
97 			Tcp = 0,
98 			Http = 1,
99 			ProtocolCount = 2,
100 		};
101 		std::vector<Endpoint> data[AddressTypeCount][ProtocolCount];
102 	};
103 	[[nodiscard]] Variants lookup(
104 		DcId dcId,
105 		DcType type,
106 		bool throughProxy) const;
107 	[[nodiscard]] DcType dcType(ShiftedDcId shiftedDcId) const;
108 
109 	void setCDNConfig(const MTPDcdnConfig &config);
110 	[[nodiscard]] bool hasCDNKeysForDc(DcId dcId) const;
111 	[[nodiscard]] details::RSAPublicKey getDcRSAKey(
112 		DcId dcId,
113 		const QVector<MTPlong> &fingerprints) const;
114 
115 	// Debug feature for now.
116 	bool loadFromFile(const QString &path);
117 	bool writeToFile(const QString &path) const;
118 
119 private:
120 	bool applyOneGuarded(
121 		DcId dcId,
122 		Flags flags,
123 		const std::string &ip,
124 		int port,
125 		const bytes::vector &secret);
126 	static bool ApplyOneOption(
127 		base::flat_map<DcId, std::vector<Endpoint>> &data,
128 		DcId dcId,
129 		Flags flags,
130 		const std::string &ip,
131 		int port,
132 		const bytes::vector &secret);
133 	static std::vector<DcId> CountOptionsDifference(
134 		const base::flat_map<DcId, std::vector<Endpoint>> &a,
135 		const base::flat_map<DcId, std::vector<Endpoint>> &b);
136 	static void FilterIfHasWithFlag(Variants &variants, Flag flag);
137 
138 	[[nodiscard]] bool hasMediaOnlyOptionsFor(DcId dcId) const;
139 
140 	void processFromList(const QVector<MTPDcOption> &options, bool overwrite);
141 	void computeCdnDcIds();
142 
143 	void readBuiltInPublicKeys();
144 
145 	class WriteLocker;
146 	friend class WriteLocker;
147 
148 	class ReadLocker;
149 	friend class ReadLocker;
150 
151 	const Environment _environment = Environment();
152 	base::flat_map<DcId, std::vector<Endpoint>> _data;
153 	base::flat_set<DcId> _cdnDcIds;
154 	base::flat_map<uint64, details::RSAPublicKey> _publicKeys;
155 	base::flat_map<
156 		DcId,
157 		base::flat_map<uint64, details::RSAPublicKey>> _cdnPublicKeys;
158 	mutable QReadWriteLock _useThroughLockers;
159 
160 	rpl::event_stream<DcId> _changed;
161 	rpl::event_stream<> _cdnConfigChanged;
162 
163 	// True when we have overriden options from a .tdesktop-endpoints file.
164 	bool _immutable = false;
165 
166 };
167 
168 } // namespace MTP
169