mirror of https://github.com/procxx/kepka.git
Fix mtproto-proxy working with domain names.
Also refactor a bit TcpConnection and HttpConnection classes.
This commit is contained in:
parent
694e8cd19f
commit
a053384618
|
@ -41,7 +41,7 @@ QMap<QString, QString> url_parse_params(
|
||||||
bool is_ipv6(const QString &ip) {
|
bool is_ipv6(const QString &ip) {
|
||||||
//static const auto regexp = QRegularExpression("^[a-fA-F0-9:]+$");
|
//static const auto regexp = QRegularExpression("^[a-fA-F0-9:]+$");
|
||||||
//return regexp.match(ip).hasMatch();
|
//return regexp.match(ip).hasMatch();
|
||||||
return ip.indexOf(':') >= 0;
|
return ip.indexOf('.') < 0 && ip.indexOf(':') >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace qthelp
|
} // namespace qthelp
|
||||||
|
|
|
@ -17,8 +17,6 @@ constexpr str_const AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"; // used in
|
||||||
constexpr str_const AppFile = "Telegram";
|
constexpr str_const AppFile = "Telegram";
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MTPShortBufferSize = 65535, // of ints, 256 kb
|
|
||||||
MTPPacketSizeMax = 67108864, // 64 mb
|
|
||||||
MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored
|
MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored
|
||||||
MTPCheckResendTimeout = 10000, // how much time passed from send till we resend request or check it's state, in ms
|
MTPCheckResendTimeout = 10000, // how much time passed from send till we resend request or check it's state, in ms
|
||||||
MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms
|
MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms
|
||||||
|
|
|
@ -38,6 +38,7 @@ class HistoryInner
|
||||||
: public Ui::RpWidget
|
: public Ui::RpWidget
|
||||||
, public Ui::AbstractTooltipShower
|
, public Ui::AbstractTooltipShower
|
||||||
, private base::Subscriber {
|
, private base::Subscriber {
|
||||||
|
// The Q_OBJECT meta info is used for qobject_cast to HistoryInner!
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -130,9 +130,9 @@ ConnectionPointer AbstractConnection::create(
|
||||||
DcOptions::Variants::Protocol protocol,
|
DcOptions::Variants::Protocol protocol,
|
||||||
QThread *thread) {
|
QThread *thread) {
|
||||||
if (protocol == DcOptions::Variants::Tcp) {
|
if (protocol == DcOptions::Variants::Tcp) {
|
||||||
return ConnectionPointer(new TCPConnection(thread));
|
return ConnectionPointer(new TcpConnection(thread));
|
||||||
} else {
|
} else {
|
||||||
return ConnectionPointer(new HTTPConnection(thread));
|
return ConnectionPointer(new HttpConnection(thread));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,75 @@ constexpr auto kForceHttpPort = 80;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
|
HttpConnection::HttpConnection(QThread *thread)
|
||||||
|
: AbstractConnection(thread)
|
||||||
|
, _checkNonce(rand_value<MTPint128>()) {
|
||||||
|
_manager.moveToThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConnection::setProxyOverride(const ProxyData &proxy) {
|
||||||
|
_manager.setProxy(ToNetworkProxy(proxy));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConnection::sendData(mtpBuffer &buffer) {
|
||||||
|
if (_status == Status::Finished) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
||||||
|
|
||||||
|
QNetworkRequest request(url());
|
||||||
|
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 %2").arg(requestSize).arg(Logs::mb(&buffer[2], requestSize).str()));
|
||||||
|
_requests.insert(_manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConnection::disconnectFromServer() {
|
||||||
|
if (_status == Status::Finished) return;
|
||||||
|
_status = Status::Finished;
|
||||||
|
|
||||||
|
for (const auto request : base::take(_requests)) {
|
||||||
|
request->abort();
|
||||||
|
request->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(
|
||||||
|
&_manager,
|
||||||
|
&QNetworkAccessManager::finished,
|
||||||
|
this,
|
||||||
|
&HttpConnection::requestFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpConnection::connectToServer(
|
||||||
|
const QString &address,
|
||||||
|
int port,
|
||||||
|
const bytes::vector &protocolSecret,
|
||||||
|
int16 protocolDcId) {
|
||||||
|
_address = address;
|
||||||
|
TCP_LOG(("HTTP Info: address is %1").arg(url().toDisplayString()));
|
||||||
|
connect(
|
||||||
|
&_manager,
|
||||||
|
&QNetworkAccessManager::finished,
|
||||||
|
this,
|
||||||
|
&HttpConnection::requestFinished);
|
||||||
|
|
||||||
|
mtpBuffer buffer(preparePQFake(_checkNonce));
|
||||||
|
|
||||||
|
DEBUG_LOG(("Connection Info: "
|
||||||
|
"sending fake req_pq through HTTP transport to '%1'").arg(address));
|
||||||
|
|
||||||
|
_pingTime = getms();
|
||||||
|
sendData(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) {
|
||||||
QByteArray response = reply->readAll();
|
QByteArray response = reply->readAll();
|
||||||
TCP_LOG(("HTTP Info: read %1 bytes").arg(response.size()));
|
TCP_LOG(("HTTP Info: read %1 bytes").arg(response.size()));
|
||||||
|
|
||||||
|
@ -34,7 +102,7 @@ mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint32 HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
|
qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
|
||||||
auto result = qint32(kErrorCodeOther);
|
auto result = qint32(kErrorCodeOther);
|
||||||
|
|
||||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||||
|
@ -81,92 +149,31 @@ qint32 HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPConnection::HTTPConnection(QThread *thread) : AbstractConnection(thread)
|
bool HttpConnection::isConnected() const {
|
||||||
, status(WaitingHttp)
|
return (_status == Status::Ready);
|
||||||
, httpNonce(rand_value<MTPint128>()) {
|
|
||||||
manager.moveToThread(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPConnection::setProxyOverride(const ProxyData &proxy) {
|
void HttpConnection::requestFinished(QNetworkReply *reply) {
|
||||||
manager.setProxy(ToNetworkProxy(proxy));
|
if (_status == Status::Finished) return;
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPConnection::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
|
||||||
|
|
||||||
QNetworkRequest request(url());
|
|
||||||
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 %2").arg(requestSize).arg(Logs::mb(&buffer[2], requestSize).str()));
|
|
||||||
requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPConnection::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*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPConnection::connectToServer(
|
|
||||||
const QString &ip,
|
|
||||||
int port,
|
|
||||||
const bytes::vector &protocolSecret,
|
|
||||||
int16 protocolDcId) {
|
|
||||||
_address = ip;
|
|
||||||
TCP_LOG(("HTTP Info: address is %1").arg(url().toDisplayString()));
|
|
||||||
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
|
||||||
|
|
||||||
mtpBuffer buffer(preparePQFake(httpNonce));
|
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP transport to %1").arg(ip));
|
|
||||||
|
|
||||||
_pingTime = getms();
|
|
||||||
sendData(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTTPConnection::isConnected() const {
|
|
||||||
return (status == UsingHttp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTTPConnection::requestFinished(QNetworkReply *reply) {
|
|
||||||
if (status == FinishedWork) return;
|
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
requests.remove(reply);
|
_requests.remove(reply);
|
||||||
|
|
||||||
mtpBuffer data = handleResponse(reply);
|
mtpBuffer data = handleResponse(reply);
|
||||||
if (data.size() == 1) {
|
if (data.size() == 1) {
|
||||||
emit error(data[0]);
|
emit error(data[0]);
|
||||||
} else if (!data.isEmpty()) {
|
} else if (!data.isEmpty()) {
|
||||||
if (status == UsingHttp) {
|
if (_status == Status::Ready) {
|
||||||
_receivedQueue.push_back(data);
|
_receivedQueue.push_back(data);
|
||||||
emit receivedData();
|
emit receivedData();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
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 == _checkNonce) {
|
||||||
DEBUG_LOG(("Connection Info: HTTP-transport to %1 connected by pq-response").arg(_address));
|
DEBUG_LOG(("Connection Info: HTTP-transport to %1 connected by pq-response").arg(_address));
|
||||||
status = UsingHttp;
|
_status = Status::Ready;
|
||||||
_pingTime = getms() - _pingTime;
|
_pingTime = getms() - _pingTime;
|
||||||
emit connected();
|
emit connected();
|
||||||
}
|
}
|
||||||
|
@ -177,7 +184,7 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!requests.remove(reply)) {
|
if (!_requests.remove(reply)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,23 +192,23 @@ void HTTPConnection::requestFinished(QNetworkReply *reply) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeMs HTTPConnection::pingTime() const {
|
TimeMs HttpConnection::pingTime() const {
|
||||||
return isConnected() ? _pingTime : TimeMs(0);
|
return isConnected() ? _pingTime : TimeMs(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPConnection::usingHttpWait() {
|
bool HttpConnection::usingHttpWait() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPConnection::needHttpWait() {
|
bool HttpConnection::needHttpWait() {
|
||||||
return requests.isEmpty();
|
return _requests.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 HTTPConnection::debugState() const {
|
int32 HttpConnection::debugState() const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HTTPConnection::transport() const {
|
QString HttpConnection::transport() const {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
@ -212,7 +219,7 @@ QString HTTPConnection::transport() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HTTPConnection::tag() const {
|
QString HttpConnection::tag() const {
|
||||||
auto result = qsl("HTTP");
|
auto result = qsl("HTTP");
|
||||||
if (qthelp::is_ipv6(_address)) {
|
if (qthelp::is_ipv6(_address)) {
|
||||||
result += qsl("/IPv6");
|
result += qsl("/IPv6");
|
||||||
|
@ -222,7 +229,7 @@ QString HTTPConnection::tag() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl HTTPConnection::url() const {
|
QUrl HttpConnection::url() const {
|
||||||
const auto pattern = qthelp::is_ipv6(_address)
|
const auto pattern = qthelp::is_ipv6(_address)
|
||||||
? qsl("http://[%1]:%2/api")
|
? qsl("http://[%1]:%2/api")
|
||||||
: qsl("http://%1:%2/api");
|
: qsl("http://%1:%2/api");
|
||||||
|
|
|
@ -12,18 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class HTTPConnection : public AbstractConnection {
|
class HttpConnection : public AbstractConnection {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HTTPConnection(QThread *thread);
|
HttpConnection(QThread *thread);
|
||||||
|
|
||||||
void setProxyOverride(const ProxyData &proxy) override;
|
void setProxyOverride(const ProxyData &proxy) override;
|
||||||
TimeMs pingTime() const override;
|
TimeMs pingTime() const override;
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectToServer(
|
void connectToServer(
|
||||||
const QString &ip,
|
const QString &address,
|
||||||
int port,
|
int port,
|
||||||
const bytes::vector &protocolSecret,
|
const bytes::vector &protocolSecret,
|
||||||
int16 protocolDcId) override;
|
int16 protocolDcId) override;
|
||||||
|
@ -39,25 +37,23 @@ public:
|
||||||
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
|
||||||
|
|
||||||
public slots:
|
|
||||||
void requestFinished(QNetworkReply *reply);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl url() const;
|
QUrl url() const;
|
||||||
|
|
||||||
enum Status {
|
void requestFinished(QNetworkReply *reply);
|
||||||
WaitingHttp = 0,
|
|
||||||
UsingHttp,
|
|
||||||
FinishedWork
|
|
||||||
};
|
|
||||||
Status status;
|
|
||||||
MTPint128 httpNonce;
|
|
||||||
|
|
||||||
QNetworkAccessManager manager;
|
enum class Status {
|
||||||
|
Waiting = 0,
|
||||||
|
Ready,
|
||||||
|
Finished,
|
||||||
|
};
|
||||||
|
Status _status = Status::Waiting;
|
||||||
|
MTPint128 _checkNonce;
|
||||||
|
|
||||||
|
QNetworkAccessManager _manager;
|
||||||
QString _address;
|
QString _address;
|
||||||
|
|
||||||
typedef QSet<QNetworkReply*> Requests;
|
QSet<QNetworkReply*> _requests;
|
||||||
Requests requests;
|
|
||||||
|
|
||||||
TimeMs _pingTime = 0;
|
TimeMs _pingTime = 0;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kMinReceiveTimeout = TimeMs(2000);
|
constexpr auto kMinReceiveTimeout = TimeMs(2000);
|
||||||
constexpr auto kMaxReceiveTimeout = TimeMs(8000);
|
constexpr auto kMaxReceiveTimeout = TimeMs(8000);
|
||||||
|
constexpr auto kPacketSizeMax = 64 * 1024 * 1024U;
|
||||||
|
|
||||||
uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readable
|
uint32 CountTcpPacketSize(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) {
|
||||||
const uchar *bytes = reinterpret_cast<const uchar*>(packet);
|
const uchar *bytes = reinterpret_cast<const uchar*>(packet);
|
||||||
|
@ -29,92 +30,113 @@ uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readabl
|
||||||
return (result << 2) + 1;
|
return (result << 2) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using ErrorSignal = void(QTcpSocket::*)(QAbstractSocket::SocketError);
|
||||||
|
const auto QTcpSocket_error = ErrorSignal(&QAbstractSocket::error);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AbstractTCPConnection::AbstractTCPConnection(
|
TcpConnection::TcpConnection(QThread *thread)
|
||||||
QThread *thread)
|
|
||||||
: AbstractConnection(thread)
|
: AbstractConnection(thread)
|
||||||
, currentPos((char*)shortBuffer) {
|
, _currentPosition(reinterpret_cast<char*>(_shortBuffer))
|
||||||
|
, _checkNonce(rand_value<MTPint128>())
|
||||||
|
, _timeout(kMinReceiveTimeout)
|
||||||
|
, _timeoutTimer(thread, [=] { handleTimeout(); }) {
|
||||||
|
_socket.moveToThread(thread);
|
||||||
|
connect(&_socket, QTcpSocket_error, this, &TcpConnection::socketError);
|
||||||
|
connect(
|
||||||
|
&_socket,
|
||||||
|
&QTcpSocket::connected,
|
||||||
|
this,
|
||||||
|
&TcpConnection::socketConnected);
|
||||||
|
connect(
|
||||||
|
&_socket,
|
||||||
|
&QTcpSocket::disconnected,
|
||||||
|
this,
|
||||||
|
&TcpConnection::socketDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractTCPConnection::setProxyOverride(const ProxyData &proxy) {
|
void TcpConnection::setProxyOverride(const ProxyData &proxy) {
|
||||||
sock.setProxy(ToNetworkProxy(proxy));
|
_socket.setProxy(ToNetworkProxy(proxy));
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractTCPConnection::~AbstractTCPConnection() = default;
|
void TcpConnection::socketRead() {
|
||||||
|
if (_socket.state() != QAbstractSocket::ConnectedState) {
|
||||||
void AbstractTCPConnection::socketRead() {
|
LOG(("MTP error: "
|
||||||
if (sock.state() != QAbstractSocket::ConnectedState) {
|
"socket not connected in socketRead(), state: %1"
|
||||||
LOG(("MTP error: socket not connected in socketRead(), state: %1").arg(sock.state()));
|
).arg(_socket.state()));
|
||||||
emit error(kErrorCodeOther);
|
emit error(kErrorCodeOther);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint32 toRead = packetLeft ? packetLeft : (readingToShort ? (MTPShortBufferSize * sizeof(mtpPrime) - packetRead) : 4);
|
uint32 toRead = _packetLeft
|
||||||
if (readingToShort) {
|
? _packetLeft
|
||||||
if (currentPos + toRead > ((char*)shortBuffer) + MTPShortBufferSize * sizeof(mtpPrime)) {
|
: (_readingToShort
|
||||||
longBuffer.resize(((packetRead + toRead) >> 2) + 1);
|
? (kShortBufferSize * sizeof(mtpPrime) - _packetRead)
|
||||||
memcpy(&longBuffer[0], shortBuffer, packetRead);
|
: 4);
|
||||||
currentPos = ((char*)&longBuffer[0]) + packetRead;
|
if (_readingToShort) {
|
||||||
readingToShort = false;
|
if (_currentPosition + toRead > ((char*)_shortBuffer) + kShortBufferSize * sizeof(mtpPrime)) {
|
||||||
|
_longBuffer.resize(((_packetRead + toRead) >> 2) + 1);
|
||||||
|
memcpy(&_longBuffer[0], _shortBuffer, _packetRead);
|
||||||
|
_currentPosition = ((char*)&_longBuffer[0]) + _packetRead;
|
||||||
|
_readingToShort = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (longBuffer.size() * sizeof(mtpPrime) < packetRead + toRead) {
|
if (_longBuffer.size() * sizeof(mtpPrime) < _packetRead + toRead) {
|
||||||
longBuffer.resize(((packetRead + toRead) >> 2) + 1);
|
_longBuffer.resize(((_packetRead + toRead) >> 2) + 1);
|
||||||
currentPos = ((char*)&longBuffer[0]) + packetRead;
|
_currentPosition = ((char*)&_longBuffer[0]) + _packetRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int32 bytes = (int32)sock.read(currentPos, toRead);
|
int32 bytes = (int32)_socket.read(_currentPosition, toRead);
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
aesCtrEncrypt(currentPos, bytes, _receiveKey, &_receiveState);
|
aesCtrEncrypt(_currentPosition, bytes, _receiveKey, &_receiveState);
|
||||||
TCP_LOG(("TCP Info: read %1 bytes").arg(bytes));
|
TCP_LOG(("TCP Info: read %1 bytes").arg(bytes));
|
||||||
|
|
||||||
packetRead += bytes;
|
_packetRead += bytes;
|
||||||
currentPos += bytes;
|
_currentPosition += bytes;
|
||||||
if (packetLeft) {
|
if (_packetLeft) {
|
||||||
packetLeft -= bytes;
|
_packetLeft -= bytes;
|
||||||
if (!packetLeft) {
|
if (!_packetLeft) {
|
||||||
socketPacket(currentPos - packetRead, packetRead);
|
socketPacket(_currentPosition - _packetRead, _packetRead);
|
||||||
currentPos = (char*)shortBuffer;
|
_currentPosition = (char*)_shortBuffer;
|
||||||
packetRead = packetLeft = 0;
|
_packetRead = _packetLeft = 0;
|
||||||
readingToShort = true;
|
_readingToShort = true;
|
||||||
longBuffer.clear();
|
_longBuffer.clear();
|
||||||
} else {
|
} else {
|
||||||
TCP_LOG(("TCP Info: not enough %1 for packet! read %2").arg(packetLeft).arg(packetRead));
|
TCP_LOG(("TCP Info: not enough %1 for packet! read %2").arg(_packetLeft).arg(_packetRead));
|
||||||
emit receivedSome();
|
emit receivedSome();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool move = false;
|
bool move = false;
|
||||||
while (packetRead >= 4) {
|
while (_packetRead >= 4) {
|
||||||
uint32 packetSize = tcpPacketSize(currentPos - packetRead);
|
uint32 packetSize = CountTcpPacketSize(_currentPosition - _packetRead);
|
||||||
if (packetSize < 5 || packetSize > MTPPacketSizeMax) {
|
if (packetSize < 5 || packetSize > kPacketSizeMax) {
|
||||||
LOG(("TCP Error: packet size = %1").arg(packetSize));
|
LOG(("TCP Error: packet size = %1").arg(packetSize));
|
||||||
emit error(kErrorCodeOther);
|
emit error(kErrorCodeOther);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packetRead >= packetSize) {
|
if (_packetRead >= packetSize) {
|
||||||
socketPacket(currentPos - packetRead, packetSize);
|
socketPacket(_currentPosition - _packetRead, packetSize);
|
||||||
packetRead -= packetSize;
|
_packetRead -= packetSize;
|
||||||
packetLeft = 0;
|
_packetLeft = 0;
|
||||||
move = true;
|
move = true;
|
||||||
} else {
|
} else {
|
||||||
packetLeft = packetSize - packetRead;
|
_packetLeft = packetSize - _packetRead;
|
||||||
TCP_LOG(("TCP Info: not enough %1 for packet! size %2 read %3").arg(packetLeft).arg(packetSize).arg(packetRead));
|
TCP_LOG(("TCP Info: not enough %1 for packet! size %2 read %3").arg(_packetLeft).arg(packetSize).arg(_packetRead));
|
||||||
emit receivedSome();
|
emit receivedSome();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (move) {
|
if (move) {
|
||||||
if (!packetRead) {
|
if (!_packetRead) {
|
||||||
currentPos = (char*)shortBuffer;
|
_currentPosition = (char*)_shortBuffer;
|
||||||
readingToShort = true;
|
_readingToShort = true;
|
||||||
longBuffer.clear();
|
_longBuffer.clear();
|
||||||
} else if (!readingToShort && packetRead < MTPShortBufferSize * sizeof(mtpPrime)) {
|
} else if (!_readingToShort && _packetRead < kShortBufferSize * sizeof(mtpPrime)) {
|
||||||
memcpy(shortBuffer, currentPos - packetRead, packetRead);
|
memcpy(_shortBuffer, _currentPosition - _packetRead, _packetRead);
|
||||||
currentPos = (char*)shortBuffer + packetRead;
|
_currentPosition = (char*)_shortBuffer + _packetRead;
|
||||||
readingToShort = true;
|
_readingToShort = true;
|
||||||
longBuffer.clear();
|
_longBuffer.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,11 +148,11 @@ void AbstractTCPConnection::socketRead() {
|
||||||
TCP_LOG(("TCP Info: no bytes read, but bytes available was true..."));
|
TCP_LOG(("TCP Info: no bytes read, but bytes available was true..."));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (sock.state() == QAbstractSocket::ConnectedState && sock.bytesAvailable());
|
} while (_socket.state() == QAbstractSocket::ConnectedState && _socket.bytesAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpBuffer AbstractTCPConnection::handleResponse(const char *packet, uint32 length) {
|
mtpBuffer TcpConnection::handleResponse(const char *packet, uint32 length) {
|
||||||
if (length < 5 || length > MTPPacketSizeMax) {
|
if (length < 5 || length > kPacketSizeMax) {
|
||||||
LOG(("TCP Error: bad packet size %1").arg(length));
|
LOG(("TCP Error: bad packet size %1").arg(length));
|
||||||
return mtpBuffer(1, -500);
|
return mtpBuffer(1, -500);
|
||||||
}
|
}
|
||||||
|
@ -158,26 +180,26 @@ mtpBuffer AbstractTCPConnection::handleResponse(const char *packet, uint32 lengt
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractTCPConnection::handleError(QAbstractSocket::SocketError e, QTcpSocket &sock) {
|
void TcpConnection::handleError(QAbstractSocket::SocketError e, QTcpSocket &socket) {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case QAbstractSocket::ConnectionRefusedError:
|
case QAbstractSocket::ConnectionRefusedError:
|
||||||
LOG(("TCP Error: socket connection refused - %1").arg(sock.errorString()));
|
LOG(("TCP Error: socket connection refused - %1").arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QAbstractSocket::RemoteHostClosedError:
|
case QAbstractSocket::RemoteHostClosedError:
|
||||||
TCP_LOG(("TCP Info: remote host closed socket connection - %1").arg(sock.errorString()));
|
TCP_LOG(("TCP Info: remote host closed socket connection - %1").arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QAbstractSocket::HostNotFoundError:
|
case QAbstractSocket::HostNotFoundError:
|
||||||
LOG(("TCP Error: host not found - %1").arg(sock.errorString()));
|
LOG(("TCP Error: host not found - %1").arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QAbstractSocket::SocketTimeoutError:
|
case QAbstractSocket::SocketTimeoutError:
|
||||||
LOG(("TCP Error: socket timeout - %1").arg(sock.errorString()));
|
LOG(("TCP Error: socket timeout - %1").arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QAbstractSocket::NetworkError:
|
case QAbstractSocket::NetworkError:
|
||||||
LOG(("TCP Error: network - %1").arg(sock.errorString()));
|
LOG(("TCP Error: network - %1").arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
||||||
|
@ -186,77 +208,62 @@ void AbstractTCPConnection::handleError(QAbstractSocket::SocketError e, QTcpSock
|
||||||
case QAbstractSocket::ProxyConnectionTimeoutError:
|
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||||
case QAbstractSocket::ProxyNotFoundError:
|
case QAbstractSocket::ProxyNotFoundError:
|
||||||
case QAbstractSocket::ProxyProtocolError:
|
case QAbstractSocket::ProxyProtocolError:
|
||||||
LOG(("TCP Error: proxy (%1) - %2").arg(e).arg(sock.errorString()));
|
LOG(("TCP Error: proxy (%1) - %2").arg(e).arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG(("TCP Error: other (%1) - %2").arg(e).arg(sock.errorString()));
|
LOG(("TCP Error: other (%1) - %2").arg(e).arg(socket.errorString()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(sock.errorString()));
|
TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(socket.errorString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TCPConnection::TCPConnection(QThread *thread)
|
void TcpConnection::socketConnected() {
|
||||||
: AbstractTCPConnection(thread)
|
if (_status == Status::Waiting) {
|
||||||
, status(WaitingTcp)
|
mtpBuffer buffer(preparePQFake(_checkNonce));
|
||||||
, tcpNonce(rand_value<MTPint128>())
|
|
||||||
, _tcpTimeout(kMinReceiveTimeout) {
|
|
||||||
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 TCPConnection::onSocketConnected() {
|
|
||||||
if (status == WaitingTcp) {
|
|
||||||
mtpBuffer buffer(preparePQFake(tcpNonce));
|
|
||||||
|
|
||||||
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP transport to %1").arg(_address));
|
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP transport to %1").arg(_address));
|
||||||
|
|
||||||
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
if (_timeout < 0) _timeout = -_timeout;
|
||||||
tcpTimeoutTimer.start(_tcpTimeout);
|
_timeoutTimer.callOnce(_timeout);
|
||||||
|
|
||||||
_pingTime = getms();
|
_pingTime = getms();
|
||||||
sendData(buffer);
|
sendData(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::onTcpTimeoutTimer() {
|
void TcpConnection::handleTimeout() {
|
||||||
if (status == WaitingTcp) {
|
if (_status == Status::Waiting) {
|
||||||
if (_tcpTimeout < kMaxReceiveTimeout) {
|
if (_timeout < kMaxReceiveTimeout) {
|
||||||
_tcpTimeout *= 2;
|
_timeout *= 2;
|
||||||
}
|
}
|
||||||
_tcpTimeout = -_tcpTimeout;
|
_timeout = -_timeout;
|
||||||
|
|
||||||
QAbstractSocket::SocketState state = sock.state();
|
QAbstractSocket::SocketState state = _socket.state();
|
||||||
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||||
sock.disconnectFromHost();
|
_socket.disconnectFromHost();
|
||||||
} else if (state != QAbstractSocket::ClosingState) {
|
} else if (state != QAbstractSocket::ClosingState) {
|
||||||
sock.connectToHost(QHostAddress(_address), _port);
|
_socket.connectToHost(_address, _port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::onSocketDisconnected() {
|
void TcpConnection::socketDisconnected() {
|
||||||
if (_tcpTimeout < 0) {
|
if (_timeout < 0) {
|
||||||
_tcpTimeout = -_tcpTimeout;
|
_timeout = -_timeout;
|
||||||
if (status == WaitingTcp) {
|
if (_status == Status::Waiting) {
|
||||||
sock.connectToHost(QHostAddress(_address), _port);
|
_socket.connectToHost(_address, _port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status == WaitingTcp || status == UsingTcp) {
|
if (_status == Status::Waiting || _status == Status::Ready) {
|
||||||
emit disconnected();
|
emit disconnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::sendData(mtpBuffer &buffer) {
|
void TcpConnection::sendData(mtpBuffer &buffer) {
|
||||||
if (status == FinishedWork) return;
|
if (_status == Status::Finished) return;
|
||||||
|
|
||||||
if (buffer.size() < 3) {
|
if (buffer.size() < 3) {
|
||||||
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
|
LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime)));
|
||||||
|
@ -265,10 +272,10 @@ void TCPConnection::sendData(mtpBuffer &buffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpSend(buffer);
|
sendBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractTCPConnection::writeConnectionStart() {
|
void TcpConnection::writeConnectionStart() {
|
||||||
// prepare random part
|
// prepare random part
|
||||||
auto nonceBytes = bytes::vector(64);
|
auto nonceBytes = bytes::vector(64);
|
||||||
const auto nonce = bytes::make_span(nonceBytes);
|
const auto nonce = bytes::make_span(nonceBytes);
|
||||||
|
@ -280,8 +287,7 @@ void AbstractTCPConnection::writeConnectionStart() {
|
||||||
const auto reserved11 = 0x44414548U;
|
const auto reserved11 = 0x44414548U;
|
||||||
const auto reserved12 = 0x54534F50U;
|
const auto reserved12 = 0x54534F50U;
|
||||||
const auto reserved13 = 0x20544547U;
|
const auto reserved13 = 0x20544547U;
|
||||||
const auto reserved14 = 0x20544547U;
|
const auto reserved14 = 0xEEEEEEEEU;
|
||||||
const auto reserved15 = 0xEEEEEEEEU;
|
|
||||||
const auto reserved21 = 0x00000000U;
|
const auto reserved21 = 0x00000000U;
|
||||||
do {
|
do {
|
||||||
bytes::set_random(nonce);
|
bytes::set_random(nonce);
|
||||||
|
@ -290,7 +296,6 @@ void AbstractTCPConnection::writeConnectionStart() {
|
||||||
|| *first == reserved12
|
|| *first == reserved12
|
||||||
|| *first == reserved13
|
|| *first == reserved13
|
||||||
|| *first == reserved14
|
|| *first == reserved14
|
||||||
|| *first == reserved15
|
|
||||||
|| *second == reserved21);
|
|| *second == reserved21);
|
||||||
|
|
||||||
const auto prepareKey = [&](bytes::span key, bytes::const_span from) {
|
const auto prepareKey = [&](bytes::span key, bytes::const_span from) {
|
||||||
|
@ -330,80 +335,79 @@ void AbstractTCPConnection::writeConnectionStart() {
|
||||||
const auto dcId = reinterpret_cast<int16*>(nonce.data() + 60);
|
const auto dcId = reinterpret_cast<int16*>(nonce.data() + 60);
|
||||||
*dcId = _protocolDcId;
|
*dcId = _protocolDcId;
|
||||||
|
|
||||||
sock.write(reinterpret_cast<const char*>(nonce.data()), 56);
|
_socket.write(reinterpret_cast<const char*>(nonce.data()), 56);
|
||||||
aesCtrEncrypt(nonce.data(), 64, _sendKey, &_sendState);
|
aesCtrEncrypt(nonce.data(), 64, _sendKey, &_sendState);
|
||||||
sock.write(reinterpret_cast<const char*>(nonce.subspan(56).data()), 8);
|
_socket.write(reinterpret_cast<const char*>(nonce.subspan(56).data()), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractTCPConnection::tcpSend(mtpBuffer &buffer) {
|
void TcpConnection::sendBuffer(mtpBuffer &buffer) {
|
||||||
if (!packetNum) {
|
if (!_packetIndex++) {
|
||||||
writeConnectionStart();
|
writeConnectionStart();
|
||||||
}
|
}
|
||||||
++packetNum;
|
|
||||||
|
|
||||||
uint32 size = buffer.size() - 3, len = size * 4;
|
uint32 size = buffer.size() - 3, len = size * 4;
|
||||||
char *data = reinterpret_cast<char*>(&buffer[0]);
|
char *data = reinterpret_cast<char*>(&buffer[0]);
|
||||||
if (size < 0x7f) {
|
if (size < 0x7f) {
|
||||||
data[7] = char(size);
|
data[7] = char(size);
|
||||||
TCP_LOG(("TCP Info: write %1 packet %2").arg(packetNum).arg(len + 1));
|
TCP_LOG(("TCP Info: write %1 packet %2").arg(_packetIndex).arg(len + 1));
|
||||||
|
|
||||||
aesCtrEncrypt(data + 7, len + 1, _sendKey, &_sendState);
|
aesCtrEncrypt(data + 7, len + 1, _sendKey, &_sendState);
|
||||||
sock.write(data + 7, len + 1);
|
_socket.write(data + 7, len + 1);
|
||||||
} else {
|
} else {
|
||||||
data[4] = 0x7f;
|
data[4] = 0x7f;
|
||||||
reinterpret_cast<uchar*>(data)[5] = uchar(size & 0xFF);
|
reinterpret_cast<uchar*>(data)[5] = uchar(size & 0xFF);
|
||||||
reinterpret_cast<uchar*>(data)[6] = uchar((size >> 8) & 0xFF);
|
reinterpret_cast<uchar*>(data)[6] = uchar((size >> 8) & 0xFF);
|
||||||
reinterpret_cast<uchar*>(data)[7] = uchar((size >> 16) & 0xFF);
|
reinterpret_cast<uchar*>(data)[7] = uchar((size >> 16) & 0xFF);
|
||||||
TCP_LOG(("TCP Info: write %1 packet %2").arg(packetNum).arg(len + 4));
|
TCP_LOG(("TCP Info: write %1 packet %2").arg(_packetIndex).arg(len + 4));
|
||||||
|
|
||||||
aesCtrEncrypt(data + 4, len + 4, _sendKey, &_sendState);
|
aesCtrEncrypt(data + 4, len + 4, _sendKey, &_sendState);
|
||||||
sock.write(data + 4, len + 4);
|
_socket.write(data + 4, len + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::disconnectFromServer() {
|
void TcpConnection::disconnectFromServer() {
|
||||||
if (status == FinishedWork) return;
|
if (_status == Status::Finished) return;
|
||||||
status = FinishedWork;
|
_status = Status::Finished;
|
||||||
|
|
||||||
disconnect(&sock, SIGNAL(readyRead()), 0, 0);
|
disconnect(&_socket, &QTcpSocket::readyRead, nullptr, nullptr);
|
||||||
sock.close();
|
_socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::connectToServer(
|
void TcpConnection::connectToServer(
|
||||||
const QString &ip,
|
const QString &address,
|
||||||
int port,
|
int port,
|
||||||
const bytes::vector &protocolSecret,
|
const bytes::vector &protocolSecret,
|
||||||
int16 protocolDcId) {
|
int16 protocolDcId) {
|
||||||
_address = ip;
|
_address = address;
|
||||||
_port = port;
|
_port = port;
|
||||||
_protocolSecret = protocolSecret;
|
_protocolSecret = protocolSecret;
|
||||||
_protocolDcId = protocolDcId;
|
_protocolDcId = protocolDcId;
|
||||||
|
|
||||||
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
connect(&_socket, &QTcpSocket::readyRead, this, &TcpConnection::socketRead);
|
||||||
sock.connectToHost(QHostAddress(_address), _port);
|
_socket.connectToHost(_address, _port);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeMs TCPConnection::pingTime() const {
|
TimeMs TcpConnection::pingTime() const {
|
||||||
return isConnected() ? _pingTime : TimeMs(0);
|
return isConnected() ? _pingTime : TimeMs(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
void TcpConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
if (status == FinishedWork) return;
|
if (_status == Status::Finished) return;
|
||||||
|
|
||||||
mtpBuffer data = handleResponse(packet, length);
|
mtpBuffer data = handleResponse(packet, length);
|
||||||
if (data.size() == 1) {
|
if (data.size() == 1) {
|
||||||
emit error(data[0]);
|
emit error(data[0]);
|
||||||
} else if (status == UsingTcp) {
|
} else if (_status == Status::Ready) {
|
||||||
_receivedQueue.push_back(data);
|
_receivedQueue.push_back(data);
|
||||||
emit receivedData();
|
emit receivedData();
|
||||||
} else if (status == WaitingTcp) {
|
} else if (_status == Status::Waiting) {
|
||||||
tcpTimeoutTimer.stop();
|
_timeoutTimer.cancel();
|
||||||
try {
|
try {
|
||||||
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 == _checkNonce) {
|
||||||
DEBUG_LOG(("Connection Info: TCP-transport to %1 chosen by pq-response").arg(_address));
|
DEBUG_LOG(("Connection Info: TCP-transport to %1 chosen by pq-response").arg(_address));
|
||||||
status = UsingTcp;
|
_status = Status::Ready;
|
||||||
_pingTime = (getms() - _pingTime);
|
_pingTime = (getms() - _pingTime);
|
||||||
emit connected();
|
emit connected();
|
||||||
}
|
}
|
||||||
|
@ -414,15 +418,15 @@ void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TCPConnection::isConnected() const {
|
bool TcpConnection::isConnected() const {
|
||||||
return (status == UsingTcp);
|
return (_status == Status::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 TCPConnection::debugState() const {
|
int32 TcpConnection::debugState() const {
|
||||||
return sock.state();
|
return _socket.state();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TCPConnection::transport() const {
|
QString TcpConnection::transport() const {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
@ -433,7 +437,7 @@ QString TCPConnection::transport() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TCPConnection::tag() const {
|
QString TcpConnection::tag() const {
|
||||||
auto result = qsl("TCP");
|
auto result = qsl("TCP");
|
||||||
if (qthelp::is_ipv6(_address)) {
|
if (qthelp::is_ipv6(_address)) {
|
||||||
result += qsl("/IPv6");
|
result += qsl("/IPv6");
|
||||||
|
@ -443,10 +447,10 @@ QString TCPConnection::tag() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCPConnection::socketError(QAbstractSocket::SocketError e) {
|
void TcpConnection::socketError(QAbstractSocket::SocketError e) {
|
||||||
if (status == FinishedWork) return;
|
if (_status == Status::Finished) return;
|
||||||
|
|
||||||
handleError(e, sock);
|
handleError(e, _socket);
|
||||||
emit error(kErrorCodeOther);
|
emit error(kErrorCodeOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,64 +9,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "mtproto/auth_key.h"
|
#include "mtproto/auth_key.h"
|
||||||
#include "mtproto/connection_abstract.h"
|
#include "mtproto/connection_abstract.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class AbstractTCPConnection : public AbstractConnection {
|
class TcpConnection : public AbstractConnection {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractTCPConnection(QThread *thread);
|
TcpConnection(QThread *thread);
|
||||||
|
|
||||||
void setProxyOverride(const ProxyData &proxy) override;
|
void setProxyOverride(const ProxyData &proxy) override;
|
||||||
virtual ~AbstractTCPConnection() = 0;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void socketRead();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void writeConnectionStart();
|
|
||||||
|
|
||||||
QTcpSocket sock;
|
|
||||||
uint32 packetNum = 0; // sent packet number
|
|
||||||
|
|
||||||
uint32 packetRead = 0;
|
|
||||||
uint32 packetLeft = 0; // reading from socket
|
|
||||||
bool readingToShort = true;
|
|
||||||
char *currentPos;
|
|
||||||
mtpBuffer longBuffer;
|
|
||||||
mtpPrime shortBuffer[MTPShortBufferSize];
|
|
||||||
virtual void socketPacket(const char *packet, uint32 length) = 0;
|
|
||||||
|
|
||||||
static mtpBuffer handleResponse(const char *packet, uint32 length);
|
|
||||||
static void handleError(QAbstractSocket::SocketError e, QTcpSocket &sock);
|
|
||||||
static uint32 fourCharsToUInt(char ch1, char ch2, char ch3, char ch4) {
|
|
||||||
char ch[4] = { ch1, ch2, ch3, ch4 };
|
|
||||||
return *reinterpret_cast<uint32*>(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tcpSend(mtpBuffer &buffer);
|
|
||||||
uchar _sendKey[CTRState::KeySize];
|
|
||||||
CTRState _sendState;
|
|
||||||
uchar _receiveKey[CTRState::KeySize];
|
|
||||||
CTRState _receiveState;
|
|
||||||
int16 _protocolDcId = 0;
|
|
||||||
bytes::vector _protocolSecret;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class TCPConnection : public AbstractTCPConnection {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
TCPConnection(QThread *thread);
|
|
||||||
|
|
||||||
TimeMs pingTime() const override;
|
TimeMs pingTime() const override;
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
void disconnectFromServer() override;
|
void disconnectFromServer() override;
|
||||||
void connectToServer(
|
void connectToServer(
|
||||||
const QString &ip,
|
const QString &address,
|
||||||
int port,
|
int port,
|
||||||
const bytes::vector &protocolSecret,
|
const bytes::vector &protocolSecret,
|
||||||
int16 protocolDcId) override;
|
int16 protocolDcId) override;
|
||||||
|
@ -77,29 +35,57 @@ public:
|
||||||
QString transport() const override;
|
QString transport() const override;
|
||||||
QString tag() const override;
|
QString tag() const override;
|
||||||
|
|
||||||
public slots:
|
|
||||||
void socketError(QAbstractSocket::SocketError e);
|
|
||||||
|
|
||||||
void onSocketConnected();
|
|
||||||
void onSocketDisconnected();
|
|
||||||
|
|
||||||
void onTcpTimeoutTimer();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void socketPacket(const char *packet, uint32 length) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Status {
|
enum class Status {
|
||||||
WaitingTcp = 0,
|
Waiting = 0,
|
||||||
UsingTcp,
|
Ready,
|
||||||
FinishedWork
|
Finished,
|
||||||
};
|
};
|
||||||
Status status;
|
static constexpr auto kShortBufferSize = 65535; // Of ints, 256 kb.
|
||||||
MTPint128 tcpNonce;
|
|
||||||
|
void socketRead();
|
||||||
|
void writeConnectionStart();
|
||||||
|
|
||||||
|
void socketPacket(const char *packet, uint32 length);
|
||||||
|
|
||||||
|
void socketConnected();
|
||||||
|
void socketDisconnected();
|
||||||
|
void socketError(QAbstractSocket::SocketError e);
|
||||||
|
void handleTimeout();
|
||||||
|
|
||||||
|
static mtpBuffer handleResponse(const char *packet, uint32 length);
|
||||||
|
static void handleError(QAbstractSocket::SocketError e, QTcpSocket &sock);
|
||||||
|
static uint32 fourCharsToUInt(char ch1, char ch2, char ch3, char ch4) {
|
||||||
|
char ch[4] = { ch1, ch2, ch3, ch4 };
|
||||||
|
return *reinterpret_cast<uint32*>(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendBuffer(mtpBuffer &buffer);
|
||||||
|
|
||||||
|
QTcpSocket _socket;
|
||||||
|
uint32 _packetIndex = 0; // sent packet number
|
||||||
|
|
||||||
|
uint32 _packetRead = 0;
|
||||||
|
uint32 _packetLeft = 0; // reading from socket
|
||||||
|
bool _readingToShort = true;
|
||||||
|
mtpBuffer _longBuffer;
|
||||||
|
mtpPrime _shortBuffer[kShortBufferSize];
|
||||||
|
char *_currentPosition = nullptr;
|
||||||
|
|
||||||
|
uchar _sendKey[CTRState::KeySize];
|
||||||
|
CTRState _sendState;
|
||||||
|
uchar _receiveKey[CTRState::KeySize];
|
||||||
|
CTRState _receiveState;
|
||||||
|
int16 _protocolDcId = 0;
|
||||||
|
bytes::vector _protocolSecret;
|
||||||
|
|
||||||
|
Status _status = Status::Waiting;
|
||||||
|
MTPint128 _checkNonce;
|
||||||
|
|
||||||
QString _address;
|
QString _address;
|
||||||
int32 _port, _tcpTimeout;
|
int32 _port = 0;
|
||||||
QTimer tcpTimeoutTimer;
|
int32 _timeout = 0;
|
||||||
|
base::Timer _timeoutTimer;
|
||||||
TimeMs _pingTime = 0;
|
TimeMs _pingTime = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
class MainWindow : public Window::MainWindow {
|
class MainWindow : public Window::MainWindow {
|
||||||
|
// The Q_OBJECT meta info is used for qobject_cast to MainWindow!
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue