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 "mtproto/mtproto_dc_options.h"
11 #include "mtproto/mtproto_proxy_data.h"
12 #include "base/bytes.h"
13
14 #include <QtCore/QObject>
15 #include <QtCore/QThread>
16
17 namespace MTP {
18
19 class Instance;
20
21 namespace details {
22
23 struct ConnectionOptions;
24
25 class AbstractConnection;
26
27 class ConnectionPointer {
28 public:
29 ConnectionPointer();
30 ConnectionPointer(std::nullptr_t);
31 ConnectionPointer(ConnectionPointer &&other);
32 ConnectionPointer &operator=(ConnectionPointer &&other);
33
34 template <typename ConnectionType, typename ...Args>
New(Args &&...args)35 static ConnectionPointer New(Args &&...args) {
36 return ConnectionPointer(new ConnectionType(
37 std::forward<Args>(args)...
38 ));
39 }
40
41 AbstractConnection *get() const;
42 void reset(AbstractConnection *value = nullptr);
43 operator AbstractConnection*() const;
44 AbstractConnection *operator->() const;
45 AbstractConnection &operator*() const;
46 explicit operator bool() const;
47
48 ~ConnectionPointer();
49
50 private:
51 explicit ConnectionPointer(AbstractConnection *value);
52
53 AbstractConnection *_value = nullptr;
54
55 };
56
57 class AbstractConnection : public QObject {
58 Q_OBJECT
59
60 public:
61 AbstractConnection(QThread *thread, const ProxyData &proxy);
62 AbstractConnection(const AbstractConnection &other) = delete;
63 AbstractConnection &operator=(const AbstractConnection &other) = delete;
64 virtual ~AbstractConnection() = default;
65
66 // virtual constructor
67 [[nodiscard]] static ConnectionPointer Create(
68 not_null<Instance*> instance,
69 DcOptions::Variants::Protocol protocol,
70 QThread *thread,
71 const bytes::vector &secret,
72 const ProxyData &proxy);
73
74 [[nodiscard]] virtual ConnectionPointer clone(const ProxyData &proxy) = 0;
75
76 [[nodiscard]] virtual crl::time pingTime() const = 0;
77 [[nodiscard]] virtual crl::time fullConnectTimeout() const = 0;
78 virtual void sendData(mtpBuffer &&buffer) = 0;
79 virtual void disconnectFromServer() = 0;
80 virtual void connectToServer(
81 const QString &ip,
82 int port,
83 const bytes::vector &protocolSecret,
84 int16 protocolDcId,
85 bool protocolForFiles) = 0;
timedOut()86 virtual void timedOut() {
87 }
88 [[nodiscard]] virtual bool isConnected() const = 0;
usingHttpWait()89 [[nodiscard]] virtual bool usingHttpWait() {
90 return false;
91 }
needHttpWait()92 [[nodiscard]] virtual bool needHttpWait() {
93 return false;
94 }
95
96 [[nodiscard]] virtual int32 debugState() const = 0;
97
98 [[nodiscard]] virtual QString transport() const = 0;
99 [[nodiscard]] virtual QString tag() const = 0;
100
setSentEncryptedWithKeyId(uint64 keyId)101 void setSentEncryptedWithKeyId(uint64 keyId) {
102 _sentEncryptedWithKeyId = keyId;
103 }
sentEncryptedWithKeyId()104 [[nodiscard]] uint64 sentEncryptedWithKeyId() const {
105 return _sentEncryptedWithKeyId;
106 }
107
108 using BuffersQueue = std::deque<mtpBuffer>;
received()109 [[nodiscard]] BuffersQueue &received() {
110 return _receivedQueue;
111 }
112
113 template <typename Request>
114 [[nodiscard]] mtpBuffer prepareNotSecurePacket(
115 const Request &request,
116 mtpMsgId newId) const;
117 [[nodiscard]] mtpBuffer prepareSecurePacket(
118 uint64 keyId,
119 MTPint128 msgKey,
120 uint32 size) const;
121
122 [[nodiscard]] gsl::span<const mtpPrime> parseNotSecureResponse(
123 const mtpBuffer &buffer) const;
124
125 // Used to emit error(...) with no real code from the server.
126 static constexpr auto kErrorCodeOther = -499;
127
128 Q_SIGNALS:
129 void receivedData();
130 void receivedSome(); // to stop restart timer
131
132 void error(qint32 errorCodebool);
133
134 void connected();
135 void disconnected();
136
137 void syncTimeRequest();
138
139 protected:
140 BuffersQueue _receivedQueue; // list of received packets, not processed yet
141 int _pingTime = 0;
142 ProxyData _proxy;
143
144 // first we always send fake MTPReq_pq to see if connection works at all
145 // we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one
146 [[nodiscard]] mtpBuffer preparePQFake(const MTPint128 &nonce) const;
147 [[nodiscard]] std::optional<MTPResPQ> readPQFakeReply(
148 const mtpBuffer &buffer) const;
149
150 private:
151 [[nodiscard]] uint32 extendedNotSecurePadding() const;
152
153 uint64 _sentEncryptedWithKeyId = 0;
154
155 };
156
157 template <typename Request>
prepareNotSecurePacket(const Request & request,mtpMsgId newId)158 mtpBuffer AbstractConnection::prepareNotSecurePacket(
159 const Request &request,
160 mtpMsgId newId) const {
161 const auto intsSize = tl::count_length(request) >> 2;
162 const auto intsPadding = extendedNotSecurePadding();
163
164 auto result = mtpBuffer();
165 constexpr auto kTcpPrefixInts = 2;
166 constexpr auto kAuthKeyIdInts = 2;
167 constexpr auto kMessageIdInts = 2;
168 constexpr auto kMessageLengthInts = 1;
169 constexpr auto kPrefixInts = kTcpPrefixInts
170 + kAuthKeyIdInts
171 + kMessageIdInts
172 + kMessageLengthInts;
173 constexpr auto kTcpPostfixInts = 4;
174
175 result.reserve(kPrefixInts + intsSize + intsPadding + kTcpPostfixInts);
176 result.resize(kPrefixInts);
177
178 const auto messageId = &result[kTcpPrefixInts + kAuthKeyIdInts];
179 *reinterpret_cast<mtpMsgId*>(messageId) = newId;
180
181 request.write(result);
182
183 const auto messageLength = messageId + kMessageIdInts;
184 *messageLength = (result.size() - kPrefixInts + intsPadding) << 2;
185
186 if (intsPadding > 0) {
187 const auto skipPrimes = result.size();
188 result.resize(skipPrimes + intsPadding);
189 const auto skipBytes = skipPrimes * sizeof(mtpPrime);
190 bytes::set_random(bytes::make_span(result).subspan(skipBytes));
191 }
192
193 return result;
194 }
195
196 } // namespace details
197 } // namespace MTP
198