mirror of https://github.com/procxx/kepka.git
Support many config endpoints for one dc+params.
This commit is contained in:
parent
7482025c10
commit
93f6d4b6e7
|
@ -38,4 +38,10 @@ QMap<QString, QString> url_parse_params(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_ipv6(const QString &ip) {
|
||||||
|
//static const auto regexp = QRegularExpression("^[a-fA-F0-9:]+$");
|
||||||
|
//return regexp.match(ip).hasMatch();
|
||||||
|
return ip.indexOf(':') >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace qthelp
|
} // namespace qthelp
|
||||||
|
|
|
@ -24,4 +24,6 @@ enum class UrlParamNameTransform {
|
||||||
// Parses a string like "p1=v1&p2=v2&..&pn=vn" to a map.
|
// Parses a string like "p1=v1&p2=v2&..&pn=vn" to a map.
|
||||||
QMap<QString, QString> url_parse_params(const QString ¶ms, UrlParamNameTransform transform = UrlParamNameTransform::NoTransform);
|
QMap<QString, QString> url_parse_params(const QString ¶ms, UrlParamNameTransform transform = UrlParamNameTransform::NoTransform);
|
||||||
|
|
||||||
|
bool is_ipv6(const QString &ip);
|
||||||
|
|
||||||
} // namespace qthelp
|
} // namespace qthelp
|
||||||
|
|
|
@ -17,12 +17,26 @@ QObject *TimersAdjuster() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Timer::Timer(base::lambda<void()> callback) : QObject(nullptr)
|
Timer::Timer(
|
||||||
|
not_null<QThread*> thread,
|
||||||
|
base::lambda<void()> callback)
|
||||||
|
: Timer(std::move(callback)) {
|
||||||
|
moveToThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timer::Timer(base::lambda<void()> callback)
|
||||||
|
: QObject(nullptr)
|
||||||
, _callback(std::move(callback))
|
, _callback(std::move(callback))
|
||||||
, _type(Qt::PreciseTimer)
|
, _type(Qt::PreciseTimer)
|
||||||
, _adjusted(false) {
|
, _adjusted(false) {
|
||||||
setRepeat(Repeat::Interval);
|
setRepeat(Repeat::Interval);
|
||||||
connect(TimersAdjuster(), &QObject::destroyed, this, [this] { adjust(); }, Qt::QueuedConnection);
|
connect(
|
||||||
|
TimersAdjuster(),
|
||||||
|
&QObject::destroyed,
|
||||||
|
this,
|
||||||
|
[this] { adjust(); },
|
||||||
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
|
void Timer::start(TimeMs timeout, Qt::TimerType type, Repeat repeat) {
|
||||||
|
@ -56,7 +70,11 @@ TimeMs Timer::remainingTime() const {
|
||||||
|
|
||||||
void Timer::Adjust() {
|
void Timer::Adjust() {
|
||||||
QObject emitter;
|
QObject emitter;
|
||||||
connect(&emitter, &QObject::destroyed, TimersAdjuster(), &QObject::destroyed);
|
connect(
|
||||||
|
&emitter,
|
||||||
|
&QObject::destroyed,
|
||||||
|
TimersAdjuster(),
|
||||||
|
&QObject::destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::adjust() {
|
void Timer::adjust() {
|
||||||
|
@ -70,6 +88,7 @@ void Timer::adjust() {
|
||||||
|
|
||||||
void Timer::setTimeout(TimeMs timeout) {
|
void Timer::setTimeout(TimeMs timeout) {
|
||||||
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
|
Expects(timeout >= 0 && timeout <= std::numeric_limits<int>::max());
|
||||||
|
|
||||||
_timeout = static_cast<unsigned int>(timeout);
|
_timeout = static_cast<unsigned int>(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +112,12 @@ void Timer::timerEvent(QTimerEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type) {
|
int DelayedCallTimer::call(
|
||||||
|
TimeMs timeout,
|
||||||
|
lambda_once<void()> callback,
|
||||||
|
Qt::TimerType type) {
|
||||||
Expects(timeout >= 0);
|
Expects(timeout >= 0);
|
||||||
|
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +131,7 @@ int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::Tim
|
||||||
void DelayedCallTimer::cancel(int callId) {
|
void DelayedCallTimer::cancel(int callId) {
|
||||||
if (callId) {
|
if (callId) {
|
||||||
killTimer(callId);
|
killTimer(callId);
|
||||||
_callbacks.erase(callId);
|
_callbacks.remove(callId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ namespace base {
|
||||||
|
|
||||||
class Timer final : private QObject {
|
class Timer final : private QObject {
|
||||||
public:
|
public:
|
||||||
Timer(base::lambda<void()> callback = base::lambda<void()>());
|
explicit Timer(
|
||||||
|
not_null<QThread*> thread,
|
||||||
|
base::lambda<void()> callback = nullptr);
|
||||||
|
explicit Timer(base::lambda<void()> callback = nullptr);
|
||||||
|
|
||||||
static Qt::TimerType DefaultType(TimeMs timeout) {
|
static Qt::TimerType DefaultType(TimeMs timeout) {
|
||||||
constexpr auto kThreshold = TimeMs(1000);
|
constexpr auto kThreshold = TimeMs(1000);
|
||||||
|
@ -85,17 +88,23 @@ private:
|
||||||
class DelayedCallTimer final : private QObject {
|
class DelayedCallTimer final : private QObject {
|
||||||
public:
|
public:
|
||||||
int call(TimeMs timeout, lambda_once<void()> callback) {
|
int call(TimeMs timeout, lambda_once<void()> callback) {
|
||||||
return call(timeout, std::move(callback), Timer::DefaultType(timeout));
|
return call(
|
||||||
|
timeout,
|
||||||
|
std::move(callback),
|
||||||
|
Timer::DefaultType(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
int call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type);
|
int call(
|
||||||
|
TimeMs timeout,
|
||||||
|
lambda_once<void()> callback,
|
||||||
|
Qt::TimerType type);
|
||||||
void cancel(int callId);
|
void cancel(int callId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent *e) override;
|
void timerEvent(QTimerEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<int, lambda_once<void()>> _callbacks; // Better to use flatmap.
|
base::flat_map<int, lambda_once<void()>> _callbacks;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ bool ConnectionBox::badProxyValue() const {
|
||||||
|
|
||||||
void ConnectionBox::updateControlsVisibility() {
|
void ConnectionBox::updateControlsVisibility() {
|
||||||
auto newHeight = st::boxOptionListPadding.top() + _autoRadio->heightNoMargins() + st::boxOptionListSkip + _httpProxyRadio->heightNoMargins() + st::boxOptionListSkip + _tcpProxyRadio->heightNoMargins() + st::boxOptionListSkip + st::connectionIPv6Skip + _tryIPv6->heightNoMargins() + st::defaultCheckbox.margin.bottom() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom();
|
auto newHeight = st::boxOptionListPadding.top() + _autoRadio->heightNoMargins() + st::boxOptionListSkip + _httpProxyRadio->heightNoMargins() + st::boxOptionListSkip + _tcpProxyRadio->heightNoMargins() + st::boxOptionListSkip + st::connectionIPv6Skip + _tryIPv6->heightNoMargins() + st::defaultCheckbox.margin.bottom() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom();
|
||||||
if (_typeGroup->value() == dbictAuto && badProxyValue()) {
|
if (!proxyFieldsVisible()) {
|
||||||
_hostInput->hide();
|
_hostInput->hide();
|
||||||
_portInput->hide();
|
_portInput->hide();
|
||||||
_userInput->hide();
|
_userInput->hide();
|
||||||
|
@ -104,6 +104,13 @@ void ConnectionBox::updateControlsVisibility() {
|
||||||
updateControlsPosition();
|
updateControlsPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ConnectionBox::proxyFieldsVisible() const {
|
||||||
|
return (_typeGroup->value() != dbictAuto)
|
||||||
|
|| (!badProxyValue()
|
||||||
|
&& (_currentProxyType == ProxyData::Type::Http
|
||||||
|
|| _currentProxyType == ProxyData::Type::Socks5));
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionBox::setInnerFocus() {
|
void ConnectionBox::setInnerFocus() {
|
||||||
if (_typeGroup->value() == dbictAuto) {
|
if (_typeGroup->value() == dbictAuto) {
|
||||||
setFocus();
|
setFocus();
|
||||||
|
@ -124,7 +131,7 @@ void ConnectionBox::updateControlsPosition() {
|
||||||
_httpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio->bottomNoMargins() + st::boxOptionListSkip);
|
_httpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio->bottomNoMargins() + st::boxOptionListSkip);
|
||||||
|
|
||||||
auto inputy = 0;
|
auto inputy = 0;
|
||||||
auto fieldsVisible = (type != dbictAuto) || (!badProxyValue() && _currentProxyType != ProxyData::Type::None);
|
auto fieldsVisible = proxyFieldsVisible();
|
||||||
auto fieldsBelowHttp = fieldsVisible && (type == dbictHttpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Http));
|
auto fieldsBelowHttp = fieldsVisible && (type == dbictHttpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Http));
|
||||||
auto fieldsBelowTcp = fieldsVisible && (type == dbictTcpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Socks5));
|
auto fieldsBelowTcp = fieldsVisible && (type == dbictTcpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Socks5));
|
||||||
if (fieldsBelowHttp) {
|
if (fieldsBelowHttp) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ private:
|
||||||
void updateControlsVisibility();
|
void updateControlsVisibility();
|
||||||
void updateControlsPosition();
|
void updateControlsPosition();
|
||||||
bool badProxyValue() const;
|
bool badProxyValue() const;
|
||||||
|
bool proxyFieldsVisible() const;
|
||||||
|
|
||||||
object_ptr<Ui::InputField> _hostInput;
|
object_ptr<Ui::InputField> _hostInput;
|
||||||
object_ptr<Ui::PortInput> _portInput;
|
object_ptr<Ui::PortInput> _portInput;
|
||||||
|
|
|
@ -25,13 +25,6 @@ enum {
|
||||||
MTPAckSendWaiting = 10000, // how much time to wait for some more requests, when sending msg acks
|
MTPAckSendWaiting = 10000, // how much time to wait for some more requests, when sending msg acks
|
||||||
MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state
|
MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state
|
||||||
MTPContainerLives = 600, // container lives 10 minutes in haveSent map
|
MTPContainerLives = 600, // container lives 10 minutes in haveSent map
|
||||||
MTPMinReceiveDelay = 4000, // 4 seconds
|
|
||||||
MTPMaxReceiveDelay = 64000, // 64 seconds
|
|
||||||
MTPMinConnectDelay = 1000, // tcp connect should take less then 1 second
|
|
||||||
MTPMaxConnectDelay = 8000, // tcp connect should take 8 seconds max
|
|
||||||
MTPConnectionOldTimeout = 192000, // 192 seconds
|
|
||||||
MTPTcpConnectionWaitTimeout = 2000, // 2 seconds waiting for tcp, until we accept http
|
|
||||||
MTPIPv4ConnectionWaitTimeout = 1000, // 1 seconds waiting for ipv4, until we accept ipv6
|
|
||||||
|
|
||||||
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
|
MTPKillFileSessionTimeout = 5000, // how much time without upload / download causes additional session kill
|
||||||
|
|
||||||
|
@ -39,10 +32,6 @@ enum {
|
||||||
|
|
||||||
MaxUsersPerInvite = 100, // max users in one super group invite request
|
MaxUsersPerInvite = 100, // max users in one super group invite request
|
||||||
|
|
||||||
MTPPingDelayDisconnect = 60, // 1 min
|
|
||||||
MTPPingSendAfterAuto = 30, // send new ping starting from 30 seconds (add to existing container)
|
|
||||||
MTPPingSendAfter = 45, // send new ping after 45 seconds without ping
|
|
||||||
|
|
||||||
MTPChannelGetDifferenceLimit = 100,
|
MTPChannelGetDifferenceLimit = 100,
|
||||||
|
|
||||||
MaxSelectedItems = 100,
|
MaxSelectedItems = 100,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "mtproto/auth_key.h"
|
#include "mtproto/auth_key.h"
|
||||||
#include "mtproto/dc_options.h"
|
#include "mtproto/dc_options.h"
|
||||||
#include "core/single_timer.h"
|
#include "mtproto/connection_abstract.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ public:
|
||||||
HttpConnection
|
HttpConnection
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection(Instance *instance);
|
Connection(not_null<Instance*> instance);
|
||||||
|
|
||||||
void start(SessionData *data, ShiftedDcId shiftedDcId);
|
void start(SessionData *data, ShiftedDcId shiftedDcId);
|
||||||
|
|
||||||
|
@ -71,9 +72,9 @@ public:
|
||||||
QString transport() const;
|
QString transport() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Instance *_instance = nullptr;
|
not_null<Instance*> _instance;
|
||||||
std::unique_ptr<QThread> thread;
|
std::unique_ptr<QThread> _thread;
|
||||||
ConnectionPrivate *data = nullptr;
|
ConnectionPrivate *_private = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,7 +82,12 @@ class ConnectionPrivate : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, ShiftedDcId shiftedDcId);
|
ConnectionPrivate(
|
||||||
|
not_null<Instance*> instance,
|
||||||
|
not_null<QThread*> thread,
|
||||||
|
not_null<Connection*> owner,
|
||||||
|
not_null<SessionData*> data,
|
||||||
|
ShiftedDcId shiftedDcId);
|
||||||
~ConnectionPrivate();
|
~ConnectionPrivate();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -109,29 +115,15 @@ signals:
|
||||||
void finished(internal::Connection *connection);
|
void finished(internal::Connection *connection);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void retryByTimer();
|
|
||||||
void restartNow();
|
void restartNow();
|
||||||
|
|
||||||
void onPingSender();
|
|
||||||
void onPingSendForce();
|
void onPingSendForce();
|
||||||
|
|
||||||
void onWaitConnectedFailed();
|
|
||||||
void onWaitReceivedFailed();
|
|
||||||
void onWaitIPv4Failed();
|
|
||||||
|
|
||||||
void onOldConnection();
|
|
||||||
void onSentSome(uint64 size);
|
void onSentSome(uint64 size);
|
||||||
void onReceivedSome();
|
void onReceivedSome();
|
||||||
|
|
||||||
void onReadyData();
|
void onReadyData();
|
||||||
|
|
||||||
void onConnected4();
|
|
||||||
void onConnected6();
|
|
||||||
void onDisconnected4();
|
|
||||||
void onDisconnected6();
|
|
||||||
void onError4(qint32 errorCode);
|
|
||||||
void onError6(qint32 errorCode);
|
|
||||||
|
|
||||||
// Auth key creation packet receive slots
|
// Auth key creation packet receive slots
|
||||||
void pqAnswered();
|
void pqAnswered();
|
||||||
void dhParamsAnswered();
|
void dhParamsAnswered();
|
||||||
|
@ -149,16 +141,32 @@ public slots:
|
||||||
void onCDNConfigLoaded();
|
void onCDNConfigLoaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct TestConnection {
|
||||||
|
ConnectionPointer data;
|
||||||
|
int priority = 0;
|
||||||
|
};
|
||||||
void connectToServer(bool afterConfig = false);
|
void connectToServer(bool afterConfig = false);
|
||||||
void doDisconnect();
|
void doDisconnect();
|
||||||
void restart();
|
void restart();
|
||||||
void finishAndDestroy();
|
void finishAndDestroy();
|
||||||
void requestCDNConfig();
|
void requestCDNConfig();
|
||||||
void handleError(int errorCode);
|
void handleError(int errorCode);
|
||||||
|
void onError(
|
||||||
|
not_null<AbstractConnection*> connection,
|
||||||
|
qint32 errorCode);
|
||||||
|
void onConnected(not_null<AbstractConnection*> connection);
|
||||||
|
void onDisconnected(not_null<AbstractConnection*> connection);
|
||||||
|
|
||||||
|
void retryByTimer();
|
||||||
|
void waitConnectedFailed();
|
||||||
|
void waitReceivedFailed();
|
||||||
|
void waitBetterFailed();
|
||||||
|
void markConnectionOld();
|
||||||
|
void sendPingByTimer();
|
||||||
|
|
||||||
void createConn(bool createIPv4, bool createIPv6);
|
|
||||||
void destroyAllConnections();
|
void destroyAllConnections();
|
||||||
void destroyConnection(AbstractConnection *&connection);
|
void confirmBestConnection();
|
||||||
|
void removeTestConnection(not_null<AbstractConnection*> connection);
|
||||||
|
|
||||||
mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req);
|
mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req);
|
||||||
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
|
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
|
||||||
|
@ -183,6 +191,26 @@ private:
|
||||||
|
|
||||||
base::byte_vector encryptPQInnerRSA(const MTPP_Q_inner_data &data, const MTP::internal::RSAPublicKey &key);
|
base::byte_vector encryptPQInnerRSA(const MTPP_Q_inner_data &data, const MTP::internal::RSAPublicKey &key);
|
||||||
std::string encryptClientDHInner(const MTPClient_DH_Inner_Data &data);
|
std::string encryptClientDHInner(const MTPClient_DH_Inner_Data &data);
|
||||||
|
void appendTestConnection(
|
||||||
|
DcOptions::Variants::Protocol protocol,
|
||||||
|
const QString &ip,
|
||||||
|
int port,
|
||||||
|
const bytes::vector &protocolSecret);
|
||||||
|
|
||||||
|
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
|
||||||
|
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
|
||||||
|
|
||||||
|
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
|
||||||
|
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
|
||||||
|
|
||||||
|
void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
|
||||||
|
void resendMany(QVector<quint64> msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
|
||||||
|
|
||||||
|
template <typename TRequest>
|
||||||
|
void sendRequestNotSecure(const TRequest &request);
|
||||||
|
|
||||||
|
template <typename TResponse>
|
||||||
|
bool readResponseNotSecure(TResponse &response);
|
||||||
|
|
||||||
Instance *_instance = nullptr;
|
Instance *_instance = nullptr;
|
||||||
DcType _dcType = DcType::Regular;
|
DcType _dcType = DcType::Regular;
|
||||||
|
@ -194,45 +222,32 @@ private:
|
||||||
void resetSession();
|
void resetSession();
|
||||||
|
|
||||||
ShiftedDcId _shiftedDcId = 0;
|
ShiftedDcId _shiftedDcId = 0;
|
||||||
Connection *_owner = nullptr;
|
not_null<Connection*> _owner;
|
||||||
AbstractConnection *_conn = nullptr;
|
ConnectionPointer _connection;
|
||||||
AbstractConnection *_conn4 = nullptr;
|
std::vector<TestConnection> _testConnections;
|
||||||
AbstractConnection *_conn6 = nullptr;
|
|
||||||
TimeMs _configWasFineAt = 0;
|
TimeMs _configWasFineAt = 0;
|
||||||
|
|
||||||
SingleTimer retryTimer; // exp retry timer
|
base::Timer _retryTimer; // exp retry timer
|
||||||
int retryTimeout = 1;
|
int _retryTimeout = 1;
|
||||||
qint64 retryWillFinish;
|
qint64 _retryWillFinish = 0;
|
||||||
|
|
||||||
SingleTimer oldConnectionTimer;
|
base::Timer _oldConnectionTimer;
|
||||||
bool oldConnection = true;
|
bool _oldConnection = true;
|
||||||
|
|
||||||
SingleTimer _waitForConnectedTimer, _waitForReceivedTimer, _waitForIPv4Timer;
|
base::Timer _waitForConnectedTimer;
|
||||||
uint32 _waitForReceived, _waitForConnected;
|
base::Timer _waitForReceivedTimer;
|
||||||
|
base::Timer _waitForBetterTimer;
|
||||||
|
uint32 _waitForReceived = 0;
|
||||||
|
uint32 _waitForConnected = 0;
|
||||||
TimeMs firstSentAt = -1;
|
TimeMs firstSentAt = -1;
|
||||||
|
|
||||||
QVector<MTPlong> ackRequestData, resendRequestData;
|
QVector<MTPlong> ackRequestData, resendRequestData;
|
||||||
|
|
||||||
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
|
|
||||||
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
|
|
||||||
|
|
||||||
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
|
|
||||||
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
|
|
||||||
|
|
||||||
mtpPingId _pingId = 0;
|
mtpPingId _pingId = 0;
|
||||||
mtpPingId _pingIdToSend = 0;
|
mtpPingId _pingIdToSend = 0;
|
||||||
TimeMs _pingSendAt = 0;
|
TimeMs _pingSendAt = 0;
|
||||||
mtpMsgId _pingMsgId = 0;
|
mtpMsgId _pingMsgId = 0;
|
||||||
SingleTimer _pingSender;
|
base::Timer _pingSender;
|
||||||
|
|
||||||
void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
|
|
||||||
void resendMany(QVector<quint64> msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
|
|
||||||
|
|
||||||
template <typename TRequest>
|
|
||||||
void sendRequestNotSecure(const TRequest &request);
|
|
||||||
|
|
||||||
template <typename TResponse>
|
|
||||||
bool readResponseNotSecure(TResponse &response);
|
|
||||||
|
|
||||||
bool restarted = false;
|
bool restarted = false;
|
||||||
bool _finished = false;
|
bool _finished = false;
|
||||||
|
|
|
@ -9,12 +9,71 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "mtproto/connection_tcp.h"
|
#include "mtproto/connection_tcp.h"
|
||||||
#include "mtproto/connection_http.h"
|
#include "mtproto/connection_http.h"
|
||||||
#include "mtproto/connection_auto.h"
|
|
||||||
#include "mtproto/session.h"
|
#include "mtproto/session.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
ConnectionPointer::ConnectionPointer() = default;
|
||||||
|
|
||||||
|
ConnectionPointer::ConnectionPointer(std::nullptr_t) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer::ConnectionPointer(AbstractConnection *value)
|
||||||
|
: _value(value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer::ConnectionPointer(ConnectionPointer &&other)
|
||||||
|
: _value(base::take(other._value)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer &ConnectionPointer::operator=(ConnectionPointer &&other) {
|
||||||
|
reset(base::take(other._value));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractConnection *ConnectionPointer::get() const {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPointer::reset(AbstractConnection *value) {
|
||||||
|
if (_value == value) {
|
||||||
|
return;
|
||||||
|
} else if (const auto old = base::take(_value)) {
|
||||||
|
const auto disconnect = [&](auto signal) {
|
||||||
|
old->disconnect(old, signal, nullptr, nullptr);
|
||||||
|
};
|
||||||
|
disconnect(&AbstractConnection::receivedData);
|
||||||
|
disconnect(&AbstractConnection::receivedSome);
|
||||||
|
disconnect(&AbstractConnection::error);
|
||||||
|
disconnect(&AbstractConnection::connected);
|
||||||
|
disconnect(&AbstractConnection::disconnected);
|
||||||
|
old->disconnectFromServer();
|
||||||
|
old->deleteLater();
|
||||||
|
}
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer::operator AbstractConnection*() const {
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractConnection *ConnectionPointer::operator->() const {
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractConnection &ConnectionPointer::operator*() const {
|
||||||
|
return *get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer::operator bool() const {
|
||||||
|
return get() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPointer::~ConnectionPointer() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
AbstractConnection::~AbstractConnection() {
|
AbstractConnection::~AbstractConnection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +122,14 @@ MTPResPQ AbstractConnection::readPQFakeReply(const mtpBuffer &buffer) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractConnection *AbstractConnection::create(
|
ConnectionPointer AbstractConnection::create(
|
||||||
const ConnectionOptions &options,
|
DcOptions::Variants::Protocol protocol,
|
||||||
ShiftedDcId shiftedDcId,
|
|
||||||
DcType type,
|
|
||||||
QThread *thread) {
|
QThread *thread) {
|
||||||
const auto protocolDcId = (type == DcType::MediaDownload)
|
if (protocol == DcOptions::Variants::Tcp) {
|
||||||
? -MTP::bareDcId(shiftedDcId)
|
return ConnectionPointer(new TCPConnection(thread));
|
||||||
: MTP::bareDcId(shiftedDcId);
|
} else {
|
||||||
if ((type == DcType::Temporary) || (!options.useHttp)) {
|
return ConnectionPointer(new HTTPConnection(thread));
|
||||||
return new TCPConnection(thread, protocolDcId);
|
|
||||||
} else if (!options.useTcp) {
|
|
||||||
return new HTTPConnection(thread);
|
|
||||||
}
|
}
|
||||||
return new AutoConnection(thread, protocolDcId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -8,12 +8,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "mtproto/dc_options.h"
|
#include "mtproto/dc_options.h"
|
||||||
|
#include "base/bytes.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
struct ConnectionOptions;
|
struct ConnectionOptions;
|
||||||
|
|
||||||
|
class AbstractConnection;
|
||||||
|
|
||||||
|
class ConnectionPointer {
|
||||||
|
public:
|
||||||
|
ConnectionPointer();
|
||||||
|
ConnectionPointer(std::nullptr_t);
|
||||||
|
explicit ConnectionPointer(AbstractConnection *value);
|
||||||
|
ConnectionPointer(ConnectionPointer &&other);
|
||||||
|
ConnectionPointer &operator=(ConnectionPointer &&other);
|
||||||
|
|
||||||
|
AbstractConnection *get() const;
|
||||||
|
void reset(AbstractConnection *value = nullptr);
|
||||||
|
operator AbstractConnection*() const;
|
||||||
|
AbstractConnection *operator->() const;
|
||||||
|
AbstractConnection &operator*() const;
|
||||||
|
explicit operator bool() const;
|
||||||
|
|
||||||
|
~ConnectionPointer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractConnection *_value = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class AbstractConnection : public QObject {
|
class AbstractConnection : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -26,10 +51,8 @@ public:
|
||||||
virtual ~AbstractConnection() = 0;
|
virtual ~AbstractConnection() = 0;
|
||||||
|
|
||||||
// virtual constructor
|
// virtual constructor
|
||||||
static AbstractConnection *create(
|
static ConnectionPointer create(
|
||||||
const ConnectionOptions &options,
|
DcOptions::Variants::Protocol protocol,
|
||||||
ShiftedDcId shiftedDcId,
|
|
||||||
DcType type,
|
|
||||||
QThread *thread);
|
QThread *thread);
|
||||||
|
|
||||||
void setSentEncrypted() {
|
void setSentEncrypted() {
|
||||||
|
@ -38,8 +61,11 @@ public:
|
||||||
|
|
||||||
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
||||||
virtual void disconnectFromServer() = 0;
|
virtual void disconnectFromServer() = 0;
|
||||||
virtual void connectTcp(const DcOptions::Endpoint &endpoint) = 0;
|
virtual void connectToServer(
|
||||||
virtual void connectHttp(const DcOptions::Endpoint &endpoint) = 0;
|
const QString &ip,
|
||||||
|
int port,
|
||||||
|
const bytes::vector &protocolSecret,
|
||||||
|
int16 protocolDcId) = 0;
|
||||||
virtual bool isConnected() const = 0;
|
virtual bool isConnected() const = 0;
|
||||||
virtual bool usingHttpWait() {
|
virtual bool usingHttpWait() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -51,6 +77,7 @@ public:
|
||||||
virtual int32 debugState() const = 0;
|
virtual int32 debugState() const = 0;
|
||||||
|
|
||||||
virtual QString transport() const = 0;
|
virtual QString transport() const = 0;
|
||||||
|
virtual QString tag() const = 0;
|
||||||
|
|
||||||
using BuffersQueue = std::deque<mtpBuffer>;
|
using BuffersQueue = std::deque<mtpBuffer>;
|
||||||
BuffersQueue &received() {
|
BuffersQueue &received() {
|
||||||
|
|
|
@ -1,323 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#include "mtproto/connection_auto.h"
|
|
||||||
|
|
||||||
#include "mtproto/connection_http.h"
|
|
||||||
|
|
||||||
namespace MTP {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
AutoConnection::AutoConnection(QThread *thread, int16 protocolDcId)
|
|
||||||
: AbstractTCPConnection(thread, protocolDcId)
|
|
||||||
, status(WaitingBoth)
|
|
||||||
, tcpNonce(rand_value<MTPint128>())
|
|
||||||
, httpNonce(rand_value<MTPint128>())
|
|
||||||
, _flagsTcp(0)
|
|
||||||
, _flagsHttp(0)
|
|
||||||
, _tcpTimeout(MTPMinReceiveDelay) {
|
|
||||||
manager.moveToThread(thread);
|
|
||||||
|
|
||||||
httpStartTimer.moveToThread(thread);
|
|
||||||
httpStartTimer.setSingleShot(true);
|
|
||||||
connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart()));
|
|
||||||
|
|
||||||
tcpTimeoutTimer.moveToThread(thread);
|
|
||||||
tcpTimeoutTimer.setSingleShot(true);
|
|
||||||
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
|
||||||
|
|
||||||
sock.moveToThread(thread);
|
|
||||||
connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
|
|
||||||
connect(&sock, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
|
||||||
connect(&sock, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::onHttpStart() {
|
|
||||||
if (status == HttpReady) {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by timer").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
emit connected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::onSocketConnected() {
|
|
||||||
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
|
||||||
mtpBuffer buffer(preparePQFake(tcpNonce));
|
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flagsTcp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
|
|
||||||
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
|
||||||
tcpTimeoutTimer.start(_tcpTimeout);
|
|
||||||
|
|
||||||
tcpSend(buffer);
|
|
||||||
} else if (status == WaitingHttp || status == UsingHttp) {
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::onTcpTimeoutTimer() {
|
|
||||||
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
|
||||||
if (_tcpTimeout < MTPMaxReceiveDelay) _tcpTimeout *= 2;
|
|
||||||
_tcpTimeout = -_tcpTimeout;
|
|
||||||
|
|
||||||
QAbstractSocket::SocketState state = sock.state();
|
|
||||||
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
} else if (state != QAbstractSocket::ClosingState) {
|
|
||||||
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::onSocketDisconnected() {
|
|
||||||
if (_tcpTimeout < 0) {
|
|
||||||
_tcpTimeout = -_tcpTimeout;
|
|
||||||
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
|
||||||
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingHttp;
|
|
||||||
} else if (status == WaitingTcp || status == UsingTcp) {
|
|
||||||
emit disconnected();
|
|
||||||
} else if (status == HttpReady) {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by socket disconnect").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
emit connected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::sendData(mtpBuffer &buffer) {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
|
|
||||||
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(kErrorCodeOther);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == UsingTcp) {
|
|
||||||
tcpSend(buffer);
|
|
||||||
} else {
|
|
||||||
httpSend(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::httpSend(mtpBuffer &buffer) {
|
|
||||||
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
|
||||||
|
|
||||||
QNetworkRequest request(address);
|
|
||||||
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
|
||||||
|
|
||||||
TCP_LOG(("HTTP Info: sending %1 len request").arg(requestSize));
|
|
||||||
requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::disconnectFromServer() {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
status = FinishedWork;
|
|
||||||
|
|
||||||
Requests copy = requests;
|
|
||||||
requests.clear();
|
|
||||||
for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) {
|
|
||||||
(*i)->abort();
|
|
||||||
(*i)->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
|
||||||
|
|
||||||
address = QUrl();
|
|
||||||
|
|
||||||
disconnect(&sock, SIGNAL(readyRead()), 0, 0);
|
|
||||||
sock.close();
|
|
||||||
|
|
||||||
httpStartTimer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
|
|
||||||
_addrTcp = QString::fromStdString(endpoint.ip);
|
|
||||||
_portTcp = endpoint.port;
|
|
||||||
_flagsTcp = endpoint.flags;
|
|
||||||
|
|
||||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
|
||||||
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
|
|
||||||
_addrHttp = QString::fromStdString(endpoint.ip);
|
|
||||||
_portHttp = endpoint.port;
|
|
||||||
_flagsHttp = endpoint.flags;
|
|
||||||
|
|
||||||
// not endpoint.port - always 80 port for http transport
|
|
||||||
address = QUrl(((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(_addrHttp).arg(80));
|
|
||||||
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
|
||||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
|
||||||
|
|
||||||
mtpBuffer buffer(preparePQFake(httpNonce));
|
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
|
|
||||||
httpSend(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AutoConnection::isConnected() const {
|
|
||||||
return (status == UsingTcp) || (status == UsingHttp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::requestFinished(QNetworkReply *reply) {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
|
|
||||||
reply->deleteLater();
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
|
||||||
requests.remove(reply);
|
|
||||||
|
|
||||||
mtpBuffer data = HTTPConnection::handleResponse(reply);
|
|
||||||
if (data.size() == 1) {
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingTcp;
|
|
||||||
} else {
|
|
||||||
emit error(data[0]);
|
|
||||||
}
|
|
||||||
} else if (!data.isEmpty()) {
|
|
||||||
if (status == UsingHttp) {
|
|
||||||
_receivedQueue.push_back(data);
|
|
||||||
emit receivedData();
|
|
||||||
} else if (status == WaitingBoth || status == WaitingHttp) {
|
|
||||||
try {
|
|
||||||
auto res_pq = readPQFakeReply(data);
|
|
||||||
const auto &res_pq_data(res_pq.c_resPQ());
|
|
||||||
if (res_pq_data.vnonce == httpNonce) {
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = HttpReady;
|
|
||||||
httpStartTimer.start(MTPTcpConnectionWaitTimeout);
|
|
||||||
} else {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by pq-response, awaited").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
emit connected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception &e) {
|
|
||||||
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingTcp;
|
|
||||||
} else {
|
|
||||||
emit error(kErrorCodeOther);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (status == UsingTcp) {
|
|
||||||
DEBUG_LOG(("Connection Info: already using tcp, ignoring http response"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!requests.remove(reply)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingTcp;
|
|
||||||
} else if (status == WaitingHttp || status == UsingHttp) {
|
|
||||||
emit error(HTTPConnection::handleError(reply));
|
|
||||||
} else {
|
|
||||||
LOG(("Strange Http Error: status %1").arg(status));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::socketPacket(const char *packet, uint32 length) {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
|
|
||||||
mtpBuffer data = AbstractTCPConnection::handleResponse(packet, length);
|
|
||||||
if (data.size() == 1) {
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
} else if (status == HttpReady) {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, ready").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
emit connected();
|
|
||||||
} else if (status == WaitingTcp || status == UsingTcp) {
|
|
||||||
emit error(data[0]);
|
|
||||||
} else {
|
|
||||||
LOG(("Strange Tcp Error; status %1").arg(status));
|
|
||||||
}
|
|
||||||
} else if (status == UsingTcp) {
|
|
||||||
_receivedQueue.push_back(data);
|
|
||||||
emit receivedData();
|
|
||||||
} else if (status == WaitingBoth || status == WaitingTcp || status == HttpReady) {
|
|
||||||
tcpTimeoutTimer.stop();
|
|
||||||
try {
|
|
||||||
auto res_pq = readPQFakeReply(data);
|
|
||||||
const auto &res_pq_data(res_pq.c_resPQ());
|
|
||||||
if (res_pq_data.vnonce == tcpNonce) {
|
|
||||||
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flagsTcp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingTcp;
|
|
||||||
emit connected();
|
|
||||||
}
|
|
||||||
} catch (Exception &e) {
|
|
||||||
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
} else if (status == HttpReady) {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, awaited").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
sock.disconnectFromHost();
|
|
||||||
emit connected();
|
|
||||||
} else {
|
|
||||||
emit error(kErrorCodeOther);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AutoConnection::usingHttpWait() {
|
|
||||||
return (status == UsingHttp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AutoConnection::needHttpWait() {
|
|
||||||
return (status == UsingHttp) ? requests.isEmpty() : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 AutoConnection::debugState() const {
|
|
||||||
return (status == UsingHttp) ? -1 : ((status == UsingTcp) ? sock.state() : -777);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AutoConnection::transport() const {
|
|
||||||
if (status == UsingTcp) {
|
|
||||||
return qsl("TCP");
|
|
||||||
} else if (status == UsingHttp) {
|
|
||||||
return qsl("HTTP");
|
|
||||||
} else {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoConnection::socketError(QAbstractSocket::SocketError e) {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
|
|
||||||
AbstractTCPConnection::handleError(e, sock);
|
|
||||||
if (status == WaitingBoth) {
|
|
||||||
status = WaitingHttp;
|
|
||||||
} else if (status == HttpReady) {
|
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by tcp error, ready").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
|
||||||
status = UsingHttp;
|
|
||||||
emit connected();
|
|
||||||
} else if (status == WaitingTcp || status == UsingTcp) {
|
|
||||||
emit error(kErrorCodeOther);
|
|
||||||
} else {
|
|
||||||
LOG(("Strange Tcp Error: status %1").arg(status));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace MTP
|
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "mtproto/connection_tcp.h"
|
|
||||||
|
|
||||||
namespace MTP {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
class AutoConnection : public AbstractTCPConnection {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
AutoConnection(QThread *thread, int16 protocolDcId);
|
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
|
||||||
void disconnectFromServer() override;
|
|
||||||
void connectTcp(const DcOptions::Endpoint &endpoint) override;
|
|
||||||
void connectHttp(const DcOptions::Endpoint &endpoint) override;
|
|
||||||
bool isConnected() const override;
|
|
||||||
bool usingHttpWait() override;
|
|
||||||
bool needHttpWait() override;
|
|
||||||
|
|
||||||
int32 debugState() const override;
|
|
||||||
|
|
||||||
QString transport() const override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void socketError(QAbstractSocket::SocketError e);
|
|
||||||
void requestFinished(QNetworkReply *reply);
|
|
||||||
|
|
||||||
void onSocketConnected();
|
|
||||||
void onSocketDisconnected();
|
|
||||||
void onHttpStart();
|
|
||||||
|
|
||||||
void onTcpTimeoutTimer();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void socketPacket(const char *packet, uint32 length) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void httpSend(mtpBuffer &buffer);
|
|
||||||
enum Status {
|
|
||||||
WaitingBoth = 0,
|
|
||||||
WaitingHttp,
|
|
||||||
WaitingTcp,
|
|
||||||
HttpReady,
|
|
||||||
UsingHttp,
|
|
||||||
UsingTcp,
|
|
||||||
FinishedWork
|
|
||||||
};
|
|
||||||
Status status;
|
|
||||||
MTPint128 tcpNonce, httpNonce;
|
|
||||||
QTimer httpStartTimer;
|
|
||||||
|
|
||||||
QNetworkAccessManager manager;
|
|
||||||
QUrl address;
|
|
||||||
|
|
||||||
typedef QSet<QNetworkReply*> Requests;
|
|
||||||
Requests requests;
|
|
||||||
|
|
||||||
QString _addrTcp, _addrHttp;
|
|
||||||
int32 _portTcp, _portHttp;
|
|
||||||
MTPDdcOption::Flags _flagsTcp, _flagsHttp;
|
|
||||||
int32 _tcpTimeout;
|
|
||||||
QTimer tcpTimeoutTimer;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace MTP
|
|
|
@ -7,8 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "mtproto/connection_http.h"
|
#include "mtproto/connection_http.h"
|
||||||
|
|
||||||
|
#include "base/qthelp_url.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kForceHttpPort = 80;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
|
mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
|
||||||
QByteArray response = reply->readAll();
|
QByteArray response = reply->readAll();
|
||||||
|
@ -76,8 +83,7 @@ qint32 HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
|
||||||
|
|
||||||
HTTPConnection::HTTPConnection(QThread *thread) : AbstractConnection(thread)
|
HTTPConnection::HTTPConnection(QThread *thread) : AbstractConnection(thread)
|
||||||
, status(WaitingHttp)
|
, status(WaitingHttp)
|
||||||
, httpNonce(rand_value<MTPint128>())
|
, httpNonce(rand_value<MTPint128>()) {
|
||||||
, _flags(0) {
|
|
||||||
manager.moveToThread(thread);
|
manager.moveToThread(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +99,7 @@ void HTTPConnection::sendData(mtpBuffer &buffer) {
|
||||||
|
|
||||||
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
||||||
|
|
||||||
QNetworkRequest request(address);
|
QNetworkRequest request(url());
|
||||||
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
||||||
|
|
||||||
|
@ -113,22 +119,20 @@ void HTTPConnection::disconnectFromServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
address = QUrl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::connectHttp(const DcOptions::Endpoint &endpoint) {
|
void HTTPConnection::connectToServer(
|
||||||
_flags = endpoint.flags;
|
const QString &ip,
|
||||||
auto addr = QString::fromStdString(endpoint.ip);
|
int port,
|
||||||
|
const bytes::vector &protocolSecret,
|
||||||
// not endpoint.port - always 80 port for http transport
|
int16 protocolDcId) {
|
||||||
address = QUrl(((_flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));
|
_address = ip;
|
||||||
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
TCP_LOG(("HTTP Info: address is %1").arg(url().toDisplayString()));
|
||||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
mtpBuffer buffer(preparePQFake(httpNonce));
|
mtpBuffer buffer(preparePQFake(httpNonce));
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP transport to %1").arg(ip));
|
||||||
|
|
||||||
sendData(buffer);
|
sendData(buffer);
|
||||||
}
|
}
|
||||||
|
@ -156,7 +160,7 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
|
||||||
auto res_pq = readPQFakeReply(data);
|
auto res_pq = readPQFakeReply(data);
|
||||||
const auto &res_pq_data(res_pq.c_resPQ());
|
const auto &res_pq_data(res_pq.c_resPQ());
|
||||||
if (res_pq_data.vnonce == httpNonce) {
|
if (res_pq_data.vnonce == httpNonce) {
|
||||||
DEBUG_LOG(("Connection Info: HTTP/%1-transport connected by pq-response").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: HTTP-transport to %1 connected by pq-response").arg(_address));
|
||||||
status = UsingHttp;
|
status = UsingHttp;
|
||||||
emit connected();
|
emit connected();
|
||||||
}
|
}
|
||||||
|
@ -188,11 +192,33 @@ int32 HTTPConnection::debugState() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HTTPConnection::transport() const {
|
QString HTTPConnection::transport() const {
|
||||||
if (status == UsingHttp) {
|
if (!isConnected()) {
|
||||||
return qsl("HTTP");
|
|
||||||
} else {
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
auto result = qsl("HTTP");
|
||||||
|
if (qthelp::is_ipv6(_address)) {
|
||||||
|
result += qsl("/IPv6");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HTTPConnection::tag() const {
|
||||||
|
auto result = qsl("HTTP");
|
||||||
|
if (qthelp::is_ipv6(_address)) {
|
||||||
|
result += qsl("/IPv6");
|
||||||
|
} else {
|
||||||
|
result += qsl("/IPv4");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl HTTPConnection::url() const {
|
||||||
|
const auto pattern = qthelp::is_ipv6(_address)
|
||||||
|
? qsl("http://[%1]:%2/api")
|
||||||
|
: qsl("http://%1:%2/api");
|
||||||
|
|
||||||
|
// Not endpoint.port - always 80 port for http transport.
|
||||||
|
return QUrl(pattern.arg(_address).arg(kForceHttpPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
@ -20,9 +20,11 @@ public:
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectTcp(const DcOptions::Endpoint &endpoint) override { // not supported
|
void connectToServer(
|
||||||
}
|
const QString &ip,
|
||||||
void connectHttp(const DcOptions::Endpoint &endpoint) override;
|
int port,
|
||||||
|
const bytes::vector &protocolSecret,
|
||||||
|
int16 protocolDcId) override;
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
bool usingHttpWait() override;
|
bool usingHttpWait() override;
|
||||||
bool needHttpWait() override;
|
bool needHttpWait() override;
|
||||||
|
@ -30,6 +32,7 @@ public:
|
||||||
int32 debugState() const override;
|
int32 debugState() const override;
|
||||||
|
|
||||||
QString transport() const override;
|
QString transport() const override;
|
||||||
|
QString tag() const override;
|
||||||
|
|
||||||
static mtpBuffer handleResponse(QNetworkReply *reply);
|
static mtpBuffer handleResponse(QNetworkReply *reply);
|
||||||
static qint32 handleError(QNetworkReply *reply); // returnes error code
|
static qint32 handleError(QNetworkReply *reply); // returnes error code
|
||||||
|
@ -38,6 +41,8 @@ public slots:
|
||||||
void requestFinished(QNetworkReply *reply);
|
void requestFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QUrl url() const;
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
WaitingHttp = 0,
|
WaitingHttp = 0,
|
||||||
UsingHttp,
|
UsingHttp,
|
||||||
|
@ -45,10 +50,9 @@ private:
|
||||||
};
|
};
|
||||||
Status status;
|
Status status;
|
||||||
MTPint128 httpNonce;
|
MTPint128 httpNonce;
|
||||||
MTPDdcOption::Flags _flags;
|
|
||||||
|
|
||||||
QNetworkAccessManager manager;
|
QNetworkAccessManager manager;
|
||||||
QUrl address;
|
QString _address;
|
||||||
|
|
||||||
typedef QSet<QNetworkReply*> Requests;
|
typedef QSet<QNetworkReply*> Requests;
|
||||||
Requests requests;
|
Requests requests;
|
||||||
|
|
|
@ -9,13 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "base/bytes.h"
|
#include "base/bytes.h"
|
||||||
#include "base/openssl_help.h"
|
#include "base/openssl_help.h"
|
||||||
|
#include "base/qthelp_url.h"
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kMinReceiveTimeout = TimeMs(2000);
|
||||||
|
constexpr auto kMaxReceiveTimeout = TimeMs(8000);
|
||||||
|
|
||||||
uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readable
|
uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readable
|
||||||
uint32 result = (packet[0] > 0) ? packet[0] : 0;
|
uint32 result = (packet[0] > 0) ? packet[0] : 0;
|
||||||
if (result == 0x7f) {
|
if (result == 0x7f) {
|
||||||
|
@ -29,14 +32,8 @@ uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readabl
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AbstractTCPConnection::AbstractTCPConnection(
|
AbstractTCPConnection::AbstractTCPConnection(
|
||||||
QThread *thread,
|
QThread *thread)
|
||||||
int16 protocolDcId)
|
|
||||||
: AbstractConnection(thread)
|
: AbstractConnection(thread)
|
||||||
, _protocolDcId(protocolDcId)
|
|
||||||
, packetNum(0)
|
|
||||||
, packetRead(0)
|
|
||||||
, packetLeft(0)
|
|
||||||
, readingToShort(true)
|
|
||||||
, currentPos((char*)shortBuffer) {
|
, currentPos((char*)shortBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +194,11 @@ void AbstractTCPConnection::handleError(QAbstractSocket::SocketError e, QTcpSock
|
||||||
TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(sock.errorString()));
|
TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(sock.errorString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TCPConnection::TCPConnection(QThread *thread, int16 protocolDcId)
|
TCPConnection::TCPConnection(QThread *thread)
|
||||||
: AbstractTCPConnection(thread, protocolDcId)
|
: AbstractTCPConnection(thread)
|
||||||
, status(WaitingTcp)
|
, status(WaitingTcp)
|
||||||
, tcpNonce(rand_value<MTPint128>())
|
, tcpNonce(rand_value<MTPint128>())
|
||||||
, _tcpTimeout(MTPMinReceiveDelay)
|
, _tcpTimeout(kMinReceiveTimeout) {
|
||||||
, _flags(0) {
|
|
||||||
tcpTimeoutTimer.moveToThread(thread);
|
tcpTimeoutTimer.moveToThread(thread);
|
||||||
tcpTimeoutTimer.setSingleShot(true);
|
tcpTimeoutTimer.setSingleShot(true);
|
||||||
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
||||||
|
@ -217,7 +213,7 @@ void TCPConnection::onSocketConnected() {
|
||||||
if (status == WaitingTcp) {
|
if (status == WaitingTcp) {
|
||||||
mtpBuffer buffer(preparePQFake(tcpNonce));
|
mtpBuffer buffer(preparePQFake(tcpNonce));
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP transport to %1").arg(_address));
|
||||||
|
|
||||||
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
||||||
tcpTimeoutTimer.start(_tcpTimeout);
|
tcpTimeoutTimer.start(_tcpTimeout);
|
||||||
|
@ -228,14 +224,16 @@ void TCPConnection::onSocketConnected() {
|
||||||
|
|
||||||
void TCPConnection::onTcpTimeoutTimer() {
|
void TCPConnection::onTcpTimeoutTimer() {
|
||||||
if (status == WaitingTcp) {
|
if (status == WaitingTcp) {
|
||||||
if (_tcpTimeout < MTPMaxReceiveDelay) _tcpTimeout *= 2;
|
if (_tcpTimeout < kMaxReceiveTimeout) {
|
||||||
|
_tcpTimeout *= 2;
|
||||||
|
}
|
||||||
_tcpTimeout = -_tcpTimeout;
|
_tcpTimeout = -_tcpTimeout;
|
||||||
|
|
||||||
QAbstractSocket::SocketState state = sock.state();
|
QAbstractSocket::SocketState state = sock.state();
|
||||||
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||||
sock.disconnectFromHost();
|
sock.disconnectFromHost();
|
||||||
} else if (state != QAbstractSocket::ClosingState) {
|
} else if (state != QAbstractSocket::ClosingState) {
|
||||||
sock.connectToHost(QHostAddress(_addr), _port);
|
sock.connectToHost(QHostAddress(_address), _port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +242,7 @@ void TCPConnection::onSocketDisconnected() {
|
||||||
if (_tcpTimeout < 0) {
|
if (_tcpTimeout < 0) {
|
||||||
_tcpTimeout = -_tcpTimeout;
|
_tcpTimeout = -_tcpTimeout;
|
||||||
if (status == WaitingTcp) {
|
if (status == WaitingTcp) {
|
||||||
sock.connectToHost(QHostAddress(_addr), _port);
|
sock.connectToHost(QHostAddress(_address), _port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,8 +289,19 @@ void AbstractTCPConnection::writeConnectionStart() {
|
||||||
|| *first == reserved15
|
|| *first == reserved15
|
||||||
|| *second == reserved21);
|
|| *second == reserved21);
|
||||||
|
|
||||||
|
const auto prepareKey = [&](bytes::span key, bytes::const_span from) {
|
||||||
|
if (_protocolSecret.size() == 16) {
|
||||||
|
const auto payload = bytes::concatenate(from, _protocolSecret);
|
||||||
|
bytes::copy(key, openssl::Sha256(payload));
|
||||||
|
} else if (_protocolSecret.empty()) {
|
||||||
|
bytes::copy(key, from);
|
||||||
|
} else {
|
||||||
|
bytes::set_with_const(key, gsl::byte{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// prepare encryption key/iv
|
// prepare encryption key/iv
|
||||||
bytes::copy(
|
prepareKey(
|
||||||
bytes::make_span(_sendKey),
|
bytes::make_span(_sendKey),
|
||||||
nonce.subspan(8, CTRState::KeySize));
|
nonce.subspan(8, CTRState::KeySize));
|
||||||
bytes::copy(
|
bytes::copy(
|
||||||
|
@ -304,7 +313,7 @@ void AbstractTCPConnection::writeConnectionStart() {
|
||||||
const auto reversed = bytes::make_span(reversedBytes);
|
const auto reversed = bytes::make_span(reversedBytes);
|
||||||
bytes::copy(reversed, nonce.subspan(8, reversed.size()));
|
bytes::copy(reversed, nonce.subspan(8, reversed.size()));
|
||||||
std::reverse(reversed.begin(), reversed.end());
|
std::reverse(reversed.begin(), reversed.end());
|
||||||
bytes::copy(
|
prepareKey(
|
||||||
bytes::make_span(_receiveKey),
|
bytes::make_span(_receiveKey),
|
||||||
reversed.subspan(0, CTRState::KeySize));
|
reversed.subspan(0, CTRState::KeySize));
|
||||||
bytes::copy(
|
bytes::copy(
|
||||||
|
@ -356,14 +365,18 @@ void TCPConnection::disconnectFromServer() {
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::connectTcp(const DcOptions::Endpoint &endpoint) {
|
void TCPConnection::connectToServer(
|
||||||
_addr = QString::fromStdString(endpoint.ip);
|
const QString &ip,
|
||||||
_port = endpoint.port;
|
int port,
|
||||||
_flags = endpoint.flags;
|
const bytes::vector &protocolSecret,
|
||||||
|
int16 protocolDcId) {
|
||||||
|
_address = ip;
|
||||||
|
_port = port;
|
||||||
|
_protocolSecret = protocolSecret;
|
||||||
|
_protocolDcId = protocolDcId;
|
||||||
|
|
||||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||||
sock.connectToHost(QHostAddress(_addr), _port);
|
sock.connectToHost(QHostAddress(_address), _port);
|
||||||
auto proxy = sock.proxy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
|
@ -381,7 +394,7 @@ void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
auto res_pq = readPQFakeReply(data);
|
auto res_pq = readPQFakeReply(data);
|
||||||
const auto &res_pq_data(res_pq.c_resPQ());
|
const auto &res_pq_data(res_pq.c_resPQ());
|
||||||
if (res_pq_data.vnonce == tcpNonce) {
|
if (res_pq_data.vnonce == tcpNonce) {
|
||||||
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
DEBUG_LOG(("Connection Info: TCP-transport to %1 chosen by pq-response").arg(_address));
|
||||||
status = UsingTcp;
|
status = UsingTcp;
|
||||||
emit connected();
|
emit connected();
|
||||||
}
|
}
|
||||||
|
@ -401,7 +414,24 @@ int32 TCPConnection::debugState() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TCPConnection::transport() const {
|
QString TCPConnection::transport() const {
|
||||||
return isConnected() ? qsl("TCP") : QString();
|
if (!isConnected()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
auto result = qsl("TCP");
|
||||||
|
if (qthelp::is_ipv6(_address)) {
|
||||||
|
result += qsl("/IPv6");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TCPConnection::tag() const {
|
||||||
|
auto result = qsl("TCP");
|
||||||
|
if (qthelp::is_ipv6(_address)) {
|
||||||
|
result += qsl("/IPv6");
|
||||||
|
} else {
|
||||||
|
result += qsl("/IPv4");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::socketError(QAbstractSocket::SocketError e) {
|
void TCPConnection::socketError(QAbstractSocket::SocketError e) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ class AbstractTCPConnection : public AbstractConnection {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractTCPConnection(QThread *thread, int16 protocolDcId);
|
AbstractTCPConnection(QThread *thread);
|
||||||
virtual ~AbstractTCPConnection() = 0;
|
virtual ~AbstractTCPConnection() = 0;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -27,10 +27,11 @@ protected:
|
||||||
void writeConnectionStart();
|
void writeConnectionStart();
|
||||||
|
|
||||||
QTcpSocket sock;
|
QTcpSocket sock;
|
||||||
uint32 packetNum; // sent packet number
|
uint32 packetNum = 0; // sent packet number
|
||||||
|
|
||||||
uint32 packetRead, packetLeft; // reading from socket
|
uint32 packetRead = 0;
|
||||||
bool readingToShort;
|
uint32 packetLeft = 0; // reading from socket
|
||||||
|
bool readingToShort = true;
|
||||||
char *currentPos;
|
char *currentPos;
|
||||||
mtpBuffer longBuffer;
|
mtpBuffer longBuffer;
|
||||||
mtpPrime shortBuffer[MTPShortBufferSize];
|
mtpPrime shortBuffer[MTPShortBufferSize];
|
||||||
|
@ -49,6 +50,7 @@ protected:
|
||||||
uchar _receiveKey[CTRState::KeySize];
|
uchar _receiveKey[CTRState::KeySize];
|
||||||
CTRState _receiveState;
|
CTRState _receiveState;
|
||||||
int16 _protocolDcId = 0;
|
int16 _protocolDcId = 0;
|
||||||
|
bytes::vector _protocolSecret;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,21 +58,23 @@ class TCPConnection : public AbstractTCPConnection {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TCPConnection(QThread *thread, int16 protocolDcId);
|
TCPConnection(QThread *thread);
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectTcp(const DcOptions::Endpoint &endpoint) override;
|
void connectToServer(
|
||||||
void connectHttp(const DcOptions::Endpoint &endpoint) override { // not supported
|
const QString &ip,
|
||||||
}
|
int port,
|
||||||
|
const bytes::vector &protocolSecret,
|
||||||
|
int16 protocolDcId) override;
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
|
|
||||||
int32 debugState() const override;
|
int32 debugState() const override;
|
||||||
|
|
||||||
QString transport() const override;
|
QString transport() const override;
|
||||||
|
QString tag() const override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void socketError(QAbstractSocket::SocketError e);
|
void socketError(QAbstractSocket::SocketError e);
|
||||||
|
|
||||||
void onSocketConnected();
|
void onSocketConnected();
|
||||||
|
@ -79,11 +83,9 @@ public slots:
|
||||||
void onTcpTimeoutTimer();
|
void onTcpTimeoutTimer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void socketPacket(const char *packet, uint32 length) override;
|
void socketPacket(const char *packet, uint32 length) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
WaitingTcp = 0,
|
WaitingTcp = 0,
|
||||||
UsingTcp,
|
UsingTcp,
|
||||||
|
@ -92,9 +94,8 @@ private:
|
||||||
Status status;
|
Status status;
|
||||||
MTPint128 tcpNonce;
|
MTPint128 tcpNonce;
|
||||||
|
|
||||||
QString _addr;
|
QString _address;
|
||||||
int32 _port, _tcpTimeout;
|
int32 _port, _tcpTimeout;
|
||||||
MTPDdcOption::Flags _flags;
|
|
||||||
QTimer tcpTimeoutTimer;
|
QTimer tcpTimeoutTimer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -105,22 +105,36 @@ void DcOptions::constructFromBuiltIn() {
|
||||||
|
|
||||||
auto bdcs = builtInDcs();
|
auto bdcs = builtInDcs();
|
||||||
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
|
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
|
||||||
auto flags = MTPDdcOption::Flags(0);
|
const auto flags = MTPDdcOption::Flags(0);
|
||||||
auto idWithShift = MTP::shiftDcId(bdcs[i].id, flags);
|
const auto bdc = bdcs[i];
|
||||||
_data.emplace(idWithShift, Option(bdcs[i].id, flags, bdcs[i].ip, bdcs[i].port));
|
const auto idWithShift = MTP::shiftDcId(bdc.id, flags);
|
||||||
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));
|
_data.emplace(
|
||||||
|
idWithShift,
|
||||||
|
std::vector<Option>(
|
||||||
|
1,
|
||||||
|
Option(bdc.id, flags, bdc.ip, bdc.port)));
|
||||||
|
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: "
|
||||||
|
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bdcsipv6 = builtInDcsIPv6();
|
auto bdcsipv6 = builtInDcsIPv6();
|
||||||
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
|
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
|
||||||
auto flags = MTPDdcOption::Flags(MTPDdcOption::Flag::f_ipv6);
|
const auto flags = MTPDdcOption::Flags(MTPDdcOption::Flag::f_ipv6);
|
||||||
auto idWithShift = MTP::shiftDcId(bdcsipv6[i].id, flags);
|
const auto bdc = bdcsipv6[i];
|
||||||
_data.emplace(idWithShift, Option(bdcsipv6[i].id, flags, bdcsipv6[i].ip, bdcsipv6[i].port));
|
const auto idWithShift = MTP::shiftDcId(bdc.id, flags);
|
||||||
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));
|
_data.emplace(
|
||||||
|
idWithShift,
|
||||||
|
std::vector<Option>(
|
||||||
|
1,
|
||||||
|
Option(bdc.id, flags, bdc.ip, bdc.port)));
|
||||||
|
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: "
|
||||||
|
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DcOptions::processFromList(const QVector<MTPDcOption> &options, bool overwrite) {
|
void DcOptions::processFromList(
|
||||||
|
const QVector<MTPDcOption> &options,
|
||||||
|
bool overwrite) {
|
||||||
if (options.empty() || _immutable) {
|
if (options.empty() || _immutable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -144,12 +158,15 @@ void DcOptions::processFromList(const QVector<MTPDcOption> &options, bool overwr
|
||||||
auto dcId = option.vid.v;
|
auto dcId = option.vid.v;
|
||||||
auto flags = option.vflags.v;
|
auto flags = option.vflags.v;
|
||||||
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
||||||
if (base::contains(shiftedIdsProcessed, dcIdWithShift)) {
|
if (overwrite) {
|
||||||
continue;
|
if (!base::contains(shiftedIdsProcessed, dcIdWithShift)) {
|
||||||
|
shiftedIdsProcessed.push_back(dcIdWithShift);
|
||||||
|
_data.erase(dcIdWithShift);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
auto ip = std::string(
|
||||||
shiftedIdsProcessed.push_back(dcIdWithShift);
|
option.vip_address.v.constData(),
|
||||||
auto ip = std::string(option.vip_address.v.constData(), option.vip_address.v.size());
|
option.vip_address.v.size());
|
||||||
auto port = option.vport.v;
|
auto port = option.vport.v;
|
||||||
if (applyOneGuarded(dcId, flags, ip, port)) {
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
||||||
if (!base::contains(idsChanged, dcId)) {
|
if (!base::contains(idsChanged, dcId)) {
|
||||||
|
@ -162,8 +179,10 @@ void DcOptions::processFromList(const QVector<MTPDcOption> &options, bool overwr
|
||||||
if (base::contains(shiftedIdsProcessed, i->first)) {
|
if (base::contains(shiftedIdsProcessed, i->first)) {
|
||||||
++i;
|
++i;
|
||||||
} else {
|
} else {
|
||||||
if (!base::contains(idsChanged, i->second.id)) {
|
const auto &options = i->second;
|
||||||
idsChanged.push_back(i->second.id);
|
Assert(!options.empty());
|
||||||
|
if (!base::contains(idsChanged, options.front().id)) {
|
||||||
|
idsChanged.push_back(options.front().id);
|
||||||
}
|
}
|
||||||
i = _data.erase(i);
|
i = _data.erase(i);
|
||||||
}
|
}
|
||||||
|
@ -199,14 +218,16 @@ void DcOptions::addFromOther(DcOptions &&options) {
|
||||||
idsChanged.reserve(options._data.size());
|
idsChanged.reserve(options._data.size());
|
||||||
{
|
{
|
||||||
WriteLocker lock(this);
|
WriteLocker lock(this);
|
||||||
for (auto &item : base::take(options._data)) {
|
for (const auto &item : base::take(options._data)) {
|
||||||
auto dcId = item.second.id;
|
for (const auto &option : item.second) {
|
||||||
auto flags = item.second.flags;
|
auto dcId = option.id;
|
||||||
auto &ip = item.second.ip;
|
auto flags = option.flags;
|
||||||
auto port = item.second.port;
|
auto &ip = option.ip;
|
||||||
if (applyOneGuarded(dcId, flags, ip, port)) {
|
auto port = option.port;
|
||||||
if (!base::contains(idsChanged, dcId)) {
|
if (applyOneGuarded(dcId, flags, ip, port)) {
|
||||||
idsChanged.push_back(dcId);
|
if (!base::contains(idsChanged, dcId)) {
|
||||||
|
idsChanged.push_back(dcId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,17 +249,24 @@ void DcOptions::constructAddOne(int id, MTPDdcOption::Flags flags, const std::st
|
||||||
applyOneGuarded(bareDcId(id), flags, ip, port);
|
applyOneGuarded(bareDcId(id), flags, ip, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DcOptions::applyOneGuarded(DcId dcId, MTPDdcOption::Flags flags, const std::string &ip, int port) {
|
bool DcOptions::applyOneGuarded(
|
||||||
|
DcId dcId,
|
||||||
|
MTPDdcOption::Flags flags,
|
||||||
|
const std::string &ip,
|
||||||
|
int port) {
|
||||||
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
auto dcIdWithShift = MTP::shiftDcId(dcId, flags);
|
||||||
auto i = _data.find(dcIdWithShift);
|
auto i = _data.find(dcIdWithShift);
|
||||||
if (i != _data.cend()) {
|
if (i != _data.cend()) {
|
||||||
if (i->second.ip == ip && i->second.port == port) {
|
for (auto &option : i->second) {
|
||||||
return false;
|
if (option.ip == ip && option.port == port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i->second.ip = ip;
|
i->second.push_back(Option(dcId, flags, ip, port));
|
||||||
i->second.port = port;
|
|
||||||
} else {
|
} else {
|
||||||
_data.emplace(dcIdWithShift, Option(dcId, flags, ip, port));
|
_data.emplace(dcIdWithShift, std::vector<Option>(
|
||||||
|
1,
|
||||||
|
Option(dcId, flags, ip, port)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -252,12 +280,14 @@ QByteArray DcOptions::serialize() const {
|
||||||
ReadLocker lock(this);
|
ReadLocker lock(this);
|
||||||
|
|
||||||
auto size = sizeof(qint32);
|
auto size = sizeof(qint32);
|
||||||
for (auto &item : _data) {
|
for (const auto &item : _data) {
|
||||||
if (isTemporaryDcId(item.first)) {
|
if (isTemporaryDcId(item.first)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // id + flags + port
|
for (const auto &option : item.second) {
|
||||||
size += sizeof(qint32) + item.second.ip.size();
|
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // id + flags + port
|
||||||
|
size += sizeof(qint32) + option.ip.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto count = 0;
|
auto count = 0;
|
||||||
|
@ -271,8 +301,8 @@ QByteArray DcOptions::serialize() const {
|
||||||
};
|
};
|
||||||
std::vector<SerializedPublicKey> publicKeys;
|
std::vector<SerializedPublicKey> publicKeys;
|
||||||
publicKeys.reserve(count);
|
publicKeys.reserve(count);
|
||||||
for (auto &keysInDc : _cdnPublicKeys) {
|
for (const auto &keysInDc : _cdnPublicKeys) {
|
||||||
for (auto &entry : keysInDc.second) {
|
for (const auto &entry : keysInDc.second) {
|
||||||
publicKeys.push_back({ keysInDc.first, entry.second.getN(), entry.second.getE() });
|
publicKeys.push_back({ keysInDc.first, entry.second.getN(), entry.second.getE() });
|
||||||
size += sizeof(qint32) + Serialize::bytesSize(publicKeys.back().n) + Serialize::bytesSize(publicKeys.back().e);
|
size += sizeof(qint32) + Serialize::bytesSize(publicKeys.back().n) + Serialize::bytesSize(publicKeys.back().e);
|
||||||
}
|
}
|
||||||
|
@ -284,13 +314,15 @@ QByteArray DcOptions::serialize() const {
|
||||||
QDataStream stream(&result, QIODevice::WriteOnly);
|
QDataStream stream(&result, QIODevice::WriteOnly);
|
||||||
stream.setVersion(QDataStream::Qt_5_1);
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
stream << qint32(_data.size());
|
stream << qint32(_data.size());
|
||||||
for (auto &item : _data) {
|
for (const auto &item : _data) {
|
||||||
if (isTemporaryDcId(item.first)) {
|
if (isTemporaryDcId(item.first)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
stream << qint32(item.second.id) << qint32(item.second.flags) << qint32(item.second.port);
|
for (const auto &option : item.second) {
|
||||||
stream << qint32(item.second.ip.size());
|
stream << qint32(option.id) << qint32(option.flags) << qint32(option.port);
|
||||||
stream.writeRawData(item.second.ip.data(), item.second.ip.size());
|
stream << qint32(option.ip.size());
|
||||||
|
stream.writeRawData(option.ip.data(), option.ip.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stream << qint32(publicKeys.size());
|
stream << qint32(publicKeys.size());
|
||||||
for (auto &key : publicKeys) {
|
for (auto &key : publicKeys) {
|
||||||
|
@ -368,10 +400,12 @@ DcOptions::Ids DcOptions::configEnumDcIds() const {
|
||||||
ReadLocker lock(this);
|
ReadLocker lock(this);
|
||||||
result.reserve(_data.size());
|
result.reserve(_data.size());
|
||||||
for (auto &item : _data) {
|
for (auto &item : _data) {
|
||||||
if (!isCdnDc(item.second.flags)
|
const auto dcId = bareDcId(item.first);
|
||||||
|
Assert(!item.second.empty());
|
||||||
|
if (!isCdnDc(item.second.front().flags)
|
||||||
&& !isTemporaryDcId(item.first)
|
&& !isTemporaryDcId(item.first)
|
||||||
&& !base::contains(result, item.second.id)) {
|
&& !base::contains(result, dcId)) {
|
||||||
result.push_back(item.second.id);
|
result.push_back(dcId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,10 +472,11 @@ bool DcOptions::getDcRSAKey(DcId dcId, const QVector<MTPlong> &fingerprints, int
|
||||||
return findKey(_publicKeys);
|
return findKey(_publicKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
DcOptions::Variants DcOptions::lookup(DcId dcId, DcType type) const {
|
DcOptions::Variants DcOptions::lookup(
|
||||||
auto lookupDesiredFlags = [type](int address, int protocol) -> std::vector<MTPDdcOption::Flags> {
|
DcId dcId,
|
||||||
auto throughProxy = (Global::ConnectionType() != dbictAuto);
|
DcType type,
|
||||||
|
bool throughProxy) const {
|
||||||
|
auto lookupDesiredFlags = [&](int address, int protocol) -> std::vector<MTPDdcOption::Flags> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DcType::Regular:
|
case DcType::Regular:
|
||||||
case DcType::Temporary: {
|
case DcType::Temporary: {
|
||||||
|
@ -575,14 +610,15 @@ DcOptions::Variants DcOptions::lookup(DcId dcId, DcType type) const {
|
||||||
for (auto protocol = 0; protocol != Variants::ProtocolCount; ++protocol) {
|
for (auto protocol = 0; protocol != Variants::ProtocolCount; ++protocol) {
|
||||||
auto desiredFlags = lookupDesiredFlags(address, protocol);
|
auto desiredFlags = lookupDesiredFlags(address, protocol);
|
||||||
for (auto flags : desiredFlags) {
|
for (auto flags : desiredFlags) {
|
||||||
auto shift = static_cast<int>(flags);
|
const auto shift = static_cast<int>(flags);
|
||||||
if (shift < 0) continue;
|
const auto it = _data.find(shiftDcId(dcId, shift));
|
||||||
|
|
||||||
auto it = _data.find(shiftDcId(dcId, shift));
|
|
||||||
if (it != _data.cend()) {
|
if (it != _data.cend()) {
|
||||||
result.data[address][protocol].ip = it->second.ip;
|
for (const auto &option : it->second) {
|
||||||
result.data[address][protocol].flags = it->second.flags;
|
result.data[address][protocol].push_back({
|
||||||
result.data[address][protocol].port = it->second.port;
|
option.ip,
|
||||||
|
option.port
|
||||||
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,8 +631,9 @@ DcOptions::Variants DcOptions::lookup(DcId dcId, DcType type) const {
|
||||||
void DcOptions::computeCdnDcIds() {
|
void DcOptions::computeCdnDcIds() {
|
||||||
_cdnDcIds.clear();
|
_cdnDcIds.clear();
|
||||||
for (auto &item : _data) {
|
for (auto &item : _data) {
|
||||||
if (item.second.flags & MTPDdcOption::Flag::f_cdn) {
|
Assert(!item.second.empty());
|
||||||
_cdnDcIds.insert(item.second.id);
|
if (item.second.front().flags & MTPDdcOption::Flag::f_cdn) {
|
||||||
|
_cdnDcIds.insert(bareDcId(item.first));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -670,16 +707,21 @@ bool DcOptions::writeToFile(const QString &path) const {
|
||||||
stream.setCodec("UTF-8");
|
stream.setCodec("UTF-8");
|
||||||
|
|
||||||
ReadLocker lock(this);
|
ReadLocker lock(this);
|
||||||
for (auto &item : _data) {
|
for (const auto &item : _data) {
|
||||||
auto &endpoint = item.second;
|
for (const auto &option : item.second) {
|
||||||
stream << endpoint.id << ' ' << QString::fromStdString(endpoint.ip) << ' ' << endpoint.port;
|
stream
|
||||||
if (endpoint.flags & MTPDdcOption::Flag::f_tcpo_only) {
|
<< option.id
|
||||||
stream << " tcpo_only";
|
<< ' '
|
||||||
|
<< QString::fromStdString(option.ip)
|
||||||
|
<< ' ' << option.port;
|
||||||
|
if (option.flags & MTPDdcOption::Flag::f_tcpo_only) {
|
||||||
|
stream << " tcpo_only";
|
||||||
|
}
|
||||||
|
if (option.flags & MTPDdcOption::Flag::f_media_only) {
|
||||||
|
stream << " media_only";
|
||||||
|
}
|
||||||
|
stream << '\n';
|
||||||
}
|
}
|
||||||
if (endpoint.flags & MTPDdcOption::Flag::f_media_only) {
|
|
||||||
stream << " media_only";
|
|
||||||
}
|
|
||||||
stream << '\n';
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/observer.h"
|
#include "base/observer.h"
|
||||||
|
#include "base/bytes.h"
|
||||||
#include "mtproto/rsa_public_key.h"
|
#include "mtproto/rsa_public_key.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -26,7 +27,11 @@ public:
|
||||||
// construct methods don't notify "changed" subscribers.
|
// construct methods don't notify "changed" subscribers.
|
||||||
void constructFromSerialized(const QByteArray &serialized);
|
void constructFromSerialized(const QByteArray &serialized);
|
||||||
void constructFromBuiltIn();
|
void constructFromBuiltIn();
|
||||||
void constructAddOne(int id, MTPDdcOption::Flags flags, const std::string &ip, int port);
|
void constructAddOne(
|
||||||
|
int id,
|
||||||
|
MTPDdcOption::Flags flags,
|
||||||
|
const std::string &ip,
|
||||||
|
int port);
|
||||||
QByteArray serialize() const;
|
QByteArray serialize() const;
|
||||||
|
|
||||||
using Ids = std::vector<DcId>;
|
using Ids = std::vector<DcId>;
|
||||||
|
@ -42,22 +47,22 @@ public:
|
||||||
struct Endpoint {
|
struct Endpoint {
|
||||||
std::string ip;
|
std::string ip;
|
||||||
int port = 0;
|
int port = 0;
|
||||||
MTPDdcOption::Flags flags = 0;
|
bytes::vector protocolSecret;
|
||||||
};
|
};
|
||||||
struct Variants {
|
struct Variants {
|
||||||
enum {
|
enum Address {
|
||||||
IPv4 = 0,
|
IPv4 = 0,
|
||||||
IPv6 = 1,
|
IPv6 = 1,
|
||||||
AddressTypeCount = 2,
|
AddressTypeCount = 2,
|
||||||
};
|
};
|
||||||
enum {
|
enum Protocol {
|
||||||
Tcp = 0,
|
Tcp = 0,
|
||||||
Http = 1,
|
Http = 1,
|
||||||
ProtocolCount = 2,
|
ProtocolCount = 2,
|
||||||
};
|
};
|
||||||
Endpoint data[AddressTypeCount][ProtocolCount];
|
std::vector<Endpoint> data[AddressTypeCount][ProtocolCount];
|
||||||
};
|
};
|
||||||
Variants lookup(DcId dcId, DcType type) const;
|
Variants lookup(DcId dcId, DcType type, bool throughProxy) const;
|
||||||
DcType dcType(ShiftedDcId shiftedDcId) const;
|
DcType dcType(ShiftedDcId shiftedDcId) const;
|
||||||
|
|
||||||
void setCDNConfig(const MTPDcdnConfig &config);
|
void setCDNConfig(const MTPDcdnConfig &config);
|
||||||
|
@ -91,7 +96,7 @@ private:
|
||||||
class ReadLocker;
|
class ReadLocker;
|
||||||
friend class ReadLocker;
|
friend class ReadLocker;
|
||||||
|
|
||||||
std::map<ShiftedDcId, Option> _data;
|
std::map<ShiftedDcId, std::vector<Option>> _data;
|
||||||
std::set<DcId> _cdnDcIds;
|
std::set<DcId> _cdnDcIds;
|
||||||
std::map<uint64, internal::RSAPublicKey> _publicKeys;
|
std::map<uint64, internal::RSAPublicKey> _publicKeys;
|
||||||
std::map<DcId, std::map<uint64, internal::RSAPublicKey>> _cdnPublicKeys;
|
std::map<DcId, std::map<uint64, internal::RSAPublicKey>> _cdnPublicKeys;
|
||||||
|
|
|
@ -178,8 +178,7 @@ void Session::refreshDataFields() {
|
||||||
(connectionType == dbictAuto
|
(connectionType == dbictAuto
|
||||||
|| connectionType == dbictHttpProxy);
|
|| connectionType == dbictHttpProxy);
|
||||||
const auto useIPv4 = true;
|
const auto useIPv4 = true;
|
||||||
const auto useIPv6 = (proxyType != ProxyData::Type::Mtproto) &&
|
const auto useIPv6 = Global::TryIPv6();
|
||||||
Global::TryIPv6();
|
|
||||||
data.setConnectionOptions(ConnectionOptions(
|
data.setConnectionOptions(ConnectionOptions(
|
||||||
_instance->systemLangCode(),
|
_instance->systemLangCode(),
|
||||||
_instance->cloudLangCode(),
|
_instance->cloudLangCode(),
|
||||||
|
|
|
@ -422,8 +422,6 @@
|
||||||
<(src_loc)/mtproto/connection.h
|
<(src_loc)/mtproto/connection.h
|
||||||
<(src_loc)/mtproto/connection_abstract.cpp
|
<(src_loc)/mtproto/connection_abstract.cpp
|
||||||
<(src_loc)/mtproto/connection_abstract.h
|
<(src_loc)/mtproto/connection_abstract.h
|
||||||
<(src_loc)/mtproto/connection_auto.cpp
|
|
||||||
<(src_loc)/mtproto/connection_auto.h
|
|
||||||
<(src_loc)/mtproto/connection_http.cpp
|
<(src_loc)/mtproto/connection_http.cpp
|
||||||
<(src_loc)/mtproto/connection_http.h
|
<(src_loc)/mtproto/connection_http.h
|
||||||
<(src_loc)/mtproto/connection_tcp.cpp
|
<(src_loc)/mtproto/connection_tcp.cpp
|
||||||
|
|
Loading…
Reference in New Issue