Ability to delete authorization keys added.

If we start logging in and we know, that some of the authorization
keys were read from the hard drive, not generated, we destroy all
the existing authorization keys and start generating new keys.
This commit is contained in:
John Preston 2017-02-25 19:44:02 +03:00
parent dd933cf61c
commit 7d89b54d1c
38 changed files with 714 additions and 432 deletions

View File

@ -922,7 +922,7 @@ float64 StickersBox::Inner::aboveShadowOpacity() const {
}
void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = base::take(_pressed, -1);
auto pressed = std::exchange(_pressed, -1);
if (_section != Section::Installed && _selected < 0 && pressed >= 0) {
setCursor(style::cur_default);

View File

@ -772,7 +772,7 @@ void palette::finalize() {\n\
auto result = module_.enumVariables([this, &indexInPalette, &checksumString, &dataRows, &names](const Variable &variable) -> bool {
auto name = variable.name.back();
auto index = indexInPalette++;
paletteIndices_.insert(std::make_pair(name, index));
paletteIndices_.emplace(name, index);
if (variable.value.type().tag != structure::TypeTag::Color) {
return false;
}

View File

@ -33,9 +33,8 @@ inline constexpr size_t array_size(const T(&)[N]) {
}
template <typename T>
inline T take(T &source, T &&new_value = T()) {
std::swap(new_value, source);
return std::move(new_value);
inline T take(T &source) {
return std::exchange(source, T());
}
namespace internal {

View File

@ -103,7 +103,7 @@ void FileUploader::currentFailed() {
void FileUploader::killSessions() {
for (int i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::stopSession(MTP::uplDcId(i));
MTP::stopSession(MTP::uploadDcId(i));
}
}
@ -187,9 +187,9 @@ void FileUploader::sendNext() {
}
mtpRequestId requestId;
if (i->docSize > UseBigFilesFrom) {
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
requestId = MTP::send(MTPupload_SaveBigFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_int(i->docPartsCount), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uploadDcId(todc));
} else {
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->id()), MTP_int(i->docSentParts), MTP_bytes(toSend)), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uploadDcId(todc));
}
docRequestsSent.insert(requestId, i->docSentParts);
dcMap.insert(requestId, todc);
@ -200,7 +200,7 @@ void FileUploader::sendNext() {
} else {
UploadFileParts::iterator part = parts.begin();
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_bytes(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uplDcId(todc));
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_bytes(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::uploadDcId(todc));
requestsSent.insert(requestId, part.value());
dcMap.insert(requestId, todc);
sentSize += part.value().size();
@ -246,7 +246,7 @@ void FileUploader::clear() {
dcMap.clear();
sentSize = 0;
for (int32 i = 0; i < MTPUploadSessionsCount; ++i) {
MTP::stopSession(MTP::uplDcId(i));
MTP::stopSession(MTP::uploadDcId(i));
sentSizes[i] = 0;
}
killSessionsTimer.stop();

View File

@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/effects/widget_fade_wrap.h"
#include "core/click_handler_types.h"
#include "boxes/confirmbox.h"
#include "messenger.h"
namespace Intro {
@ -57,6 +58,8 @@ PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat
_country->onChooseCountry(qsl("US"));
}
_changed = false;
Messenger::Instance().destroyStaleAuthorizationKeys();
}
void PhoneWidget::resizeEvent(QResizeEvent *e) {

View File

@ -265,7 +265,7 @@ bool Widget::resetFail(const RPCError &error) {
void Widget::gotNearestDC(const MTPNearestDc &result) {
auto &nearest = result.c_nearestDc();
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
Messenger::Instance().mtp()->suggestMainDcId(nearest.vnearest_dc.v);
Messenger::Instance().suggestMainDcId(nearest.vnearest_dc.v);
auto nearestCountry = qs(nearest.vcountry);
if (getData()->country != nearestCountry) {
getData()->country = nearestCountry;

View File

@ -139,11 +139,16 @@ bool _checkStreamStatus(QDataStream &stream) {
QByteArray _settingsSalt, _passKeySalt, _passKeyEncrypted;
constexpr auto kLocalKeySize = MTP::AuthKey::kSize;
MTP::AuthKey _oldKey, _settingsKey, _passKey, _localKey;
void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKey *result) {
MTP::AuthKey::Data key = { 0 };
int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
QByteArray newSalt;
auto OldKey = MTP::AuthKeyPtr();
auto SettingsKey = MTP::AuthKeyPtr();
auto PassKey = MTP::AuthKeyPtr();
auto LocalKey = MTP::AuthKeyPtr();
void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKeyPtr *result) {
auto key = MTP::AuthKey::Data { 0 };
auto iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
auto newSalt = QByteArray();
if (!salt) {
newSalt.resize(LocalEncryptSaltSize);
memset_rand(newSalt.data(), newSalt.size());
@ -154,7 +159,7 @@ void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKey *resu
PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, key.size(), (uchar*)key.data());
result->setKey(key);
*result = std::make_shared<MTP::AuthKey>(key);
}
struct FileReadDescriptor {
@ -261,7 +266,7 @@ struct FileWriteDescriptor {
return true;
}
static QByteArray prepareEncrypted(EncryptedDescriptor &data, const MTP::AuthKey &key = _localKey) {
static QByteArray prepareEncrypted(EncryptedDescriptor &data, const MTP::AuthKeyPtr &key = LocalKey) {
data.finish();
QByteArray &toEncrypt(data.data);
@ -275,11 +280,11 @@ struct FileWriteDescriptor {
*(uint32*)toEncrypt.data() = size;
QByteArray encrypted(0x10 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
MTP::aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 0x10, fullSize, &key, encrypted.constData());
MTP::aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 0x10, fullSize, key, encrypted.constData());
return encrypted;
}
bool writeEncrypted(EncryptedDescriptor &data, const MTP::AuthKey &key = _localKey) {
bool writeEncrypted(EncryptedDescriptor &data, const MTP::AuthKeyPtr &key = LocalKey) {
return writeData(prepareEncrypted(data, key));
}
void finish() {
@ -408,7 +413,7 @@ bool readFile(FileReadDescriptor &result, const QString &name, FileOptions optio
return false;
}
bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, const MTP::AuthKey &key = _localKey) {
bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, const MTP::AuthKeyPtr &key = LocalKey) {
if (encrypted.size() <= 16 || (encrypted.size() & 0x0F)) {
LOG(("App Error: bad encrypted part size: %1").arg(encrypted.size()));
return false;
@ -418,7 +423,7 @@ bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, cons
QByteArray decrypted;
decrypted.resize(fullLen);
const char *encryptedKey = encrypted.constData(), *encryptedData = encrypted.constData() + 16;
aesDecryptLocal(encryptedData, decrypted.data(), fullLen, &key, encryptedKey);
aesDecryptLocal(encryptedData, decrypted.data(), fullLen, key, encryptedKey);
uchar sha1Buffer[20];
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), encryptedKey, 16)) {
LOG(("App Info: bad decrypt key, data not decrypted - incorrect password?"));
@ -444,7 +449,7 @@ bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, cons
return true;
}
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKey &key = _localKey) {
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKeyPtr &key = LocalKey) {
if (!readFile(result, name, options)) {
return false;
}
@ -474,7 +479,7 @@ bool readEncryptedFile(FileReadDescriptor &result, const QString &name, FileOpti
return true;
}
bool readEncryptedFile(FileReadDescriptor &result, const FileKey &fkey, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKey &key = _localKey) {
bool readEncryptedFile(FileReadDescriptor &result, const FileKey &fkey, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKeyPtr &key = LocalKey) {
return readEncryptedFile(result, toFilePart(fkey), options, key);
}
@ -1536,7 +1541,7 @@ void _readOldUserSettingsFields(QIODevice *device, qint32 &version, ReadSettings
continue;
}
createLocalKey(QByteArray(), &salt, &_oldKey);
createLocalKey(QByteArray(), &salt, &OldKey);
if (data.size() <= 16 || (data.size() & 0x0F)) {
LOG(("App Error: bad encrypted part size in old user config: %1").arg(data.size()));
@ -1545,7 +1550,7 @@ void _readOldUserSettingsFields(QIODevice *device, qint32 &version, ReadSettings
uint32 fullDataLen = data.size() - 16;
decrypted.resize(fullDataLen);
const char *dataKey = data.constData(), *encrypted = data.constData() + 16;
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &_oldKey, dataKey);
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, OldKey, dataKey);
uchar sha1Buffer[20];
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) {
LOG(("App Error: bad decrypt key, data from old user config not decrypted"));
@ -1608,7 +1613,7 @@ void _readOldMtpDataFields(QIODevice *device, qint32 &version, ReadSettingsConte
break;
}
if (!_oldKey.created()) {
if (!OldKey) {
LOG(("MTP Error: reading old encrypted keys without old key!"));
continue;
}
@ -1620,7 +1625,7 @@ void _readOldMtpDataFields(QIODevice *device, qint32 &version, ReadSettingsConte
uint32 fullDataLen = data.size() - 16;
decrypted.resize(fullDataLen);
const char *dataKey = data.constData(), *encrypted = data.constData() + 16;
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, &_oldKey, dataKey);
aesDecryptLocal(encrypted, decrypted.data(), fullDataLen, OldKey, dataKey);
uchar sha1Buffer[20];
if (memcmp(hashSha1(decrypted.constData(), decrypted.size(), sha1Buffer), dataKey, 16)) {
LOG(("MTP Error: bad decrypt key, data from old keys not decrypted"));
@ -1780,7 +1785,7 @@ void _readUserSettings() {
void _writeMtpData() {
FileWriteDescriptor mtp(toFilePart(_dataNameKey), FileOption::Safe);
if (!_localKey.created()) {
if (!LocalKey) {
LOG(("App Error: localkey not created in _writeMtpData()"));
return;
}
@ -1798,7 +1803,7 @@ void _readMtpData() {
ReadSettingsContext context;
FileReadDescriptor mtp;
if (!readEncryptedFile(mtp, toFilePart(_dataNameKey), FileOption::Safe)) {
if (_localKey.created()) {
if (LocalKey) {
_readOldMtpData(true, context);
applyReadContext(context);
@ -1846,10 +1851,10 @@ ReadMapState _readMap(const QByteArray &pass) {
LOG(("App Error: bad salt in map file, size: %1").arg(salt.size()));
return ReadMapFailed;
}
createLocalKey(pass, &salt, &_passKey);
createLocalKey(pass, &salt, &PassKey);
EncryptedDescriptor keyData, map;
if (!decryptLocal(keyData, keyEncrypted, _passKey)) {
if (!decryptLocal(keyData, keyEncrypted, PassKey)) {
LOG(("App Info: could not decrypt pass-protected key from map file, maybe bad password..."));
return ReadMapPassNeeded;
}
@ -1858,7 +1863,7 @@ ReadMapState _readMap(const QByteArray &pass) {
LOG(("App Error: could not read pass-protected key from map file"));
return ReadMapFailed;
}
_localKey.setKey(key);
LocalKey = std::make_shared<MTP::AuthKey>(key);
_passKeyEncrypted = keyEncrypted;
_passKeySalt = salt;
@ -2053,15 +2058,15 @@ void _writeMap(WriteMapWhen when) {
QByteArray pass(kLocalKeySize, Qt::Uninitialized), salt(LocalEncryptSaltSize, Qt::Uninitialized);
memset_rand(pass.data(), pass.size());
memset_rand(salt.data(), salt.size());
createLocalKey(pass, &salt, &_localKey);
createLocalKey(pass, &salt, &LocalKey);
_passKeySalt.resize(LocalEncryptSaltSize);
memset_rand(_passKeySalt.data(), _passKeySalt.size());
createLocalKey(QByteArray(), &_passKeySalt, &_passKey);
createLocalKey(QByteArray(), &_passKeySalt, &PassKey);
EncryptedDescriptor passKeyData(kLocalKeySize);
_localKey.write(passKeyData.stream);
_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, _passKey);
LocalKey->write(passKeyData.stream);
_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, PassKey);
}
map.writeData(_passKeySalt);
map.writeData(_passKeyEncrypted);
@ -2196,10 +2201,10 @@ void start() {
LOG(("App Error: bad salt in settings file, size: %1").arg(salt.size()));
return writeSettings();
}
createLocalKey(QByteArray(), &salt, &_settingsKey);
createLocalKey(QByteArray(), &salt, &SettingsKey);
EncryptedDescriptor settings;
if (!decryptLocal(settings, settingsEncrypted, _settingsKey)) {
if (!decryptLocal(settings, settingsEncrypted, SettingsKey)) {
LOG(("App Error: could not decrypt settings from settings file, maybe bad passcode..."));
return writeSettings();
}
@ -2234,10 +2239,10 @@ void writeSettings() {
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
FileWriteDescriptor settings(cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe);
if (_settingsSalt.isEmpty() || !_settingsKey.created()) {
if (_settingsSalt.isEmpty() || !SettingsKey) {
_settingsSalt.resize(LocalEncryptSaltSize);
memset_rand(_settingsSalt.data(), _settingsSalt.size());
createLocalKey(QByteArray(), &_settingsSalt, &_settingsKey);
createLocalKey(QByteArray(), &_settingsSalt, &SettingsKey);
}
settings.writeData(_settingsSalt);
@ -2287,7 +2292,7 @@ void writeSettings() {
TWindowPos pos(cWindowPos());
data.stream << quint32(dbiWindowPosition) << qint32(pos.x) << qint32(pos.y) << qint32(pos.w) << qint32(pos.h) << qint32(pos.moncrc) << qint32(pos.maximized);
settings.writeEncrypted(data, _settingsKey);
settings.writeEncrypted(data, SettingsKey);
}
void writeUserSettings() {
@ -2329,17 +2334,17 @@ void reset() {
}
bool checkPasscode(const QByteArray &passcode) {
auto checkKey = MTP::AuthKey();
auto checkKey = MTP::AuthKeyPtr();
createLocalKey(passcode, &_passKeySalt, &checkKey);
return (checkKey == _passKey);
return checkKey->equals(PassKey);
}
void setPasscode(const QByteArray &passcode) {
createLocalKey(passcode, &_passKeySalt, &_passKey);
createLocalKey(passcode, &_passKeySalt, &PassKey);
EncryptedDescriptor passKeyData(kLocalKeySize);
_localKey.write(passKeyData.stream);
_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, _passKey);
LocalKey->write(passKeyData.stream);
_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, PassKey);
_mapChanged = true;
_writeMap(WriteMapNow);
@ -3639,7 +3644,7 @@ void readSavedGifs() {
void writeBackground(int32 id, const QImage &img) {
if (!_working() || !_backgroundCanWrite) return;
if (!_localKey.created()) {
if (!LocalKey) {
LOG(("App Error: localkey not created in writeBackground()"));
return;
}
@ -3716,7 +3721,7 @@ bool readBackground() {
bool readThemeUsingKey(FileKey key) {
FileReadDescriptor theme;
if (!readEncryptedFile(theme, key, FileOption::Safe, _settingsKey)) {
if (!readEncryptedFile(theme, key, FileOption::Safe, SettingsKey)) {
return false;
}
@ -3787,7 +3792,7 @@ void writeTheme(const QString &pathRelative, const QString &pathAbsolute, const
data.stream << cache.paletteChecksum << cache.contentChecksum << cache.colors << cache.background << backgroundTiled;
FileWriteDescriptor file(_themeKey, FileOption::Safe);
file.writeEncrypted(data, _settingsKey);
file.writeEncrypted(data, SettingsKey);
}
void clearTheme() {
@ -3814,7 +3819,7 @@ bool copyThemeColorsToPalette(const QString &path) {
}
FileReadDescriptor theme;
if (!readEncryptedFile(theme, _themeKey, FileOption::Safe, _settingsKey)) {
if (!readEncryptedFile(theme, _themeKey, FileOption::Safe, SettingsKey)) {
return false;
}
@ -4269,18 +4274,18 @@ bool isBotTrusted(UserData *bot) {
}
bool encrypt(const void *src, void *dst, uint32 len, const void *key128) {
if (!_localKey.created()) {
if (!LocalKey) {
return false;
}
MTP::aesEncryptLocal(src, dst, len, &_localKey, key128);
MTP::aesEncryptLocal(src, dst, len, LocalKey, key128);
return true;
}
bool decrypt(const void *src, void *dst, uint32 len, const void *key128) {
if (!_localKey.created()) {
if (!LocalKey) {
return false;
}
MTP::aesDecryptLocal(src, dst, len, &_localKey, key128);
MTP::aesDecryptLocal(src, dst, len, LocalKey, key128);
return true;
}

View File

@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "history/history_location_manager.h"
#include "ui/widgets/tooltip.h"
#include "ui/filedialog.h"
#include "serialize/serialize_common.h"
namespace {
@ -52,10 +53,12 @@ Messenger *Messenger::InstancePointer() {
struct Messenger::Private {
MTP::Instance::Config mtpConfig;
MTP::AuthKeysList mtpKeysToDestroy;
};
Messenger::Messenger() : QObject()
, _private(std::make_unique<Private>()) {
, _private(std::make_unique<Private>())
, _delayedLoadersDestroyer(this, "onDelayedDestroyLoaders") {
t_assert(SingleInstance == nullptr);
SingleInstance = this;
@ -166,14 +169,25 @@ void Messenger::setMtpMainDcId(MTP::DcId mainDcId) {
void Messenger::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) {
t_assert(!_mtproto);
_private->mtpConfig.keys.insert(std::make_pair(dcId, keyData));
_private->mtpConfig.keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
QByteArray Messenger::serializeMtpAuthorization() const {
auto serialize = [this](auto keysCount, auto mainDcId, auto writeKeys) {
auto serialize = [this](auto mainDcId, auto &keys, auto &keysToDestroy) {
auto keysSize = [](auto &list) {
return sizeof(qint32) + list.size() * (sizeof(qint32) + MTP::AuthKey::Data().size());
};
auto writeKeys = [](QDataStream &stream, auto &keys) {
stream << qint32(keys.size());
for (auto &key : keys) {
stream << qint32(key->dcId());
key->write(stream);
}
};
auto result = QByteArray();
auto size = sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // userId + mainDcId + keys count
size += keysCount * (sizeof(qint32) + MTP::AuthKey::Data().size());
auto size = sizeof(qint32) + sizeof(qint32); // userId + mainDcId
size += keysSize(keys) + keysSize(keysToDestroy);
result.reserve(size);
{
QBuffer buffer(&result);
@ -184,27 +198,20 @@ QByteArray Messenger::serializeMtpAuthorization() const {
QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_1);
stream << qint32(AuthSession::CurrentUserId()) << qint32(mainDcId) << qint32(keysCount);
writeKeys(stream);
stream << qint32(AuthSession::CurrentUserId()) << qint32(mainDcId);
writeKeys(stream, keys);
writeKeys(stream, keysToDestroy);
}
return result;
};
if (_mtproto) {
auto keys = _mtproto->getKeysForWrite();
return serialize(keys.size(), _mtproto->mainDcId(), [&keys](QDataStream &stream) {
for (auto &key : keys) {
stream << qint32(key->getDC());
key->write(stream);
}
});
auto keysToDestroy = _mtprotoForKeysDestroy ? _mtprotoForKeysDestroy->getKeysForWrite() : MTP::AuthKeysList();
return serialize(_mtproto->mainDcId(), keys, keysToDestroy);
}
auto &keys = _private->mtpConfig.keys;
return serialize(keys.size(), _private->mtpConfig.mainDcId, [&keys](QDataStream &stream) {
for (auto &key : keys) {
stream << qint32(key.first);
stream.writeRawData(key.second.data(), key.second.size());
}
});
auto &keysToDestroy = _private->mtpKeysToDestroy;
return serialize(_private->mtpConfig.mainDcId, keys, keysToDestroy);
}
void Messenger::setMtpAuthorization(const QByteArray &serialized) {
@ -220,8 +227,8 @@ void Messenger::setMtpAuthorization(const QByteArray &serialized) {
QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_1);
qint32 userId = 0, mainDcId = 0, count = 0;
stream >> userId >> mainDcId >> count;
auto userId = Serialize::read<qint32>(stream);
auto mainDcId = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read main fields from serialized mtp authorization."));
return;
@ -231,22 +238,33 @@ void Messenger::setMtpAuthorization(const QByteArray &serialized) {
authSessionCreate(userId);
}
_private->mtpConfig.mainDcId = mainDcId;
for (auto i = 0; i != count; ++i) {
qint32 dcId = 0;
MTP::AuthKey::Data keyData;
stream >> dcId;
stream.readRawData(keyData.data(), keyData.size());
auto readKeys = [&stream](auto &keys) {
auto count = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read key from serialized mtp authorization."));
LOG(("MTP Error: could not read keys count from serialized mtp authorization."));
return;
}
_private->mtpConfig.keys.insert(std::make_pair(dcId, keyData));
}
keys.reserve(count);
for (auto i = 0; i != count; ++i) {
auto dcId = Serialize::read<qint32>(stream);
auto keyData = Serialize::read<MTP::AuthKey::Data>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read key from serialized mtp authorization."));
return;
}
keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
};
readKeys(_private->mtpConfig.keys);
readKeys(_private->mtpKeysToDestroy);
LOG(("MTP Info: read keys, current: %1, to destroy: %2").arg(_private->mtpConfig.keys.size()).arg(_private->mtpKeysToDestroy.size()));
}
void Messenger::startMtp() {
t_assert(!_mtproto);
_mtproto = std::make_unique<MTP::Instance>(_dcOptions.get(), std::move(_private->mtpConfig));
_mtproto = std::make_unique<MTP::Instance>(_dcOptions.get(), MTP::Instance::Mode::Normal, base::take(_private->mtpConfig));
_private->mtpConfig.mainDcId = _mtproto->mainDcId();
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId shiftedDcId, int32 state) {
if (App::wnd()) {
@ -258,6 +276,57 @@ void Messenger::startMtp() {
App::main()->getDifference();
}
});
if (!_private->mtpKeysToDestroy.empty()) {
destroyMtpKeys(base::take(_private->mtpKeysToDestroy));
}
}
void Messenger::destroyMtpKeys(MTP::AuthKeysList &&keys) {
if (keys.empty()) {
return;
}
if (_mtprotoForKeysDestroy) {
_mtprotoForKeysDestroy->addKeysForDestroy(std::move(keys));
Local::writeMtpData();
return;
}
auto destroyConfig = MTP::Instance::Config();
destroyConfig.mainDcId = MTP::Instance::Config::kNoneMainDc;
destroyConfig.keys = std::move(keys);
_mtprotoForKeysDestroy = std::make_unique<MTP::Instance>(_dcOptions.get(), MTP::Instance::Mode::KeysDestroyer, std::move(destroyConfig));
connect(_mtprotoForKeysDestroy.get(), SIGNAL(allKeysDestroyed()), this, SLOT(onAllKeysDestroyed()));
}
void Messenger::onAllKeysDestroyed() {
LOG(("MTP Info: all keys scheduled for destroy are destroyed."));
_mtprotoForKeysDestroy.reset();
Local::writeMtpData();
}
void Messenger::suggestMainDcId(MTP::DcId mainDcId) {
t_assert(_mtproto != nullptr);
_mtproto->suggestMainDcId(mainDcId);
if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
_private->mtpConfig.mainDcId = mainDcId;
}
}
void Messenger::destroyStaleAuthorizationKeys() {
t_assert(_mtproto != nullptr);
auto keys = _mtproto->getKeysForWrite();
for (auto &key : keys) {
if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
_private->mtpKeysToDestroy = _mtproto->getKeysForWrite();
_mtproto.reset();
LOG(("MTP Info: destroying stale keys, count: %1").arg(_private->mtpKeysToDestroy.size()));
startMtp();
Local::writeMtpData();
return;
}
}
}
void Messenger::loadLanguage() {
@ -449,7 +518,7 @@ void Messenger::killDownloadSessions() {
for (auto i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) {
if (i.value() <= ms) {
for (int j = 0; j < MTPDownloadSessionsCount; ++j) {
MTP::stopSession(MTP::dldDcId(i.key(), j));
MTP::stopSession(MTP::downloadDcId(i.key(), j));
}
i = killDownloadSessionTimes.erase(i);
} else {
@ -593,7 +662,13 @@ void Messenger::checkMapVersion() {
void Messenger::prepareToDestroy() {
_window.reset();
// Some MTP requests can be cancelled from data clearing.
App::clearHistories();
_delayedDestroyedLoaders.clear();
_mtproto.reset();
_mtprotoForKeysDestroy.reset();
}
Messenger::~Messenger() {
@ -602,8 +677,6 @@ Messenger::~Messenger() {
Shortcuts::finish();
App::clearHistories();
Window::Notifications::finish();
anim::stopManager();
@ -628,3 +701,12 @@ Messenger::~Messenger() {
MainWindow *Messenger::mainWindow() {
return _window.get();
}
void Messenger::delayedDestroyLoader(std::unique_ptr<FileLoader> loader) {
_delayedDestroyedLoaders.push_back(std::move(loader));
_delayedLoadersDestroyer.call();
}
void Messenger::onDelayedDestroyLoaders() {
_delayedDestroyedLoaders.clear();
}

View File

@ -65,6 +65,8 @@ public:
MTP::Instance *mtp() {
return _mtproto.get();
}
void suggestMainDcId(MTP::DcId mainDcId);
void destroyStaleAuthorizationKeys();
AuthSession *authSession() {
return _authSession.get();
@ -96,11 +98,17 @@ public:
void handleAppActivated();
void handleAppDeactivated();
// Temporary here, when all Images and Documents are owned by AuthSession it'll have this.
void delayedDestroyLoader(std::unique_ptr<FileLoader> loader);
signals:
void peerPhotoDone(PeerId peer);
void peerPhotoFail(PeerId peer);
public slots:
void onAllKeysDestroyed();
void onDelayedDestroyLoaders();
void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void onSwitchDebugMode();
@ -117,6 +125,7 @@ public slots:
void call_handleObservables();
private:
void destroyMtpKeys(MTP::AuthKeysList &&keys);
void startLocalStorage();
void loadLanguage();
@ -135,6 +144,10 @@ private:
std::unique_ptr<MTP::DcOptions> _dcOptions;
std::unique_ptr<MTP::Instance> _mtproto;
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
std::unique_ptr<AuthSession> _authSession;
SingleDelayedCall _delayedLoadersDestroyer;
std::vector<std::unique_ptr<FileLoader>> _delayedDestroyedLoaders;
};

View File

@ -29,37 +29,36 @@ class AuthKey {
public:
static constexpr auto kSize = 256; // 2048 bits.
using Data = std::array<char, kSize>;
using KeyId = uint64;
bool created() const {
return _isset;
enum class Type {
Generated,
ReadFromFile,
Local,
};
AuthKey(Type type, DcId dcId, const Data &data) : _type(type), _dcId(dcId), _key(data) {
countKeyId();
}
AuthKey(const Data &data) : _type(Type::Local), _key(data) {
countKeyId();
}
void setKey(const Data &from) {
_key = from;
auto sha1 = hashSha1(_key.data(), _key.size());
AuthKey(const AuthKey &other) = delete;
AuthKey &operator=(const AuthKey &other) = delete;
// Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
_keyId = *reinterpret_cast<uint64*>(sha1.data() + 12);
_isset = true;
Type type() const {
return _type;
}
void setDC(int dc) {
_dc = dc;
int dcId() const {
return _dcId;
}
int getDC() const {
t_assert(_isset);
return _dc;
}
uint64 keyId() const {
t_assert(_isset);
KeyId keyId() const {
return _keyId;
}
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) const {
t_assert(_isset);
uint32 x = send ? 0 : 8;
uchar data_a[16 + 32], sha1_a[20];
@ -95,28 +94,30 @@ public:
}
void write(QDataStream &to) const {
t_assert(_isset);
to.writeRawData(_key.data(), _key.size());
}
static const uint64 RecreateKeyId = 0xFFFFFFFFFFFFFFFFL;
friend bool operator==(const AuthKey &a, const AuthKey &b);
bool equals(const std::shared_ptr<AuthKey> &other) const {
return other ? (_key == other->_key) : false;
}
private:
void countKeyId() {
auto sha1 = hashSha1(_key.data(), _key.size());
// Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
_keyId = *reinterpret_cast<KeyId*>(sha1.data() + 12);
}
Type _type = Type::Generated;
DcId _dcId = 0;
Data _key = { 0 };
uint64 _keyId = 0;
bool _isset = false;
int _dc = 0;
KeyId _keyId = 0;
};
inline bool operator==(const AuthKey &a, const AuthKey &b) {
return (a._key == b._key);
}
using AuthKeyPtr = std::shared_ptr<AuthKey>;
using AuthKeysMap = QVector<AuthKeyPtr>;
using AuthKeysList = std::vector<AuthKeyPtr>;
void aesIgeEncrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
void aesIgeDecrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
@ -128,7 +129,7 @@ inline void aesIgeEncrypt(const void *src, void *dst, uint32 len, const AuthKeyP
return aesIgeEncrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
}
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, const AuthKey *authKey, const void *key128) {
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, const AuthKeyPtr &authKey, const void *key128) {
MTPint256 aesKey, aesIV;
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
@ -142,7 +143,7 @@ inline void aesIgeDecrypt(const void *src, void *dst, uint32 len, const AuthKeyP
return aesIgeDecrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
}
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, const AuthKey *authKey, const void *key128) {
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, const AuthKeyPtr &authKey, const void *key128) {
MTPint256 aesKey, aesIV;
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);

View File

@ -42,6 +42,8 @@ namespace MTP {
namespace internal {
namespace {
constexpr auto kRecreateKeyId = AuthKey::KeyId(0xFFFFFFFFFFFFFFFFULL);
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0) {
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
@ -346,22 +348,14 @@ RSAPublicKeys InitRSAPublicKeys() {
Connection::Connection(Instance *instance) : _instance(instance) {
}
int32 Connection::prepare(SessionData *sessionData, int32 dc) {
void Connection::start(SessionData *sessionData, ShiftedDcId shiftedDcId) {
t_assert(thread == nullptr && data == nullptr);
thread = std::make_unique<Thread>();
auto newData = std::make_unique<ConnectionPrivate>(_instance, thread.get(), this, sessionData, dc);
dc = newData->getDC();
if (dc) {
// will be deleted in the thread::finished signal
data = newData.release();
} else {
thread.reset();
}
return dc;
}
auto newData = std::make_unique<ConnectionPrivate>(_instance, thread.get(), this, sessionData, shiftedDcId);
void Connection::start() {
// will be deleted in the thread::finished signal
data = newData.release();
thread->start();
}
@ -404,13 +398,13 @@ void ConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
if (createIPv4) {
QWriteLocker lock(&stateConnMutex);
_conn4 = AbstractConnection::create(thread());
connect(_conn4, SIGNAL(error(bool)), this, SLOT(onError4(bool)));
connect(_conn4, SIGNAL(error(qint32)), this, SLOT(onError4(qint32)));
connect(_conn4, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
}
if (createIPv6) {
QWriteLocker lock(&stateConnMutex);
_conn6 = AbstractConnection::create(thread());
connect(_conn6, SIGNAL(error(bool)), this, SLOT(onError6(bool)));
connect(_conn6, SIGNAL(error(qint32)), this, SLOT(onError6(qint32)));
connect(_conn6, SIGNAL(receivedSome()), this, SLOT(onReceivedSome()));
}
firstSentAt = 0;
@ -431,7 +425,7 @@ void ConnectionPrivate::destroyConn(AbstractConnection **conn) {
toDisconnect = *conn;
disconnect(*conn, SIGNAL(connected()), nullptr, nullptr);
disconnect(*conn, SIGNAL(disconnected()), nullptr, nullptr);
disconnect(*conn, SIGNAL(error(bool)), nullptr, nullptr);
disconnect(*conn, SIGNAL(error(qint32)), nullptr, nullptr);
disconnect(*conn, SIGNAL(receivedData()), nullptr, nullptr);
disconnect(*conn, SIGNAL(receivedSome()), nullptr, nullptr);
*conn = nullptr;
@ -448,10 +442,10 @@ void ConnectionPrivate::destroyConn(AbstractConnection **conn) {
}
}
ConnectionPrivate::ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, uint32 _dc) : QObject()
ConnectionPrivate::ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, ShiftedDcId shiftedDcId) : QObject()
, _instance(instance)
, _state(DisconnectedState)
, dc(_dc)
, _shiftedDcId(shiftedDcId)
, _owner(owner)
, _waitForReceived(MTPMinReceiveDelay)
, _waitForConnected(MTPMinConnectDelay)
@ -465,10 +459,7 @@ ConnectionPrivate::ConnectionPrivate(Instance *instance, QThread *thread, Connec
retryTimer.moveToThread(thread);
moveToThread(thread);
if (!dc) {
dc = Messenger::Instance().dcOptions()->getDefaultDcId();
DEBUG_LOG(("MTP Info: searching for any DC, %1 selected...").arg(dc));
}
t_assert(_shiftedDcId != 0);
connect(thread, SIGNAL(started()), this, SLOT(socketStart()));
connect(thread, SIGNAL(finished()), this, SLOT(doFinish()));
@ -509,8 +500,8 @@ void ConnectionPrivate::onConfigLoaded() {
socketStart(true);
}
int32 ConnectionPrivate::getDC() const {
return dc;
int32 ConnectionPrivate::getShiftedDcId() const {
return _shiftedDcId;
}
int32 ConnectionPrivate::getState() const {
@ -586,7 +577,7 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno
newId = m;
}
MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
MTP_LOG(_shiftedDcId, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
replaces.insert(id, newId);
id = newId;
*(mtpMsgId*)(i.value()->data() + 4) = id;
@ -613,7 +604,7 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno
newId = m;
}
MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
MTP_LOG(_shiftedDcId, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
replaces.insert(id, newId);
id = newId;
*(mtpMsgId*)(j.value()->data() + 4) = id;
@ -777,13 +768,13 @@ void ConnectionPrivate::tryToSend() {
int32 state = getState();
bool prependOnly = (state != ConnectedState);
mtpRequest pingRequest;
if (dc == bareDcId(dc)) { // main session
if (_shiftedDcId == bareDcId(_shiftedDcId)) { // main session
if (!prependOnly && !_pingIdToSend && !_pingId && _pingSendAt <= getms(true)) {
_pingIdToSend = rand_value<mtpPingId>();
}
}
if (_pingIdToSend) {
if (prependOnly || dc != bareDcId(dc)) {
if (prependOnly || _shiftedDcId != bareDcId(_shiftedDcId)) {
MTPPing ping(MTPping(MTP_long(_pingIdToSend)));
uint32 pingSize = ping.innerLength() >> 2; // copy from Session::send
pingRequest = mtpRequestData::prepare(pingSize);
@ -801,7 +792,7 @@ void ConnectionPrivate::tryToSend() {
_pingSendAt = pingRequest->msDate + (MTPPingSendAfterAuto * 1000LL);
pingRequest->requestId = 0; // dont add to haveSent / wereAcked maps
if (dc == bareDcId(dc) && !prependOnly) { // main session
if (_shiftedDcId == bareDcId(_shiftedDcId) && !prependOnly) { // main session
_pingSender.start(MTPPingSendAfter * 1000);
}
@ -809,10 +800,10 @@ void ConnectionPrivate::tryToSend() {
_pingIdToSend = 0;
} else {
if (prependOnly) {
DEBUG_LOG(("MTP Info: dc %1 not sending, waiting for Connected state, state: %2").arg(dc).arg(state));
DEBUG_LOG(("MTP Info: dc %1 not sending, waiting for Connected state, state: %2").arg(_shiftedDcId).arg(state));
return; // just do nothing, if is not connected yet
} else {
DEBUG_LOG(("MTP Info: dc %1 trying to send after ping, state: %2").arg(dc).arg(state));
DEBUG_LOG(("MTP Info: dc %1 trying to send after ping, state: %2").arg(_shiftedDcId).arg(state));
}
}
@ -1064,7 +1055,7 @@ void ConnectionPrivate::retryByTimer() {
} else if (retryTimeout < 64000) {
retryTimeout *= 2;
}
if (keyId == AuthKey::RecreateKeyId) {
if (keyId == kRecreateKeyId) {
if (sessionData->getKey()) {
unlockKey();
@ -1088,31 +1079,36 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
return;
}
auto dcType = DcOptions::DcType::Regular;
bool isDldDc = isDldDcId(dc);
if (isDldDcId(dc)) { // using media_only addresses only if key for this dc is already created
auto isDownloadDc = isDownloadDcId(_shiftedDcId);
if (isDownloadDc) { // using media_only addresses only if key for this dc is already created
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData || sessionData->getKey()) {
dcType = DcOptions::DcType::MediaDownload;
}
}
auto bareDc = bareDcId(dc);
auto bareDc = bareDcId(_shiftedDcId);
using Variants = DcOptions::Variants;
auto kIPv4 = Variants::IPv4;
auto kIPv6 = Variants::IPv6;
auto kTcp = Variants::Tcp;
auto kHttp = Variants::Http;
auto variants = Messenger::Instance().dcOptions()->lookup(bareDcId(dc), dcType);
auto variants = Messenger::Instance().dcOptions()->lookup(bareDc, 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));
if (Global::TryIPv6() && noIPv6) LOG(("MTP Error: DC %1 options for IPv6 over HTTP not found right after config load!").arg(dc));
if (_instance->isKeysDestroyer()) {
LOG(("MTP Error: DC %1 options for IPv4 over HTTP not found for auth key destruction!").arg(_shiftedDcId));
if (Global::TryIPv6() && noIPv6) LOG(("MTP Error: DC %1 options for IPv6 over HTTP not found for auth key destruction!").arg(_shiftedDcId));
emit _instance->keyDestroyed(_shiftedDcId);
return;
} else if (afterConfig) {
LOG(("MTP Error: DC %1 options for IPv4 over HTTP not found right after config load!").arg(_shiftedDcId));
if (Global::TryIPv6() && noIPv6) LOG(("MTP Error: DC %1 options for IPv6 over HTTP not found right after config load!").arg(_shiftedDcId));
return restart();
}
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(dc));
if (Global::TryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(dc));
DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(_shiftedDcId));
if (Global::TryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(_shiftedDcId));
connect(_instance, SIGNAL(configLoaded()), this, SLOT(onConfigLoaded()), Qt::UniqueConnection);
QMetaObject::invokeMethod(_instance, "configLoadRequest", Qt::QueuedConnection);
return;
@ -1146,11 +1142,11 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
}
}
void ConnectionPrivate::restart(bool mayBeBadKey) {
void ConnectionPrivate::restart() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData) return;
DEBUG_LOG(("MTP Info: restarting Connection, maybe bad key = %1").arg(Logs::b(mayBeBadKey)));
DEBUG_LOG(("MTP Info: restarting Connection"));
_waitForReceivedTimer.stop();
_waitForConnectedTimer.stop();
@ -1158,12 +1154,14 @@ void ConnectionPrivate::restart(bool mayBeBadKey) {
auto key = sessionData->getKey();
if (key) {
if (!sessionData->isCheckedKey()) {
if (mayBeBadKey) {
clearMessages();
keyId = AuthKey::RecreateKeyId;
// No destroying in case of an error.
//
//if (mayBeBadKey) {
// clearMessages();
// keyId = kRecreateKeyId;
// retryTimeout = 1; // no ddos please
LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now..."));
}
// LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now..."));
//}
} else {
sessionData->setCheckedKey(false);
}
@ -1193,9 +1191,9 @@ void ConnectionPrivate::onSentSome(uint64 size) {
DEBUG_LOG(("Checking connect for request with size %1 bytes, delay will be %2").arg(size).arg(remain));
}
}
if (isUplDcId(dc)) {
if (isUploadDcId(_shiftedDcId)) {
remain *= MTPUploadSessionsCount;
} else if (isDldDcId(dc)) {
} else if (isDownloadDcId(_shiftedDcId)) {
remain *= MTPDownloadSessionsCount;
}
_waitForReceivedTimer.start(remain);
@ -1318,7 +1316,7 @@ void ConnectionPrivate::handleReceived() {
ReadLockerAttempt lock(sessionData->keyMutex());
if (!lock) {
DEBUG_LOG(("MTP Error: auth_key for dc %1 busy, cant lock").arg(dc));
DEBUG_LOG(("MTP Error: auth_key for dc %1 busy, cant lock").arg(_shiftedDcId));
clearMessages();
keyId = 0;
@ -1328,7 +1326,7 @@ void ConnectionPrivate::handleReceived() {
auto key = sessionData->getKey();
if (!key || key->keyId() != keyId) {
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(_shiftedDcId));
lockFinished.unlock();
return restart();
@ -1434,7 +1432,7 @@ void ConnectionPrivate::handleReceived() {
auto res = HandleResult::Success; // if no need to handle, then succeed
end = data + 8 + (msgLen >> 2);
const mtpPrime *sfrom(data + 4);
MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end));
MTP_LOG(_shiftedDcId, ("Recv: ") + mtpTextSerialize(sfrom, end));
bool needToHandle = false;
{
@ -2308,7 +2306,7 @@ void ConnectionPrivate::updateAuthKey() {
QReadLocker lockFinished(&sessionDataMutex);
if (!sessionData || !_conn) return;
DEBUG_LOG(("AuthKey Info: Connection updating key from Session, dc %1").arg(dc));
DEBUG_LOG(("AuthKey Info: Connection updating key from Session, dc %1").arg(_shiftedDcId));
uint64 newKeyId = 0;
{
ReadLockerAttempt lock(sessionData->keyMutex());
@ -2325,7 +2323,7 @@ void ConnectionPrivate::updateAuthKey() {
clearMessages();
keyId = newKeyId;
}
DEBUG_LOG(("AuthKey Info: Connection update key from Session, dc %1 result: %2").arg(dc).arg(Logs::mb(&keyId, sizeof(keyId)).str()));
DEBUG_LOG(("AuthKey Info: Connection update key from Session, dc %1 result: %2").arg(_shiftedDcId).arg(Logs::mb(&keyId, sizeof(keyId)).str()));
if (keyId) {
return authKeyCreated();
}
@ -2339,6 +2337,11 @@ void ConnectionPrivate::updateAuthKey() {
keyId = key->keyId();
unlockKey();
return authKeyCreated();
} else if (_instance->isKeysDestroyer()) {
// We are here to destroy an old key, so we're done.
LOG(("MTP Error: No key %1 in updateAuthKey() for destroying.").arg(_shiftedDcId));
emit _instance->keyDestroyed(_shiftedDcId);
return;
}
_authKeyData = std::make_unique<ConnectionPrivate::AuthKeyCreateData>();
@ -2357,7 +2360,7 @@ void ConnectionPrivate::updateAuthKey() {
}
void ConnectionPrivate::clearMessages() {
if (keyId && keyId != AuthKey::RecreateKeyId && _conn) {
if (keyId && keyId != kRecreateKeyId && _conn) {
_conn->received().clear();
}
}
@ -2684,9 +2687,7 @@ void ConnectionPrivate::dhClientParamsAnswered() {
uint64 salt1 = _authKeyData->new_nonce.l.l, salt2 = _authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2;
sessionData->setSalt(serverSalt);
auto authKey = std::make_shared<AuthKey>();
authKey->setKey(_authKeyStrings->auth_key);
authKey->setDC(bareDcId(dc));
auto authKey = std::make_shared<AuthKey>(AuthKey::Type::Generated, bareDcId(_shiftedDcId), _authKeyStrings->auth_key);
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(serverSalt));
@ -2806,29 +2807,47 @@ void ConnectionPrivate::clearAuthKeyData() {
}
}
void ConnectionPrivate::onError4(bool mayBeBadKey) {
void ConnectionPrivate::onError4(qint32 errorCode) {
if (_conn && _conn == _conn6) return; // error in the unused
if (errorCode == -429) {
LOG(("Protocol Error: -429 flood code returned!"));
}
if (_conn || !_conn6) {
destroyConn();
_waitForConnectedTimer.stop();
MTP_LOG(dc, ("Restarting after error in IPv4 connection, maybe bad key: %1...").arg(Logs::b(mayBeBadKey)));
return restart(mayBeBadKey);
if (errorCode == -404 && _instance->isKeysDestroyer()) {
LOG(("MTP Info: -404 error received on destroying key %1, assuming it is destroyed.").arg(_shiftedDcId));
emit _instance->keyDestroyed(_shiftedDcId);
return;
} else {
MTP_LOG(_shiftedDcId, ("Restarting after error in IPv4 connection, error code: %1...").arg(errorCode));
return restart();
}
} else {
destroyConn(&_conn4);
}
}
void ConnectionPrivate::onError6(bool mayBeBadKey) {
void ConnectionPrivate::onError6(qint32 errorCode) {
if (_conn && _conn == _conn4) return; // error in the unused
if (errorCode == -429) {
LOG(("Protocol Error: -429 flood code returned!"));
}
if (_conn || !_conn4) {
destroyConn();
_waitForConnectedTimer.stop();
MTP_LOG(dc, ("Restarting after error in IPv6 connection, maybe bad key: %1...").arg(Logs::b(mayBeBadKey)));
return restart(mayBeBadKey);
if (errorCode == -404 && _instance->isKeysDestroyer()) {
LOG(("MTP Info: -404 error received on destroying key %1, assuming it is destroyed.").arg(_shiftedDcId));
emit _instance->keyDestroyed(_shiftedDcId);
return;
} else {
MTP_LOG(_shiftedDcId, ("Restarting after error in IPv6 connection, error code: %1...").arg(errorCode));
return restart();
}
} else {
destroyConn(&_conn6);
}
@ -2914,7 +2933,7 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q
ReadLockerAttempt lock(sessionData->keyMutex());
if (!lock) {
DEBUG_LOG(("MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting...").arg(dc));
DEBUG_LOG(("MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting...").arg(_shiftedDcId));
lockFinished.unlock();
restart();
@ -2923,7 +2942,7 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q
AuthKeyPtr key(sessionData->getKey());
if (!key || key->keyId() != keyId) {
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(_shiftedDcId));
lockFinished.unlock();
restart();
@ -2937,7 +2956,7 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q
memcpy(request->data() + 2, &session, 2 * sizeof(mtpPrime));
const mtpPrime *from = request->constData() + 4;
MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize));
MTP_LOG(_shiftedDcId, ("Send: ") + mtpTextSerialize(from, from + messageSize));
uchar encryptedSHA[20];
MTPint128 &msgKey(*(MTPint128*)(encryptedSHA + 4));

View File

@ -60,8 +60,7 @@ public:
Connection(Instance *instance);
int32 prepare(SessionData *data, int32 dc = 0); // return dc
void start();
void start(SessionData *data, ShiftedDcId shiftedDcId);
void kill();
void waitTillFinish();
@ -83,12 +82,12 @@ class ConnectionPrivate : public QObject {
Q_OBJECT
public:
ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, uint32 dc);
ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, ShiftedDcId shiftedDcId);
~ConnectionPrivate();
void stop();
int32 getDC() const;
int32 getShiftedDcId() const;
int32 getState() const;
QString transport() const;
@ -113,7 +112,6 @@ signals:
public slots:
void retryByTimer();
void restartNow();
void restart(bool mayBeBadKey = false);
void onPingSender();
void onPingSendForce();
@ -133,8 +131,8 @@ public slots:
void onConnected6();
void onDisconnected4();
void onDisconnected6();
void onError4(bool mayBeBadKey = false);
void onError6(bool mayBeBadKey = false);
void onError4(qint32 errorCode);
void onError6(qint32 errorCode);
void doFinish();
@ -155,6 +153,7 @@ public slots:
private:
void doDisconnect();
void restart();
void createConn(bool createIPv4, bool createIPv6);
void destroyConn(AbstractConnection **conn = 0); // 0 - destory all
@ -188,7 +187,7 @@ private:
bool _needSessionReset = false;
void resetSession();
ShiftedDcId dc = 0;
ShiftedDcId _shiftedDcId = 0;
Connection *_owner = nullptr;
AbstractConnection *_conn = nullptr;
AbstractConnection *_conn4 = nullptr;

View File

@ -65,18 +65,19 @@ public:
return receivedQueue;
}
signals:
// Used to emit error(...) with no real code from the server.
static constexpr auto kErrorCodeOther = -499;
signals:
void receivedData();
void receivedSome(); // to stop restart timer
void error(bool mayBeBadKey = false);
void error(qint32 errorCodebool);
void connected();
void disconnected();
protected:
BuffersQueue receivedQueue; // list of received packets, not processed yet
bool _sentEncrypted;

View File

@ -119,7 +119,7 @@ void AutoConnection::sendData(mtpBuffer &buffer) {
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(Logs::mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
emit error();
emit error(kErrorCodeOther);
return;
}
@ -204,7 +204,7 @@ void AutoConnection::requestFinished(QNetworkReply *reply) {
if (status == WaitingBoth) {
status = WaitingTcp;
} else {
emit error();
emit error(data[0]);
}
} else if (!data.isEmpty()) {
if (status == UsingHttp) {
@ -230,7 +230,7 @@ void AutoConnection::requestFinished(QNetworkReply *reply) {
if (status == WaitingBoth) {
status = WaitingTcp;
} else {
emit error();
emit error(kErrorCodeOther);
}
}
} else if (status == UsingTcp) {
@ -242,11 +242,10 @@ void AutoConnection::requestFinished(QNetworkReply *reply) {
return;
}
bool mayBeBadKey = HTTPConnection::handleError(reply) && _sentEncrypted;
if (status == WaitingBoth) {
status = WaitingTcp;
} else if (status == WaitingHttp || status == UsingHttp) {
emit error(mayBeBadKey);
emit error(HTTPConnection::handleError(reply));
} else {
LOG(("Strange Http Error: status %1").arg(status));
}
@ -267,8 +266,7 @@ void AutoConnection::socketPacket(const char *packet, uint32 length) {
sock.disconnectFromHost();
emit connected();
} else if (status == WaitingTcp || status == UsingTcp) {
bool mayBeBadKey = (data[0] == -410) && _sentEncrypted;
emit error(mayBeBadKey);
emit error(data[0]);
} else {
LOG(("Strange Tcp Error; status %1").arg(status));
}
@ -296,7 +294,7 @@ void AutoConnection::socketPacket(const char *packet, uint32 length) {
sock.disconnectFromHost();
emit connected();
} else {
emit error();
emit error(kErrorCodeOther);
}
}
}
@ -335,7 +333,7 @@ void AutoConnection::socketError(QAbstractSocket::SocketError e) {
status = UsingHttp;
emit connected();
} else if (status == WaitingTcp || status == UsingTcp) {
emit error();
emit error(kErrorCodeOther);
} else {
LOG(("Strange Tcp Error: status %1").arg(status));
}

View File

@ -42,16 +42,13 @@ mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
return data;
}
bool HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
bool mayBeBadKey = false;
qint32 HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
auto result = qint32(kErrorCodeOther);
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) {
int status = statusCode.toInt();
mayBeBadKey = (status == 410);
if (status == 429) {
LOG(("Protocol Error: 429 flood code returned!"));
}
result = -status;
}
switch (reply->error()) {
@ -66,7 +63,7 @@ bool HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad
case QNetworkReply::BackgroundRequestNotAllowedError:
case QNetworkReply::UnknownNetworkError: LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
// proxy errors (101-199):
// proxy errors (101-199):
case QNetworkReply::ProxyConnectionRefusedError:
case QNetworkReply::ProxyConnectionClosedError:
case QNetworkReply::ProxyNotFoundError:
@ -74,7 +71,7 @@ bool HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad
case QNetworkReply::ProxyAuthenticationRequiredError:
case QNetworkReply::UnknownProxyError:LOG(("HTTP Error: proxy error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
// content errors (201-299):
// content errors (201-299):
case QNetworkReply::ContentAccessDenied:
case QNetworkReply::ContentOperationNotPermittedError:
case QNetworkReply::ContentNotFoundError:
@ -82,14 +79,14 @@ bool HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad
case QNetworkReply::ContentReSendError:
case QNetworkReply::UnknownContentError: LOG(("HTTP Error: content error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
// protocol errors
// protocol errors
case QNetworkReply::ProtocolUnknownError:
case QNetworkReply::ProtocolInvalidOperationError:
case QNetworkReply::ProtocolFailure: LOG(("HTTP Error: protocol error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
};
TCP_LOG(("HTTP Error %1, restarting! - %2").arg(reply->error()).arg(reply->errorString()));
return mayBeBadKey;
return result;
}
HTTPConnection::HTTPConnection(QThread *thread) : AbstractConnection(thread)
@ -106,7 +103,7 @@ void HTTPConnection::sendData(mtpBuffer &buffer) {
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(Logs::mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
emit error();
emit error(kErrorCodeOther);
return;
}
@ -165,7 +162,7 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
mtpBuffer data = handleResponse(reply);
if (data.size() == 1) {
emit error();
emit error(data[0]);
} else if (!data.isEmpty()) {
if (status == UsingHttp) {
receivedQueue.push_back(data);
@ -181,7 +178,7 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
emit error();
emit error(kErrorCodeOther);
}
}
}
@ -190,9 +187,7 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
return;
}
bool mayBeBadKey = handleError(reply) && _sentEncrypted;
emit error(mayBeBadKey);
emit error(handleError(reply));
}
}

View File

@ -45,12 +45,12 @@ public:
QString transport() const override;
static mtpBuffer handleResponse(QNetworkReply *reply);
static qint32 handleError(QNetworkReply *reply); // returnes error code
public slots:
void requestFinished(QNetworkReply *reply);
static mtpBuffer handleResponse(QNetworkReply *reply);
static bool handleError(QNetworkReply *reply); // returnes "maybe bad key"
private:
enum Status {
WaitingHttp = 0,

View File

@ -55,7 +55,7 @@ AbstractTCPConnection::~AbstractTCPConnection() {
void AbstractTCPConnection::socketRead() {
if (sock.state() != QAbstractSocket::ConnectedState) {
LOG(("MTP error: socket not connected in socketRead(), state: %1").arg(sock.state()));
emit error();
emit error(kErrorCodeOther);
return;
}
@ -99,7 +99,7 @@ void AbstractTCPConnection::socketRead() {
uint32 packetSize = tcpPacketSize(currentPos - packetRead);
if (packetSize < 5 || packetSize > MTPPacketSizeMax) {
LOG(("TCP Error: packet size = %1").arg(packetSize));
emit error();
emit error(kErrorCodeOther);
return;
}
if (packetRead >= packetSize) {
@ -129,7 +129,7 @@ void AbstractTCPConnection::socketRead() {
}
} else if (bytes < 0) {
LOG(("TCP Error: socket read return -1"));
emit error();
emit error(kErrorCodeOther);
return;
} else {
TCP_LOG(("TCP Info: no bytes read, but bytes available was true..."));
@ -157,11 +157,7 @@ mtpBuffer AbstractTCPConnection::handleResponse(const char *packet, uint32 lengt
const mtpPrime *packetdata = reinterpret_cast<const mtpPrime*>(packet + (length - len));
TCP_LOG(("TCP Info: packet received, size = %1").arg(size * sizeof(mtpPrime)));
if (size == 1) {
if (*packetdata == -429) {
LOG(("Protocol Error: -429 flood code returned!"));
} else {
LOG(("TCP Error: error packet received, code = %1").arg(*packetdata));
}
LOG(("TCP Error: error packet received, code = %1").arg(*packetdata));
return mtpBuffer(1, *packetdata);
}
@ -272,7 +268,7 @@ void TCPConnection::sendData(mtpBuffer &buffer) {
if (buffer.size() < 3) {
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
TCP_LOG(("TCP Error: bad packet %1").arg(Logs::mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str()));
emit error();
emit error(kErrorCodeOther);
return;
}
@ -353,8 +349,7 @@ void TCPConnection::socketPacket(const char *packet, uint32 length) {
mtpBuffer data = handleResponse(packet, length);
if (data.size() == 1) {
bool mayBeBadKey = (data[0] == -410) && _sentEncrypted;
emit error(mayBeBadKey);
emit error(data[0]);
} else if (status == UsingTcp) {
receivedQueue.push_back(data);
emit receivedData();
@ -370,7 +365,7 @@ void TCPConnection::socketPacket(const char *packet, uint32 length) {
}
} catch (Exception &e) {
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
emit error();
emit error(kErrorCodeOther);
}
}
}
@ -391,7 +386,7 @@ void TCPConnection::socketError(QAbstractSocket::SocketError e) {
if (status == FinishedWork) return;
handleError(e, sock);
emit error();
emit error(kErrorCodeOther);
}
} // namespace internal

View File

@ -26,23 +26,22 @@ namespace MTP {
// type DcId represents actual data center id, while in most cases
// we use some shifted ids, like DcId() + X * DCShift
typedef int32 DcId;
typedef int32 ShiftedDcId;
using DcId = int32;
using ShiftedDcId = int32 ;
}
typedef int32 mtpPrime;
typedef int32 mtpRequestId;
typedef uint64 mtpMsgId;
typedef uint64 mtpPingId;
using mtpPrime = int32;
using mtpRequestId = int32;
using mtpMsgId = uint64;
using mtpPingId = uint64;
typedef QVector<mtpPrime> mtpBuffer;
typedef uint32 mtpTypeId;
using mtpBuffer = QVector<mtpPrime>;
using mtpTypeId = uint32;
class mtpRequestData;
class mtpRequest : public QSharedPointer<mtpRequestData> {
public:
mtpRequest() {
}
explicit mtpRequest(mtpRequestData *ptr) : QSharedPointer<mtpRequestData>(ptr) {
@ -51,7 +50,7 @@ public:
uint32 innerLength() const;
void write(mtpBuffer &to) const;
typedef void ResponseType; // don't know real response type =(
using ResponseType = void; // don't know real response type =(
};
@ -138,13 +137,13 @@ public:
}
};
typedef QMap<mtpRequestId, mtpRequest> mtpPreRequestMap;
typedef QMap<mtpMsgId, mtpRequest> mtpRequestMap;
typedef QMap<mtpMsgId, bool> mtpMsgIdsSet;
using mtpPreRequestMap = QMap<mtpRequestId, mtpRequest>;
using mtpRequestMap = QMap<mtpMsgId, mtpRequest>;
using mtpMsgIdsSet = QMap<mtpMsgId, bool>;
class mtpRequestIdsMap : public QMap<mtpMsgId, mtpRequestId> {
public:
typedef QMap<mtpMsgId, mtpRequestId> ParentType;
using ParentType = QMap<mtpMsgId, mtpRequestId>;
mtpMsgId min() const {
return size() ? cbegin().key() : 0;
@ -156,7 +155,7 @@ public:
}
};
typedef QMap<mtpRequestId, mtpResponse> mtpResponseMap;
using mtpResponseMap = QMap<mtpRequestId, mtpResponse>;
class mtpErrorUnexpected : public Exception {
public:
@ -200,6 +199,7 @@ public:
private:
uint32 cnt;
};
template <typename T>
@ -377,7 +377,7 @@ private:
inline MTPint MTP_int(int32 v) {
return MTPint(v);
}
typedef MTPBoxed<MTPint> MTPInt;
using MTPInt = MTPBoxed<MTPint>;
template <typename Flags>
class MTPflags {
@ -465,7 +465,7 @@ private:
inline MTPlong MTP_long(uint64 v) {
return MTPlong(v);
}
typedef MTPBoxed<MTPlong> MTPLong;
using MTPLong = MTPBoxed<MTPlong>;
inline bool operator==(const MTPlong &a, const MTPlong &b) {
return a.v == b.v;
@ -514,7 +514,7 @@ private:
inline MTPint128 MTP_int128(uint64 l, uint64 h) {
return MTPint128(l, h);
}
typedef MTPBoxed<MTPint128> MTPInt128;
using MTPInt128 = MTPBoxed<MTPint128>;
inline bool operator==(const MTPint128 &a, const MTPint128 &b) {
return a.l == b.l && a.h == b.h;
@ -559,7 +559,7 @@ private:
inline MTPint256 MTP_int256(const MTPint128 &l, const MTPint128 &h) {
return MTPint256(l, h);
}
typedef MTPBoxed<MTPint256> MTPInt256;
using MTPInt256 = MTPBoxed<MTPint256>;
inline bool operator==(const MTPint256 &a, const MTPint256 &b) {
return a.l == b.l && a.h == b.h;
@ -605,7 +605,7 @@ private:
inline MTPdouble MTP_double(float64 v) {
return MTPdouble(v);
}
typedef MTPBoxed<MTPdouble> MTPDouble;
using MTPDouble = MTPBoxed<MTPdouble>;
inline bool operator==(const MTPdouble &a, const MTPdouble &b) {
return a.v == b.v;
@ -724,7 +724,7 @@ inline MTPstring MTP_string(const char *v) {
return MTPstring(new MTPDstring(v));
}
MTPstring MTP_string(const QByteArray &v) = delete;
typedef MTPBoxed<MTPstring> MTPString;
using MTPString = MTPBoxed<MTPstring>;
using MTPbytes = MTPstring;
using MTPBytes = MTPBoxed<MTPbytes>;
@ -762,7 +762,7 @@ public:
MTPDvector(const QVector<T> &vec) : v(vec) {
}
typedef QVector<T> VType;
using VType = QVector<T>;
VType v;
};
@ -825,7 +825,7 @@ private:
friend MTPvector<U> MTP_vector(uint32 count, const U &value);
template <typename U>
friend MTPvector<U> MTP_vector(const QVector<U> &v);
typedef typename MTPDvector<T>::VType VType;
using VType = typename MTPDvector<T>::VType;
};
template <typename T>
inline MTPvector<T> MTP_vector(uint32 count) {

View File

@ -31,7 +31,7 @@ void DcOptions::constructFromBuiltIn() {
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)));
_data.emplace(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));
}
@ -39,7 +39,7 @@ void DcOptions::constructFromBuiltIn() {
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)));
_data.emplace(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));
}
}
@ -157,7 +157,7 @@ bool DcOptions::applyOneGuarded(DcId dcId, MTPDdcOption::Flags flags, const std:
i->second.ip = ip;
i->second.port = port;
} else {
_data.insert(std::make_pair(dcIdWithShift, Option(dcId, flags, ip, port)));
_data.emplace(dcIdWithShift, Option(dcId, flags, ip, port));
}
return true;
}

View File

@ -52,9 +52,8 @@ void Dcenter::setKey(AuthKeyPtr &&key) {
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
_key = std::move(key);
_connectionInited = false;
emit authKeyCreated();
_instance->setKeyForWrite(_id, _key);
emit authKeyCreated();
}
QReadWriteLock *Dcenter::keyMutex() const {
@ -76,9 +75,15 @@ ConfigLoader::ConfigLoader(Instance *instance, RPCDoneHandlerPtr onDone, RPCFail
}
void ConfigLoader::load() {
sendRequest(_instance->mainDcId());
_enumDCTimer.start(kEnumerateDcTimeout);
if (!_instance->isKeysDestroyer()) {
sendRequest(_instance->mainDcId());
_enumDCTimer.start(kEnumerateDcTimeout);
} else {
auto ids = _instance->dcOptions()->sortedDcIds();
t_assert(!ids.empty());
_enumCurrent = ids.front();
enumDC();
}
}
mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
@ -86,12 +91,11 @@ mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
}
ConfigLoader::~ConfigLoader() {
_enumDCTimer.stop();
if (_enumRequest) {
_instance->cancel(_enumRequest);
}
if (_enumCurrent) {
_instance->killSession(MTP::cfgDcId(_enumCurrent));
_instance->killSession(MTP::configDcId(_enumCurrent));
}
}
@ -103,7 +107,7 @@ void ConfigLoader::enumDC() {
if (!_enumCurrent) {
_enumCurrent = _instance->mainDcId();
} else {
_instance->killSession(MTP::cfgDcId(_enumCurrent));
_instance->killSession(MTP::configDcId(_enumCurrent));
}
auto ids = _instance->dcOptions()->sortedDcIds();
t_assert(!ids.empty());
@ -114,7 +118,7 @@ void ConfigLoader::enumDC() {
} else {
_enumCurrent = *i;
}
_enumRequest = sendRequest(MTP::cfgDcId(_enumCurrent));
_enumRequest = sendRequest(MTP::configDcId(_enumCurrent));
_enumDCTimer.start(kEnumerateDcTimeout);
}

View File

@ -32,6 +32,14 @@ bool paused();
void pause();
void unpause();
constexpr auto kDcShift = ShiftedDcId(10000);
constexpr auto kConfigDcShift = 0x01;
constexpr auto kLogoutDcShift = 0x02;
constexpr auto kMaxMediaDcCount = 0x10;
constexpr auto kBaseDownloadDcShift = 0x10;
constexpr auto kBaseUploadDcShift = 0x20;
constexpr auto kDestroyKeyStartDcShift = 0x100;
} // namespace internal
class PauseHolder {
@ -40,12 +48,12 @@ public:
restart();
}
void restart() {
if (!base::take(_paused, true)) {
if (!std::exchange(_paused, true)) {
internal::pause();
}
}
void release() {
if (base::take(_paused)) {
if (std::exchange(_paused, false)) {
internal::unpause();
}
}
@ -58,64 +66,68 @@ private:
};
constexpr ShiftedDcId DCShift = 10000;
constexpr DcId bareDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId % DCShift);
return (shiftedDcId % internal::kDcShift);
}
constexpr ShiftedDcId shiftDcId(DcId dcId, int value) {
return dcId + DCShift * value;
return dcId + internal::kDcShift * value;
}
constexpr int getDcIdShift(ShiftedDcId shiftedDcId) {
return (shiftedDcId - bareDcId(shiftedDcId)) / DCShift;
return shiftedDcId / internal::kDcShift;
}
// send(MTPhelp_GetConfig(), MTP::cfgDcId(dc)) - for dc enumeration
constexpr ShiftedDcId cfgDcId(DcId dcId) {
return shiftDcId(dcId, 0x01);
// send(MTPhelp_GetConfig(), MTP::configDcId(dc)) - for dc enumeration
constexpr ShiftedDcId configDcId(DcId dcId) {
return shiftDcId(dcId, internal::kConfigDcShift);
}
// send(MTPauth_LogOut(), MTP::lgtDcId(dc)) - for logout of guest dcs enumeration
constexpr ShiftedDcId lgtDcId(DcId dcId) {
return shiftDcId(dcId, 0x02);
// send(MTPauth_LogOut(), MTP::logoutDcId(dc)) - for logout of guest dcs enumeration
constexpr ShiftedDcId logoutDcId(DcId dcId) {
return shiftDcId(dcId, internal::kLogoutDcShift);
}
namespace internal {
constexpr ShiftedDcId downloadDcId(DcId dcId, int index) {
static_assert(MTPDownloadSessionsCount < 0x10, "Too large MTPDownloadSessionsCount!");
return shiftDcId(dcId, 0x10 + index);
static_assert(MTPDownloadSessionsCount < internal::kMaxMediaDcCount, "Too large MTPDownloadSessionsCount!");
return shiftDcId(dcId, internal::kBaseDownloadDcShift + index);
};
} // namespace internal
// send(req, callbacks, MTP::dldDcId(dc, index)) - for download shifted dc id
inline ShiftedDcId dldDcId(DcId dcId, int index) {
// send(req, callbacks, MTP::downloadDcId(dc, index)) - for download shifted dc id
inline ShiftedDcId downloadDcId(DcId dcId, int index) {
t_assert(index >= 0 && index < MTPDownloadSessionsCount);
return internal::downloadDcId(dcId, index);
}
constexpr bool isDldDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::downloadDcId(0, 0)) && (shiftedDcId < internal::downloadDcId(0, MTPDownloadSessionsCount - 1) + DCShift);
constexpr bool isDownloadDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::downloadDcId(0, 0)) && (shiftedDcId < internal::downloadDcId(0, MTPDownloadSessionsCount - 1) + internal::kDcShift);
}
namespace internal {
constexpr ShiftedDcId uploadDcId(DcId dcId, int index) {
static_assert(MTPUploadSessionsCount < 0x10, "Too large MTPUploadSessionsCount!");
return shiftDcId(dcId, 0x20 + index);
static_assert(MTPUploadSessionsCount < internal::kMaxMediaDcCount, "Too large MTPUploadSessionsCount!");
return shiftDcId(dcId, internal::kBaseUploadDcShift + index);
};
} // namespace internal
// send(req, callbacks, MTP::uplDcId(index)) - for upload shifted dc id
// send(req, callbacks, MTP::uploadDcId(index)) - for upload shifted dc id
// uploading always to the main dc so bareDcId == 0
inline ShiftedDcId uplDcId(int index) {
inline ShiftedDcId uploadDcId(int index) {
t_assert(index >= 0 && index < MTPUploadSessionsCount);
return internal::uploadDcId(0, index);
};
constexpr bool isUplDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + DCShift);
constexpr bool isUploadDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + internal::kDcShift);
}
inline ShiftedDcId destroyKeyNextDcId(ShiftedDcId shiftedDcId) {
auto shift = getDcIdShift(shiftedDcId);
return shiftDcId(bareDcId(shiftedDcId), shift ? (shift + 1) : internal::kDestroyKeyStartDcShift);
}
enum {

View File

@ -343,9 +343,10 @@ mtpFileLoader::mtpFileLoader(const StorageImageLocation *location, int32 size, L
: FileLoader(QString(), size, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading)
, _dc(location->dc())
, _location(location) {
LoaderQueues::iterator i = queues.find(MTP::dldDcId(_dc, 0));
auto shiftedDcId = MTP::downloadDcId(_dc, 0);
auto i = queues.find(shiftedDcId);
if (i == queues.cend()) {
i = queues.insert(MTP::dldDcId(_dc, 0), FileLoaderQueue(MaxFileQueries));
i = queues.insert(shiftedDcId, FileLoaderQueue(MaxFileQueries));
}
_queue = &i.value();
}
@ -356,9 +357,10 @@ mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, i
, _id(id)
, _access(access)
, _version(version) {
LoaderQueues::iterator i = queues.find(MTP::dldDcId(_dc, 0));
auto shiftedDcId = MTP::downloadDcId(_dc, 0);
auto i = queues.find(shiftedDcId);
if (i == queues.cend()) {
i = queues.insert(MTP::dldDcId(_dc, 0), FileLoaderQueue(MaxFileQueries));
i = queues.insert(shiftedDcId, FileLoaderQueue(MaxFileQueries));
}
_queue = &i.value();
}
@ -420,7 +422,7 @@ bool mtpFileLoader::loadPart() {
App::app()->killDownloadSessionsStop(_dc);
mtpRequestId reqId = MTP::send(MTPupload_GetFile(loc, MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::dldDcId(_dc, dcIndex), 50);
mtpRequestId reqId = MTP::send(MTPupload_GetFile(loc, MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::partLoaded, offset), rpcFail(&mtpFileLoader::partFailed), MTP::downloadDcId(_dc, dcIndex), 50);
++_queue->queries;
dr.v[dcIndex] += limit;

View File

@ -220,6 +220,9 @@ protected:
mutable QByteArray _imageFormat;
mutable QPixmap _imagePixmap;
private:
void deleteLater();
};
class StorageImageLocation;

View File

@ -31,7 +31,7 @@ namespace MTP {
class Instance::Private {
public:
Private(Instance *instance, DcOptions *options);
Private(Instance *instance, DcOptions *options, Instance::Mode mode);
void start(Config &&config);
@ -40,7 +40,8 @@ public:
DcId mainDcId() const;
void setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
AuthKeysMap getKeysForWrite() const;
AuthKeysList getKeysForWrite() const;
void addKeysForDestroy(AuthKeysList &&keys);
DcOptions *dcOptions();
@ -54,10 +55,11 @@ public:
void cancel(mtpRequestId requestId);
int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
void killSession(ShiftedDcId shiftedDcId);
void killSession(std::unique_ptr<internal::Session> session);
void stopSession(ShiftedDcId shiftedDcId);
void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
internal::DcenterPtr getDcById(DcId dcId);
internal::DcenterPtr getDcById(ShiftedDcId shiftedDcId);
void unpaused();
void queueQuittingConnection(std::unique_ptr<internal::Connection> connection);
@ -91,6 +93,16 @@ public:
internal::Session *getSession(ShiftedDcId shiftedDcId);
bool isKeysDestroyer() const {
return (_mode == Instance::Mode::KeysDestroyer);
}
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
void performKeyDestroy(ShiftedDcId shiftedDcId);
void completedKeyDestroy(ShiftedDcId shiftedDcId);
void clearKilledSessions();
~Private();
private:
@ -109,8 +121,8 @@ private:
void checkDelayedRequests();
Instance *_instance = nullptr;
DcOptions *_dcOptions = nullptr;
Instance::Mode _mode = Instance::Mode::Normal;
DcId _mainDcId = Config::kDefaultMainDc;
bool _mainDcIdForced = false;
@ -118,6 +130,7 @@ private:
internal::Session *_mainSession = nullptr;
std::map<ShiftedDcId, std::unique_ptr<internal::Session>> _sessions;
std::vector<std::unique_ptr<internal::Session>> _killedSessions; // delayed delete
base::set_of_unique_ptr<internal::Connection> _quittingConnections;
@ -160,41 +173,64 @@ private:
};
Instance::Private::Private(Instance *instance, DcOptions *options) : _instance(instance)
, _dcOptions(options) {
Instance::Private::Private(Instance *instance, DcOptions *options, Instance::Mode mode) : _instance(instance)
, _dcOptions(options)
, _mode(mode) {
}
void Instance::Private::start(Config &&config) {
unixtimeInit();
if (isKeysDestroyer()) {
_instance->connect(_instance, SIGNAL(keyDestroyed(qint32)), _instance, SLOT(onKeyDestroyed(qint32)), Qt::QueuedConnection);
} else {
unixtimeInit();
}
for (auto &keyData : config.keys) {
auto dcId = keyData.first;
auto key = std::make_shared<AuthKey>();
key->setDC(dcId);
key->setKey(keyData.second);
for (auto &key : config.keys) {
auto dcId = key->dcId();
_keysForWrite[dcId] = key;
auto shiftedDcId = dcId;
if (isKeysDestroyer()) {
shiftedDcId = MTP::destroyKeyNextDcId(shiftedDcId);
// There could be several keys for one dc if we're destroying them.
// Place them all in separate shiftedDcId so that they won't conflict.
while (_keysForWrite.find(shiftedDcId) != _keysForWrite.cend()) {
shiftedDcId = MTP::destroyKeyNextDcId(shiftedDcId);
}
}
_keysForWrite[shiftedDcId] = key;
auto dc = std::make_shared<internal::Dcenter>(_instance, dcId, std::move(key));
_dcenters.emplace(dcId, std::move(dc));
_dcenters.emplace(shiftedDcId, std::move(dc));
}
if (config.mainDcId != Config::kNotSetMainDc) {
_mainDcId = config.mainDcId;
_mainDcIdForced = true;
}
if (_mainDcId != Config::kNoneMainDc) {
if (isKeysDestroyer()) {
for (auto &dc : _dcenters) {
auto shiftedDcId = dc.first;
auto session = std::make_unique<internal::Session>(_instance, shiftedDcId);
auto it = _sessions.emplace(shiftedDcId, std::move(session)).first;
it->second->start();
}
} else if (_mainDcId != Config::kNoneMainDc) {
auto main = std::make_unique<internal::Session>(_instance, _mainDcId);
_mainSession = main.get();
auto newMainDcId = main->getDcWithShift();
_sessions.emplace(newMainDcId, std::move(main));
_sessions.emplace(_mainDcId, std::move(main));
_mainSession->start();
}
_checkDelayedTimer.setTimeoutHandler([this] {
checkDelayedRequests();
});
configLoadRequest();
t_assert((_mainDcId == Config::kNoneMainDc) == isKeysDestroyer());
if (!isKeysDestroyer()) {
configLoadRequest();
}
}
void Instance::Private::suggestMainDcId(DcId mainDcId) {
@ -335,27 +371,29 @@ int32 Instance::Private::state(mtpRequestId requestId) { // < 0 means waiting fo
}
void Instance::Private::killSession(ShiftedDcId shiftedDcId) {
auto it = _sessions.find(shiftedDcId);
if (it != _sessions.cend()) {
bool wasMain = (it->second.get() == _mainSession);
it->second->kill();
it->second.release()->deleteLater();
_sessions.erase(it);
if (wasMain) {
auto main = std::make_unique<internal::Session>(_instance, _mainDcId);
_mainSession = main.get();
auto newMainDcId = main->getDcWithShift();
it = _sessions.find(newMainDcId);
if (it != _sessions.cend()) {
it->second->kill();
it->second.release()->deleteLater();
_sessions.erase(it);
}
_sessions.insert(std::make_pair(newMainDcId, std::move(main)));
auto checkIfMainAndKill = [this](ShiftedDcId shiftedDcId) {
auto it = _sessions.find(shiftedDcId);
if (it != _sessions.cend()) {
_killedSessions.push_back(std::move(it->second));
_sessions.erase(it);
_killedSessions.back()->kill();
return (_killedSessions.back().get() == _mainSession);
}
return false;
};
if (checkIfMainAndKill(shiftedDcId)) {
checkIfMainAndKill(_mainDcId);
auto main = std::make_unique<internal::Session>(_instance, _mainDcId);
_mainSession = main.get();
_sessions.emplace(_mainDcId, std::move(main));
_mainSession->start();
}
QMetaObject::invokeMethod(_instance, "onClearKilledSessions", Qt::QueuedConnection);
}
void Instance::Private::clearKilledSessions() {
_killedSessions.clear();
}
void Instance::Private::stopSession(ShiftedDcId shiftedDcId) {
@ -380,13 +418,13 @@ void Instance::Private::logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFai
}
for (auto dcId : dcIds) {
if (dcId != mainDcId()) {
auto shiftedDcId = MTP::lgtDcId(dcId);
auto shiftedDcId = MTP::logoutDcId(dcId);
auto requestId = _instance->send(MTPauth_LogOut(), rpcDone([this](mtpRequestId requestId) {
logoutGuestDone(requestId);
}), rpcFail([this](mtpRequestId requestId) {
return logoutGuestDone(requestId);
}), shiftedDcId);
_logoutGuestRequestIds.insert(std::make_pair(shiftedDcId, requestId));
_logoutGuestRequestIds.emplace(shiftedDcId, requestId);
}
}
}
@ -402,12 +440,15 @@ bool Instance::Private::logoutGuestDone(mtpRequestId requestId) {
return false;
}
internal::DcenterPtr Instance::Private::getDcById(DcId dcId) {
auto it = _dcenters.find(dcId);
internal::DcenterPtr Instance::Private::getDcById(ShiftedDcId shiftedDcId) {
auto it = _dcenters.find(shiftedDcId);
if (it == _dcenters.cend()) {
auto result = std::make_shared<internal::Dcenter>(_instance, dcId, AuthKeyPtr());
auto insert = std::make_pair(dcId, std::move(result));
it = _dcenters.insert(std::move(insert)).first;
auto dcId = bareDcId(shiftedDcId);
it = _dcenters.find(dcId);
if (it == _dcenters.cend()) {
auto result = std::make_shared<internal::Dcenter>(_instance, dcId, AuthKeyPtr());
it = _dcenters.emplace(dcId, std::move(result)).first;
}
}
return it->second;
}
@ -421,15 +462,43 @@ void Instance::Private::setKeyForWrite(DcId dcId, const AuthKeyPtr &key) {
}
}
AuthKeysMap Instance::Private::getKeysForWrite() const {
auto result = AuthKeysMap();
AuthKeysList Instance::Private::getKeysForWrite() const {
auto result = AuthKeysList();
QReadLocker lock(&_keysForWriteLock);
result.reserve(_keysForWrite.size());
for (auto &key : _keysForWrite) {
result.push_back(key.second);
}
return result;
}
void Instance::Private::addKeysForDestroy(AuthKeysList &&keys) {
t_assert(isKeysDestroyer());
for (auto &key : keys) {
auto dcId = key->dcId();
auto shiftedDcId = MTP::destroyKeyNextDcId(dcId);
{
QWriteLocker lock(&_keysForWriteLock);
// There could be several keys for one dc if we're destroying them.
// Place them all in separate shiftedDcId so that they won't conflict.
while (_keysForWrite.find(shiftedDcId) != _keysForWrite.cend()) {
shiftedDcId = MTP::destroyKeyNextDcId(shiftedDcId);
}
_keysForWrite[shiftedDcId] = key;
}
auto dc = std::make_shared<internal::Dcenter>(_instance, dcId, std::move(key));
_dcenters.emplace(shiftedDcId, std::move(dc));
auto session = std::make_unique<internal::Session>(_instance, shiftedDcId);
auto it = _sessions.emplace(shiftedDcId, std::move(session)).first;
it->second->start();
}
}
DcOptions *Instance::Private::dcOptions() {
return _dcOptions;
}
@ -1046,10 +1115,57 @@ internal::Session *Instance::Private::getSession(ShiftedDcId shiftedDcId) {
auto it = _sessions.find(shiftedDcId);
if (it == _sessions.cend()) {
it = _sessions.emplace(shiftedDcId, std::make_unique<internal::Session>(_instance, shiftedDcId)).first;
it->second->start();
}
return it->second.get();
}
void Instance::Private::scheduleKeyDestroy(ShiftedDcId shiftedDcId) {
t_assert(isKeysDestroyer());
_instance->send(MTPauth_LogOut(), rpcDone([this, shiftedDcId](const MTPBool &result) {
performKeyDestroy(shiftedDcId);
}), rpcFail([this, shiftedDcId](const RPCError &error) {
if (isDefaultHandledError(error)) return false;
performKeyDestroy(shiftedDcId);
return true;
}), shiftedDcId);
}
void Instance::Private::performKeyDestroy(ShiftedDcId shiftedDcId) {
t_assert(isKeysDestroyer());
_instance->send(MTPDestroy_auth_key(), rpcDone([this, shiftedDcId](const MTPDestroyAuthKeyRes &result) {
switch (result.type()) {
case mtpc_destroy_auth_key_ok: LOG(("MTP Info: key %1 destroyed.").arg(shiftedDcId)); break;
case mtpc_destroy_auth_key_fail: {
LOG(("MTP Error: key %1 destruction fail, leave it for now.").arg(shiftedDcId));
killSession(shiftedDcId);
} break;
case mtpc_destroy_auth_key_none: LOG(("MTP Info: key %1 already destroyed.").arg(shiftedDcId)); break;
}
emit _instance->keyDestroyed(shiftedDcId);
}), rpcFail([this, shiftedDcId](const RPCError &error) {
LOG(("MTP Error: key %1 destruction resulted in error: %2").arg(shiftedDcId).arg(error.type()));
emit _instance->keyDestroyed(shiftedDcId);
return true;
}), shiftedDcId);
}
void Instance::Private::completedKeyDestroy(ShiftedDcId shiftedDcId) {
t_assert(isKeysDestroyer());
_dcenters.erase(shiftedDcId);
{
QWriteLocker lock(&_keysForWriteLock);
_keysForWrite.erase(shiftedDcId);
}
killSession(shiftedDcId);
if (_dcenters.empty()) {
emit _instance->allKeysDestroyed();
}
}
void Instance::Private::setUpdatesHandler(RPCDoneHandlerPtr onDone) {
_globalHandler.onDone = onDone;
}
@ -1077,10 +1193,13 @@ Instance::Private::~Private() {
for (auto &session : base::take(_sessions)) {
session.second->kill();
}
// It accesses Instance in destructor, so it should be destroyed first.
_configLoader.reset();
}
Instance::Instance(DcOptions *options, Config &&config) : QObject()
, _private(std::make_unique<Private>(this, options)) {
Instance::Instance(DcOptions *options, Mode mode, Config &&config) : QObject()
, _private(std::make_unique<Private>(this, options, mode)) {
_private->start(std::move(config));
}
@ -1144,18 +1263,22 @@ void Instance::logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) {
_private->logout(onDone, onFail);
}
internal::DcenterPtr Instance::getDcById(DcId dcId) {
return _private->getDcById(dcId);
internal::DcenterPtr Instance::getDcById(ShiftedDcId shiftedDcId) {
return _private->getDcById(shiftedDcId);
}
void Instance::setKeyForWrite(DcId dcId, const AuthKeyPtr &key) {
_private->setKeyForWrite(dcId, key);
}
AuthKeysMap Instance::getKeysForWrite() const {
AuthKeysList Instance::getKeysForWrite() const {
return _private->getKeysForWrite();
}
void Instance::addKeysForDestroy(AuthKeysList &&keys) {
_private->addKeysForDestroy(std::move(keys));
}
DcOptions *Instance::dcOptions() {
return _private->dcOptions();
}
@ -1232,6 +1355,22 @@ internal::Session *Instance::getSession(ShiftedDcId shiftedDcId) {
return _private->getSession(shiftedDcId);
}
bool Instance::isKeysDestroyer() const {
return _private->isKeysDestroyer();
}
void Instance::scheduleKeyDestroy(ShiftedDcId shiftedDcId) {
_private->scheduleKeyDestroy(shiftedDcId);
}
void Instance::onKeyDestroyed(qint32 shiftedDcId) {
_private->completedKeyDestroy(shiftedDcId);
}
void Instance::onClearKilledSessions() {
_private->clearKilledSessions();
}
Instance::~Instance() = default;
} // namespace MTP

View File

@ -39,9 +39,13 @@ public:
static constexpr auto kDefaultMainDc = 2;
DcId mainDcId = kNotSetMainDc;
std::map<DcId, AuthKey::Data> keys;
AuthKeysList keys;
};
Instance(DcOptions *options, Config &&config);
enum class Mode {
Normal,
KeysDestroyer,
};
Instance(DcOptions *options, Mode mode, Config &&config);
Instance(const Instance &other) = delete;
Instance &operator=(const Instance &other) = delete;
@ -50,8 +54,9 @@ public:
void setMainDcId(DcId mainDcId);
DcId mainDcId() const;
void Instance::setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
AuthKeysMap Instance::getKeysForWrite() const;
void setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
AuthKeysList getKeysForWrite() const;
void addKeysForDestroy(AuthKeysList &&keys);
DcOptions *dcOptions();
@ -85,7 +90,7 @@ public:
void stopSession(ShiftedDcId shiftedDcId);
void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
internal::DcenterPtr getDcById(DcId dcId);
internal::DcenterPtr getDcById(ShiftedDcId shiftedDcId);
void unpaused();
void queueQuittingConnection(std::unique_ptr<internal::Connection> connection);
@ -111,6 +116,9 @@ public:
// return true if need to clean request data
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
bool isKeysDestroyer() const;
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
~Instance();
public slots:
@ -119,6 +127,12 @@ public slots:
signals:
void configLoaded();
void keyDestroyed(qint32 shiftedDcId);
void allKeysDestroyed();
private slots:
void onKeyDestroyed(qint32 shiftedDcId);
void onClearKilledSessions();
private:
internal::Session *getSession(ShiftedDcId shiftedDcId);

View File

@ -70,33 +70,30 @@ void SessionData::clear(Instance *instance) {
instance->clearCallbacksDelayed(clearCallbacks);
}
Session::Session(Instance *instance, ShiftedDcId requestedShiftedDcId) : QObject()
Session::Session(Instance *instance, ShiftedDcId shiftedDcId) : QObject()
, _instance(instance)
, data(this) {
, data(this)
, dcWithShift(shiftedDcId) {
connect(&timeouter, SIGNAL(timeout()), this, SLOT(checkRequestsByTimer()));
timeouter.start(1000);
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
}
_connection = std::make_unique<Connection>(_instance);
dcWithShift = _connection->prepare(&data, requestedShiftedDcId);
if (!dcWithShift) {
_connection.reset();
DEBUG_LOG(("Session Info: could not start connection to dc %1").arg(requestedShiftedDcId));
return;
}
void Session::start() {
createDcData();
_connection->start();
_connection = std::make_unique<Connection>(_instance);
_connection->start(&data, dcWithShift);
if (_instance->isKeysDestroyer()) {
_instance->scheduleKeyDestroy(dcWithShift);
}
}
void Session::createDcData() {
if (dc) {
return;
}
auto dcId = bareDcId(dcWithShift);
dc = _instance->getDcById(dcId);
dc = _instance->getDcById(dcWithShift);
ReadLockerAttempt lock(keyMutex());
data.setKey(lock ? dc->getKey() : AuthKeyPtr());
@ -193,15 +190,9 @@ void Session::needToResumeAndSend() {
}
if (!_connection) {
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
_connection = std::make_unique<Connection>(_instance);
if (!_connection->prepare(&data, dcWithShift)) {
_connection.reset();
DEBUG_LOG(("Session Info: could not start connection to dcWithShift %1").arg(dcWithShift));
dcWithShift = 0;
return;
}
createDcData();
_connection->start();
_connection = std::make_unique<Connection>(_instance);
_connection->start(&data, dcWithShift);
}
if (_ping) {
_ping = false;

View File

@ -278,8 +278,9 @@ class Session : public QObject {
Q_OBJECT
public:
Session(Instance *instance, ShiftedDcId requestedShiftedDcId);
Session(Instance *instance, ShiftedDcId shiftedDcId);
void start();
void restart();
void stop();
void kill();

View File

@ -169,7 +169,7 @@ void PeerListWidget::mouseReleaseEvent(QMouseEvent *e) {
void PeerListWidget::mousePressReleased(Qt::MouseButton button) {
repaintRow(_pressed);
auto pressed = base::take(_pressed, -1);
auto pressed = std::exchange(_pressed, -1);
auto pressedRemove = base::take(_pressedRemove);
if (pressed >= 0 && pressed < _items.size()) {
if (auto &ripple = _items[pressed]->ripple) {

View File

@ -306,7 +306,7 @@ void InnerWidget::mouseMoveEvent(QMouseEvent *e) {
void InnerWidget::mouseReleaseEvent(QMouseEvent *e) {
updateRow(_pressed);
auto pressed = base::take(_pressed, -1);
auto pressed = std::exchange(_pressed, -1);
if (pressed >= 0 && pressed < _items.size()) {
if (auto &ripple = _items[pressed]->ripple) {
ripple->lastStop();

View File

@ -40,4 +40,18 @@ void writeStorageImageLocation(QDataStream &stream, const StorageImageLocation &
StorageImageLocation readStorageImageLocation(QDataStream &stream);
int storageImageLocationSize();
template <typename T>
inline T read(QDataStream &stream) {
auto result = T();
stream >> result;
return result;
}
template <>
inline MTP::AuthKey::Data read<MTP::AuthKey::Data>(QDataStream &stream) {
auto result = MTP::AuthKey::Data();
stream.readRawData(result.data(), result.size());
return result;
}
} // namespace Serialize

View File

@ -1133,8 +1133,8 @@ void StickerPanInner::setPressedFeaturedSetAdd(int newPressedFeaturedSetAdd) {
void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
auto pressed = base::take(_pressed, -1);
auto pressedFeaturedSet = base::take(_pressedFeaturedSet, -1);
auto pressed = std::exchange(_pressed, -1);
auto pressedFeaturedSet = std::exchange(_pressedFeaturedSet, -1);
auto pressedFeaturedSetAdd = _pressedFeaturedSetAdd;
setPressedFeaturedSetAdd(-1);
if (pressedFeaturedSetAdd != _selectedFeaturedSetAdd) {

View File

@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_history.h"
#include "window/themes/window_theme.h"
#include "auth_session.h"
#include "messenger.h"
namespace {
@ -1530,26 +1531,27 @@ void DocumentData::performActionOnLoad() {
bool DocumentData::loaded(FilePathResolveType type) const {
if (loading() && _loader->done()) {
if (_loader->fileType() == mtpc_storage_fileUnknown) {
_loader->deleteLater();
_loader->stop();
_loader = CancelledMtpFileLoader;
destroyLoaderDelayed(CancelledMtpFileLoader);
} else {
DocumentData *that = const_cast<DocumentData*>(this);
auto that = const_cast<DocumentData*>(this);
that->_location = FileLocation(mtpToStorageType(_loader->fileType()), _loader->fileName());
that->_data = _loader->bytes();
if (that->sticker() && !_loader->imagePixmap().isNull()) {
that->sticker()->img = ImagePtr(_data, _loader->imageFormat(), _loader->imagePixmap());
}
_loader->deleteLater();
_loader->stop();
_loader = nullptr;
destroyLoaderDelayed();
}
notifyLayoutChanged();
}
return !data().isEmpty() || !filepath(type).isEmpty();
}
void DocumentData::destroyLoaderDelayed(mtpFileLoader *newValue) const {
_loader->stop();
auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, newValue));
Messenger::Instance().delayedDestroyLoader(std::move(loader));
}
bool DocumentData::loading() const {
return _loader && _loader != CancelledMtpFileLoader;
}
@ -1632,11 +1634,10 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs
void DocumentData::cancel() {
if (!loading()) return;
auto loader = base::take(_loader);
_loader = CancelledMtpFileLoader;
auto loader = std::exchange(_loader, CancelledMtpFileLoader);
loader->cancel();
loader->deleteLater();
loader->stop();
Messenger::Instance().delayedDestroyLoader(std::unique_ptr<FileLoader>(loader));
notifyLayoutChanged();
if (auto main = App::main()) {
@ -1803,9 +1804,7 @@ bool DocumentData::setRemoteVersion(int32 version) {
_data = QByteArray();
status = FileReady;
if (loading()) {
_loader->deleteLater();
_loader->stop();
_loader = nullptr;
destroyLoaderDelayed();
}
return true;
}
@ -1849,9 +1848,7 @@ void DocumentData::collectLocalData(DocumentData *local) {
DocumentData::~DocumentData() {
if (loading()) {
_loader->deleteLater();
_loader->stop();
_loader = nullptr;
destroyLoaderDelayed();
}
}

View File

@ -1256,6 +1256,8 @@ private:
void notifyLayoutChanged() const;
void destroyLoaderDelayed(mtpFileLoader *newValue = nullptr) const;
};
VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit);

View File

@ -23,8 +23,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "localstorage.h"
#include "pspecific.h"
#include "messenger.h"
namespace Images {
namespace {
@ -828,9 +828,7 @@ void RemoteImage::doCheckload() const {
QPixmap data = _loader->imagePixmap(shrinkBox());
if (data.isNull()) {
_loader->deleteLater();
_loader->stop();
_loader = CancelledFileLoader;
destroyLoaderDelayed(CancelledFileLoader);
return;
}
@ -846,13 +844,17 @@ void RemoteImage::doCheckload() const {
invalidateSizeCache();
_loader->deleteLater();
_loader->stop();
_loader = nullptr;
destroyLoaderDelayed();
_forgot = false;
}
void RemoteImage::destroyLoaderDelayed(FileLoader *newValue) const {
_loader->stop();
auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, newValue));
Messenger::Instance().delayedDestroyLoader(std::move(loader));
}
void RemoteImage::loadLocal() {
if (loaded() || amLoading()) return;
@ -875,9 +877,7 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
invalidateSizeCache();
if (amLoading()) {
_loader->deleteLater();
_loader->stop();
_loader = nullptr;
destroyLoaderDelayed();
}
_saved = bytes;
_format = fmt;
@ -930,9 +930,7 @@ RemoteImage::~RemoteImage() {
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
}
if (amLoading()) {
_loader->deleteLater();
_loader->stop();
_loader = 0;
destroyLoaderDelayed();
}
}
@ -948,13 +946,10 @@ bool RemoteImage::displayLoading() const {
void RemoteImage::cancel() {
if (!amLoading()) return;
FileLoader *l = _loader;
_loader = CancelledFileLoader;
if (l) {
l->cancel();
l->deleteLater();
l->stop();
}
auto loader = std::exchange(_loader, CancelledFileLoader);
loader->cancel();
loader->stop();
Messenger::Instance().delayedDestroyLoader(std::unique_ptr<FileLoader>(loader));
}
float64 RemoteImage::progress() const {

View File

@ -282,10 +282,6 @@ inline StorageKey storageKey(const StorageImageLocation &location) {
class RemoteImage : public Image {
public:
RemoteImage() : _loader(0) {
}
void automaticLoad(const HistoryItem *item); // auto load photo
void automaticLoadSettingsChanged();
@ -320,12 +316,14 @@ protected:
void loadLocal();
private:
mutable FileLoader *_loader;
mutable FileLoader *_loader = nullptr;
bool amLoading() const {
return _loader && _loader != CancelledFileLoader;
}
void doCheckload() const;
void destroyLoaderDelayed(FileLoader *newValue = nullptr) const;
};
class StorageImage : public RemoteImage {

View File

@ -122,7 +122,7 @@ void DiscreteSlider::mouseMoveEvent(QMouseEvent *e) {
}
void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = base::take(_pressed, -1);
auto pressed = std::exchange(_pressed, -1);
if (pressed < 0) return;
auto index = getIndexFromPosition(e->pos());

View File

@ -233,7 +233,7 @@ void Menu::itemPressed(TriggeredSource source) {
}
void Menu::itemReleased(TriggeredSource source) {
auto pressed = base::take(_pressed, -1);
auto pressed = std::exchange(_pressed, -1);
if (pressed >= 0 && pressed < _actions.size()) {
if (source == TriggeredSource::Mouse && _actionsData[pressed].ripple) {
_actionsData[pressed].ripple->lastStop();

View File

@ -528,7 +528,7 @@ void EditorBlock::saveEditing(QColor value) {
auto &row = _data[_editing];
auto name = row.name();
if (_type == Type::New) {
auto removing = base::take(_editing, -1);
auto removing = std::exchange(_editing, -1);
setSelected(-1);
setPressed(-1);