mirror of
https://github.com/vale981/tdesktop
synced 2025-03-11 21:46:41 -04:00

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.
303 lines
8.8 KiB
C++
303 lines
8.8 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|
*/
|
|
#include "stdafx.h"
|
|
#include "mtproto/dc_options.h"
|
|
|
|
namespace MTP {
|
|
|
|
void DcOptions::constructFromBuiltIn() {
|
|
QWriteLocker lock(&_mutex);
|
|
_data.clear();
|
|
|
|
auto bdcs = builtInDcs();
|
|
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
|
|
auto flags = MTPDdcOption::Flags(0);
|
|
auto idWithShift = MTP::shiftDcId(bdcs[i].id, flags);
|
|
_data.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));
|
|
}
|
|
|
|
auto bdcsipv6 = builtInDcsIPv6();
|
|
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
|
|
auto flags = MTPDdcOption::Flags(MTPDdcOption::Flag::f_ipv6);
|
|
auto idWithShift = MTP::shiftDcId(bdcsipv6[i].id, flags);
|
|
_data.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));
|
|
}
|
|
}
|
|
|
|
void DcOptions::processFromList(const QVector<MTPDcOption> &options, bool overwrite) {
|
|
if (options.empty()) {
|
|
return;
|
|
}
|
|
|
|
auto idsChanged = std::vector<DcId>();
|
|
idsChanged.reserve(options.size());
|
|
auto shiftedIdsProcessed = std::vector<ShiftedDcId>();
|
|
shiftedIdsProcessed.reserve(options.size());
|
|
{
|
|
QWriteLocker lock(&_mutex);
|
|
if (overwrite) {
|
|
idsChanged.reserve(_data.size());
|
|
}
|
|
for (auto &mtpOption : options) {
|
|
if (mtpOption.type() != mtpc_dcOption) {
|
|
LOG(("Wrong type in DcOptions: %1").arg(mtpOption.type()));
|
|
continue;
|
|
}
|
|
|
|
auto &option = mtpOption.c_dcOption();
|
|
auto dcId = option.vid.v;
|
|
auto flags = option.vflags.v;
|
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
|
if (base::contains(shiftedIdsProcessed, dcIdWithShift)) {
|
|
continue;
|
|
}
|
|
|
|
shiftedIdsProcessed.push_back(dcIdWithShift);
|
|
auto &ip = option.vip_address.c_string().v;
|
|
auto port = option.vport.v;
|
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
|
if (!base::contains(idsChanged, dcId)) {
|
|
idsChanged.push_back(dcId);
|
|
}
|
|
}
|
|
}
|
|
if (overwrite && shiftedIdsProcessed.size() < _data.size()) {
|
|
for (auto i = _data.begin(); i != _data.end();) {
|
|
if (base::contains(shiftedIdsProcessed, i->first)) {
|
|
++i;
|
|
} else {
|
|
if (!base::contains(idsChanged, i->second.id)) {
|
|
idsChanged.push_back(i->second.id);
|
|
}
|
|
i = _data.erase(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!idsChanged.empty()) {
|
|
_changed.notify(std::move(idsChanged));
|
|
}
|
|
}
|
|
|
|
void DcOptions::setFromList(const MTPVector<MTPDcOption> &options) {
|
|
processFromList(options.c_vector().v, true);
|
|
}
|
|
|
|
void DcOptions::addFromList(const MTPVector<MTPDcOption> &options) {
|
|
processFromList(options.c_vector().v, false);
|
|
}
|
|
|
|
void DcOptions::addFromOther(const DcOptions &options) {
|
|
if (this == &options) {
|
|
return;
|
|
}
|
|
|
|
auto idsChanged = std::vector<DcId>();
|
|
{
|
|
QReadLocker lock(&options._mutex);
|
|
if (options._data.empty()) {
|
|
return;
|
|
}
|
|
|
|
idsChanged.reserve(options._data.size());
|
|
{
|
|
QWriteLocker lock(&_mutex);
|
|
for (auto &item : options._data) {
|
|
auto dcId = item.second.id;
|
|
auto flags = item.second.flags;
|
|
auto &ip = item.second.ip;
|
|
auto port = item.second.port;
|
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
|
if (!base::contains(idsChanged, dcId)) {
|
|
idsChanged.push_back(dcId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!idsChanged.empty()) {
|
|
_changed.notify(std::move(idsChanged));
|
|
}
|
|
}
|
|
|
|
void DcOptions::constructAddOne(int id, MTPDdcOption::Flags flags, const std::string &ip, int port) {
|
|
QWriteLocker lock(&_mutex);
|
|
applyOneGuarded(bareDcId(id), flags, ip, port);
|
|
}
|
|
|
|
bool DcOptions::applyOneGuarded(DcId dcId, MTPDdcOption::Flags flags, const std::string &ip, int port) {
|
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
|
auto i = _data.find(dcIdWithShift);
|
|
if (i != _data.cend()) {
|
|
if (i->second.ip == ip && i->second.port == port) {
|
|
return false;
|
|
}
|
|
i->second.ip = ip;
|
|
i->second.port = port;
|
|
} else {
|
|
_data.emplace(dcIdWithShift, Option(dcId, flags, ip, port));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QByteArray DcOptions::serialize() const {
|
|
QReadLocker lock(&_mutex);
|
|
|
|
auto size = sizeof(qint32);
|
|
for (auto &item : _data) {
|
|
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // id + flags + port
|
|
size += sizeof(qint32) + item.second.ip.size();
|
|
}
|
|
|
|
auto result = QByteArray();
|
|
result.reserve(size);
|
|
{
|
|
QBuffer buffer(&result);
|
|
if (!buffer.open(QIODevice::WriteOnly)) {
|
|
LOG(("MTP Error: Can't open data for DcOptions::serialize()"));
|
|
return result;
|
|
}
|
|
|
|
QDataStream stream(&buffer);
|
|
stream.setVersion(QDataStream::Qt_5_1);
|
|
stream << qint32(_data.size());
|
|
for (auto &item : _data) {
|
|
stream << qint32(item.second.id) << qint32(item.second.flags) << qint32(item.second.port);
|
|
stream << qint32(item.second.ip.size());
|
|
stream.writeRawData(item.second.ip.data(), item.second.ip.size());
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void DcOptions::constructFromSerialized(const QByteArray &serialized) {
|
|
auto readonly = serialized;
|
|
QBuffer buffer(&readonly);
|
|
if (!buffer.open(QIODevice::ReadOnly)) {
|
|
LOG(("MTP Error: Can't open data for DcOptions::constructFromSerialized()"));
|
|
return;
|
|
}
|
|
QDataStream stream(&buffer);
|
|
stream.setVersion(QDataStream::Qt_5_1);
|
|
qint32 count = 0;
|
|
stream >> count;
|
|
if (stream.status() != QDataStream::Ok) {
|
|
LOG(("MTP Error: Bad data for DcOptions::constructFromSerialized()"));
|
|
return;
|
|
}
|
|
|
|
QWriteLocker lock(&_mutex);
|
|
_data.clear();
|
|
for (auto i = 0; i != count; ++i) {
|
|
qint32 id = 0, flags = 0, port = 0, ipSize = 0;
|
|
stream >> id >> flags >> port >> ipSize;
|
|
std::string ip(ipSize, ' ');
|
|
stream.readRawData(&ip[0], ipSize);
|
|
|
|
if (stream.status() != QDataStream::Ok) {
|
|
LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
|
|
return;
|
|
}
|
|
|
|
applyOneGuarded(DcId(id), MTPDdcOption::Flags(flags), ip, port);
|
|
}
|
|
}
|
|
|
|
DcOptions::Ids DcOptions::sortedDcIds() const {
|
|
auto result = Ids();
|
|
{
|
|
QReadLocker lock(&_mutex);
|
|
result.reserve(_data.size());
|
|
for (auto &item : _data) {
|
|
if (!base::contains(result, item.second.id)) {
|
|
result.push_back(item.second.id);
|
|
}
|
|
}
|
|
}
|
|
std::sort(result.begin(), result.end());
|
|
return result;
|
|
}
|
|
|
|
DcId DcOptions::getDefaultDcId() const {
|
|
auto result = sortedDcIds();
|
|
t_assert(!result.empty());
|
|
|
|
return result[0];
|
|
}
|
|
|
|
DcOptions::Variants DcOptions::lookup(DcId dcId, DcType type) const {
|
|
auto isMediaDownload = (type == DcType::MediaDownload);
|
|
int shifts[2][2][4] = {
|
|
{ // IPv4
|
|
{ // TCP IPv4
|
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only) : -1,
|
|
qFlags(MTPDdcOption::Flag::f_tcpo_only),
|
|
isMediaDownload ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
|
0
|
|
}, { // HTTP IPv4
|
|
-1,
|
|
-1,
|
|
isMediaDownload ? qFlags(MTPDdcOption::Flag::f_media_only) : -1,
|
|
0
|
|
},
|
|
}, { // IPv6
|
|
{ // TCP IPv6
|
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
MTPDdcOption::Flag::f_tcpo_only | MTPDdcOption::Flag::f_ipv6,
|
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
qFlags(MTPDdcOption::Flag::f_ipv6)
|
|
}, { // HTTP IPv6
|
|
-1,
|
|
-1,
|
|
isMediaDownload ? (MTPDdcOption::Flag::f_media_only | MTPDdcOption::Flag::f_ipv6) : -1,
|
|
qFlags(MTPDdcOption::Flag::f_ipv6)
|
|
},
|
|
},
|
|
};
|
|
|
|
auto result = Variants();
|
|
{
|
|
QReadLocker lock(&_mutex);
|
|
for (auto address = 0; address != Variants::AddressTypeCount; ++address) {
|
|
for (auto protocol = 0; protocol != Variants::ProtocolCount; ++protocol) {
|
|
for (auto variant = 0; variant != base::array_size(shifts[address][protocol]); ++variant) {
|
|
auto shift = shifts[address][protocol][variant];
|
|
if (shift < 0) continue;
|
|
|
|
auto it = _data.find(shiftDcId(dcId, shift));
|
|
if (it != _data.cend()) {
|
|
result.data[address][protocol].ip = it->second.ip;
|
|
result.data[address][protocol].flags = it->second.flags;
|
|
result.data[address][protocol].port = it->second.port;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // namespace MTP
|