Encapsulated DcOptions to an independent class.

This commit is contained in:
John Preston 2017-02-23 09:57:04 +03:00
parent 90b3b5c3e5
commit a35947141c
24 changed files with 606 additions and 329 deletions

View file

@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/notifications_manager.h"
#include "history/history_location_manager.h"
#include "core/task_queue.h"
#include "mtproto/dc_options.h"
namespace {
@ -340,7 +341,10 @@ void Application::closeApplication() {
manager->clearAllFast();
}
delete base::take(AppObject);
if (AppObject) {
AppClass::Instance().joinThreads();
delete base::take(AppObject);
}
Sandbox::finish();
@ -682,7 +686,6 @@ namespace Sandbox {
new AppClass();
}
}
AppClass::AppClass() : QObject() {
@ -692,7 +695,9 @@ AppClass::AppClass() : QObject() {
ThirdParty::start();
Global::start();
Local::start();
startLocalStorage();
if (Local::oldSettingsVersion() < AppVersion) {
psNewVersion();
}
@ -816,6 +821,18 @@ void AppClass::loadLanguage() {
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) {
photoUpdates.insert(msgId, peer);
}
@ -1096,6 +1113,10 @@ void AppClass::checkMapVersion() {
}
}
void AppClass::joinThreads() {
MTP::finish();
}
AppClass::~AppClass() {
Shortcuts::finish();
@ -1110,8 +1131,6 @@ AppClass::~AppClass() {
App::deinitMedia();
deinitLocationManager();
MTP::finish();
AppObject = nullptr;
delete base::take(_uploader);
delete base::take(_translator);

View file

@ -23,6 +23,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "pspecific.h"
#include "core/single_timer.h"
#include "core/observer.h"
namespace MTP {
class DcOptions;
} // namespace MTP
class UpdateChecker;
class Application : public QApplication {
@ -143,17 +148,28 @@ class MainWidget;
class FileUploader;
class Translator;
class AppClass : public QObject, public RPCSender {
class AppClass : public QObject, public RPCSender, private base::Subscriber {
Q_OBJECT
public:
AppClass();
void joinThreads();
~AppClass();
static AppClass *app();
static MainWindow *wnd();
static MainWidget *main();
static AppClass &Instance() {
auto result = app();
t_assert(result != nullptr);
return *result;
}
MTP::DcOptions *dcOptions() {
return _dcOptions.get();
}
FileUploader *uploader();
void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
void regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId);
@ -179,7 +195,6 @@ public:
void handleAppDeactivated();
signals:
void peerPhotoDone(PeerId peer);
void peerPhotoFail(PeerId peer);
@ -202,6 +217,7 @@ public slots:
void call_handleObservables();
private:
void startLocalStorage();
void loadLanguage();
QMap<FullMsgId, PeerId> photoUpdates;
@ -215,4 +231,6 @@ private:
FileUploader *_uploader = nullptr;
Translator *_translator = nullptr;
std::unique_ptr<MTP::DcOptions> _dcOptions;
};

View file

@ -51,8 +51,6 @@ enum {
MTPDownloadSessionsCount = 2, // max 2 download sessions is created
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
MaxUsersPerInvite = 100, // max users in one super group invite request

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "core/basic_types.h"
#include <array>
#include <algorithm>
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));
}
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
// using for_const instead of plain range-based for loop to ensure usage of const_iterator

View file

@ -671,8 +671,6 @@ struct Data {
TimeMs LastFeaturedStickersUpdate = 0;
Stickers::Order ArchivedStickerSetsOrder;
MTP::DcOptions DcOptions;
CircleMasksMap CircleMasks;
base::Observable<void> SelfChanged;
@ -795,8 +793,6 @@ DefineRefVar(Global, base::Observable<void>, FeaturedStickerSetsUnreadCountChang
DefineVar(Global, TimeMs, LastFeaturedStickersUpdate);
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);
DefineVar(Global, MTP::DcOptions, DcOptions);
DefineRefVar(Global, CircleMasksMap, CircleMasks);
DefineRefVar(Global, base::Observable<void>, SelfChanged);

View file

@ -369,8 +369,6 @@ DeclareRefVar(base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
DeclareVar(TimeMs, LastFeaturedStickersUpdate);
DeclareVar(Stickers::Order, ArchivedStickerSetsOrder);
DeclareVar(MTP::DcOptions, DcOptions);
typedef QMap<uint64, QPixmap> CircleMasksMap;
DeclareRefVar(CircleMasksMap, CircleMasks);

View file

@ -33,6 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang.h"
#include "media/media_audio.h"
#include "ui/widgets/input_fields.h"
#include "mtproto/dc_options.h"
#include "application.h"
#include "apiwrap.h"
@ -563,6 +564,7 @@ enum {
dbiTheme = 0x47,
dbiDialogsWidthRatio = 0x48,
dbiUseExternalVideoPlayer = 0x49,
dbiDcOptions = 0x4a,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,
@ -829,8 +831,15 @@ void _readReportSpamStatuses() {
}
}
MTP::DcOptions *_dcOpts = 0;
bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
struct ReadSettingsContext {
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) {
case dbiDcOptionOld: {
quint32 dcId, port;
@ -838,7 +847,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
stream >> dcId >> host >> ip >> port;
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;
case dbiDcOption: {
@ -848,7 +857,15 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
stream >> dcIdWithShift >> flags >> ip >> port;
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;
case dbiChatSizeMax: {
@ -1445,7 +1462,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
return true;
}
bool _readOldSettings(bool remove = true) {
bool _readOldSettings(bool remove, ReadSettingsContext &context) {
bool result = false;
QFile file(cWorkingDir() + qsl("tdata/config"));
if (file.open(QIODevice::ReadOnly)) {
@ -1464,7 +1481,7 @@ bool _readOldSettings(bool remove = true) {
if (!_checkStreamStatus(stream)) break;
if (version > AppVersion) break;
} else if (!_readSetting(blockId, stream, version)) {
} else if (!_readSetting(blockId, stream, version, context)) {
break;
}
}
@ -1475,7 +1492,7 @@ bool _readOldSettings(bool remove = true) {
return result;
}
void _readOldUserSettingsFields(QIODevice *device, qint32 &version) {
void _readOldUserSettingsFields(QIODevice *device, qint32 &version, ReadSettingsContext &context) {
QDataStream stream(device);
stream.setVersion(QDataStream::Qt_5_1);
@ -1531,32 +1548,20 @@ void _readOldUserSettingsFields(QIODevice *device, qint32 &version) {
decryptedStream.seek(4); // skip size
LOG(("App Info: reading encrypted old user config..."));
_readOldUserSettingsFields(&decryptedStream, version);
} else if (!_readSetting(blockId, stream, version)) {
_readOldUserSettingsFields(&decryptedStream, version, context);
} else if (!_readSetting(blockId, stream, version, context)) {
return;
}
}
}
bool _readOldUserSettings(bool remove = true) {
bool _readOldUserSettings(bool remove, ReadSettingsContext &context) {
bool result = false;
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()) + qsl("_config"));
if (file.open(QIODevice::ReadOnly)) {
LOG(("App Info: reading old user config..."));
qint32 version = 0;
MTP::DcOptions dcOpts;
{
QReadLocker lock(MTP::dcOptionsMutex());
dcOpts = Global::DcOptions();
}
_dcOpts = &dcOpts;
_readOldUserSettingsFields(&file, version);
{
QWriteLocker lock(MTP::dcOptionsMutex());
Global::SetDcOptions(dcOpts);
}
_readOldUserSettingsFields(&file, version, context);
file.close();
result = true;
}
@ -1564,7 +1569,7 @@ bool _readOldUserSettings(bool remove = true) {
return result;
}
void _readOldMtpDataFields(QIODevice *device, qint32 &version) {
void _readOldMtpDataFields(QIODevice *device, qint32 &version, ReadSettingsContext &context) {
QDataStream stream(device);
stream.setVersion(QDataStream::Qt_5_1);
@ -1618,32 +1623,20 @@ void _readOldMtpDataFields(QIODevice *device, qint32 &version) {
decryptedStream.seek(4); // skip size
LOG(("App Info: reading encrypted old keys..."));
_readOldMtpDataFields(&decryptedStream, version);
} else if (!_readSetting(blockId, stream, version)) {
_readOldMtpDataFields(&decryptedStream, version, context);
} else if (!_readSetting(blockId, stream, version, context)) {
return;
}
}
}
bool _readOldMtpData(bool remove = true) {
bool _readOldMtpData(bool remove, ReadSettingsContext &context) {
bool result = false;
QFile file(cWorkingDir() + cDataFile() + (cTestMode() ? qsl("_test") : QString()));
if (file.open(QIODevice::ReadOnly)) {
LOG(("App Info: reading old keys..."));
qint32 version = 0;
MTP::DcOptions dcOpts;
{
QReadLocker lock(MTP::dcOptionsMutex());
dcOpts = Global::DcOptions();
}
_dcOpts = &dcOpts;
_readOldMtpDataFields(&file, version);
{
QWriteLocker lock(MTP::dcOptionsMutex());
Global::SetDcOptions(dcOpts);
}
_readOldMtpDataFields(&file, version, context);
file.close();
result = true;
}
@ -1739,10 +1732,14 @@ void _writeUserSettings() {
}
void _readUserSettings() {
ReadSettingsContext context;
FileReadDescriptor userSettings;
if (!readEncryptedFile(userSettings, _userSettingsKey)) {
LOG(("App Info: could not read encrypted user settings..."));
_readOldUserSettings();
_readOldUserSettings(true, context);
applyReadContext(context);
return _writeUserSettings();
}
@ -1756,13 +1753,15 @@ void _readUserSettings() {
return _writeUserSettings();
}
if (!_readSetting(blockId, userSettings.stream, userSettings.version)) {
if (!_readSetting(blockId, userSettings.stream, userSettings.version, context)) {
_readingUserSettings = false;
return _writeUserSettings();
}
}
_readingUserSettings = false;
LOG(("App Info: encrypted user settings read."));
applyReadContext(context);
}
void _writeMtpData() {
@ -1788,10 +1787,13 @@ void _writeMtpData() {
}
void _readMtpData() {
ReadSettingsContext context;
FileReadDescriptor mtp;
if (!readEncryptedFile(mtp, toFilePart(_dataNameKey), FileOption::Safe)) {
if (_localKey.created()) {
_readOldMtpData();
_readOldMtpData(true, context);
applyReadContext(context);
_writeMtpData();
}
return;
@ -1805,10 +1807,11 @@ void _readMtpData() {
return _writeMtpData();
}
if (!_readSetting(blockId, mtp.stream, mtp.version)) {
if (!_readSetting(blockId, mtp.stream, mtp.version, context)) {
return _writeMtpData();
}
}
applyReadContext(context);
}
ReadMapState _readMap(const QByteArray &pass) {
@ -2163,11 +2166,14 @@ void start() {
_basePath = cWorkingDir() + qsl("tdata/");
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
ReadSettingsContext context;
FileReadDescriptor settingsData;
if (!readFile(settingsData, cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe)) {
_readOldSettings();
_readOldUserSettings(false); // needed further in _readUserSettings
_readOldMtpData(false); // needed further in _readMtpData
_readOldSettings(true, context);
_readOldUserSettings(false, context); // needed further in _readUserSettings
_readOldMtpData(false, context); // needed further in _readMtpData
applyReadContext(context);
return writeSettings();
}
LOG(("App Info: reading settings..."));
@ -2189,12 +2195,7 @@ void start() {
LOG(("App Error: could not decrypt settings from settings file, maybe bad passcode..."));
return writeSettings();
}
MTP::DcOptions dcOpts;
{
QReadLocker lock(MTP::dcOptionsMutex());
dcOpts = Global::DcOptions();
}
_dcOpts = &dcOpts;
LOG(("App Info: reading encrypted settings..."));
while (!settings.stream.atEnd()) {
quint32 blockId;
@ -2203,36 +2204,17 @@ void start() {
return writeSettings();
}
if (!_readSetting(blockId, settings.stream, settingsData.version)) {
if (!_readSetting(blockId, settings.stream, settingsData.version, context)) {
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;
_settingsSalt = salt;
readTheme();
applyReadContext(context);
}
void writeSettings() {
@ -2251,37 +2233,10 @@ void writeSettings() {
}
settings.writeData(_settingsSalt);
MTP::DcOptions dcOpts;
{
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);
}
auto dcOptionsSerialized = AppClass::Instance().dcOptions()->serialize();
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
for (auto i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
size += sizeof(quint32) + Serialize::stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
}
size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized);
size += sizeof(quint32) + Serialize::stringSize(cLangFile());
size += sizeof(quint32) + sizeof(qint32);
@ -2308,11 +2263,7 @@ void writeSettings() {
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
data.stream << quint32(dbiScale) << qint32(cConfigScale());
data.stream << quint32(dbiLang) << qint32(cLang());
for (auto i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
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(dbiDcOptions) << dcOptionsSerialized;
data.stream << quint32(dbiLangFile) << cLangFile();
data.stream << quint32(dbiConnectionType) << qint32(Global::ConnectionType());

View file

@ -60,6 +60,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/themes/window_theme.h"
#include "window/player_wrap_widget.h"
#include "styles/style_boxes.h"
#include "mtproto/dc_options.h"
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
, _memento(std::move(memento)) {
@ -4907,7 +4908,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateDcOptions: {
auto &d = update.c_updateDcOptions();
MTP::updateDcOptions(d.vdc_options.c_vector().v);
AppClass::Instance().dcOptions()->addFromList(d.vdc_options);
} break;
case mtpc_updateUserPhone: {

View file

@ -32,6 +32,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang.h"
#include "mtproto/rsa_public_key.h"
#include "application.h"
#include "mtproto/dc_options.h"
#include "mtproto/connection_abstract.h"
using std::string;
@ -454,14 +457,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session
moveToThread(thread);
if (!dc) {
QReadLocker lock(dcOptionsMutex());
const auto &options(Global::DcOptions());
if (options.isEmpty()) {
LOG(("MTP Error: connect failed, no DCs"));
dc = 0;
return;
}
dc = options.cbegin().value().id;
dc = AppClass::Instance().dcOptions()->getDefaultDcId();
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!"));
return;
}
auto dcType = DcOptions::DcType::Regular;
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);
if (sessionData) {
if (!sessionData->getKey()) {
isDldDc = false;
}
}
}
int32 bareDc = bareDcId(dc);
static const int IPv4address = 0, IPv6address = 1;
static const int TcpProtocol = 0, HttpProtocol = 1;
MTPDdcOption::Flags flags[2][2] = { { 0 } };
string ip[2][2];
uint32 port[2][2] = { { 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;
}
}
}
if (!sessionData || sessionData->getKey()) {
dcType = DcOptions::DcType::MediaDownload;
}
}
bool noIPv4 = !port[IPv4address][HttpProtocol], noIPv6 = (!Global::TryIPv6() || !port[IPv6address][HttpProtocol]);
auto bareDc = bareDcId(dc);
using Variants = DcOptions::Variants;
auto kIPv4 = Variants::IPv4;
auto kIPv6 = Variants::IPv6;
auto kTcp = Variants::Tcp;
auto kHttp = Variants::Http;
auto variants = AppClass::Instance().dcOptions()->lookup(bareDcId(dc), dcType);
auto noIPv4 = (variants.data[kIPv4][kHttp].port == 0);
auto noIPv6 = (!Global::TryIPv6() || (variants.data[kIPv6][kHttp].port == 0));
if (noIPv4 && noIPv6) {
if (afterConfig) {
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;
_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 (!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 (!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(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);
if (auto conn = _conn4) {
connect(conn, SIGNAL(connected()), this, SLOT(onConnected4()));
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected4()));
conn->connectTcp(ip[IPv4address][TcpProtocol].c_str(), port[IPv4address][TcpProtocol], flags[IPv4address][TcpProtocol]);
conn->connectHttp(ip[IPv4address][HttpProtocol].c_str(), port[IPv4address][HttpProtocol], flags[IPv4address][HttpProtocol]);
conn->connectTcp(variants.data[kIPv4][kTcp]);
conn->connectHttp(variants.data[kIPv4][kHttp]);
}
if (auto conn = _conn6) {
connect(conn, SIGNAL(connected()), this, SLOT(onConnected6()));
connect(conn, SIGNAL(disconnected()), this, SLOT(onDisconnected6()));
conn->connectTcp(ip[IPv6address][TcpProtocol].c_str(), port[IPv6address][TcpProtocol], flags[IPv6address][TcpProtocol]);
conn->connectHttp(ip[IPv6address][HttpProtocol].c_str(), port[IPv6address][HttpProtocol], flags[IPv6address][HttpProtocol]);
conn->connectTcp(variants.data[kIPv6][kTcp]);
conn->connectHttp(variants.data[kIPv6][kHttp]);
}
}

View file

@ -22,12 +22,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mtproto/core_types.h"
#include "mtproto/auth_key.h"
#include "mtproto/connection_abstract.h"
#include "core/single_timer.h"
namespace MTP {
namespace internal {
class AbstractConnection;
class ConnectionPrivate;
class SessionData;

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once
#include "mtproto/core_types.h"
#include "mtproto/dc_options.h"
namespace MTP {
namespace internal {
@ -29,7 +30,6 @@ class AbstractConnection : public QObject {
Q_OBJECT
public:
AbstractConnection(QThread *thread) : _sentEncrypted(false) {
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 disconnectFromServer() = 0;
virtual void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
virtual void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
virtual void connectTcp(const DcOptions::Endpoint &endpoint) = 0;
virtual void connectHttp(const DcOptions::Endpoint &endpoint) = 0;
virtual bool isConnected() const = 0;
virtual bool usingHttpWait() {
return false;

View file

@ -162,24 +162,25 @@ void AutoConnection::disconnectFromServer() {
httpStartTimer.stop();
}
void AutoConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
_addrTcp = addr;
_portTcp = port;
_flagsTcp = flags;
void AutoConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
_addrTcp = QString::fromStdString(endpoint.ip);
_portTcp = endpoint.port;
_flagsTcp = endpoint.flags;
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
}
void AutoConnection::connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
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
void AutoConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
_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()));
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
_addrHttp = addr;
_portHttp = port;
_flagsHttp = flags;
mtpBuffer buffer(preparePQFake(httpNonce));
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));

View file

@ -35,8 +35,8 @@ public:
void sendData(mtpBuffer &buffer) override;
void disconnectFromServer() override;
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
void connectTcp(const DcOptions::Endpoint &endpoint) override;
void connectHttp(const DcOptions::Endpoint &endpoint) override;
bool isConnected() const override;
bool usingHttpWait() override;
bool needHttpWait() override;

View file

@ -136,16 +136,18 @@ void HTTPConnection::disconnectFromServer() {
address = QUrl();
}
void HTTPConnection::connectHttp(const QString &addr, int32 p, MTPDdcOption::Flags flags) {
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
void HTTPConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
_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()));
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
_flags = flags;
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);
}

View file

@ -34,9 +34,9 @@ public:
void sendData(mtpBuffer &buffer) 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 usingHttpWait() override;
bool needHttpWait() override;

View file

@ -339,10 +339,10 @@ void TCPConnection::disconnectFromServer() {
sock.close();
}
void TCPConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
_addr = addr;
_port = port;
_flags = flags;
void TCPConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
_addr = QString::fromStdString(endpoint.ip);
_port = endpoint.port;
_flags = endpoint.flags;
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
sock.connectToHost(QHostAddress(_addr), _port);

View file

@ -75,8 +75,8 @@ public:
void sendData(mtpBuffer &buffer) override;
void disconnectFromServer() override;
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override { // not supported
void connectTcp(const DcOptions::Endpoint &endpoint) override;
void connectHttp(const DcOptions::Endpoint &endpoint) override { // not supported
}
bool isConnected() const override;

View 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

View 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

View file

@ -19,25 +19,29 @@ 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/dcenter.h"
#include "mtproto/facade.h"
#include "mtproto/dc_options.h"
#include "application.h"
#include "localstorage.h"
namespace MTP {
namespace internal {
namespace {
DcenterMap gDCs;
bool configLoadedOnce = false;
bool mainDCChanged = false;
int32 _mainDC = 2;
int32 userId = 0;
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
_KeysMapForWrite _keysMapForWrite;
QMutex _keysMapForWriteMutex;
DcenterMap gDCs;
bool configLoadedOnce = false;
bool mainDCChanged = false;
int32 _mainDC = 2;
int32 userId = 0;
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
_KeysMapForWrite _keysMapForWrite;
QMutex _keysMapForWriteMutex;
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
} // namespace
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()));
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::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
@ -191,47 +199,7 @@ bool configFailed(const RPCError &error) {
};
void updateDcOptions(const QVector<MTPDcOption> &options) {
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) {
ConfigLoader::ConfigLoader() {
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
}
@ -241,7 +209,7 @@ void ConfigLoader::load() {
MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed));
_enumDCTimer.start(MTPEnumDCTimeout);
_enumDCTimer.start(kEnumerateDcTimeout);
}
void ConfigLoader::done() {
@ -267,23 +235,18 @@ void ConfigLoader::enumDC() {
} else {
MTP::killSession(MTP::cfgDcId(_enumCurrent));
}
OrderedSet<int32> dcs;
{
QReadLocker lock(dcOptionsMutex());
const auto &options(Global::DcOptions());
for (auto i = options.cbegin(), e = options.cend(); i != e; ++i) {
dcs.insert(MTP::bareDcId(i.key()));
}
}
auto i = dcs.constFind(_enumCurrent);
if (i == dcs.cend() || (++i) == dcs.cend()) {
_enumCurrent = *dcs.cbegin();
auto ids = AppClass::Instance().dcOptions()->sortedDcIds();
t_assert(!ids.empty());
auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
if (i == ids.cend() || (++i) == ids.cend()) {
_enumCurrent = ids.front();
} else {
_enumCurrent = *i;
}
_enumRequest = MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed), MTP::cfgDcId(_enumCurrent));
_enumDCTimer.start(MTPEnumDCTimeout);
_enumDCTimer.start(kEnumerateDcTimeout);
}
ConfigLoader *configLoader() {

View file

@ -81,8 +81,8 @@ signals:
private:
SingleTimer _enumDCTimer;
int32 _enumCurrent;
mtpRequestId _enumRequest;
DcId _enumCurrent = 0;
mtpRequestId _enumRequest = 0;
};
@ -101,8 +101,5 @@ void authed(int32 uid);
AuthKeysMap getAuthKeys();
void setAuthKey(int32 dc, AuthKeyPtr key);
void updateDcOptions(const QVector<MTPDcOption> &options);
QReadWriteLock *dcOptionsMutex();
} // namespace internal
} // namespace MTP

View file

@ -829,14 +829,13 @@ int32 state(mtpRequestId requestId) {
}
void finish() {
for (Sessions::iterator i = sessions.begin(), e = sessions.end(); i != e; ++i) {
i.value()->kill();
delete i.value();
}
sessions.clear();
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();
delete connection;
}
@ -886,11 +885,6 @@ void clearGlobalHandlers() {
setSessionResetHandler(0);
}
void updateDcOptions(const QVector<MTPDcOption> &options) {
internal::updateDcOptions(options);
Local::writeSettings();
}
AuthKeysMap getKeys() {
return internal::getAuthKeys();
}
@ -903,8 +897,4 @@ void setKey(int dc, const AuthKey::Data &key) {
return internal::setAuthKey(dc, std::move(keyPtr));
}
QReadWriteLock *dcOptionsMutex() {
return internal::dcOptionsMutex();
}
} // namespace MTP

View file

@ -217,24 +217,9 @@ void setStateChangedHandler(MTPStateChangedHandler handler);
void setSessionResetHandler(MTPSessionResetHandler handler);
void clearGlobalHandlers();
void updateDcOptions(const QVector<MTPDcOption> &options);
AuthKeysMap getKeys();
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 {
template <typename TRequest>

View file

@ -337,6 +337,8 @@
'<(src_loc)/mtproto/core_types.h',
'<(src_loc)/mtproto/dcenter.cpp',
'<(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.h',
'<(src_loc)/mtproto/rsa_public_key.cpp',