2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-30 22:16:14 +00:00

Check keys that receive -404 error codes.

This commit is contained in:
John Preston
2019-11-14 16:34:58 +03:00
parent 1524b4a930
commit 7243fb52ad
15 changed files with 460 additions and 159 deletions

View File

@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/connection.h"
#include "mtproto/details/mtproto_dc_key_creator.h"
#include "mtproto/details/mtproto_dc_key_checker.h"
#include "mtproto/session.h"
#include "mtproto/rsa_public_key.h"
#include "mtproto/rpc_sender.h"
@@ -94,7 +95,8 @@ void wrapInvokeAfter(SecureRequest &to, const SecureRequest &from, const Request
} // namespace
Connection::Connection(not_null<Instance*> instance) : _instance(instance) {
Connection::Connection(not_null<Instance*> instance)
: _instance(instance) {
}
void Connection::start(SessionData *sessionData, ShiftedDcId shiftedDcId) {
@@ -457,27 +459,31 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno
emit sessionResetDone();
}
mtpMsgId ConnectionPrivate::prepareToSend(SecureRequest &request, mtpMsgId currentLastId) {
if (request->size() < 9) return 0;
mtpMsgId msgId = *(mtpMsgId*)(request->constData() + 4);
if (msgId) { // resending this request
mtpMsgId ConnectionPrivate::prepareToSend(
SecureRequest &request,
mtpMsgId currentLastId) {
if (request->size() < 9) {
return 0;
}
if (const auto msgId = request.getMsgId()) {
// resending this request
QWriteLocker locker(_sessionData->toResendMutex());
auto &toResend = _sessionData->toResendMap();
const auto i = toResend.find(msgId);
if (i != toResend.cend()) {
toResend.erase(i);
}
} else {
msgId = *(mtpMsgId*)(request->data() + 4) = currentLastId;
*(request->data() + 6) = _sessionData->nextRequestSeqNumber(request.needAck());
return msgId;
}
return msgId;
request.setMsgId(currentLastId);
request.setSeqNo(_sessionData->nextRequestSeqNumber(request.needAck()));
return currentLastId;
}
mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId) {
if (request->size() < 9) return 0;
mtpMsgId oldMsgId = *(mtpMsgId*)(request->constData() + 4);
const auto oldMsgId = request.getMsgId();
if (oldMsgId != newId) {
if (oldMsgId) {
QWriteLocker locker(_sessionData->toResendMutex());
@@ -530,9 +536,9 @@ mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId)
}
}
} else {
*(request->data() + 6) = _sessionData->nextRequestSeqNumber(request.needAck());
request.setSeqNo(_sessionData->nextRequestSeqNumber(request.needAck()));
}
*(mtpMsgId*)(request->data() + 4) = newId;
request.setMsgId(newId);
}
return newId;
}
@@ -562,15 +568,25 @@ void ConnectionPrivate::tryToSend() {
auto needsLayer = !_connectionOptions->inited;
auto state = getState();
auto prependOnly = (state != ConnectedState);
auto sendOnlyFirstPing = (state != ConnectedState);
if (sendOnlyFirstPing && !_pingIdToSend) {
DEBUG_LOG(("MTP Info: dc %1 not sending, waiting for Connected state, state: %2").arg(_shiftedDcId).arg(state));
return; // just do nothing, if is not connected yet
}
auto pingRequest = SecureRequest();
auto ackRequest = SecureRequest();
auto resendRequest = SecureRequest();
auto stateRequest = SecureRequest();
auto httpWaitRequest = SecureRequest();
auto checkDcKeyRequest = SecureRequest();
if (_shiftedDcId == BareDcId(_shiftedDcId)) { // main session
if (!prependOnly && !_pingIdToSend && !_pingId && _pingSendAt <= crl::now()) {
if (!sendOnlyFirstPing && !_pingIdToSend && !_pingId && _pingSendAt <= crl::now()) {
_pingIdToSend = rand_value<mtpPingId>();
}
}
if (_pingIdToSend) {
if (prependOnly || _shiftedDcId != BareDcId(_shiftedDcId)) {
if (sendOnlyFirstPing || _shiftedDcId != BareDcId(_shiftedDcId)) {
pingRequest = SecureRequest::Serialize(MTPPing(
MTP_long(_pingIdToSend)
));
@@ -584,44 +600,28 @@ void ConnectionPrivate::tryToSend() {
"ping_id: %1").arg(_pingIdToSend));
}
pingRequest->msDate = crl::now(); // > 0 - can send without container
_pingSendAt = pingRequest->msDate + kPingSendAfter;
pingRequest->requestId = 0; // dont add to haveSent / wereAcked maps
if (_shiftedDcId == BareDcId(_shiftedDcId) && !prependOnly) { // main session
if (_shiftedDcId == BareDcId(_shiftedDcId) && !sendOnlyFirstPing) { // main session
_pingSender.callOnce(kPingSendAfterForce);
}
_pingId = _pingIdToSend;
_pingIdToSend = 0;
_pingId = base::take(_pingIdToSend);
} else {
if (prependOnly) {
DEBUG_LOG(("MTP Info: dc %1 not sending, waiting for Connected state, state: %2").arg(_shiftedDcId).arg(state));
return; // just do nothing, if is not connected yet
} else {
DEBUG_LOG(("MTP Info: dc %1 trying to send after ping, state: %2").arg(_shiftedDcId).arg(state));
DEBUG_LOG(("MTP Info: dc %1 trying to send after ping, state: %2").arg(_shiftedDcId).arg(state));
}
if (!sendOnlyFirstPing) {
if (!_ackRequestData.isEmpty()) {
ackRequest = SecureRequest::Serialize(MTPMsgsAck(
MTP_msgs_ack(MTP_vector<MTPlong>(
base::take(_ackRequestData)))));
}
if (!_resendRequestData.isEmpty()) {
resendRequest = SecureRequest::Serialize(MTPMsgResendReq(
MTP_msg_resend_req(MTP_vector<MTPlong>(
base::take(_resendRequestData)))));
}
}
SecureRequest ackRequest, resendRequest, stateRequest, httpWaitRequest;
if (!prependOnly && !_ackRequestData.isEmpty()) {
ackRequest = SecureRequest::Serialize(MTPMsgsAck(
MTP_msgs_ack(MTP_vector<MTPlong>(_ackRequestData))));
ackRequest->msDate = crl::now(); // > 0 - can send without container
ackRequest->requestId = 0; // dont add to haveSent / wereAcked maps
_ackRequestData.clear();
}
if (!prependOnly && !_resendRequestData.isEmpty()) {
resendRequest = SecureRequest::Serialize(MTPMsgResendReq(
MTP_msg_resend_req(MTP_vector<MTPlong>(_resendRequestData))));
resendRequest->msDate = crl::now(); // > 0 - can send without container
resendRequest->requestId = 0; // dont add to haveSent / wereAcked maps
_resendRequestData.clear();
}
if (!prependOnly) {
QVector<MTPlong> stateReq;
auto stateReq = QVector<MTPlong>();
{
QWriteLocker locker(_sessionData->stateRequestMutex());
auto &ids = _sessionData->stateRequestMap();
@@ -636,14 +636,30 @@ void ConnectionPrivate::tryToSend() {
if (!stateReq.isEmpty()) {
stateRequest = SecureRequest::Serialize(MTPMsgsStateReq(
MTP_msgs_state_req(MTP_vector<MTPlong>(stateReq))));
stateRequest->msDate = crl::now(); // > 0 - can send without container
stateRequest->requestId = GetNextRequestId();// add to haveSent / wereAcked maps, but don't add to requestMap
// Add to haveSent / wereAcked maps, but don't add to requestMap.
stateRequest->requestId = GetNextRequestId();
}
if (_connection->usingHttpWait()) {
httpWaitRequest = SecureRequest::Serialize(MTPHttpWait(
MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000))));
httpWaitRequest->msDate = crl::now(); // > 0 - can send without container
httpWaitRequest->requestId = 0; // dont add to haveSent / wereAcked maps
}
if (!_keyChecker) {
if (const auto &keyForCheck = _sessionData->getKeyForCheck()) {
_keyChecker = std::make_unique<details::DcKeyChecker>(
_instance,
_shiftedDcId,
keyForCheck);
checkDcKeyRequest = _keyChecker->prepareRequest(
_sessionData->getKey(),
_sessionData->getSessionId());
// This is a special request with msgId used inside the message
// body, so it is prepared already with a msgId and we place
// seqNo for it manually here.
checkDcKeyRequest.setSeqNo(
_sessionData->nextRequestSeqNumber(
checkDcKeyRequest.needAck()));
}
}
}
@@ -698,8 +714,12 @@ void ConnectionPrivate::tryToSend() {
QWriteLocker locker1(_sessionData->toSendMutex());
auto toSendDummy = PreRequestMap();
auto &toSend = prependOnly ? toSendDummy : _sessionData->toSendMap();
if (prependOnly) locker1.unlock();
auto &toSend = sendOnlyFirstPing
? toSendDummy
: _sessionData->toSendMap();
if (sendOnlyFirstPing) {
locker1.unlock();
}
uint32 toSendCount = toSend.size();
if (pingRequest) ++toSendCount;
@@ -707,13 +727,28 @@ void ConnectionPrivate::tryToSend() {
if (resendRequest) ++toSendCount;
if (stateRequest) ++toSendCount;
if (httpWaitRequest) ++toSendCount;
if (checkDcKeyRequest) ++toSendCount;
if (!toSendCount) return; // nothing to send
if (!toSendCount) {
return; // nothing to send
}
auto first = pingRequest ? pingRequest : (ackRequest ? ackRequest : (resendRequest ? resendRequest : (stateRequest ? stateRequest : (httpWaitRequest ? httpWaitRequest : toSend.cbegin().value()))));
const auto first = pingRequest
? pingRequest
: ackRequest
? ackRequest
: resendRequest
? resendRequest
: stateRequest
? stateRequest
: httpWaitRequest
? httpWaitRequest
: checkDcKeyRequest
? checkDcKeyRequest
: toSend.cbegin().value();
if (toSendCount == 1 && first->msDate > 0) { // if can send without container
toSendRequest = first;
if (!prependOnly) {
if (!sendOnlyFirstPing) {
toSend.clear();
locker1.unlock();
}
@@ -774,6 +809,7 @@ void ConnectionPrivate::tryToSend() {
if (resendRequest) containerSize += resendRequest.messageSize();
if (stateRequest) containerSize += stateRequest.messageSize();
if (httpWaitRequest) containerSize += httpWaitRequest.messageSize();
if (checkDcKeyRequest) containerSize += checkDcKeyRequest.messageSize();
for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) {
containerSize += i.value().messageSize();
if (needsLayer && i.value()->needsLayer) {
@@ -815,7 +851,7 @@ void ConnectionPrivate::tryToSend() {
if (pingRequest) {
_pingMsgId = placeToContainer(toSendRequest, bigMsgId, haveSentArr, pingRequest);
needAnyResponse = true;
} else if (resendRequest || stateRequest) {
} else if (resendRequest || stateRequest || checkDcKeyRequest) {
needAnyResponse = true;
}
for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) {
@@ -869,6 +905,7 @@ void ConnectionPrivate::tryToSend() {
if (resendRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, resendRequest);
if (ackRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, ackRequest);
if (httpWaitRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, httpWaitRequest);
if (checkDcKeyRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, checkDcKeyRequest);
mtpMsgId contMsgId = prepareToSend(toSendRequest, bigMsgId);
*(mtpMsgId*)(haveSentIdsWrap->data() + 4) = contMsgId;
@@ -1945,6 +1982,9 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
}
}
if (_keyChecker && _keyChecker->handleResponse(reqMsgId, response)) {
return HandleResult::Success;
}
auto requestId = wasSent(reqMsgId.v);
if (requestId && requestId != mtpRequestId(0xFFFFFFFF)) {
// Save rpc_result for processing in the main thread.
@@ -2437,7 +2477,8 @@ void ConnectionPrivate::createDcKey() {
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(result->serverSalt));
_sessionData->owner()->notifyKeyCreated(std::move(authKey)); // slot will call authKeyCreated()
// slot will call authKeyCreated().
_sessionData->owner()->notifyKeyCreated(std::move(authKey));
_sessionData->clear(_instance);
unlockKey();
} else if (result.error() == Error::UnknownPublicKey) {
@@ -2539,7 +2580,13 @@ bool ConnectionPrivate::sendSecureRequest(
SecureRequest &&request,
bool needAnyResponse,
QReadLocker &lockFinished) {
request.addPadding(_connection->requiresExtendedPadding());
#ifdef TDESKTOP_MTPROTO_OLD
const auto oldPadding = true;
#else // TDESKTOP_MTPROTO_OLD
const auto oldPadding = false;
#endif // TDESKTOP_MTPROTO_OLD
request.addPadding(_connection->requiresExtendedPadding(), oldPadding);
uint32 fullSize = request->size();
if (fullSize < 9) {
return false;
@@ -2660,14 +2707,18 @@ mtpRequestId ConnectionPrivate::wasSent(mtpMsgId msgId) const {
void ConnectionPrivate::lockKey() {
unlockKey();
_sessionData->keyMutex()->lockForWrite();
if (const auto mutex = _sessionData->keyMutex()) {
mutex->lockForWrite();
}
_myKeyLock = true;
}
void ConnectionPrivate::unlockKey() {
if (_myKeyLock) {
_myKeyLock = false;
_sessionData->keyMutex()->unlock();
if (const auto mutex = _sessionData->keyMutex()) {
mutex->unlock();
}
}
}
@@ -2683,8 +2734,7 @@ void ConnectionPrivate::stop() {
if (_sessionData) {
if (_myKeyLock) {
_sessionData->owner()->notifyKeyCreated(AuthKeyPtr()); // release key lock, let someone else create it
_sessionData->keyMutex()->unlock();
_myKeyLock = false;
unlockKey();
}
_sessionData = nullptr;
}