Better special config implementation.

This commit is contained in:
John Preston 2018-05-02 22:27:03 +03:00
parent 95fee543ec
commit 4bf66cb6e9
12 changed files with 200 additions and 85 deletions

View File

@ -107,8 +107,13 @@ new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long =
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait; http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
ipPort ipv4:int port:int = IpPort; //ipPort ipv4:int port:int = IpPort;
help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple; //help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
ipPort#d433ad73 ipv4:int port:int = IpPort;
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;
---functions--- ---functions---

View File

@ -57,6 +57,9 @@ parentFlagsCheck = {};
countedTypeIdExceptions = {}; countedTypeIdExceptions = {};
countedTypeIdExceptions[77] = countedTypeIdExceptions[78] = {} countedTypeIdExceptions[77] = countedTypeIdExceptions[78] = {}
countedTypeIdExceptions[77]['channel'] = countedTypeIdExceptions[78]['channel'] = True countedTypeIdExceptions[77]['channel'] = countedTypeIdExceptions[78]['channel'] = True
countedTypeIdExceptions['ipPortSecret'] = True
countedTypeIdExceptions['accessPointRule'] = True
countedTypeIdExceptions['help_configSimple'] = True
lines = []; lines = [];
layer = ''; layer = '';
@ -143,8 +146,9 @@ for line in lines:
typeid = '0x' + typeid; typeid = '0x' + typeid;
if (typeid != countTypeId): if (typeid != countTypeId):
if (not layerIndex in countedTypeIdExceptions or not name in countedTypeIdExceptions[layerIndex]): if (not layerIndex in countedTypeIdExceptions or not name in countedTypeIdExceptions[layerIndex]):
print('Warning: counted ' + countTypeId + ' mismatch with provided ' + typeid + ' (' + cleanline + ')'); if (not name in countedTypeIdExceptions):
continue; print('Warning: counted ' + countTypeId + ' mismatch with provided ' + typeid + ' (' + cleanline + ')');
continue;
else: else:
typeid = countTypeId; typeid = countTypeId;
@ -519,7 +523,9 @@ def addTextSerialize(lst, dct, dataLetter):
if (not vtypeget): if (not vtypeget):
result += '); vtypes.push_back(0'; result += '); vtypes.push_back(0';
else: else:
result += '0); vtypes.push_back(0'; if (not vtypeget):
result += '0';
result += '); vtypes.push_back(0';
result += '); stages.push_back(0); flags.push_back(0); '; result += '); stages.push_back(0); flags.push_back(0); ';
if (k in conditions): if (k in conditions):
result += '} else { to.add("[ SKIPPED BY BIT ' + conditions[k] + ' IN FIELD ' + hasFlags + ' ]"); } '; result += '} else { to.add("[ SKIPPED BY BIT ' + conditions[k] + ' IN FIELD ' + hasFlags + ' ]"); } ';

View File

@ -435,7 +435,11 @@ void UserData::setName(const QString &newFirstName, const QString &newLastName,
} }
void UserData::setPhone(const QString &newPhone) { void UserData::setPhone(const QString &newPhone) {
_phone = newPhone; if (_phone != newPhone) {
_phone = newPhone;
if (bareId() == Auth().userId()) {
}
}
} }
void UserData::setBotInfoVersion(int version) { void UserData::setBotInfoVersion(int version) {

View File

@ -390,7 +390,11 @@ void Messenger::setMtpAuthorization(const QByteArray &serialized) {
void Messenger::startMtp() { void Messenger::startMtp() {
Expects(!_mtproto); Expects(!_mtproto);
_mtproto = std::make_unique<MTP::Instance>(_dcOptions.get(), MTP::Instance::Mode::Normal, base::take(_private->mtpConfig)); _mtproto = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::Normal,
base::take(_private->mtpConfig));
_mtproto->setUserPhone(cLoggedPhoneNumber());
_private->mtpConfig.mainDcId = _mtproto->mainDcId(); _private->mtpConfig.mainDcId = _mtproto->mainDcId();
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId shiftedDcId, int32 state) { _mtproto->setStateChangedHandler([](MTP::ShiftedDcId shiftedDcId, int32 state) {
@ -489,6 +493,20 @@ void Messenger::startLocalStorage() {
} }
}); });
}); });
subscribe(Global::RefSelfChanged(), [=] {
InvokeQueued(this, [=] {
const auto phone = App::self()
? App::self()->phone()
: QString();
if (cLoggedPhoneNumber() != phone) {
cSetLoggedPhoneNumber(phone);
if (_mtproto) {
_mtproto->setUserPhone(phone);
}
Local::writeSettings();
}
});
});
} }
void Messenger::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) { void Messenger::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) {

View File

@ -22,9 +22,11 @@ constexpr auto kSpecialRequestTimeoutMs = 6000; // 4 seconds timeout for it to w
ConfigLoader::ConfigLoader( ConfigLoader::ConfigLoader(
not_null<Instance*> instance, not_null<Instance*> instance,
const QString &phone,
RPCDoneHandlerPtr onDone, RPCDoneHandlerPtr onDone,
RPCFailHandlerPtr onFail) RPCFailHandlerPtr onFail)
: _instance(instance) : _instance(instance)
, _phone(phone)
, _doneHandler(onDone) , _doneHandler(onDone)
, _failHandler(onFail) { , _failHandler(onFail) {
_enumDCTimer.setCallback([this] { enumerate(); }); _enumDCTimer.setCallback([this] { enumerate(); });
@ -96,24 +98,51 @@ void ConfigLoader::enumerate() {
_enumDCTimer.callOnce(kEnumerateDcTimeout); _enumDCTimer.callOnce(kEnumerateDcTimeout);
createSpecialLoader(); refreshSpecialLoader();
} }
void ConfigLoader::createSpecialLoader() { void ConfigLoader::refreshSpecialLoader() {
if (Global::UseProxy()) { if (Global::UseProxy()) {
_specialLoader.reset(); _specialLoader.reset();
return; return;
} }
if (!_specialLoader || (!_specialEnumRequest && _specialEndpoints.empty())) { if (!_specialLoader
_specialLoader = std::make_unique<SpecialConfigRequest>([this](DcId dcId, const std::string &ip, int port) { || (!_specialEnumRequest && _specialEndpoints.empty())) {
addSpecialEndpoint(dcId, ip, port); createSpecialLoader();
});
_triedSpecialEndpoints.clear();
} }
} }
void ConfigLoader::addSpecialEndpoint(DcId dcId, const std::string &ip, int port) { void ConfigLoader::setPhone(const QString &phone) {
auto endpoint = SpecialEndpoint { dcId, ip, port }; if (_phone != phone) {
_phone = phone;
if (_specialLoader) {
createSpecialLoader();
}
}
}
void ConfigLoader::createSpecialLoader() {
_triedSpecialEndpoints.clear();
_specialLoader = std::make_unique<SpecialConfigRequest>([=](
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret) {
addSpecialEndpoint(dcId, ip, port, secret);
}, _phone);
}
void ConfigLoader::addSpecialEndpoint(
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret) {
auto endpoint = SpecialEndpoint {
dcId,
ip,
port,
bytes::make_vector(secret)
};
if (base::contains(_specialEndpoints, endpoint) if (base::contains(_specialEndpoints, endpoint)
|| base::contains(_triedSpecialEndpoints, endpoint)) { || base::contains(_triedSpecialEndpoints, endpoint)) {
return; return;
@ -133,7 +162,7 @@ void ConfigLoader::sendSpecialRequest() {
return; return;
} }
if (_specialEndpoints.empty()) { if (_specialEndpoints.empty()) {
createSpecialLoader(); refreshSpecialLoader();
return; return;
} }

View File

@ -21,16 +21,26 @@ namespace internal {
class ConfigLoader : public base::has_weak_ptr { class ConfigLoader : public base::has_weak_ptr {
public: public:
ConfigLoader(not_null<Instance*> instance, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail); ConfigLoader(
not_null<Instance*> instance,
const QString &phone,
RPCDoneHandlerPtr onDone,
RPCFailHandlerPtr onFail);
~ConfigLoader(); ~ConfigLoader();
void load(); void load();
void setPhone(const QString &phone);
private: private:
mtpRequestId sendRequest(ShiftedDcId shiftedDcId); mtpRequestId sendRequest(ShiftedDcId shiftedDcId);
void addSpecialEndpoint(DcId dcId, const std::string &ip, int port); void addSpecialEndpoint(
DcId dcId,
const std::string &ip,
int port,
bytes::const_span secret);
void sendSpecialRequest(); void sendSpecialRequest();
void enumerate(); void enumerate();
void refreshSpecialLoader();
void createSpecialLoader(); void createSpecialLoader();
DcId specialToRealDcId(DcId specialDcId); DcId specialToRealDcId(DcId specialDcId);
void specialConfigLoaded(const MTPConfig &result); void specialConfigLoaded(const MTPConfig &result);
@ -55,6 +65,7 @@ private:
base::Timer _specialEnumTimer; base::Timer _specialEnumTimer;
DcId _specialEnumCurrent = 0; DcId _specialEnumCurrent = 0;
mtpRequestId _specialEnumRequest = 0; mtpRequestId _specialEnumRequest = 0;
QString _phone;
RPCDoneHandlerPtr _doneHandler; RPCDoneHandlerPtr _doneHandler;
RPCFailHandlerPtr _failHandler; RPCFailHandlerPtr _failHandler;

View File

@ -388,9 +388,13 @@ void ConnectionPrivate::appendTestConnection(
onDisconnected(weak); onDisconnected(weak);
}); });
const auto dcId = MTP::bareDcId(_shiftedDcId);
const auto simpleDcId = MTP::isTemporaryDcId(dcId)
? MTP::getRealIdFromTemporaryDcId(dcId)
: dcId;
const auto protocolDcId = (_dcType == DcType::MediaDownload) const auto protocolDcId = (_dcType == DcType::MediaDownload)
? -MTP::bareDcId(_shiftedDcId) ? -simpleDcId
: MTP::bareDcId(_shiftedDcId); : simpleDcId;
InvokeQueued(_testConnections.back().data, [=] { InvokeQueued(_testConnections.back().data, [=] {
weak->connectToServer(ip, port, protocolSecret, protocolDcId); weak->connectToServer(ip, port, protocolSecret, protocolDcId);
}); });

View File

@ -48,6 +48,7 @@ public:
void requestConfig(); void requestConfig();
void requestConfigIfOld(); void requestConfigIfOld();
void requestCDNConfig(); void requestCDNConfig();
void setUserPhone(const QString &phone);
void restart(); void restart();
void restart(ShiftedDcId shiftedDcId); void restart(ShiftedDcId shiftedDcId);
@ -156,6 +157,7 @@ private:
base::set_of_unique_ptr<internal::Connection> _quittingConnections; base::set_of_unique_ptr<internal::Connection> _quittingConnections;
std::unique_ptr<internal::ConfigLoader> _configLoader; std::unique_ptr<internal::ConfigLoader> _configLoader;
QString _userPhone;
mtpRequestId _cdnConfigLoadRequestId = 0; mtpRequestId _cdnConfigLoadRequestId = 0;
TimeMs _lastConfigLoadedTime = 0; TimeMs _lastConfigLoadedTime = 0;
@ -283,14 +285,23 @@ void Instance::Private::requestConfig() {
if (_configLoader || isKeysDestroyer()) { if (_configLoader || isKeysDestroyer()) {
return; return;
} }
_configLoader = std::make_unique<internal::ConfigLoader>(_instance, rpcDone([this](const MTPConfig &result) { _configLoader = std::make_unique<internal::ConfigLoader>(
configLoadDone(result); _instance,
}), rpcFail([this](const RPCError &error) { _userPhone,
return configLoadFail(error); rpcDone([=](const MTPConfig &result) { configLoadDone(result); }),
})); rpcFail([=](const RPCError &error) { return configLoadFail(error); }));
_configLoader->load(); _configLoader->load();
} }
void Instance::Private::setUserPhone(const QString &phone) {
if (_userPhone != phone) {
_userPhone = phone;
if (_configLoader) {
_configLoader->setPhone(_userPhone);
}
}
}
void Instance::Private::requestConfigIfOld() { void Instance::Private::requestConfigIfOld() {
if (getms(true) - _lastConfigLoadedTime >= kConfigBecomesOldIn) { if (getms(true) - _lastConfigLoadedTime >= kConfigBecomesOldIn) {
requestConfig(); requestConfig();
@ -1318,6 +1329,10 @@ void Instance::requestConfig() {
_private->requestConfig(); _private->requestConfig();
} }
void Instance::setUserPhone(const QString &phone) {
_private->setUserPhone(phone);
}
void Instance::requestConfigIfOld() { void Instance::requestConfigIfOld() {
_private->requestConfigIfOld(); _private->requestConfigIfOld();
} }

View File

@ -137,6 +137,7 @@ public:
void requestConfig(); void requestConfig();
void requestConfigIfOld(); void requestConfigIfOld();
void requestCDNConfig(); void requestCDNConfig();
void setUserPhone(const QString &phone);
~Instance(); ~Instance();

View File

@ -27,57 +27,58 @@ Y1hZCxdv6cs5UnW9+PWvS+WIbkh+GaWYxwIDAQAB\n\
-----END RSA PUBLIC KEY-----\ -----END RSA PUBLIC KEY-----\
"); ");
bool CheckPhoneByPrefixesRules(const QString &phone, const QString &rules) {
auto result = false;
for (const auto &prefix : rules.split(',')) {
if (prefix.isEmpty()) {
result = true;
} else if (prefix[0] == '+' && phone.startsWith(prefix.mid(1))) {
result = true;
} else if (prefix[0] == '-' && phone.startsWith(prefix.mid(1))) {
return false;
}
}
return result;
}
} // namespace } // namespace
SpecialConfigRequest::SpecialConfigRequest( SpecialConfigRequest::SpecialConfigRequest(
base::lambda<void( base::lambda<void(
DcId dcId, DcId dcId,
const std::string &ip, const std::string &ip,
int port)> callback) int port,
: _callback(std::move(callback)) { bytes::const_span secret)> callback,
performApp1Request(); const QString &phone)
performApp2Request(); : _callback(std::move(callback))
, _phone(phone) {
performAppRequest();
performDnsRequest(); performDnsRequest();
} }
void SpecialConfigRequest::performApp1Request() { void SpecialConfigRequest::performAppRequest() {
auto appUrl = QUrl();
appUrl.setScheme(qsl("https"));
appUrl.setHost(qsl("google.com"));
if (cTestMode()) {
appUrl.setPath(qsl("/test/"));
}
auto appRequest = QNetworkRequest(appUrl);
appRequest.setRawHeader("Host", "dns-telegram.appspot.com");
_app1Reply.reset(_manager.get(appRequest));
connect(_app1Reply.get(), &QNetworkReply::finished, this, [=] {
app1Finished();
});
}
void SpecialConfigRequest::performApp2Request() {
auto appUrl = QUrl(); auto appUrl = QUrl();
appUrl.setScheme(qsl("https")); appUrl.setScheme(qsl("https"));
appUrl.setHost(qsl("software-download.microsoft.com")); appUrl.setHost(qsl("software-download.microsoft.com"));
appUrl.setPath(cTestMode() appUrl.setPath(cTestMode()
? qsl("/test/config.txt") ? qsl("/test/config.txt")
: qsl("/prod/config.txt")); : qsl("/prodv2/config.txt"));
auto appRequest = QNetworkRequest(appUrl); auto appRequest = QNetworkRequest(appUrl);
appRequest.setRawHeader("Host", "tcdnb.azureedge.net"); appRequest.setRawHeader("Host", "tcdnb.azureedge.net");
_app2Reply.reset(_manager.get(appRequest)); _appReply.reset(_manager.get(appRequest));
connect(_app2Reply.get(), &QNetworkReply::finished, this, [=] { connect(_appReply.get(), &QNetworkReply::finished, this, [=] {
app2Finished(); appFinished();
}); });
} }
void SpecialConfigRequest::performDnsRequest() { void SpecialConfigRequest::performDnsRequest() {
auto dnsUrl = QUrl(); auto dnsUrl = QUrl();
dnsUrl.setScheme(qsl("https")); dnsUrl.setScheme(qsl("https"));
dnsUrl.setHost(qsl("google.com")); dnsUrl.setHost(qsl("www.google.com"));
dnsUrl.setPath(qsl("/resolve")); dnsUrl.setPath(qsl("/resolve"));
dnsUrl.setQuery( dnsUrl.setQuery(
qsl("name=%1.stel.com&type=16").arg( qsl("name=%1.stel.com&type=16").arg(
cTestMode() ? qsl("tap") : qsl("ap"))); cTestMode() ? qsl("tap") : qsl("apv2")));
auto dnsRequest = QNetworkRequest(QUrl(dnsUrl)); auto dnsRequest = QNetworkRequest(QUrl(dnsUrl));
dnsRequest.setRawHeader("Host", "dns.google.com"); dnsRequest.setRawHeader("Host", "dns.google.com");
_dnsReply.reset(_manager.get(dnsRequest)); _dnsReply.reset(_manager.get(dnsRequest));
@ -86,21 +87,12 @@ void SpecialConfigRequest::performDnsRequest() {
}); });
} }
void SpecialConfigRequest::app1Finished() { void SpecialConfigRequest::appFinished() {
if (!_app1Reply) { if (!_appReply) {
return; return;
} }
auto result = _app1Reply->readAll(); auto result = _appReply->readAll();
_app1Reply.release()->deleteLater(); _appReply.release()->deleteLater();
handleResponse(result);
}
void SpecialConfigRequest::app2Finished() {
if (!_app2Reply) {
return;
}
auto result = _app2Reply->readAll();
_app2Reply.release()->deleteLater();
handleResponse(result); handleResponse(result);
} }
@ -237,25 +229,50 @@ void SpecialConfigRequest::handleResponse(const QByteArray &bytes) {
LOG(("Config Error: Bad date frame for simple config: %1-%2, our time is %3.").arg(config.vdate.v).arg(config.vexpires.v).arg(now)); LOG(("Config Error: Bad date frame for simple config: %1-%2, our time is %3.").arg(config.vdate.v).arg(config.vexpires.v).arg(now));
return; return;
} }
if (config.vip_port_list.v.empty()) { if (config.vrules.v.empty()) {
LOG(("Config Error: Empty simple config received.")); LOG(("Config Error: Empty simple config received."));
return; return;
} }
for (auto &entry : config.vip_port_list.v) { for (auto &rule : config.vrules.v) {
Assert(entry.type() == mtpc_ipPort); Assert(rule.type() == mtpc_accessPointRule);
auto &ipPort = entry.c_ipPort(); auto &data = rule.c_accessPointRule();
auto ip = *reinterpret_cast<const uint32*>(&ipPort.vipv4.v); const auto phoneRules = qs(data.vphone_prefix_rules);
auto ipString = qsl("%1.%2.%3.%4").arg((ip >> 24) & 0xFF).arg((ip >> 16) & 0xFF).arg((ip >> 8) & 0xFF).arg(ip & 0xFF); if (!CheckPhoneByPrefixesRules(_phone, phoneRules)) {
_callback(config.vdc_id.v, ipString.toStdString(), ipPort.vport.v); continue;
}
const auto dcId = data.vdc_id.v;
for (const auto &address : data.vips.v) {
const auto parseIp = [](const MTPint &ipv4) {
const auto ip = *reinterpret_cast<const uint32*>(&ipv4.v);
return qsl("%1.%2.%3.%4"
).arg((ip >> 24) & 0xFF
).arg((ip >> 16) & 0xFF
).arg((ip >> 8) & 0xFF
).arg(ip & 0xFF).toStdString();
};
switch (address.type()) {
case mtpc_ipPort: {
const auto &fields = address.c_ipPort();
_callback(dcId, parseIp(fields.vipv4), fields.vport.v, {});
} break;
case mtpc_ipPortSecret: {
const auto &fields = address.c_ipPortSecret();
_callback(
dcId,
parseIp(fields.vipv4),
fields.vport.v,
bytes::make_span(fields.vsecret.v));
} break;
default: Unexpected("Type in simpleConfig ips.");
}
}
} }
} }
SpecialConfigRequest::~SpecialConfigRequest() { SpecialConfigRequest::~SpecialConfigRequest() {
if (_app1Reply) { if (_appReply) {
_app1Reply->abort(); _appReply->abort();
}
if (_app2Reply) {
_app2Reply->abort();
} }
if (_dnsReply) { if (_dnsReply) {
_dnsReply->abort(); _dnsReply->abort();

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/bytes.h"
namespace MTP { namespace MTP {
class SpecialConfigRequest : public QObject { class SpecialConfigRequest : public QObject {
@ -15,16 +17,16 @@ public:
base::lambda<void( base::lambda<void(
DcId dcId, DcId dcId,
const std::string &ip, const std::string &ip,
int port)> callback); int port,
bytes::const_span secret)> callback,
const QString &phone);
~SpecialConfigRequest(); ~SpecialConfigRequest();
private: private:
void performApp1Request(); void performAppRequest();
void performApp2Request();
void performDnsRequest(); void performDnsRequest();
void app1Finished(); void appFinished();
void app2Finished();
void dnsFinished(); void dnsFinished();
void handleResponse(const QByteArray &bytes); void handleResponse(const QByteArray &bytes);
bool decryptSimpleConfig(const QByteArray &bytes); bool decryptSimpleConfig(const QByteArray &bytes);
@ -32,12 +34,13 @@ private:
base::lambda<void( base::lambda<void(
DcId dcId, DcId dcId,
const std::string &ip, const std::string &ip,
int port)> _callback; int port,
bytes::const_span secret)> _callback;
QString _phone;
MTPhelp_ConfigSimple _simpleConfig; MTPhelp_ConfigSimple _simpleConfig;
QNetworkAccessManager _manager; QNetworkAccessManager _manager;
std::unique_ptr<QNetworkReply> _app1Reply; std::unique_ptr<QNetworkReply> _appReply;
std::unique_ptr<QNetworkReply> _app2Reply;
std::unique_ptr<QNetworkReply> _dnsReply; std::unique_ptr<QNetworkReply> _dnsReply;
std::unique_ptr<DcOptions> _localOptions; std::unique_ptr<DcOptions> _localOptions;

View File

@ -2443,6 +2443,7 @@ void writeSettings() {
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32)); quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized); size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized);
size += sizeof(quint32) + Serialize::stringSize(cLoggedPhoneNumber());
auto &proxies = Global::RefProxiesList(); auto &proxies = Global::RefProxiesList();
const auto &proxy = Global::SelectedProxy(); const auto &proxy = Global::SelectedProxy();
@ -2480,6 +2481,7 @@ void writeSettings() {
data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck()); data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck());
data.stream << quint32(dbiScale) << qint32(cConfigScale()); data.stream << quint32(dbiScale) << qint32(cConfigScale());
data.stream << quint32(dbiDcOptions) << dcOptionsSerialized; data.stream << quint32(dbiDcOptions) << dcOptionsSerialized;
data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber();
data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList); data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList);
data.stream << qint32(proxies.size()); data.stream << qint32(proxies.size());