Improve mtproto connections logging.

This commit is contained in:
John Preston 2022-02-07 14:24:02 +03:00
parent 20c911651f
commit 8658dba97a
13 changed files with 231 additions and 150 deletions

View file

@ -16,6 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace MTP { namespace MTP {
namespace details { namespace details {
namespace {
std::atomic<int> GlobalConnectionCounter/* = 0*/;
} // namespace
ConnectionPointer::ConnectionPointer() = default; ConnectionPointer::ConnectionPointer() = default;
@ -158,7 +163,8 @@ std::optional<MTPResPQ> AbstractConnection::readPQFakeReply(
AbstractConnection::AbstractConnection( AbstractConnection::AbstractConnection(
QThread *thread, QThread *thread,
const ProxyData &proxy) const ProxyData &proxy)
: _proxy(proxy) { : _proxy(proxy)
, _debugId(QString::number(++GlobalConnectionCounter)) {
moveToThread(thread); moveToThread(thread);
} }
@ -188,6 +194,24 @@ ConnectionPointer AbstractConnection::Create(
return result; return result;
} }
QString AbstractConnection::ProtocolDcDebugId(int16 protocolDcId) {
const auto postfix = (protocolDcId < 0) ? "_media" : "";
protocolDcId = (protocolDcId < 0) ? (-protocolDcId) : protocolDcId;
const auto prefix = (protocolDcId > kTestModeDcIdShift) ? "test_" : "";
protocolDcId = (protocolDcId > kTestModeDcIdShift)
? (protocolDcId - kTestModeDcIdShift)
: protocolDcId;
return prefix + QString::number(protocolDcId) + postfix;
}
void AbstractConnection::logInfo(const QString &message) {
DEBUG_LOG(("Connection %1 Info: ").arg(_debugId) + message);
}
void AbstractConnection::logError(const QString &message) {
DEBUG_LOG(("Connection %1 Error: ").arg(_debugId) + message);
}
uint32 AbstractConnection::extendedNotSecurePadding() const { uint32 AbstractConnection::extendedNotSecurePadding() const {
return uint32(base::RandomValue<uchar>() & 0x3F); return uint32(base::RandomValue<uchar>() & 0x3F);
} }

View file

@ -24,6 +24,8 @@ struct ConnectionOptions;
class AbstractConnection; class AbstractConnection;
inline constexpr auto kTestModeDcIdShift = 10000;
class ConnectionPointer { class ConnectionPointer {
public: public:
ConnectionPointer(); ConnectionPointer();
@ -122,6 +124,13 @@ public:
[[nodiscard]] gsl::span<const mtpPrime> parseNotSecureResponse( [[nodiscard]] gsl::span<const mtpPrime> parseNotSecureResponse(
const mtpBuffer &buffer) const; const mtpBuffer &buffer) const;
[[nodiscard]] static QString ProtocolDcDebugId(int16 protocolDcId);
[[nodiscard]] QString debugId() const {
return _debugId;
}
void logInfo(const QString &message);
void logError(const QString &message);
// Used to emit error(...) with no real code from the server. // Used to emit error(...) with no real code from the server.
static constexpr auto kErrorCodeOther = -499; static constexpr auto kErrorCodeOther = -499;
@ -141,6 +150,8 @@ protected:
int _pingTime = 0; int _pingTime = 0;
ProxyData _proxy; ProxyData _proxy;
QString _debugId;
// first we always send fake MTPReq_pq to see if connection works at all // first we always send fake MTPReq_pq to see if connection works at all
// we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one // we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one
[[nodiscard]] mtpBuffer preparePQFake(const MTPint128 &nonce) const; [[nodiscard]] mtpBuffer preparePQFake(const MTPint128 &nonce) const;
@ -193,5 +204,8 @@ mtpBuffer AbstractConnection::prepareNotSecurePacket(
return result; return result;
} }
#define CONNECTION_LOG_INFO(x) if (Logs::DebugEnabled()) { logInfo(x); }
#define CONNECTION_LOG_ERROR(x) if (Logs::DebugEnabled()) { logError(x); }
} // namespace details } // namespace details
} // namespace MTP } // namespace MTP

View file

@ -43,7 +43,7 @@ void HttpConnection::sendData(mtpBuffer &&buffer) {
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")));
TCP_LOG(("HTTP Info: sending %1 len request").arg(requestSize)); CONNECTION_LOG_INFO(u"Sending %1 len request."_q.arg(requestSize));
_requests.insert(_manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize))); _requests.insert(_manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
} }
@ -78,10 +78,12 @@ void HttpConnection::connectToServer(
auto buffer = preparePQFake(_checkNonce); auto buffer = preparePQFake(_checkNonce);
DEBUG_LOG(("HTTP Info: " if (Logs::DebugEnabled()) {
"dc:%1 - Sending fake req_pq to '%2'" _debugId = u"%1(dc:%2,%3)"_q
).arg(protocolDcId .arg(_debugId.toInt())
).arg(url().toDisplayString())); .arg(ProtocolDcDebugId(protocolDcId))
.arg(url().toDisplayString());
}
_pingTime = crl::now(); _pingTime = crl::now();
sendData(std::move(buffer)); sendData(std::move(buffer));
@ -89,12 +91,12 @@ void HttpConnection::connectToServer(
mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) { mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) {
QByteArray response = reply->readAll(); QByteArray response = reply->readAll();
TCP_LOG(("HTTP Info: read %1 bytes").arg(response.size())); CONNECTION_LOG_INFO(u"Read %1 bytes."_q.arg(response.size()));
if (response.isEmpty()) return mtpBuffer(); if (response.isEmpty()) return mtpBuffer();
if (response.size() & 0x03 || response.size() < 8) { if (response.size() & 0x03 || response.size() < 8) {
LOG(("HTTP Error: bad response size %1").arg(response.size())); CONNECTION_LOG_ERROR(u"Bad response size %1."_q.arg(response.size()));
return mtpBuffer(1, -500); return mtpBuffer(1, -500);
} }
@ -104,31 +106,46 @@ mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) {
return data; return data;
} }
qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key" // Returns "maybe bad key".
qint32 HttpConnection::handleError(QNetworkReply *reply) {
auto result = qint32(kErrorCodeOther); auto result = qint32(kErrorCodeOther);
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); QVariant statusCode = reply->attribute(
QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode.isValid()) { if (statusCode.isValid()) {
int status = statusCode.toInt(); int status = statusCode.toInt();
result = -status; result = -status;
} }
switch (reply->error()) { switch (reply->error()) {
case QNetworkReply::ConnectionRefusedError: LOG(("HTTP Error: connection refused - %1").arg(reply->errorString())); break; case QNetworkReply::ConnectionRefusedError:
case QNetworkReply::RemoteHostClosedError: LOG(("HTTP Error: remote host closed - %1").arg(reply->errorString())); break; CONNECTION_LOG_ERROR(u"Connection refused - %1."_q
case QNetworkReply::HostNotFoundError: LOG(("HTTP Error: host not found - %1").arg(reply->errorString())); break; .arg(reply->errorString()));
case QNetworkReply::TimeoutError: LOG(("HTTP Error: timeout - %1").arg(reply->errorString())); break; break;
case QNetworkReply::OperationCanceledError: LOG(("HTTP Error: cancelled - %1").arg(reply->errorString())); break; case QNetworkReply::RemoteHostClosedError:
CONNECTION_LOG_ERROR(u"Remote host closed - %1."_q
.arg(reply->errorString()));
break;
case QNetworkReply::HostNotFoundError:
CONNECTION_LOG_ERROR(u"Host not found - %1."_q
.arg(reply->errorString()));
break;
case QNetworkReply::TimeoutError:
CONNECTION_LOG_ERROR(u"Timeout - %1."_q
.arg(reply->errorString()));
break;
case QNetworkReply::OperationCanceledError:
CONNECTION_LOG_ERROR(u"Cancelled - %1."_q
.arg(reply->errorString()));
break;
case QNetworkReply::SslHandshakeFailedError: case QNetworkReply::SslHandshakeFailedError:
case QNetworkReply::TemporaryNetworkFailureError: case QNetworkReply::TemporaryNetworkFailureError:
case QNetworkReply::NetworkSessionFailedError: case QNetworkReply::NetworkSessionFailedError:
case QNetworkReply::BackgroundRequestNotAllowedError: case QNetworkReply::BackgroundRequestNotAllowedError:
case QNetworkReply::UnknownNetworkError: case QNetworkReply::UnknownNetworkError:
if (reply->error() == QNetworkReply::UnknownNetworkError) { CONNECTION_LOG_ERROR(u"Network error %1 - %2."_q
DEBUG_LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString())); .arg(reply->error())
} else { .arg(reply->errorString()));
LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString()));
}
break; break;
// proxy errors (101-199): // proxy errors (101-199):
@ -137,7 +154,11 @@ qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
case QNetworkReply::ProxyNotFoundError: case QNetworkReply::ProxyNotFoundError:
case QNetworkReply::ProxyTimeoutError: case QNetworkReply::ProxyTimeoutError:
case QNetworkReply::ProxyAuthenticationRequiredError: case QNetworkReply::ProxyAuthenticationRequiredError:
case QNetworkReply::UnknownProxyError: LOG(("HTTP Error: proxy error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; case QNetworkReply::UnknownProxyError:
CONNECTION_LOG_ERROR(u"Proxy error %1 - %2."_q
.arg(reply->error())
.arg(reply->errorString()));
break;
// content errors (201-299): // content errors (201-299):
case QNetworkReply::ContentAccessDenied: case QNetworkReply::ContentAccessDenied:
@ -145,14 +166,21 @@ qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
case QNetworkReply::ContentNotFoundError: case QNetworkReply::ContentNotFoundError:
case QNetworkReply::AuthenticationRequiredError: case QNetworkReply::AuthenticationRequiredError:
case QNetworkReply::ContentReSendError: case QNetworkReply::ContentReSendError:
case QNetworkReply::UnknownContentError: LOG(("HTTP Error: content error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; case QNetworkReply::UnknownContentError:
CONNECTION_LOG_ERROR(u"Content error %1 - %2."_q
.arg(reply->error())
.arg(reply->errorString()));
break;
// protocol errors // protocol errors
case QNetworkReply::ProtocolUnknownError: case QNetworkReply::ProtocolUnknownError:
case QNetworkReply::ProtocolInvalidOperationError: case QNetworkReply::ProtocolInvalidOperationError:
case QNetworkReply::ProtocolFailure: LOG(("HTTP Error: protocol error %1 - %2").arg(reply->error()).arg(reply->errorString())); break; case QNetworkReply::ProtocolFailure:
CONNECTION_LOG_ERROR(u"Protocol error %1 - %2."_q
.arg(reply->error())
.arg(reply->errorString()));
break;
}; };
TCP_LOG(("HTTP Error %1, restarting! - %2").arg(reply->error()).arg(reply->errorString()));
return result; return result;
} }
@ -178,20 +206,19 @@ void HttpConnection::requestFinished(QNetworkReply *reply) {
} else if (const auto res_pq = readPQFakeReply(data)) { } else if (const auto res_pq = readPQFakeReply(data)) {
const auto &data = res_pq->c_resPQ(); const auto &data = res_pq->c_resPQ();
if (data.vnonce() == _checkNonce) { if (data.vnonce() == _checkNonce) {
DEBUG_LOG(("Connection Info: " CONNECTION_LOG_INFO(
"HTTP-transport to %1 connected by pq-response" "HTTP-transport connected by pq-response.");
).arg(_address));
_status = Status::Ready; _status = Status::Ready;
_pingTime = crl::now() - _pingTime; _pingTime = crl::now() - _pingTime;
connected(); connected();
} else { } else {
DEBUG_LOG(("Connection Error: " CONNECTION_LOG_ERROR(
"Wrong nonce received in HTTP fake pq-responce")); "Wrong nonce in HTTP fake pq-response.");
error(kErrorCodeOther); error(kErrorCodeOther);
} }
} else { } else {
DEBUG_LOG(("Connection Error: " CONNECTION_LOG_ERROR(
"Could not parse HTTP fake pq-responce")); "Could not parse HTTP fake pq-response.");
error(kErrorCodeOther); error(kErrorCodeOther);
} }
} }

View file

@ -40,8 +40,8 @@ public:
QString transport() const override; QString transport() const override;
QString tag() const override; QString tag() const override;
static mtpBuffer handleResponse(QNetworkReply *reply); mtpBuffer handleResponse(QNetworkReply *reply);
static qint32 handleError(QNetworkReply *reply); // Returns error code. qint32 handleError(QNetworkReply *reply); // Returns error code.
private: private:
QUrl url() const; QUrl url() const;

View file

@ -72,12 +72,6 @@ void ResolvingConnection::setChild(ConnectionPointer &&child) {
&AbstractConnection::disconnected, &AbstractConnection::disconnected,
this, this,
&ResolvingConnection::handleDisconnected); &ResolvingConnection::handleDisconnected);
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' got new child '%3'").arg(
QString::number(_protocolDcId),
_proxy.host + ':' + QString::number(_proxy.port),
(_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
? _proxy.resolvedIPs[_ipIndex]
: _proxy.host));
if (_protocolDcId) { if (_protocolDcId) {
_child->connectToServer( _child->connectToServer(
_address, _address,
@ -85,6 +79,8 @@ void ResolvingConnection::setChild(ConnectionPointer &&child) {
_protocolSecret, _protocolSecret,
_protocolDcId, _protocolDcId,
_protocolForFiles); _protocolForFiles);
CONNECTION_LOG_INFO("Resolving connected a new child: "
+ _child->debugId());
} }
} }
@ -224,18 +220,13 @@ void ResolvingConnection::connectToServer(
_protocolSecret = protocolSecret; _protocolSecret = protocolSecret;
_protocolDcId = protocolDcId; _protocolDcId = protocolDcId;
_protocolForFiles = protocolForFiles; _protocolForFiles = protocolForFiles;
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' connects a child '%3'").arg( _child->connectToServer(
QString::number(_protocolDcId),
_proxy.host +':' + QString::number(_proxy.port),
(_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
? _proxy.resolvedIPs[_ipIndex]
: _proxy.host));
return _child->connectToServer(
address, address,
port, port,
protocolSecret, protocolSecret,
protocolDcId, protocolDcId,
protocolForFiles); protocolForFiles);
CONNECTION_LOG_INFO("Resolving connected a child: " + _child->debugId());
} }
bool ResolvingConnection::isConnected() const { bool ResolvingConnection::isConnected() const {

View file

@ -40,6 +40,8 @@ public:
virtual int readPacketLength(bytes::const_span bytes) const = 0; virtual int readPacketLength(bytes::const_span bytes) const = 0;
virtual bytes::const_span readPacket(bytes::const_span bytes) const = 0; virtual bytes::const_span readPacket(bytes::const_span bytes) const = 0;
virtual QString debugPostfix() const = 0;
virtual ~Protocol() = default; virtual ~Protocol() = default;
private: private:
@ -60,6 +62,8 @@ public:
int readPacketLength(bytes::const_span bytes) const override; int readPacketLength(bytes::const_span bytes) const override;
bytes::const_span readPacket(bytes::const_span bytes) const override; bytes::const_span readPacket(bytes::const_span bytes) const override;
QString debugPostfix() const override;
}; };
uint32 TcpConnection::Protocol::Version0::id() const { uint32 TcpConnection::Protocol::Version0::id() const {
@ -129,12 +133,18 @@ bytes::const_span TcpConnection::Protocol::Version0::readPacket(
return bytes.subspan(sizeLength, size - sizeLength); return bytes.subspan(sizeLength, size - sizeLength);
} }
QString TcpConnection::Protocol::Version0::debugPostfix() const {
return QString();
}
class TcpConnection::Protocol::Version1 : public Version0 { class TcpConnection::Protocol::Version1 : public Version0 {
public: public:
explicit Version1(bytes::vector &&secret); explicit Version1(bytes::vector &&secret);
void prepareKey(bytes::span key, bytes::const_span source) override; void prepareKey(bytes::span key, bytes::const_span source) override;
QString debugPostfix() const override;
private: private:
bytes::vector _secret; bytes::vector _secret;
@ -151,6 +161,10 @@ void TcpConnection::Protocol::Version1::prepareKey(
bytes::copy(key, openssl::Sha256(payload)); bytes::copy(key, openssl::Sha256(payload));
} }
QString TcpConnection::Protocol::Version1::debugPostfix() const {
return u"_obf"_q;
}
class TcpConnection::Protocol::VersionD : public Version1 { class TcpConnection::Protocol::VersionD : public Version1 {
public: public:
using Version1::Version1; using Version1::Version1;
@ -163,6 +177,8 @@ public:
int readPacketLength(bytes::const_span bytes) const override; int readPacketLength(bytes::const_span bytes) const override;
bytes::const_span readPacket(bytes::const_span bytes) const override; bytes::const_span readPacket(bytes::const_span bytes) const override;
QString debugPostfix() const override;
}; };
uint32 TcpConnection::Protocol::VersionD::id() const { uint32 TcpConnection::Protocol::VersionD::id() const {
@ -209,6 +225,10 @@ bytes::const_span TcpConnection::Protocol::VersionD::readPacket(
return bytes.subspan(sizeLength, size - sizeLength); return bytes.subspan(sizeLength, size - sizeLength);
} }
QString TcpConnection::Protocol::VersionD::debugPostfix() const {
return u"_dd"_q;
}
auto TcpConnection::Protocol::Create(bytes::const_span secret) auto TcpConnection::Protocol::Create(bytes::const_span secret)
-> std::unique_ptr<Protocol> { -> std::unique_ptr<Protocol> {
// See also DcOptions::ValidateSecret. // See also DcOptions::ValidateSecret.
@ -269,7 +289,7 @@ void TcpConnection::socketRead() {
Expects(_leftBytes > 0 || !_usingLargeBuffer); Expects(_leftBytes > 0 || !_usingLargeBuffer);
if (!_socket || !_socket->isConnected()) { if (!_socket || !_socket->isConnected()) {
LOG(("MTP Error: Socket not connected in socketRead()")); CONNECTION_LOG_ERROR("Socket not connected in socketRead()");
error(kErrorCodeOther); error(kErrorCodeOther);
return; return;
} }
@ -290,7 +310,7 @@ void TcpConnection::socketRead() {
if (readCount > 0) { if (readCount > 0) {
const auto read = free.subspan(0, readCount); const auto read = free.subspan(0, readCount);
aesCtrEncrypt(read, _receiveKey, &_receiveState); aesCtrEncrypt(read, _receiveKey, &_receiveState);
TCP_LOG(("TCP Info: read %1 bytes").arg(readCount)); CONNECTION_LOG_INFO(u"Read %1 bytes"_q.arg(readCount));
_readBytes += readCount; _readBytes += readCount;
if (_leftBytes > 0) { if (_leftBytes > 0) {
@ -306,9 +326,10 @@ void TcpConnection::socketRead() {
_largeBuffer.clear(); _largeBuffer.clear();
_offsetBytes = _readBytes = 0; _offsetBytes = _readBytes = 0;
} else { } else {
TCP_LOG(("TCP Info: not enough %1 for packet! read %2" CONNECTION_LOG_INFO(
).arg(_leftBytes u"Not enough %1 for packet! read %2"_q
).arg(_readBytes)); .arg(_leftBytes)
.arg(_readBytes));
receivedSome(); receivedSome();
} }
} else { } else {
@ -320,8 +341,9 @@ void TcpConnection::socketRead() {
// Not enough bytes yet. // Not enough bytes yet.
break; break;
} else if (packetSize <= 0) { } else if (packetSize <= 0) {
LOG(("TCP Error: bad packet size in 4 bytes: %1" CONNECTION_LOG_ERROR(
).arg(packetSize)); u"Bad packet size in 4 bytes: %1"_q
.arg(packetSize));
error(kErrorCodeOther); error(kErrorCodeOther);
return; return;
} else if (available.size() >= packetSize) { } else if (available.size() >= packetSize) {
@ -342,22 +364,23 @@ void TcpConnection::socketRead() {
// If the next packet won't fit in the buffer. // If the next packet won't fit in the buffer.
ensureAvailableInBuffer(packetSize); ensureAvailableInBuffer(packetSize);
TCP_LOG(("TCP Info: not enough %1 for packet! " CONNECTION_LOG_INFO(u"Not enough %1 for packet! "
"full size %2 read %3" "full size %2 read %3"_q
).arg(_leftBytes .arg(_leftBytes)
).arg(packetSize .arg(packetSize)
).arg(available.size())); .arg(available.size()));
receivedSome(); receivedSome();
break; break;
} }
} }
} }
} else if (readCount < 0) { } else if (readCount < 0) {
LOG(("TCP Error: socket read return %1").arg(readCount)); CONNECTION_LOG_ERROR(u"Socket read return %1."_q.arg(readCount));
error(kErrorCodeOther); error(kErrorCodeOther);
return; return;
} else { } else {
TCP_LOG(("TCP Info: no bytes read, but bytes available was true...")); CONNECTION_LOG_INFO(
"No bytes read, but bytes available was true...");
break; break;
} }
} while (_socket } while (_socket
@ -367,8 +390,7 @@ void TcpConnection::socketRead() {
mtpBuffer TcpConnection::parsePacket(bytes::const_span bytes) { mtpBuffer TcpConnection::parsePacket(bytes::const_span bytes) {
const auto packet = _protocol->readPacket(bytes); const auto packet = _protocol->readPacket(bytes);
TCP_LOG(("TCP Info: packet received, size = %1" CONNECTION_LOG_INFO(u"Packet received, size = %1."_q.arg(packet.size()));
).arg(packet.size()));
const auto ints = gsl::make_span( const auto ints = gsl::make_span(
reinterpret_cast<const mtpPrime*>(packet.data()), reinterpret_cast<const mtpPrime*>(packet.data()),
packet.size() / sizeof(mtpPrime)); packet.size() / sizeof(mtpPrime));
@ -376,13 +398,8 @@ mtpBuffer TcpConnection::parsePacket(bytes::const_span bytes) {
if (ints.size() < 3) { if (ints.size() < 3) {
// nop or error or new quickack, latter is not yet supported. // nop or error or new quickack, latter is not yet supported.
if (ints[0] != 0) { if (ints[0] != 0) {
LOG(("TCP Error: " CONNECTION_LOG_ERROR(u"Error packet received, code = %1"_q
"error packet received, endpoint: '%1:%2', " .arg(ints[0]));
"protocolDcId: %3, code = %4"
).arg(_address.isEmpty() ? ("prx_" + _proxy.host) : _address
).arg(_address.isEmpty() ? _proxy.port : _port
).arg(_protocolDcId
).arg(ints[0]));
} }
return mtpBuffer(1, ints[0]); return mtpBuffer(1, ints[0]);
} }
@ -396,10 +413,7 @@ void TcpConnection::socketConnected() {
auto buffer = preparePQFake(_checkNonce); auto buffer = preparePQFake(_checkNonce);
DEBUG_LOG(("TCP Info: " CONNECTION_LOG_INFO("Sending fake req_pq.");
"dc:%1 - Sending fake req_pq to '%2'"
).arg(_protocolDcId
).arg(_address + ':' + QString::number(_port)));
_pingTime = crl::now(); _pingTime = crl::now();
sendData(std::move(buffer)); sendData(std::move(buffer));
@ -423,7 +437,8 @@ void TcpConnection::sendData(mtpBuffer &&buffer) {
// buffer: 2 available int-s + data + available int. // buffer: 2 available int-s + data + available int.
const auto bytes = _protocol->finalizePacket(buffer); const auto bytes = _protocol->finalizePacket(buffer);
TCP_LOG(("TCP Info: write packet %1 bytes").arg(bytes.size())); CONNECTION_LOG_INFO(u"TCP Info: write packet %1 bytes."_q
.arg(bytes.size()));
aesCtrEncrypt(bytes, _sendKey, &_sendState); aesCtrEncrypt(bytes, _sendKey, &_sendState);
_socket->write(connectionStartPrefix, bytes); _socket->write(connectionStartPrefix, bytes);
} }
@ -506,20 +521,10 @@ void TcpConnection::connectToServer(
_address = _proxy.host; _address = _proxy.host;
_port = _proxy.port; _port = _proxy.port;
_protocol = Protocol::Create(secret); _protocol = Protocol::Create(secret);
DEBUG_LOG(("TCP Info: "
"dc:%1 - Connecting to proxy '%2'"
).arg(protocolDcId
).arg(_address + ':' + QString::number(_port)));
} else { } else {
_address = address; _address = address;
_port = port; _port = port;
_protocol = Protocol::Create(secret); _protocol = Protocol::Create(secret);
DEBUG_LOG(("TCP Info: "
"dc:%1 - Connecting to '%2'"
).arg(protocolDcId
).arg(_address + ':' + QString::number(_port)));
} }
_socket = AbstractSocket::Create( _socket = AbstractSocket::Create(
thread(), thread(),
@ -528,6 +533,18 @@ void TcpConnection::connectToServer(
protocolForFiles); protocolForFiles);
_protocolDcId = protocolDcId; _protocolDcId = protocolDcId;
const auto postfix = _socket->debugPostfix();
_debugId = u"%1(dc:%2,%3%4:%5%6)"_q
.arg(_debugId.toInt())
.arg(ProtocolDcDebugId(_protocolDcId))
.arg((_proxy.type == ProxyData::Type::Mtproto) ? "mtproxy " : "")
.arg(_address)
.arg(_port)
.arg(postfix.isEmpty() ? _protocol->debugPostfix() : postfix);
_socket->setDebugId(_debugId);
CONNECTION_LOG_INFO("Connecting...");
_socket->connected( _socket->connected(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
socketConnected(); socketConnected();
@ -584,19 +601,18 @@ void TcpConnection::socketPacket(bytes::const_span bytes) {
if (const auto res_pq = readPQFakeReply(data)) { if (const auto res_pq = readPQFakeReply(data)) {
const auto &data = res_pq->c_resPQ(); const auto &data = res_pq->c_resPQ();
if (data.vnonce() == _checkNonce) { if (data.vnonce() == _checkNonce) {
DEBUG_LOG(("Connection Info: Valid pq response by TCP.")); CONNECTION_LOG_INFO("Valid pq response by TCP.");
_status = Status::Ready; _status = Status::Ready;
_connectedLifetime.destroy(); _connectedLifetime.destroy();
_pingTime = (crl::now() - _pingTime); _pingTime = (crl::now() - _pingTime);
connected(); connected();
} else { } else {
DEBUG_LOG(("Connection Error: " CONNECTION_LOG_ERROR(
"Wrong nonce received in TCP fake pq-responce")); "Wrong nonce received in TCP fake pq-responce");
error(kErrorCodeOther); error(kErrorCodeOther);
} }
} else { } else {
DEBUG_LOG(("Connection Error: " CONNECTION_LOG_ERROR("Could not parse TCP fake pq-responce");
"Could not parse TCP fake pq-responce"));
error(kErrorCodeOther); error(kErrorCodeOther);
} }
} }

View file

@ -28,4 +28,44 @@ std::unique_ptr<AbstractSocket> AbstractSocket::Create(
} }
} }
void AbstractSocket::logError(int errorCode, const QString &errorText) {
const auto log = [&](const QString &message) {
DEBUG_LOG(("Socket %1 Error: ").arg(_debugId) + message);
};
switch (errorCode) {
case QAbstractSocket::ConnectionRefusedError:
log(u"Socket connection refused - %1."_q.arg(errorText));
break;
case QAbstractSocket::RemoteHostClosedError:
log(u"Remote host closed socket connection - %1."_q.arg(errorText));
break;
case QAbstractSocket::HostNotFoundError:
log(u"Host not found - %1."_q.arg(errorText));
break;
case QAbstractSocket::SocketTimeoutError:
log(u"Socket timeout - %1."_q.arg(errorText));
break;
case QAbstractSocket::NetworkError: {
log(u"Network - %1."_q.arg(errorText));
} break;
case QAbstractSocket::ProxyAuthenticationRequiredError:
case QAbstractSocket::ProxyConnectionRefusedError:
case QAbstractSocket::ProxyConnectionClosedError:
case QAbstractSocket::ProxyConnectionTimeoutError:
case QAbstractSocket::ProxyNotFoundError:
case QAbstractSocket::ProxyProtocolError:
log(u"Proxy (%1) - %2."_q.arg(errorCode).arg(errorText));
break;
default:
log(u"Other (%1) - %2."_q.arg(errorCode).arg(errorText));
break;
}
}
} // namespace MTP::details } // namespace MTP::details

View file

@ -20,6 +20,10 @@ public:
const QNetworkProxy &proxy, const QNetworkProxy &proxy,
bool protocolForFiles); bool protocolForFiles);
void setDebugId(const QString &id) {
_debugId = id;
}
explicit AbstractSocket(not_null<QThread*> thread) { explicit AbstractSocket(not_null<QThread*> thread) {
moveToThread(thread); moveToThread(thread);
} }
@ -52,11 +56,15 @@ public:
bytes::const_span buffer) = 0; bytes::const_span buffer) = 0;
virtual int32 debugState() = 0; virtual int32 debugState() = 0;
[[nodiscard]] virtual QString debugPostfix() const = 0;
protected: protected:
static const int kFilesSendBufferSize = 2 * 1024 * 1024; static const int kFilesSendBufferSize = 2 * 1024 * 1024;
static const int kFilesReceiveBufferSize = 2 * 1024 * 1024; static const int kFilesReceiveBufferSize = 2 * 1024 * 1024;
void logError(int errorCode, const QString &errorText);
QString _debugId;
rpl::event_stream<> _connected; rpl::event_stream<> _connected;
rpl::event_stream<> _disconnected; rpl::event_stream<> _disconnected;
rpl::event_stream<> _readyRead; rpl::event_stream<> _readyRead;

View file

@ -114,50 +114,12 @@ int32 TcpSocket::debugState() {
return _socket.state(); return _socket.state();
} }
void TcpSocket::LogError(int errorCode, const QString &errorText) { QString TcpSocket::debugPostfix() const {
switch (errorCode) { return QString();
case QAbstractSocket::ConnectionRefusedError:
LOG(("TCP Error: socket connection refused - %1").arg(errorText));
break;
case QAbstractSocket::RemoteHostClosedError:
TCP_LOG(("TCP Info: remote host closed socket connection - %1"
).arg(errorText));
break;
case QAbstractSocket::HostNotFoundError:
LOG(("TCP Error: host not found - %1").arg(errorText));
break;
case QAbstractSocket::SocketTimeoutError:
LOG(("TCP Error: socket timeout - %1").arg(errorText));
break;
case QAbstractSocket::NetworkError: {
DEBUG_LOG(("TCP Error: network - %1").arg(errorText));
} break;
case QAbstractSocket::ProxyAuthenticationRequiredError:
case QAbstractSocket::ProxyConnectionRefusedError:
case QAbstractSocket::ProxyConnectionClosedError:
case QAbstractSocket::ProxyConnectionTimeoutError:
case QAbstractSocket::ProxyNotFoundError:
case QAbstractSocket::ProxyProtocolError:
LOG(("TCP Error: proxy (%1) - %2").arg(errorCode).arg(errorText));
break;
default:
LOG(("TCP Error: other (%1) - %2").arg(errorCode).arg(errorText));
break;
}
TCP_LOG(("TCP Error %1, restarting! - %2"
).arg(errorCode
).arg(errorText));
} }
void TcpSocket::handleError(int errorCode) { void TcpSocket::handleError(int errorCode) {
LogError(errorCode, _socket.errorString()); logError(errorCode, _socket.errorString());
_error.fire({}); _error.fire({});
} }

View file

@ -27,8 +27,7 @@ public:
void write(bytes::const_span prefix, bytes::const_span buffer) override; void write(bytes::const_span prefix, bytes::const_span buffer) override;
int32 debugState() override; int32 debugState() override;
QString debugPostfix() const override;
static void LogError(int errorCode, const QString &errorText);
private: private:
void handleError(int errorCode); void handleError(int errorCode);

View file

@ -505,7 +505,7 @@ void TlsSocket::plainConnected() {
domainFromSecret(), domainFromSecret(),
keyFromSecret()); keyFromSecret());
if (hello.data.isEmpty()) { if (hello.data.isEmpty()) {
LOG(("TLS Error: Could not generate Client Hello!")); logError(888, "Could not generate Client Hello.");
_state = State::Error; _state = State::Error;
_error.fire({}); _error.fire({});
} else { } else {
@ -563,7 +563,7 @@ void TlsSocket::checkHelloParts12(int parts1Size) {
- kLengthSize - kLengthSize
- kServerHelloPart1.size(); - kServerHelloPart1.size();
if (!CheckPart(data.subspan(part1Offset), kServerHelloPart1)) { if (!CheckPart(data.subspan(part1Offset), kServerHelloPart1)) {
LOG(("TLS Error: Bad Server Hello part1.")); logError(888, "Bad Server Hello part1.");
handleError(); handleError();
return; return;
} }
@ -587,7 +587,7 @@ void TlsSocket::checkHelloParts34(int parts123Size) {
- kLengthSize - kLengthSize
- kServerHelloPart3.size(); - kServerHelloPart3.size();
if (!CheckPart(data.subspan(part3Offset), kServerHelloPart3)) { if (!CheckPart(data.subspan(part3Offset), kServerHelloPart3)) {
LOG(("TLS Error: Bad Server Hello part.")); logError(888, "Bad Server Hello part.");
handleError(); handleError();
return; return;
} }
@ -611,7 +611,7 @@ void TlsSocket::checkHelloDigest() {
bytes::set_with_const(digest, bytes::type(0)); bytes::set_with_const(digest, bytes::type(0));
const auto check = openssl::HmacSha256(keyFromSecret(), fulldata); const auto check = openssl::HmacSha256(keyFromSecret(), fulldata);
if (bytes::compare(digestCopy, check) != 0) { if (bytes::compare(digestCopy, check) != 0) {
LOG(("TLS Error: Bad Server Hello digest.")); logError(888, "Bad Server Hello digest.");
handleError(); handleError();
return; return;
} }
@ -649,7 +649,7 @@ bool TlsSocket::checkNextPacket() {
return true; return true;
} }
if (!CheckPart(incoming.subspan(offset), kServerHeader)) { if (!CheckPart(incoming.subspan(offset), kServerHeader)) {
LOG(("TLS Error: Bad packet header.")); logError(888, "Bad packet header.");
return false; return false;
} }
const auto length = ReadPartLength( const auto length = ReadPartLength(
@ -773,12 +773,16 @@ int32 TlsSocket::debugState() {
return _socket.state(); return _socket.state();
} }
QString TlsSocket::debugPostfix() const {
return u"_ee"_q;
}
void TlsSocket::handleError(int errorCode) { void TlsSocket::handleError(int errorCode) {
if (_state != State::Connected) { if (_state != State::Connected) {
_syncTimeRequests.fire({}); _syncTimeRequests.fire({});
} }
if (errorCode) { if (errorCode) {
TcpSocket::LogError(errorCode, _socket.errorString()); logError(errorCode, _socket.errorString());
} }
_state = State::Error; _state = State::Error;
_error.fire({}); _error.fire({});

View file

@ -28,6 +28,7 @@ public:
void write(bytes::const_span prefix, bytes::const_span buffer) override; void write(bytes::const_span prefix, bytes::const_span buffer) override;
int32 debugState() override; int32 debugState() override;
QString debugPostfix() const override;
private: private:
enum class State { enum class State {

View file

@ -39,7 +39,6 @@ constexpr auto kPingSendAfter = 30 * crl::time(1000);
constexpr auto kPingSendAfterForce = 45 * crl::time(1000); constexpr auto kPingSendAfterForce = 45 * crl::time(1000);
constexpr auto kTemporaryExpiresIn = TimeId(86400); constexpr auto kTemporaryExpiresIn = TimeId(86400);
constexpr auto kBindKeyAdditionalExpiresTimeout = TimeId(30); constexpr auto kBindKeyAdditionalExpiresTimeout = TimeId(30);
constexpr auto kTestModeDcIdShift = 10000;
constexpr auto kKeyOldEnoughForDestroy = 60 * crl::time(1000); constexpr auto kKeyOldEnoughForDestroy = 60 * crl::time(1000);
constexpr auto kSentContainerLives = 600 * crl::time(1000); constexpr auto kSentContainerLives = 600 * crl::time(1000);
constexpr auto kFastRequestDuration = crl::time(500); constexpr auto kFastRequestDuration = crl::time(500);
@ -1252,14 +1251,10 @@ void SessionPrivate::handleReceived() {
auto ints = intsBuffer.constData(); auto ints = intsBuffer.constData();
if ((intsCount < kMinimalIntsCount) || (intsCount > kMaxMessageLength / kIntSize)) { if ((intsCount < kMinimalIntsCount) || (intsCount > kMaxMessageLength / kIntSize)) {
LOG(("TCP Error: bad message received, len %1").arg(intsCount * kIntSize)); LOG(("TCP Error: bad message received, len %1").arg(intsCount * kIntSize));
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(ints, intsCount * kIntSize).str()));
return restart(); return restart();
} }
if (_keyId != *(uint64*)ints) { if (_keyId != *(uint64*)ints) {
LOG(("TCP Error: bad auth_key_id %1 instead of %2 received").arg(_keyId).arg(*(uint64*)ints)); LOG(("TCP Error: bad auth_key_id %1 instead of %2 received").arg(_keyId).arg(*(uint64*)ints));
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(ints, intsCount * kIntSize).str()));
return restart(); return restart();
} }
@ -1297,8 +1292,6 @@ void SessionPrivate::handleReceived() {
constexpr auto kMsgKeyShift = 8U; constexpr auto kMsgKeyShift = 8U;
if (ConstTimeIsDifferent(&msgKey, sha256Buffer.data() + kMsgKeyShift, sizeof(msgKey))) { if (ConstTimeIsDifferent(&msgKey, sha256Buffer.data() + kMsgKeyShift, sizeof(msgKey))) {
LOG(("TCP Error: bad SHA256 hash after aesDecrypt in message")); LOG(("TCP Error: bad SHA256 hash after aesDecrypt in message"));
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(encryptedInts, encryptedBytesCount).str()));
return restart(); return restart();
} }
@ -1307,17 +1300,19 @@ void SessionPrivate::handleReceived() {
|| (paddingSize < kMinPaddingSize) || (paddingSize < kMinPaddingSize)
|| (paddingSize > kMaxPaddingSize)) { || (paddingSize > kMaxPaddingSize)) {
LOG(("TCP Error: bad msg_len received %1, data size: %2").arg(messageLength).arg(encryptedBytesCount)); LOG(("TCP Error: bad msg_len received %1, data size: %2").arg(messageLength).arg(encryptedBytesCount));
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(encryptedInts, encryptedBytesCount).str()));
return restart(); return restart();
} }
TCP_LOG(("TCP Info: decrypted message %1,%2,%3 is %4 len").arg(msgId).arg(seqNo).arg(Logs::b(needAck)).arg(fullDataLength)); if (Logs::DebugEnabled()) {
_connection->logInfo(u"Decrypted message %1,%2,%3 is %4 len"_q
.arg(msgId)
.arg(seqNo)
.arg(Logs::b(needAck))
.arg(fullDataLength));
}
if (session != _sessionId) { if (session != _sessionId) {
LOG(("MTP Error: bad server session received")); LOG(("MTP Error: bad server session received"));
TCP_LOG(("MTP Error: bad server session %1 instead of %2 in message received").arg(session).arg(_sessionId));
return restart(); return restart();
} }