mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
Encapsulated DcOptions to an independent class.
This commit is contained in:
parent
90b3b5c3e5
commit
a35947141c
24 changed files with 606 additions and 329 deletions
|
@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "core/task_queue.h"
|
#include "core/task_queue.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -340,7 +341,10 @@ void Application::closeApplication() {
|
||||||
manager->clearAllFast();
|
manager->clearAllFast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AppObject) {
|
||||||
|
AppClass::Instance().joinThreads();
|
||||||
delete base::take(AppObject);
|
delete base::take(AppObject);
|
||||||
|
}
|
||||||
|
|
||||||
Sandbox::finish();
|
Sandbox::finish();
|
||||||
|
|
||||||
|
@ -682,7 +686,6 @@ namespace Sandbox {
|
||||||
|
|
||||||
new AppClass();
|
new AppClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AppClass::AppClass() : QObject() {
|
AppClass::AppClass() : QObject() {
|
||||||
|
@ -692,7 +695,9 @@ AppClass::AppClass() : QObject() {
|
||||||
|
|
||||||
ThirdParty::start();
|
ThirdParty::start();
|
||||||
Global::start();
|
Global::start();
|
||||||
Local::start();
|
|
||||||
|
startLocalStorage();
|
||||||
|
|
||||||
if (Local::oldSettingsVersion() < AppVersion) {
|
if (Local::oldSettingsVersion() < AppVersion) {
|
||||||
psNewVersion();
|
psNewVersion();
|
||||||
}
|
}
|
||||||
|
@ -816,6 +821,18 @@ void AppClass::loadLanguage() {
|
||||||
application()->installTranslator(_translator = new Translator());
|
application()->installTranslator(_translator = new Translator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppClass::startLocalStorage() {
|
||||||
|
_dcOptions = std::make_unique<MTP::DcOptions>();
|
||||||
|
_dcOptions->constructFromBuiltIn();
|
||||||
|
Local::start();
|
||||||
|
subscribe(_dcOptions->changed(), [](const MTP::DcOptions::Ids &ids) {
|
||||||
|
Local::writeSettings();
|
||||||
|
for (auto id : ids) {
|
||||||
|
MTP::restart(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void AppClass::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) {
|
void AppClass::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) {
|
||||||
photoUpdates.insert(msgId, peer);
|
photoUpdates.insert(msgId, peer);
|
||||||
}
|
}
|
||||||
|
@ -1096,6 +1113,10 @@ void AppClass::checkMapVersion() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppClass::joinThreads() {
|
||||||
|
MTP::finish();
|
||||||
|
}
|
||||||
|
|
||||||
AppClass::~AppClass() {
|
AppClass::~AppClass() {
|
||||||
Shortcuts::finish();
|
Shortcuts::finish();
|
||||||
|
|
||||||
|
@ -1110,8 +1131,6 @@ AppClass::~AppClass() {
|
||||||
App::deinitMedia();
|
App::deinitMedia();
|
||||||
deinitLocationManager();
|
deinitLocationManager();
|
||||||
|
|
||||||
MTP::finish();
|
|
||||||
|
|
||||||
AppObject = nullptr;
|
AppObject = nullptr;
|
||||||
delete base::take(_uploader);
|
delete base::take(_uploader);
|
||||||
delete base::take(_translator);
|
delete base::take(_translator);
|
||||||
|
|
|
@ -23,6 +23,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
#include "core/observer.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
class DcOptions;
|
||||||
|
} // namespace MTP
|
||||||
|
|
||||||
class UpdateChecker;
|
class UpdateChecker;
|
||||||
class Application : public QApplication {
|
class Application : public QApplication {
|
||||||
|
@ -143,17 +148,28 @@ class MainWidget;
|
||||||
class FileUploader;
|
class FileUploader;
|
||||||
class Translator;
|
class Translator;
|
||||||
|
|
||||||
class AppClass : public QObject, public RPCSender {
|
class AppClass : public QObject, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AppClass();
|
AppClass();
|
||||||
|
|
||||||
|
void joinThreads();
|
||||||
~AppClass();
|
~AppClass();
|
||||||
|
|
||||||
static AppClass *app();
|
static AppClass *app();
|
||||||
static MainWindow *wnd();
|
static MainWindow *wnd();
|
||||||
static MainWidget *main();
|
static MainWidget *main();
|
||||||
|
|
||||||
|
static AppClass &Instance() {
|
||||||
|
auto result = app();
|
||||||
|
t_assert(result != nullptr);
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
|
MTP::DcOptions *dcOptions() {
|
||||||
|
return _dcOptions.get();
|
||||||
|
}
|
||||||
|
|
||||||
FileUploader *uploader();
|
FileUploader *uploader();
|
||||||
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
|
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
|
||||||
void regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId);
|
void regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId);
|
||||||
|
@ -179,7 +195,6 @@ public:
|
||||||
void handleAppDeactivated();
|
void handleAppDeactivated();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void peerPhotoDone(PeerId peer);
|
void peerPhotoDone(PeerId peer);
|
||||||
void peerPhotoFail(PeerId peer);
|
void peerPhotoFail(PeerId peer);
|
||||||
|
|
||||||
|
@ -202,6 +217,7 @@ public slots:
|
||||||
void call_handleObservables();
|
void call_handleObservables();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void startLocalStorage();
|
||||||
void loadLanguage();
|
void loadLanguage();
|
||||||
|
|
||||||
QMap<FullMsgId, PeerId> photoUpdates;
|
QMap<FullMsgId, PeerId> photoUpdates;
|
||||||
|
@ -215,4 +231,6 @@ private:
|
||||||
FileUploader *_uploader = nullptr;
|
FileUploader *_uploader = nullptr;
|
||||||
Translator *_translator = nullptr;
|
Translator *_translator = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,8 +51,6 @@ enum {
|
||||||
MTPDownloadSessionsCount = 2, // max 2 download sessions is created
|
MTPDownloadSessionsCount = 2, // max 2 download sessions is created
|
||||||
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
|
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
|
||||||
|
|
||||||
MTPEnumDCTimeout = 8000, // 8 seconds timeout for help_getConfig to work (then move to other dc)
|
|
||||||
|
|
||||||
MTPDebugBufferSize = 1024 * 1024, // 1 mb start size
|
MTPDebugBufferSize = 1024 * 1024, // 1 mb start size
|
||||||
|
|
||||||
MaxUsersPerInvite = 100, // max users in one super group invite request
|
MaxUsersPerInvite = 100, // max users in one super group invite request
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "core/basic_types.h"
|
#include "core/basic_types.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
|
@ -82,6 +83,12 @@ scope_guard_helper<Lambda> scope_guard(Lambda on_scope_exit) {
|
||||||
return scope_guard_helper<Lambda>(std::move(on_scope_exit));
|
return scope_guard_helper<Lambda>(std::move(on_scope_exit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Container, typename T>
|
||||||
|
inline bool contains(const Container &container, const T &value) {
|
||||||
|
auto end = std::end(container);
|
||||||
|
return std::find(std::begin(container), end, value) != end;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
|
|
||||||
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
||||||
|
|
|
@ -671,8 +671,6 @@ struct Data {
|
||||||
TimeMs LastFeaturedStickersUpdate = 0;
|
TimeMs LastFeaturedStickersUpdate = 0;
|
||||||
Stickers::Order ArchivedStickerSetsOrder;
|
Stickers::Order ArchivedStickerSetsOrder;
|
||||||
|
|
||||||
MTP::DcOptions DcOptions;
|
|
||||||
|
|
||||||
CircleMasksMap CircleMasks;
|
CircleMasksMap CircleMasks;
|
||||||
|
|
||||||
base::Observable<void> SelfChanged;
|
base::Observable<void> SelfChanged;
|
||||||
|
@ -795,8 +793,6 @@ DefineRefVar(Global, base::Observable<void>, FeaturedStickerSetsUnreadCountChang
|
||||||
DefineVar(Global, TimeMs, LastFeaturedStickersUpdate);
|
DefineVar(Global, TimeMs, LastFeaturedStickersUpdate);
|
||||||
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);
|
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);
|
||||||
|
|
||||||
DefineVar(Global, MTP::DcOptions, DcOptions);
|
|
||||||
|
|
||||||
DefineRefVar(Global, CircleMasksMap, CircleMasks);
|
DefineRefVar(Global, CircleMasksMap, CircleMasks);
|
||||||
|
|
||||||
DefineRefVar(Global, base::Observable<void>, SelfChanged);
|
DefineRefVar(Global, base::Observable<void>, SelfChanged);
|
||||||
|
|
|
@ -369,8 +369,6 @@ DeclareRefVar(base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
|
||||||
DeclareVar(TimeMs, LastFeaturedStickersUpdate);
|
DeclareVar(TimeMs, LastFeaturedStickersUpdate);
|
||||||
DeclareVar(Stickers::Order, ArchivedStickerSetsOrder);
|
DeclareVar(Stickers::Order, ArchivedStickerSetsOrder);
|
||||||
|
|
||||||
DeclareVar(MTP::DcOptions, DcOptions);
|
|
||||||
|
|
||||||
typedef QMap<uint64, QPixmap> CircleMasksMap;
|
typedef QMap<uint64, QPixmap> CircleMasksMap;
|
||||||
DeclareRefVar(CircleMasksMap, CircleMasks);
|
DeclareRefVar(CircleMasksMap, CircleMasks);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
|
||||||
|
@ -563,6 +564,7 @@ enum {
|
||||||
dbiTheme = 0x47,
|
dbiTheme = 0x47,
|
||||||
dbiDialogsWidthRatio = 0x48,
|
dbiDialogsWidthRatio = 0x48,
|
||||||
dbiUseExternalVideoPlayer = 0x49,
|
dbiUseExternalVideoPlayer = 0x49,
|
||||||
|
dbiDcOptions = 0x4a,
|
||||||
|
|
||||||
dbiEncryptedWithSalt = 333,
|
dbiEncryptedWithSalt = 333,
|
||||||
dbiEncrypted = 444,
|
dbiEncrypted = 444,
|
||||||
|
@ -829,8 +831,15 @@ void _readReportSpamStatuses() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MTP::DcOptions *_dcOpts = 0;
|
struct ReadSettingsContext {
|
||||||
bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
MTP::DcOptions dcOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
void applyReadContext(const ReadSettingsContext &context) {
|
||||||
|
AppClass::Instance().dcOptions()->addFromOther(context.dcOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSettingsContext &context) {
|
||||||
switch (blockId) {
|
switch (blockId) {
|
||||||
case dbiDcOptionOld: {
|
case dbiDcOptionOld: {
|
||||||
quint32 dcId, port;
|
quint32 dcId, port;
|
||||||
|
@ -838,7 +847,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
||||||
stream >> dcId >> host >> ip >> port;
|
stream >> dcId >> host >> ip >> port;
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
if (_dcOpts) _dcOpts->insert(dcId, MTP::DcOption(dcId, 0, ip.toUtf8().constData(), port));
|
context.dcOptions.constructAddOne(dcId, 0, ip.toStdString(), port);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiDcOption: {
|
case dbiDcOption: {
|
||||||
|
@ -848,7 +857,15 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
||||||
stream >> dcIdWithShift >> flags >> ip >> port;
|
stream >> dcIdWithShift >> flags >> ip >> port;
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
if (_dcOpts) _dcOpts->insert(dcIdWithShift, MTP::DcOption(MTP::bareDcId(dcIdWithShift), MTPDdcOption::Flags(flags), ip.toUtf8().constData(), port));
|
context.dcOptions.constructAddOne(dcIdWithShift, MTPDdcOption::Flags(flags), ip.toStdString(), port);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dbiDcOptions: {
|
||||||
|
QByteArray serialized;
|
||||||
|
stream >> serialized;
|
||||||
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
|
context.dcOptions.constructFromSerialized(serialized);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiChatSizeMax: {
|
case dbiChatSizeMax: {
|
||||||
|
@ -1445,7 +1462,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _readOldSettings(bool remove = true) {
|
bool _readOldSettings(bool remove, ReadSettingsContext &context) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
QFile file(cWorkingDir() + qsl("tdata/config"));
|
QFile file(cWorkingDir() + qsl("tdata/config"));
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
@ -1464,7 +1481,7 @@ bool _readOldSettings(bool remove = true) {
|
||||||
if (!_checkStreamStatus(stream)) break;
|
if (!_checkStreamStatus(stream)) break;
|
||||||
|
|
||||||
if (version > AppVersion) break;
|
if (version > AppVersion) break;
|
||||||
} else if (!_readSetting(blockId, stream, version)) {
|
} else if (!_readSetting(blockId, stream, version, context)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1475,7 +1492,7 @@ bool _readOldSettings(bool remove = true) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _readOldUserSettingsFields(QIODevice *device, qint32 &version) {
|
void _readOldUserSettingsFields(QIODevice *device, qint32 &version, ReadSettingsContext &context) {
|
||||||
QDataStream stream(device);
|
QDataStream stream(device);
|
||||||
stream.setVersion(QDataStream::Qt_5_1);
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
|
|
||||||
|
@ -1531,32 +1548,20 @@ void _readOldUserSettingsFields(QIODevice *device, qint32 &version) {
|
||||||
decryptedStream.seek(4); // skip size
|
decryptedStream.seek(4); // skip size
|
||||||
LOG(("App Info: reading encrypted old user config..."));
|
LOG(("App Info: reading encrypted old user config..."));
|
||||||
|
|
||||||
_readOldUserSettingsFields(&decryptedStream, version);
|
_readOldUserSettingsFields(&decryptedStream, version, context);
|
||||||
} else if (!_readSetting(blockId, stream, version)) {
|
} else if (!_readSetting(blockId, stream, version, context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _readOldUserSettings(bool remove = true) {
|
bool _readOldUserSettings(bool remove, ReadSettingsContext &context) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()) + qsl("_config"));
|
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()) + qsl("_config"));
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
LOG(("App Info: reading old user config..."));
|
LOG(("App Info: reading old user config..."));
|
||||||
qint32 version = 0;
|
qint32 version = 0;
|
||||||
|
_readOldUserSettingsFields(&file, version, context);
|
||||||
MTP::DcOptions dcOpts;
|
|
||||||
{
|
|
||||||
QReadLocker lock(MTP::dcOptionsMutex());
|
|
||||||
dcOpts = Global::DcOptions();
|
|
||||||
}
|
|
||||||
_dcOpts = &dcOpts;
|
|
||||||
_readOldUserSettingsFields(&file, version);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
|
||||||
Global::SetDcOptions(dcOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
@ -1564,7 +1569,7 @@ bool _readOldUserSettings(bool remove = true) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _readOldMtpDataFields(QIODevice *device, qint32 &version) {
|
void _readOldMtpDataFields(QIODevice *device, qint32 &version, ReadSettingsContext &context) {
|
||||||
QDataStream stream(device);
|
QDataStream stream(device);
|
||||||
stream.setVersion(QDataStream::Qt_5_1);
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
|
|
||||||
|
@ -1618,32 +1623,20 @@ void _readOldMtpDataFields(QIODevice *device, qint32 &version) {
|
||||||
decryptedStream.seek(4); // skip size
|
decryptedStream.seek(4); // skip size
|
||||||
LOG(("App Info: reading encrypted old keys..."));
|
LOG(("App Info: reading encrypted old keys..."));
|
||||||
|
|
||||||
_readOldMtpDataFields(&decryptedStream, version);
|
_readOldMtpDataFields(&decryptedStream, version, context);
|
||||||
} else if (!_readSetting(blockId, stream, version)) {
|
} else if (!_readSetting(blockId, stream, version, context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _readOldMtpData(bool remove = true) {
|
bool _readOldMtpData(bool remove, ReadSettingsContext &context) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()));
|
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()));
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
LOG(("App Info: reading old keys..."));
|
LOG(("App Info: reading old keys..."));
|
||||||
qint32 version = 0;
|
qint32 version = 0;
|
||||||
|
_readOldMtpDataFields(&file, version, context);
|
||||||
MTP::DcOptions dcOpts;
|
|
||||||
{
|
|
||||||
QReadLocker lock(MTP::dcOptionsMutex());
|
|
||||||
dcOpts = Global::DcOptions();
|
|
||||||
}
|
|
||||||
_dcOpts = &dcOpts;
|
|
||||||
_readOldMtpDataFields(&file, version);
|
|
||||||
{
|
|
||||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
|
||||||
Global::SetDcOptions(dcOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
@ -1739,10 +1732,14 @@ void _writeUserSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _readUserSettings() {
|
void _readUserSettings() {
|
||||||
|
ReadSettingsContext context;
|
||||||
FileReadDescriptor userSettings;
|
FileReadDescriptor userSettings;
|
||||||
if (!readEncryptedFile(userSettings, _userSettingsKey)) {
|
if (!readEncryptedFile(userSettings, _userSettingsKey)) {
|
||||||
LOG(("App Info: could not read encrypted user settings..."));
|
LOG(("App Info: could not read encrypted user settings..."));
|
||||||
_readOldUserSettings();
|
|
||||||
|
_readOldUserSettings(true, context);
|
||||||
|
applyReadContext(context);
|
||||||
|
|
||||||
return _writeUserSettings();
|
return _writeUserSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1756,13 +1753,15 @@ void _readUserSettings() {
|
||||||
return _writeUserSettings();
|
return _writeUserSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_readSetting(blockId, userSettings.stream, userSettings.version)) {
|
if (!_readSetting(blockId, userSettings.stream, userSettings.version, context)) {
|
||||||
_readingUserSettings = false;
|
_readingUserSettings = false;
|
||||||
return _writeUserSettings();
|
return _writeUserSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_readingUserSettings = false;
|
_readingUserSettings = false;
|
||||||
LOG(("App Info: encrypted user settings read."));
|
LOG(("App Info: encrypted user settings read."));
|
||||||
|
|
||||||
|
applyReadContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _writeMtpData() {
|
void _writeMtpData() {
|
||||||
|
@ -1788,10 +1787,13 @@ void _writeMtpData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _readMtpData() {
|
void _readMtpData() {
|
||||||
|
ReadSettingsContext context;
|
||||||
FileReadDescriptor mtp;
|
FileReadDescriptor mtp;
|
||||||
if (!readEncryptedFile(mtp, toFilePart(_dataNameKey), FileOption::Safe)) {
|
if (!readEncryptedFile(mtp, toFilePart(_dataNameKey), FileOption::Safe)) {
|
||||||
if (_localKey.created()) {
|
if (_localKey.created()) {
|
||||||
_readOldMtpData();
|
_readOldMtpData(true, context);
|
||||||
|
applyReadContext(context);
|
||||||
|
|
||||||
_writeMtpData();
|
_writeMtpData();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -1805,10 +1807,11 @@ void _readMtpData() {
|
||||||
return _writeMtpData();
|
return _writeMtpData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_readSetting(blockId, mtp.stream, mtp.version)) {
|
if (!_readSetting(blockId, mtp.stream, mtp.version, context)) {
|
||||||
return _writeMtpData();
|
return _writeMtpData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
applyReadContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadMapState _readMap(const QByteArray &pass) {
|
ReadMapState _readMap(const QByteArray &pass) {
|
||||||
|
@ -2163,11 +2166,14 @@ void start() {
|
||||||
_basePath = cWorkingDir() + qsl("tdata/");
|
_basePath = cWorkingDir() + qsl("tdata/");
|
||||||
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
|
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
|
||||||
|
|
||||||
|
ReadSettingsContext context;
|
||||||
FileReadDescriptor settingsData;
|
FileReadDescriptor settingsData;
|
||||||
if (!readFile(settingsData, cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe)) {
|
if (!readFile(settingsData, cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe)) {
|
||||||
_readOldSettings();
|
_readOldSettings(true, context);
|
||||||
_readOldUserSettings(false); // needed further in _readUserSettings
|
_readOldUserSettings(false, context); // needed further in _readUserSettings
|
||||||
_readOldMtpData(false); // needed further in _readMtpData
|
_readOldMtpData(false, context); // needed further in _readMtpData
|
||||||
|
applyReadContext(context);
|
||||||
|
|
||||||
return writeSettings();
|
return writeSettings();
|
||||||
}
|
}
|
||||||
LOG(("App Info: reading settings..."));
|
LOG(("App Info: reading settings..."));
|
||||||
|
@ -2189,12 +2195,7 @@ void start() {
|
||||||
LOG(("App Error: could not decrypt settings from settings file, maybe bad passcode..."));
|
LOG(("App Error: could not decrypt settings from settings file, maybe bad passcode..."));
|
||||||
return writeSettings();
|
return writeSettings();
|
||||||
}
|
}
|
||||||
MTP::DcOptions dcOpts;
|
|
||||||
{
|
|
||||||
QReadLocker lock(MTP::dcOptionsMutex());
|
|
||||||
dcOpts = Global::DcOptions();
|
|
||||||
}
|
|
||||||
_dcOpts = &dcOpts;
|
|
||||||
LOG(("App Info: reading encrypted settings..."));
|
LOG(("App Info: reading encrypted settings..."));
|
||||||
while (!settings.stream.atEnd()) {
|
while (!settings.stream.atEnd()) {
|
||||||
quint32 blockId;
|
quint32 blockId;
|
||||||
|
@ -2203,36 +2204,17 @@ void start() {
|
||||||
return writeSettings();
|
return writeSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_readSetting(blockId, settings.stream, settingsData.version)) {
|
if (!_readSetting(blockId, settings.stream, settingsData.version, context)) {
|
||||||
return writeSettings();
|
return writeSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dcOpts.isEmpty()) {
|
|
||||||
const BuiltInDc *bdcs = builtInDcs();
|
|
||||||
for (int i = 0, l = builtInDcsCount(); i < l; ++i) {
|
|
||||||
MTPDdcOption::Flags flags = 0;
|
|
||||||
MTP::ShiftedDcId idWithShift = MTP::shiftDcId(bdcs[i].id, flags);
|
|
||||||
dcOpts.insert(idWithShift, MTP::DcOption(bdcs[i].id, flags, bdcs[i].ip, bdcs[i].port));
|
|
||||||
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
|
|
||||||
}
|
|
||||||
|
|
||||||
const BuiltInDc *bdcsipv6 = builtInDcsIPv6();
|
|
||||||
for (int i = 0, l = builtInDcsCountIPv6(); i < l; ++i) {
|
|
||||||
MTPDdcOption::Flags flags = MTPDdcOption::Flag::f_ipv6;
|
|
||||||
MTP::ShiftedDcId idWithShift = MTP::shiftDcId(bdcsipv6[i].id, flags);
|
|
||||||
dcOpts.insert(idWithShift, MTP::DcOption(bdcsipv6[i].id, flags, bdcsipv6[i].ip, bdcsipv6[i].port));
|
|
||||||
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: %2:%3").arg(bdcsipv6[i].id).arg(bdcsipv6[i].ip).arg(bdcsipv6[i].port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
|
||||||
Global::SetDcOptions(dcOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
_oldSettingsVersion = settingsData.version;
|
_oldSettingsVersion = settingsData.version;
|
||||||
_settingsSalt = salt;
|
_settingsSalt = salt;
|
||||||
|
|
||||||
readTheme();
|
readTheme();
|
||||||
|
|
||||||
|
applyReadContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeSettings() {
|
void writeSettings() {
|
||||||
|
@ -2251,37 +2233,10 @@ void writeSettings() {
|
||||||
}
|
}
|
||||||
settings.writeData(_settingsSalt);
|
settings.writeData(_settingsSalt);
|
||||||
|
|
||||||
MTP::DcOptions dcOpts;
|
auto dcOptionsSerialized = AppClass::Instance().dcOptions()->serialize();
|
||||||
{
|
|
||||||
QReadLocker lock(MTP::dcOptionsMutex());
|
|
||||||
dcOpts = Global::DcOptions();
|
|
||||||
}
|
|
||||||
if (dcOpts.isEmpty()) {
|
|
||||||
const BuiltInDc *bdcs = builtInDcs();
|
|
||||||
for (int i = 0, l = builtInDcsCount(); i < l; ++i) {
|
|
||||||
MTPDdcOption::Flags flags = 0;
|
|
||||||
MTP::ShiftedDcId idWithShift = MTP::shiftDcId(bdcs[i].id, flags);
|
|
||||||
dcOpts.insert(idWithShift, MTP::DcOption(bdcs[i].id, flags, bdcs[i].ip, bdcs[i].port));
|
|
||||||
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
|
|
||||||
}
|
|
||||||
|
|
||||||
const BuiltInDc *bdcsipv6 = builtInDcsIPv6();
|
|
||||||
for (int i = 0, l = builtInDcsCountIPv6(); i < l; ++i) {
|
|
||||||
MTPDdcOption::Flags flags = MTPDdcOption::Flag::f_ipv6;
|
|
||||||
MTP::ShiftedDcId idWithShift = MTP::shiftDcId(bdcsipv6[i].id, flags);
|
|
||||||
dcOpts.insert(idWithShift, MTP::DcOption(bdcsipv6[i].id, flags, bdcsipv6[i].ip, bdcsipv6[i].port));
|
|
||||||
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: %2:%3").arg(bdcsipv6[i].id).arg(bdcsipv6[i].ip).arg(bdcsipv6[i].port));
|
|
||||||
}
|
|
||||||
|
|
||||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
|
||||||
Global::SetDcOptions(dcOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
|
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
|
||||||
for (auto i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
|
size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized);
|
||||||
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
|
|
||||||
size += sizeof(quint32) + Serialize::stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
|
|
||||||
}
|
|
||||||
size += sizeof(quint32) + Serialize::stringSize(cLangFile());
|
size += sizeof(quint32) + Serialize::stringSize(cLangFile());
|
||||||
|
|
||||||
size += sizeof(quint32) + sizeof(qint32);
|
size += sizeof(quint32) + sizeof(qint32);
|
||||||
|
@ -2308,11 +2263,7 @@ void writeSettings() {
|
||||||
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
|
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
|
||||||
data.stream << quint32(dbiScale) << qint32(cConfigScale());
|
data.stream << quint32(dbiScale) << qint32(cConfigScale());
|
||||||
data.stream << quint32(dbiLang) << qint32(cLang());
|
data.stream << quint32(dbiLang) << qint32(cLang());
|
||||||
for (auto i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
|
data.stream << quint32(dbiDcOptions) << dcOptionsSerialized;
|
||||||
data.stream << quint32(dbiDcOption) << quint32(i.key());
|
|
||||||
data.stream << qint32(i->flags) << QString::fromUtf8(i->ip.data(), i->ip.size());
|
|
||||||
data.stream << quint32(i->port);
|
|
||||||
}
|
|
||||||
data.stream << quint32(dbiLangFile) << cLangFile();
|
data.stream << quint32(dbiLangFile) << cLangFile();
|
||||||
|
|
||||||
data.stream << quint32(dbiConnectionType) << qint32(Global::ConnectionType());
|
data.stream << quint32(dbiConnectionType) << qint32(Global::ConnectionType());
|
||||||
|
|
|
@ -60,6 +60,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/player_wrap_widget.h"
|
#include "window/player_wrap_widget.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
|
||||||
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
||||||
, _memento(std::move(memento)) {
|
, _memento(std::move(memento)) {
|
||||||
|
@ -4907,7 +4908,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updateDcOptions: {
|
case mtpc_updateDcOptions: {
|
||||||
auto &d = update.c_updateDcOptions();
|
auto &d = update.c_updateDcOptions();
|
||||||
MTP::updateDcOptions(d.vdc_options.c_vector().v);
|
AppClass::Instance().dcOptions()->addFromList(d.vdc_options);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateUserPhone: {
|
case mtpc_updateUserPhone: {
|
||||||
|
|
|
@ -32,6 +32,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
#include "mtproto/rsa_public_key.h"
|
#include "mtproto/rsa_public_key.h"
|
||||||
|
#include "application.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
#include "mtproto/connection_abstract.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
@ -454,14 +457,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
|
|
||||||
if (!dc) {
|
if (!dc) {
|
||||||
QReadLocker lock(dcOptionsMutex());
|
dc = AppClass::Instance().dcOptions()->getDefaultDcId();
|
||||||
const auto &options(Global::DcOptions());
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
LOG(("MTP Error: connect failed, no DCs"));
|
|
||||||
dc = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dc = options.cbegin().value().id;
|
|
||||||
DEBUG_LOG(("MTP Info: searching for any DC, %1 selected...").arg(dc));
|
DEBUG_LOG(("MTP Info: searching for any DC, %1 selected...").arg(dc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,71 +1078,24 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
|
||||||
DEBUG_LOG(("MTP Error: socketStart() called for finished connection!"));
|
DEBUG_LOG(("MTP Error: socketStart() called for finished connection!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
auto dcType = DcOptions::DcType::Regular;
|
||||||
bool isDldDc = isDldDcId(dc);
|
bool isDldDc = isDldDcId(dc);
|
||||||
if (isDldDc) { // using media_only addresses only if key for this dc is already created
|
if (isDldDcId(dc)) { // using media_only addresses only if key for this dc is already created
|
||||||
QReadLocker lockFinished(&sessionDataMutex);
|
QReadLocker lockFinished(&sessionDataMutex);
|
||||||
if (sessionData) {
|
if (!sessionData || sessionData->getKey()) {
|
||||||
if (!sessionData->getKey()) {
|
dcType = DcOptions::DcType::MediaDownload;
|
||||||
isDldDc = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto bareDc = bareDcId(dc);
|
||||||
|
|
||||||
}
|
using Variants = DcOptions::Variants;
|
||||||
int32 bareDc = bareDcId(dc);
|
auto kIPv4 = Variants::IPv4;
|
||||||
|
auto kIPv6 = Variants::IPv6;
|
||||||
static const int IPv4address = 0, IPv6address = 1;
|
auto kTcp = Variants::Tcp;
|
||||||
static const int TcpProtocol = 0, HttpProtocol = 1;
|
auto kHttp = Variants::Http;
|
||||||
MTPDdcOption::Flags flags[2][2] = { { 0 } };
|
auto variants = AppClass::Instance().dcOptions()->lookup(bareDcId(dc), dcType);
|
||||||
string ip[2][2];
|
auto noIPv4 = (variants.data[kIPv4][kHttp].port == 0);
|
||||||
uint32 port[2][2] = { { 0 } };
|
auto noIPv6 = (!Global::TryIPv6() || (variants.data[kIPv6][kHttp].port == 0));
|
||||||
{
|
|
||||||
QReadLocker lock(dcOptionsMutex());
|
|
||||||
const auto &options(Global::DcOptions());
|
|
||||||
int32 shifts[2][2][4] = {
|
|
||||||
{ // IPv4
|
|
||||||
{ // TCP IPv4
|
|
||||||
isDldDc ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only) : -1,
|
|
||||||
qFlags(MTPDdcOption::Flag::f_tcpo_only),
|
|
||||||
isDldDc ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
|
||||||
0
|
|
||||||
}, { // HTTP IPv4
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
isDldDc ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
}, { // IPv6
|
|
||||||
{ // TCP IPv6
|
|
||||||
isDldDc ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
||||||
MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6,
|
|
||||||
isDldDc ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
||||||
qFlags(MTPDdcOption::Flag::f_ipv6)
|
|
||||||
}, { // HTTP IPv6
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
isDldDc ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
||||||
qFlags(MTPDdcOption::Flag::f_ipv6)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
for (int32 address = 0, acount = sizeof(shifts) / sizeof(shifts[0]); address < acount; ++address) {
|
|
||||||
for (int32 protocol = 0, pcount = sizeof(shifts[0]) / sizeof(shifts[0][0]); protocol < pcount; ++protocol) {
|
|
||||||
for (int32 shift = 0, scount = sizeof(shifts[0][0]) / sizeof(shifts[0][0][0]); shift < scount; ++shift) {
|
|
||||||
int32 mask = shifts[address][protocol][shift];
|
|
||||||
if (mask < 0) continue;
|
|
||||||
|
|
||||||
auto index = options.constFind(shiftDcId(bareDc, mask));
|
|
||||||
if (index != options.cend()) {
|
|
||||||
ip[address][protocol] = index->ip;
|
|
||||||
flags[address][protocol] = index->flags;
|
|
||||||
port[address][protocol] = index->port;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool noIPv4 = !port[IPv4address][HttpProtocol], noIPv6 = (!Global::TryIPv6() || !port[IPv6address][HttpProtocol]);
|
|
||||||
if (noIPv4 && noIPv6) {
|
if (noIPv4 && noIPv6) {
|
||||||
if (afterConfig) {
|
if (afterConfig) {
|
||||||
if (noIPv4) LOG(("MTP Error: DC %1 options for IPv4 over HTTP not found right after config load!").arg(dc));
|
if (noIPv4) LOG(("MTP Error: DC %1 options for IPv4 over HTTP not found right after config load!").arg(dc));
|
||||||
|
@ -1170,21 +1119,21 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
|
||||||
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
|
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
|
||||||
_pingSender.stop();
|
_pingSender.stop();
|
||||||
|
|
||||||
if (!noIPv4) DEBUG_LOG(("MTP Info: creating IPv4 connection to %1:%2 (tcp) and %3:%4 (http)...").arg(ip[IPv4address][TcpProtocol].c_str()).arg(port[IPv4address][TcpProtocol]).arg(ip[IPv4address][HttpProtocol].c_str()).arg(port[IPv4address][HttpProtocol]));
|
if (!noIPv4) DEBUG_LOG(("MTP Info: creating IPv4 connection to %1:%2 (tcp) and %3:%4 (http)...").arg(variants.data[kIPv4][kTcp].ip.c_str()).arg(variants.data[kIPv4][kTcp].port).arg(variants.data[kIPv4][kHttp].ip.c_str()).arg(variants.data[kIPv4][kHttp].port));
|
||||||
if (!noIPv6) DEBUG_LOG(("MTP Info: creating IPv6 connection to [%1]:%2 (tcp) and [%3]:%4 (http)...").arg(ip[IPv6address][TcpProtocol].c_str()).arg(port[IPv6address][TcpProtocol]).arg(ip[IPv4address][HttpProtocol].c_str()).arg(port[IPv4address][HttpProtocol]));
|
if (!noIPv6) DEBUG_LOG(("MTP Info: creating IPv6 connection to [%1]:%2 (tcp) and [%3]:%4 (http)...").arg(variants.data[kIPv6][kTcp].ip.c_str()).arg(variants.data[kIPv6][kTcp].port).arg(variants.data[kIPv4][kHttp].ip.c_str()).arg(variants.data[kIPv4][kHttp].port));
|
||||||
|
|
||||||
_waitForConnectedTimer.start(_waitForConnected);
|
_waitForConnectedTimer.start(_waitForConnected);
|
||||||
if (auto conn = _conn4) {
|
if (auto conn = _conn4) {
|
||||||
connect(conn, SIGNAL(connected()), this, SLOT(onConnected4()));
|
connect(conn, SIGNAL(connected()), this, SLOT(onConnected4()));
|
||||||
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected4()));
|
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected4()));
|
||||||
conn->connectTcp(ip[IPv4address][TcpProtocol].c_str(), port[IPv4address][TcpProtocol], flags[IPv4address][TcpProtocol]);
|
conn->connectTcp(variants.data[kIPv4][kTcp]);
|
||||||
conn->connectHttp(ip[IPv4address][HttpProtocol].c_str(), port[IPv4address][HttpProtocol], flags[IPv4address][HttpProtocol]);
|
conn->connectHttp(variants.data[kIPv4][kHttp]);
|
||||||
}
|
}
|
||||||
if (auto conn = _conn6) {
|
if (auto conn = _conn6) {
|
||||||
connect(conn, SIGNAL(connected()), this, SLOT(onConnected6()));
|
connect(conn, SIGNAL(connected()), this, SLOT(onConnected6()));
|
||||||
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected6()));
|
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected6()));
|
||||||
conn->connectTcp(ip[IPv6address][TcpProtocol].c_str(), port[IPv6address][TcpProtocol], flags[IPv6address][TcpProtocol]);
|
conn->connectTcp(variants.data[kIPv6][kTcp]);
|
||||||
conn->connectHttp(ip[IPv6address][HttpProtocol].c_str(), port[IPv6address][HttpProtocol], flags[IPv6address][HttpProtocol]);
|
conn->connectHttp(variants.data[kIPv6][kHttp]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "mtproto/core_types.h"
|
#include "mtproto/core_types.h"
|
||||||
#include "mtproto/auth_key.h"
|
#include "mtproto/auth_key.h"
|
||||||
#include "mtproto/connection_abstract.h"
|
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
class AbstractConnection;
|
||||||
class ConnectionPrivate;
|
class ConnectionPrivate;
|
||||||
class SessionData;
|
class SessionData;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "mtproto/core_types.h"
|
#include "mtproto/core_types.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -29,7 +30,6 @@ class AbstractConnection : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AbstractConnection(QThread *thread) : _sentEncrypted(false) {
|
AbstractConnection(QThread *thread) : _sentEncrypted(false) {
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ public:
|
||||||
|
|
||||||
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
||||||
virtual void disconnectFromServer() = 0;
|
virtual void disconnectFromServer() = 0;
|
||||||
virtual void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
|
virtual void connectTcp(const DcOptions::Endpoint &endpoint) = 0;
|
||||||
virtual void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
|
virtual void connectHttp(const DcOptions::Endpoint &endpoint) = 0;
|
||||||
virtual bool isConnected() const = 0;
|
virtual bool isConnected() const = 0;
|
||||||
virtual bool usingHttpWait() {
|
virtual bool usingHttpWait() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -162,24 +162,25 @@ void AutoConnection::disconnectFromServer() {
|
||||||
httpStartTimer.stop();
|
httpStartTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
void AutoConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
|
||||||
_addrTcp = addr;
|
_addrTcp = QString::fromStdString(endpoint.ip);
|
||||||
_portTcp = port;
|
_portTcp = endpoint.port;
|
||||||
_flagsTcp = flags;
|
_flagsTcp = endpoint.flags;
|
||||||
|
|
||||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||||
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoConnection::connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
void AutoConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
|
||||||
address = QUrl(((flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
|
_addrHttp = QString::fromStdString(endpoint.ip);
|
||||||
|
_portHttp = endpoint.port;
|
||||||
|
_flagsHttp = endpoint.flags;
|
||||||
|
|
||||||
|
// not endpoint.port - always 80 port for http transport
|
||||||
|
address = QUrl(((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(_addrHttp).arg(80));
|
||||||
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
||||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
_addrHttp = addr;
|
|
||||||
_portHttp = port;
|
|
||||||
_flagsHttp = flags;
|
|
||||||
|
|
||||||
mtpBuffer buffer(preparePQFake(httpNonce));
|
mtpBuffer buffer(preparePQFake(httpNonce));
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
|
@ -35,8 +35,8 @@ public:
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
void connectTcp(const DcOptions::Endpoint &endpoint) override;
|
||||||
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
void connectHttp(const DcOptions::Endpoint &endpoint) override;
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
bool usingHttpWait() override;
|
bool usingHttpWait() override;
|
||||||
bool needHttpWait() override;
|
bool needHttpWait() override;
|
||||||
|
|
|
@ -136,16 +136,18 @@ void HTTPConnection::disconnectFromServer() {
|
||||||
address = QUrl();
|
address = QUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::connectHttp(const QString &addr, int32 p, MTPDdcOption::Flags flags) {
|
void HTTPConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
|
||||||
address = QUrl(((flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
|
_flags = endpoint.flags;
|
||||||
|
auto addr = QString::fromStdString(endpoint.ip);
|
||||||
|
|
||||||
|
// not endpoint.port - always 80 port for http transport
|
||||||
|
address = QUrl(((_flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));
|
||||||
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
||||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
_flags = flags;
|
|
||||||
|
|
||||||
mtpBuffer buffer(preparePQFake(httpNonce));
|
mtpBuffer buffer(preparePQFake(httpNonce));
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
||||||
sendData(buffer);
|
sendData(buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ public:
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override { // not supported
|
void connectTcp(const DcOptions::Endpoint &endpoint) override { // not supported
|
||||||
}
|
}
|
||||||
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
void connectHttp(const DcOptions::Endpoint &endpoint) override;
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
bool usingHttpWait() override;
|
bool usingHttpWait() override;
|
||||||
bool needHttpWait() override;
|
bool needHttpWait() override;
|
||||||
|
|
|
@ -339,10 +339,10 @@ void TCPConnection::disconnectFromServer() {
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
void TCPConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
|
||||||
_addr = addr;
|
_addr = QString::fromStdString(endpoint.ip);
|
||||||
_port = port;
|
_port = endpoint.port;
|
||||||
_flags = flags;
|
_flags = endpoint.flags;
|
||||||
|
|
||||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||||
sock.connectToHost(QHostAddress(_addr), _port);
|
sock.connectToHost(QHostAddress(_addr), _port);
|
||||||
|
|
|
@ -75,8 +75,8 @@ public:
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
void connectTcp(const DcOptions::Endpoint &endpoint) override;
|
||||||
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override { // not supported
|
void connectHttp(const DcOptions::Endpoint &endpoint) override { // not supported
|
||||||
}
|
}
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
|
|
||||||
|
|
306
Telegram/SourceFiles/mtproto/dc_options.cpp
Normal file
306
Telegram/SourceFiles/mtproto/dc_options.cpp
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
|
||||||
|
void DcOptions::constructFromBuiltIn() {
|
||||||
|
QWriteLocker lock(&_mutex);
|
||||||
|
_data.clear();
|
||||||
|
|
||||||
|
auto bdcs = builtInDcs();
|
||||||
|
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
|
||||||
|
auto flags = MTPDdcOption::Flags(0);
|
||||||
|
auto idWithShift = MTP::shiftDcId(bdcs[i].id, flags);
|
||||||
|
_data.insert(std::make_pair(idWithShift, Option(bdcs[i].id, flags, bdcs[i].ip, bdcs[i].port)));
|
||||||
|
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bdcsipv6 = builtInDcsIPv6();
|
||||||
|
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
|
||||||
|
auto flags = MTPDdcOption::Flags(MTPDdcOption::Flag::f_ipv6);
|
||||||
|
auto idWithShift = MTP::shiftDcId(bdcsipv6[i].id, flags);
|
||||||
|
_data.insert(std::make_pair(idWithShift, Option(bdcsipv6[i].id, flags, bdcsipv6[i].ip, bdcsipv6[i].port)));
|
||||||
|
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: %2:%3").arg(bdcsipv6[i].id).arg(bdcsipv6[i].ip).arg(bdcsipv6[i].port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::processFromList(const QVector<MTPDcOption> &options, bool overwrite) {
|
||||||
|
if (options.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idsChanged = std::vector<DcId>();
|
||||||
|
idsChanged.reserve(options.size());
|
||||||
|
auto shiftedIdsProcessed = std::vector<ShiftedDcId>();
|
||||||
|
shiftedIdsProcessed.reserve(options.size());
|
||||||
|
{
|
||||||
|
QWriteLocker lock(&_mutex);
|
||||||
|
if (overwrite) {
|
||||||
|
idsChanged.reserve(_data.size());
|
||||||
|
}
|
||||||
|
for (auto &mtpOption : options) {
|
||||||
|
if (mtpOption.type() != mtpc_dcOption) {
|
||||||
|
LOG(("Wrong type in DcOptions: %1").arg(mtpOption.type()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &option = mtpOption.c_dcOption();
|
||||||
|
auto dcId = option.vid.v;
|
||||||
|
auto flags = option.vflags.v;
|
||||||
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
||||||
|
if (base::contains(shiftedIdsProcessed, dcIdWithShift)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftedIdsProcessed.push_back(dcIdWithShift);
|
||||||
|
auto &ip = option.vip_address.c_string().v;
|
||||||
|
auto port = option.vport.v;
|
||||||
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
||||||
|
if (!base::contains(idsChanged, dcId)) {
|
||||||
|
idsChanged.push_back(dcId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (overwrite && shiftedIdsProcessed.size() < _data.size()) {
|
||||||
|
for (auto i = _data.begin(); i != _data.end();) {
|
||||||
|
if (base::contains(shiftedIdsProcessed, i->first)) {
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
if (!base::contains(idsChanged, i->second.id)) {
|
||||||
|
idsChanged.push_back(i->second.id);
|
||||||
|
}
|
||||||
|
i = _data.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!idsChanged.empty()) {
|
||||||
|
_changed.notify(std::move(idsChanged));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::setFromList(const MTPVector<MTPDcOption> &options) {
|
||||||
|
processFromList(options.c_vector().v, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::addFromList(const MTPVector<MTPDcOption> &options) {
|
||||||
|
processFromList(options.c_vector().v, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::addFromOther(const DcOptions &options) {
|
||||||
|
if (this == &options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idsChanged = std::vector<DcId>();
|
||||||
|
{
|
||||||
|
QReadLocker lock(&options._mutex);
|
||||||
|
if (options._data.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
idsChanged.reserve(options._data.size());
|
||||||
|
{
|
||||||
|
QWriteLocker lock(&_mutex);
|
||||||
|
for (auto &item : options._data) {
|
||||||
|
auto dcId = item.second.id;
|
||||||
|
auto flags = item.second.flags;
|
||||||
|
auto &ip = item.second.ip;
|
||||||
|
auto port = item.second.port;
|
||||||
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
||||||
|
if (!base::contains(idsChanged, dcId)) {
|
||||||
|
idsChanged.push_back(dcId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!idsChanged.empty()) {
|
||||||
|
_changed.notify(std::move(idsChanged));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::constructAddOne(int id, MTPDdcOption::Flags flags, const std::string &ip, int port) {
|
||||||
|
QWriteLocker lock(&_mutex);
|
||||||
|
applyOneGuarded(bareDcId(id), flags, ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DcOptions::applyOneGuarded(DcId dcId, MTPDdcOption::Flags flags, const std::string &ip, int port) {
|
||||||
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
||||||
|
auto i = _data.find(dcIdWithShift);
|
||||||
|
if (i != _data.cend()) {
|
||||||
|
if (i->second.ip == ip && i->second.port == port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i->second.ip = ip;
|
||||||
|
i->second.port = port;
|
||||||
|
} else {
|
||||||
|
_data.insert(std::make_pair(dcIdWithShift, Option(dcId, flags, ip, port)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray DcOptions::serialize() const {
|
||||||
|
QReadLocker lock(&_mutex);
|
||||||
|
|
||||||
|
auto size = sizeof(qint32);
|
||||||
|
for (auto &item : _data) {
|
||||||
|
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // id + flags + port
|
||||||
|
size += sizeof(qint32) + item.second.ip.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = QByteArray();
|
||||||
|
result.reserve(size);
|
||||||
|
{
|
||||||
|
QBuffer buffer(&result);
|
||||||
|
if (!buffer.open(QIODevice::WriteOnly)) {
|
||||||
|
LOG(("MTP Error: Can't open data for DcOptions::serialize()"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream stream(&buffer);
|
||||||
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
|
stream << qint32(_data.size());
|
||||||
|
for (auto &item : _data) {
|
||||||
|
stream << qint32(item.second.id) << qint32(item.second.flags) << qint32(item.second.port);
|
||||||
|
stream << qint32(item.second.ip.size());
|
||||||
|
stream.writeRawData(item.second.ip.data(), item.second.ip.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DcOptions::constructFromSerialized(const QByteArray &serialized) {
|
||||||
|
auto readonly = serialized;
|
||||||
|
QBuffer buffer(&readonly);
|
||||||
|
if (!buffer.open(QIODevice::ReadOnly)) {
|
||||||
|
LOG(("MTP Error: Can't open data for DcOptions::setFromSerialized()"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDataStream stream(&buffer);
|
||||||
|
qint32 count = 0;
|
||||||
|
stream >> count;
|
||||||
|
if (stream.status() != QDataStream::Ok) {
|
||||||
|
LOG(("MTP Error: Bad data for DcOptions::setFromSerialized()"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWriteLocker lock(&_mutex);
|
||||||
|
_data.clear();
|
||||||
|
for (auto i = 0; i != count; ++i) {
|
||||||
|
qint32 id = 0, flags = 0, port = 0, ipSize = 0;
|
||||||
|
stream >> id >> flags >> port >> ipSize;
|
||||||
|
std::string ip(ipSize, ' ');
|
||||||
|
stream.readRawData(&ip[0], ipSize);
|
||||||
|
|
||||||
|
if (stream.status() != QDataStream::Ok) {
|
||||||
|
LOG(("MTP Error: Bad data inside DcOptions::setFromSerialized()"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyOneGuarded(DcId(id), MTPDdcOption::Flags(flags), ip, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DcOptions::Ids DcOptions::sortedDcIds() const {
|
||||||
|
auto result = Ids();
|
||||||
|
{
|
||||||
|
QReadLocker lock(&_mutex);
|
||||||
|
result.reserve(_data.size());
|
||||||
|
for (auto &item : _data) {
|
||||||
|
if (!base::contains(result, item.second.id)) {
|
||||||
|
result.push_back(item.second.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(result.begin(), result.end());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DcId DcOptions::getDefaultDcId() const {
|
||||||
|
auto result = sortedDcIds();
|
||||||
|
t_assert(!result.empty());
|
||||||
|
|
||||||
|
auto main = internal::mainDC();
|
||||||
|
if (base::contains(result, main)) {
|
||||||
|
return main;
|
||||||
|
}
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
DcOptions::Variants DcOptions::lookup(DcId dcId, DcType type) const {
|
||||||
|
auto isMediaDownload = (type == DcType::MediaDownload);
|
||||||
|
int shifts[2][2][4] = {
|
||||||
|
{ // IPv4
|
||||||
|
{ // TCP IPv4
|
||||||
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only) : -1,
|
||||||
|
qFlags(MTPDdcOption::Flag::f_tcpo_only),
|
||||||
|
isMediaDownload ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
||||||
|
0
|
||||||
|
}, { // HTTP IPv4
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
isMediaDownload ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
}, { // IPv6
|
||||||
|
{ // TCP IPv6
|
||||||
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
||||||
|
MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6,
|
||||||
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
||||||
|
qFlags(MTPDdcOption::Flag::f_ipv6)
|
||||||
|
}, { // HTTP IPv6
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
||||||
|
qFlags(MTPDdcOption::Flag::f_ipv6)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto result = Variants();
|
||||||
|
{
|
||||||
|
QReadLocker lock(&_mutex);
|
||||||
|
for (auto address = 0; address != Variants::AddressTypeCount; ++address) {
|
||||||
|
for (auto protocol = 0; protocol != Variants::ProtocolCount; ++protocol) {
|
||||||
|
for (auto variant = 0; variant != base::array_size(shifts[address][protocol]); ++variant) {
|
||||||
|
auto shift = shifts[address][protocol][variant];
|
||||||
|
if (shift < 0) continue;
|
||||||
|
|
||||||
|
auto it = _data.find(shiftDcId(dcId, shift));
|
||||||
|
if (it != _data.cend()) {
|
||||||
|
result.data[address][protocol].ip = it->second.ip;
|
||||||
|
result.data[address][protocol].flags = it->second.flags;
|
||||||
|
result.data[address][protocol].port = it->second.port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MTP
|
94
Telegram/SourceFiles/mtproto/dc_options.h
Normal file
94
Telegram/SourceFiles/mtproto/dc_options.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/observer.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
|
||||||
|
class DcOptions {
|
||||||
|
public:
|
||||||
|
// construct methods don't notify "changed" subscribers.
|
||||||
|
void constructFromSerialized(const QByteArray &serialized);
|
||||||
|
void constructFromBuiltIn();
|
||||||
|
void constructAddOne(int id, MTPDdcOption::Flags flags, const std::string &ip, int port);
|
||||||
|
QByteArray serialize() const;
|
||||||
|
|
||||||
|
using Ids = std::vector<DcId>;
|
||||||
|
base::Observable<Ids> &changed() const {
|
||||||
|
return _changed;
|
||||||
|
}
|
||||||
|
void setFromList(const MTPVector<MTPDcOption> &options);
|
||||||
|
void addFromList(const MTPVector<MTPDcOption> &options);
|
||||||
|
void addFromOther(const DcOptions &options);
|
||||||
|
|
||||||
|
Ids sortedDcIds() const;
|
||||||
|
DcId getDefaultDcId() const;
|
||||||
|
|
||||||
|
struct Endpoint {
|
||||||
|
std::string ip;
|
||||||
|
int port = 0;
|
||||||
|
MTPDdcOption::Flags flags = 0;
|
||||||
|
};
|
||||||
|
struct Variants {
|
||||||
|
enum {
|
||||||
|
IPv4 = 0,
|
||||||
|
IPv6 = 1,
|
||||||
|
AddressTypeCount = 2,
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
Tcp = 0,
|
||||||
|
Http = 1,
|
||||||
|
ProtocolCount = 2,
|
||||||
|
};
|
||||||
|
Endpoint data[AddressTypeCount][ProtocolCount];
|
||||||
|
};
|
||||||
|
enum class DcType {
|
||||||
|
Regular,
|
||||||
|
MediaDownload,
|
||||||
|
};
|
||||||
|
Variants lookup(DcId dcId, DcType type) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Option {
|
||||||
|
Option(DcId id, MTPDdcOption::Flags flags, const std::string &ip, int port) : id(id), flags(flags), ip(ip), port(port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
DcId id;
|
||||||
|
MTPDdcOption::Flags flags;
|
||||||
|
std::string ip;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
bool applyOneGuarded(DcId dcId, MTPDdcOption::Flags flags, const std::string &ip, int port);
|
||||||
|
|
||||||
|
void processFromList(const QVector<MTPDcOption> &options, bool overwrite);
|
||||||
|
|
||||||
|
std::map<int, Option> _data;
|
||||||
|
mutable QReadWriteLock _mutex;
|
||||||
|
|
||||||
|
mutable base::Observable<Ids> _changed;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace MTP
|
|
@ -19,16 +19,17 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
#include "mtproto/dcenter.h"
|
#include "mtproto/dcenter.h"
|
||||||
|
|
||||||
#include "mtproto/facade.h"
|
#include "mtproto/facade.h"
|
||||||
|
#include "mtproto/dc_options.h"
|
||||||
|
#include "application.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
DcenterMap gDCs;
|
DcenterMap gDCs;
|
||||||
bool configLoadedOnce = false;
|
bool configLoadedOnce = false;
|
||||||
bool mainDCChanged = false;
|
bool mainDCChanged = false;
|
||||||
|
@ -38,6 +39,9 @@ namespace {
|
||||||
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
|
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
|
||||||
_KeysMapForWrite _keysMapForWrite;
|
_KeysMapForWrite _keysMapForWrite;
|
||||||
QMutex _keysMapForWriteMutex;
|
QMutex _keysMapForWriteMutex;
|
||||||
|
|
||||||
|
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int32 authed() {
|
int32 authed() {
|
||||||
|
@ -156,7 +160,11 @@ void configLoaded(const MTPConfig &result) {
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
|
DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
|
||||||
|
|
||||||
updateDcOptions(data.vdc_options.c_vector().v);
|
if (data.vdc_options.c_vector().v.empty()) {
|
||||||
|
LOG(("MTP Error: config with empty dc_options received!"));
|
||||||
|
} else {
|
||||||
|
AppClass::Instance().dcOptions()->setFromList(data.vdc_options);
|
||||||
|
}
|
||||||
|
|
||||||
Global::SetChatSizeMax(data.vchat_size_max.v);
|
Global::SetChatSizeMax(data.vchat_size_max.v);
|
||||||
Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
|
Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
|
||||||
|
@ -191,47 +199,7 @@ bool configFailed(const RPCError &error) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options) {
|
ConfigLoader::ConfigLoader() {
|
||||||
QSet<int32> already, restart;
|
|
||||||
{
|
|
||||||
MTP::DcOptions opts;
|
|
||||||
{
|
|
||||||
QReadLocker lock(dcOptionsMutex());
|
|
||||||
opts = Global::DcOptions();
|
|
||||||
}
|
|
||||||
for (QVector<MTPDcOption>::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
|
||||||
const auto &optData(i->c_dcOption());
|
|
||||||
int32 id = optData.vid.v, idWithShift = MTP::shiftDcId(id, optData.vflags.v);
|
|
||||||
if (already.constFind(idWithShift) == already.cend()) {
|
|
||||||
already.insert(idWithShift);
|
|
||||||
auto a = opts.constFind(idWithShift);
|
|
||||||
if (a != opts.cend()) {
|
|
||||||
if (a.value().ip != optData.vip_address.c_string().v || a.value().port != optData.vport.v) {
|
|
||||||
restart.insert(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opts.insert(idWithShift, MTP::DcOption(id, optData.vflags.v, optData.vip_address.c_string().v, optData.vport.v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
QWriteLocker lock(dcOptionsMutex());
|
|
||||||
Global::SetDcOptions(opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (QSet<int32>::const_iterator i = restart.cbegin(), e = restart.cend(); i != e; ++i) {
|
|
||||||
MTP::restart(*i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
QReadWriteLock _dcOptionsMutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
QReadWriteLock *dcOptionsMutex() {
|
|
||||||
return &_dcOptionsMutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigLoader::ConfigLoader() : _enumCurrent(0), _enumRequest(0) {
|
|
||||||
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +209,7 @@ void ConfigLoader::load() {
|
||||||
|
|
||||||
MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed));
|
MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed));
|
||||||
|
|
||||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
_enumDCTimer.start(kEnumerateDcTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigLoader::done() {
|
void ConfigLoader::done() {
|
||||||
|
@ -267,23 +235,18 @@ void ConfigLoader::enumDC() {
|
||||||
} else {
|
} else {
|
||||||
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
||||||
}
|
}
|
||||||
OrderedSet<int32> dcs;
|
auto ids = AppClass::Instance().dcOptions()->sortedDcIds();
|
||||||
{
|
t_assert(!ids.empty());
|
||||||
QReadLocker lock(dcOptionsMutex());
|
|
||||||
const auto &options(Global::DcOptions());
|
auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
|
||||||
for (auto i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
if (i == ids.cend() || (++i) == ids.cend()) {
|
||||||
dcs.insert(MTP::bareDcId(i.key()));
|
_enumCurrent = ids.front();
|
||||||
}
|
|
||||||
}
|
|
||||||
auto i = dcs.constFind(_enumCurrent);
|
|
||||||
if (i == dcs.cend() || (++i) == dcs.cend()) {
|
|
||||||
_enumCurrent = *dcs.cbegin();
|
|
||||||
} else {
|
} else {
|
||||||
_enumCurrent = *i;
|
_enumCurrent = *i;
|
||||||
}
|
}
|
||||||
_enumRequest = MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed), MTP::cfgDcId(_enumCurrent));
|
_enumRequest = MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed), MTP::cfgDcId(_enumCurrent));
|
||||||
|
|
||||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
_enumDCTimer.start(kEnumerateDcTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigLoader *configLoader() {
|
ConfigLoader *configLoader() {
|
||||||
|
|
|
@ -81,8 +81,8 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SingleTimer _enumDCTimer;
|
SingleTimer _enumDCTimer;
|
||||||
int32 _enumCurrent;
|
DcId _enumCurrent = 0;
|
||||||
mtpRequestId _enumRequest;
|
mtpRequestId _enumRequest = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,8 +101,5 @@ void authed(int32 uid);
|
||||||
AuthKeysMap getAuthKeys();
|
AuthKeysMap getAuthKeys();
|
||||||
void setAuthKey(int32 dc, AuthKeyPtr key);
|
void setAuthKey(int32 dc, AuthKeyPtr key);
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options);
|
|
||||||
QReadWriteLock *dcOptionsMutex();
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -829,14 +829,13 @@ int32 state(mtpRequestId requestId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish() {
|
void finish() {
|
||||||
for (Sessions::iterator i = sessions.begin(), e = sessions.end(); i != e; ++i) {
|
|
||||||
i.value()->kill();
|
|
||||||
delete i.value();
|
|
||||||
}
|
|
||||||
sessions.clear();
|
|
||||||
mainSession = nullptr;
|
mainSession = nullptr;
|
||||||
|
for (auto session : base::take(sessions)) {
|
||||||
|
session->kill();
|
||||||
|
delete session;
|
||||||
|
}
|
||||||
|
|
||||||
for_const (internal::Connection *connection, quittingConnections) {
|
for_const (auto connection, quittingConnections) {
|
||||||
connection->waitTillFinish();
|
connection->waitTillFinish();
|
||||||
delete connection;
|
delete connection;
|
||||||
}
|
}
|
||||||
|
@ -886,11 +885,6 @@ void clearGlobalHandlers() {
|
||||||
setSessionResetHandler(0);
|
setSessionResetHandler(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options) {
|
|
||||||
internal::updateDcOptions(options);
|
|
||||||
Local::writeSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthKeysMap getKeys() {
|
AuthKeysMap getKeys() {
|
||||||
return internal::getAuthKeys();
|
return internal::getAuthKeys();
|
||||||
}
|
}
|
||||||
|
@ -903,8 +897,4 @@ void setKey(int dc, const AuthKey::Data &key) {
|
||||||
return internal::setAuthKey(dc, std::move(keyPtr));
|
return internal::setAuthKey(dc, std::move(keyPtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
QReadWriteLock *dcOptionsMutex() {
|
|
||||||
return internal::dcOptionsMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -217,24 +217,9 @@ void setStateChangedHandler(MTPStateChangedHandler handler);
|
||||||
void setSessionResetHandler(MTPSessionResetHandler handler);
|
void setSessionResetHandler(MTPSessionResetHandler handler);
|
||||||
void clearGlobalHandlers();
|
void clearGlobalHandlers();
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options);
|
|
||||||
|
|
||||||
AuthKeysMap getKeys();
|
AuthKeysMap getKeys();
|
||||||
void setKey(int dc, const AuthKey::Data &key);
|
void setKey(int dc, const AuthKey::Data &key);
|
||||||
|
|
||||||
QReadWriteLock *dcOptionsMutex();
|
|
||||||
|
|
||||||
struct DcOption {
|
|
||||||
DcOption(int id, MTPDdcOption::Flags flags, const std::string &ip, int port) : id(id), flags(flags), ip(ip), port(port) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int id;
|
|
||||||
MTPDdcOption::Flags flags;
|
|
||||||
std::string ip;
|
|
||||||
int port;
|
|
||||||
};
|
|
||||||
typedef QMap<int, DcOption> DcOptions;
|
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename TRequest>
|
template <typename TRequest>
|
||||||
|
|
|
@ -337,6 +337,8 @@
|
||||||
'<(src_loc)/mtproto/core_types.h',
|
'<(src_loc)/mtproto/core_types.h',
|
||||||
'<(src_loc)/mtproto/dcenter.cpp',
|
'<(src_loc)/mtproto/dcenter.cpp',
|
||||||
'<(src_loc)/mtproto/dcenter.h',
|
'<(src_loc)/mtproto/dcenter.h',
|
||||||
|
'<(src_loc)/mtproto/dc_options.cpp',
|
||||||
|
'<(src_loc)/mtproto/dc_options.h',
|
||||||
'<(src_loc)/mtproto/file_download.cpp',
|
'<(src_loc)/mtproto/file_download.cpp',
|
||||||
'<(src_loc)/mtproto/file_download.h',
|
'<(src_loc)/mtproto/file_download.h',
|
||||||
'<(src_loc)/mtproto/rsa_public_key.cpp',
|
'<(src_loc)/mtproto/rsa_public_key.cpp',
|
||||||
|
|
Loading…
Add table
Reference in a new issue