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/timer.h"
11 #include "mtproto/mtproto_response.h"
12 #include "mtproto/mtproto_proxy_data.h"
13 #include "mtproto/details/mtproto_serialized_request.h"
14 
15 #include <QtCore/QTimer>
16 
17 namespace MTP {
18 
19 class Instance;
20 class AuthKey;
21 using AuthKeyPtr = std::shared_ptr<AuthKey>;
22 enum class DcType;
23 
24 namespace details {
25 
26 class Dcenter;
27 class SessionPrivate;
28 
29 enum class TemporaryKeyType;
30 enum class CreatingKeyType;
31 
32 struct SessionOptions {
33 	SessionOptions() = default;
34 	SessionOptions(
35 		const QString &systemLangCode,
36 		const QString &cloudLangCode,
37 		const QString &langPackName,
38 		const ProxyData &proxy,
39 		bool useIPv4,
40 		bool useIPv6,
41 		bool useHttp,
42 		bool useTcp);
43 
44 	QString systemLangCode;
45 	QString cloudLangCode;
46 	QString langPackName;
47 	ProxyData proxy;
48 	bool useIPv4 = true;
49 	bool useIPv6 = true;
50 	bool useHttp = true;
51 	bool useTcp = true;
52 
53 };
54 
55 class Session;
56 class SessionData final {
57 public:
SessionData(not_null<Session * > creator)58 	explicit SessionData(not_null<Session*> creator) : _owner(creator) {
59 	}
60 
61 	void notifyConnectionInited(const SessionOptions &options);
setOptions(SessionOptions options)62 	void setOptions(SessionOptions options) {
63 		QWriteLocker locker(&_optionsLock);
64 		_options = options;
65 	}
options()66 	[[nodiscard]] SessionOptions options() const {
67 		QReadLocker locker(&_optionsLock);
68 		return _options;
69 	}
70 
toSendMutex()71 	not_null<QReadWriteLock*> toSendMutex() {
72 		return &_toSendLock;
73 	}
haveSentMutex()74 	not_null<QReadWriteLock*> haveSentMutex() {
75 		return &_haveSentLock;
76 	}
haveReceivedMutex()77 	not_null<QReadWriteLock*> haveReceivedMutex() {
78 		return &_haveReceivedLock;
79 	}
80 
toSendMap()81 	base::flat_map<mtpRequestId, SerializedRequest> &toSendMap() {
82 		return _toSend;
83 	}
haveSentMap()84 	base::flat_map<mtpMsgId, SerializedRequest> &haveSentMap() {
85 		return _haveSent;
86 	}
haveReceivedMessages()87 	std::vector<Response> &haveReceivedMessages() {
88 		return _receivedMessages;
89 	}
90 
91 	// SessionPrivate -> Session interface.
92 	void queueTryToReceive();
93 	void queueNeedToResumeAndSend();
94 	void queueConnectionStateChange(int newState);
95 	void queueResetDone();
96 	void queueSendAnything(crl::time msCanWait = 0);
97 
98 	[[nodiscard]] bool connectionInited() const;
99 	[[nodiscard]] AuthKeyPtr getPersistentKey() const;
100 	[[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const;
101 	[[nodiscard]] CreatingKeyType acquireKeyCreation(DcType type);
102 	[[nodiscard]] bool releaseKeyCreationOnDone(
103 		const AuthKeyPtr &temporaryKey,
104 		const AuthKeyPtr &persistentKeyUsedForBind);
105 	[[nodiscard]] bool releaseCdnKeyCreationOnDone(
106 		const AuthKeyPtr &temporaryKey);
107 	void releaseKeyCreationOnFail();
108 	void destroyTemporaryKey(uint64 keyId);
109 
110 	void detach();
111 
112 private:
113 	template <typename Callback>
114 	void withSession(Callback &&callback);
115 
116 	Session *_owner = nullptr;
117 	mutable QMutex _ownerMutex;
118 
119 	SessionOptions _options;
120 	mutable QReadWriteLock _optionsLock;
121 
122 	base::flat_map<mtpRequestId, SerializedRequest> _toSend; // map of request_id -> request, that is waiting to be sent
123 	QReadWriteLock _toSendLock;
124 
125 	base::flat_map<mtpMsgId, SerializedRequest> _haveSent; // map of msg_id -> request, that was sent
126 	QReadWriteLock _haveSentLock;
127 
128 	std::vector<Response> _receivedMessages; // list of responses / updates that should be processed in the main thread
129 	QReadWriteLock _haveReceivedLock;
130 
131 };
132 
133 class Session final : public QObject {
134 public:
135 	// Main thread.
136 	Session(
137 		not_null<Instance*> instance,
138 		not_null<QThread*> thread,
139 		ShiftedDcId shiftedDcId,
140 		not_null<Dcenter*> dc);
141 	~Session();
142 
143 	void start();
144 	void reInitConnection();
145 
146 	void restart();
147 	void refreshOptions();
148 	void stop();
149 	void kill();
150 
151 	void unpaused();
152 
153 	// Thread-safe.
154 	[[nodiscard]] ShiftedDcId getDcWithShift() const;
155 	[[nodiscard]] AuthKeyPtr getPersistentKey() const;
156 	[[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const;
157 	[[nodiscard]] bool connectionInited() const;
158 	void sendPrepared(
159 		const SerializedRequest &request,
160 		crl::time msCanWait = 0);
161 
162 	// SessionPrivate thread.
163 	[[nodiscard]] CreatingKeyType acquireKeyCreation(DcType type);
164 	[[nodiscard]] bool releaseKeyCreationOnDone(
165 		const AuthKeyPtr &temporaryKey,
166 		const AuthKeyPtr &persistentKeyUsedForBind);
167 	[[nodiscard]] bool releaseCdnKeyCreationOnDone(const AuthKeyPtr &temporaryKey);
168 	void releaseKeyCreationOnFail();
169 	void destroyTemporaryKey(uint64 keyId);
170 
171 	void notifyDcConnectionInited();
172 
173 	void ping();
174 	void cancel(mtpRequestId requestId, mtpMsgId msgId);
175 	int requestState(mtpRequestId requestId) const;
176 	int getState() const;
177 	QString transport() const;
178 
179 	void tryToReceive();
180 	void needToResumeAndSend();
181 	void connectionStateChange(int newState);
182 	void resetDone();
183 	void sendAnything(crl::time msCanWait = 0);
184 
185 private:
186 	void watchDcKeyChanges();
187 	void watchDcOptionsChanges();
188 
189 	void killConnection();
190 
191 	[[nodiscard]] bool releaseGenericKeyCreationOnDone(
192 		const AuthKeyPtr &temporaryKey,
193 		const AuthKeyPtr &persistentKeyUsedForBind);
194 
195 	const not_null<Instance*> _instance;
196 	const ShiftedDcId _shiftedDcId = 0;
197 	const not_null<Dcenter*> _dc;
198 	const std::shared_ptr<SessionData> _data;
199 	const not_null<QThread*> _thread;
200 
201 	SessionPrivate *_private = nullptr;
202 
203 	bool _killed = false;
204 	bool _needToReceive = false;
205 
206 	AuthKeyPtr _dcKeyForCheck;
207 	CreatingKeyType _myKeyCreation = CreatingKeyType();
208 
209 	crl::time _msSendCall = 0;
210 	crl::time _msWait = 0;
211 
212 	bool _ping = false;
213 
214 	base::Timer _sender;
215 
216 	rpl::lifetime _lifetime;
217 
218 };
219 
220 } // namespace details
221 } // namespace MTP
222