mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Check keys that receive -404 error codes.
This commit is contained in:
parent
1524b4a930
commit
7243fb52ad
@ -167,35 +167,6 @@ T rand_value() {
|
||||
return result;
|
||||
}
|
||||
|
||||
class ReadLockerAttempt {
|
||||
public:
|
||||
ReadLockerAttempt(not_null<QReadWriteLock*> lock) : _lock(lock), _locked(_lock->tryLockForRead()) {
|
||||
}
|
||||
ReadLockerAttempt(const ReadLockerAttempt &other) = delete;
|
||||
ReadLockerAttempt &operator=(const ReadLockerAttempt &other) = delete;
|
||||
ReadLockerAttempt(ReadLockerAttempt &&other) : _lock(other._lock), _locked(base::take(other._locked)) {
|
||||
}
|
||||
ReadLockerAttempt &operator=(ReadLockerAttempt &&other) {
|
||||
_lock = other._lock;
|
||||
_locked = base::take(other._locked);
|
||||
return *this;
|
||||
}
|
||||
~ReadLockerAttempt() {
|
||||
if (_locked) {
|
||||
_lock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return _locked;
|
||||
}
|
||||
|
||||
private:
|
||||
not_null<QReadWriteLock*> _lock;
|
||||
bool _locked = false;
|
||||
|
||||
};
|
||||
|
||||
static const QRegularExpression::PatternOptions reMultiline(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::MultilineOption);
|
||||
|
||||
template <typename T>
|
||||
|
@ -19,6 +19,9 @@ AuthKey::AuthKey(Type type, DcId dcId, const Data &data)
|
||||
, _dcId(dcId)
|
||||
, _key(data) {
|
||||
countKeyId();
|
||||
if (type == Type::Generated) {
|
||||
_lastCheckTime = crl::now();
|
||||
}
|
||||
}
|
||||
|
||||
AuthKey::AuthKey(const Data &data) : _type(Type::Local), _key(data) {
|
||||
@ -111,6 +114,14 @@ bool AuthKey::equals(const std::shared_ptr<AuthKey> &other) const {
|
||||
return other ? (_key == other->_key) : false;
|
||||
}
|
||||
|
||||
crl::time AuthKey::lastCheckTime() const {
|
||||
return _lastCheckTime;
|
||||
}
|
||||
|
||||
void AuthKey::setLastCheckTime(crl::time time) {
|
||||
_lastCheckTime = time;
|
||||
}
|
||||
|
||||
void AuthKey::FillData(Data &authKey, bytes::const_span computedAuthKey) {
|
||||
auto computedAuthKeySize = computedAuthKey.size();
|
||||
Assert(computedAuthKeySize <= kSize);
|
||||
|
@ -30,18 +30,21 @@ public:
|
||||
AuthKey(const AuthKey &other) = delete;
|
||||
AuthKey &operator=(const AuthKey &other) = delete;
|
||||
|
||||
Type type() const;
|
||||
int dcId() const;
|
||||
KeyId keyId() const;
|
||||
[[nodiscard]] Type type() const;
|
||||
[[nodiscard]] int dcId() const;
|
||||
[[nodiscard]] KeyId keyId() const;
|
||||
|
||||
void prepareAES_oldmtp(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send) const;
|
||||
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send) const;
|
||||
|
||||
const void *partForMsgKey(bool send) const;
|
||||
[[nodiscard]] const void *partForMsgKey(bool send) const;
|
||||
|
||||
void write(QDataStream &to) const;
|
||||
bytes::const_span data() const;
|
||||
bool equals(const std::shared_ptr<AuthKey> &other) const;
|
||||
[[nodiscard]] bytes::const_span data() const;
|
||||
[[nodiscard]] bool equals(const std::shared_ptr<AuthKey> &other) const;
|
||||
|
||||
[[nodiscard]] crl::time lastCheckTime() const;
|
||||
void setLastCheckTime(crl::time time);
|
||||
|
||||
static void FillData(Data &authKey, bytes::const_span computedAuthKey);
|
||||
|
||||
@ -52,6 +55,7 @@ private:
|
||||
DcId _dcId = 0;
|
||||
Data _key = { { gsl::byte{} } };
|
||||
KeyId _keyId = 0;
|
||||
crl::time _lastCheckTime = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -263,6 +263,7 @@ private:
|
||||
bool _myKeyLock = false;
|
||||
|
||||
std::unique_ptr<details::DcKeyCreator> _keyCreator;
|
||||
std::unique_ptr<details::DcKeyChecker> _keyChecker;
|
||||
|
||||
};
|
||||
|
||||
|
@ -12,12 +12,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace MTP {
|
||||
namespace {
|
||||
|
||||
uint32 CountPaddingAmountInInts(uint32 requestSize, bool extended) {
|
||||
#ifdef TDESKTOP_MTPROTO_OLD
|
||||
return ((8 + requestSize) & 0x03)
|
||||
? (4 - ((8 + requestSize) & 0x03))
|
||||
: 0;
|
||||
#else // TDESKTOP_MTPROTO_OLD
|
||||
uint32 CountPaddingPrimesCount(uint32 requestSize, bool extended, bool old) {
|
||||
if (old) {
|
||||
return ((8 + requestSize) & 0x03)
|
||||
? (4 - ((8 + requestSize) & 0x03))
|
||||
: 0;
|
||||
}
|
||||
auto result = ((8 + requestSize) & 0x03)
|
||||
? (4 - ((8 + requestSize) & 0x03))
|
||||
: 0;
|
||||
@ -33,7 +33,6 @@ uint32 CountPaddingAmountInInts(uint32 requestSize, bool extended) {
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif // TDESKTOP_MTPROTO_OLD
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -49,6 +48,7 @@ SecureRequest SecureRequest::Prepare(uint32 size, uint32 reserveSize) {
|
||||
result->reserve(kMessageBodyPosition + finalSize);
|
||||
result->resize(kMessageBodyPosition);
|
||||
result->back() = (size << 2);
|
||||
result->msDate = crl::now(); // > 0 - can send without container
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -68,11 +68,39 @@ SecureRequest::operator bool() const {
|
||||
return (_data != nullptr);
|
||||
}
|
||||
|
||||
void SecureRequest::addPadding(bool extended) {
|
||||
if (_data->size() <= kMessageBodyPosition) return;
|
||||
void SecureRequest::setMsgId(mtpMsgId msgId) {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
memcpy(_data->data() + kMessageIdPosition, &msgId, sizeof(mtpMsgId));
|
||||
}
|
||||
|
||||
mtpMsgId SecureRequest::getMsgId() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
return *(mtpMsgId*)(_data->constData() + kMessageIdPosition);
|
||||
}
|
||||
|
||||
void SecureRequest::setSeqNo(uint32 seqNo) {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
(*_data)[kSeqNoPosition] = mtpPrime(seqNo);
|
||||
}
|
||||
|
||||
uint32 SecureRequest::getSeqNo() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
return uint32((*_data)[kSeqNoPosition]);
|
||||
}
|
||||
|
||||
void SecureRequest::addPadding(bool extended, bool old) {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
if (_data->size() <= kMessageBodyPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto requestSize = (tl::count_length(*this) >> 2);
|
||||
const auto padding = CountPaddingAmountInInts(requestSize, extended);
|
||||
const auto padding = CountPaddingPrimesCount(requestSize, extended, old);
|
||||
const auto fullSize = kMessageBodyPosition + requestSize + padding;
|
||||
if (uint32(_data->size()) != fullSize) {
|
||||
_data->resize(fullSize);
|
||||
@ -85,6 +113,8 @@ void SecureRequest::addPadding(bool extended) {
|
||||
}
|
||||
|
||||
uint32 SecureRequest::messageSize() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
if (_data->size() <= kMessageBodyPosition) {
|
||||
return 0;
|
||||
}
|
||||
@ -93,13 +123,17 @@ uint32 SecureRequest::messageSize() const {
|
||||
}
|
||||
|
||||
bool SecureRequest::isSentContainer() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
if (_data->size() <= kMessageBodyPosition) {
|
||||
return false;
|
||||
}
|
||||
return (!_data->msDate && !(*_data)[kSeqNoPosition]); // msDate = 0, seqNo = 0
|
||||
return (!_data->msDate && !getSeqNo()); // msDate = 0, seqNo = 0
|
||||
}
|
||||
|
||||
bool SecureRequest::isStateRequest() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
if (_data->size() <= kMessageBodyPosition) {
|
||||
return false;
|
||||
}
|
||||
@ -108,6 +142,8 @@ bool SecureRequest::isStateRequest() const {
|
||||
}
|
||||
|
||||
bool SecureRequest::needAck() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
if (_data->size() <= kMessageBodyPosition) {
|
||||
return false;
|
||||
}
|
||||
|
@ -138,9 +138,9 @@ public:
|
||||
|
||||
static constexpr auto kSaltInts = 2;
|
||||
static constexpr auto kSessionIdInts = 2;
|
||||
static constexpr auto kMessageIdPosition = kSaltInts + kSessionIdInts;
|
||||
static constexpr auto kMessageIdInts = 2;
|
||||
static constexpr auto kSeqNoPosition = kSaltInts
|
||||
+ kSessionIdInts
|
||||
static constexpr auto kSeqNoPosition = kMessageIdPosition
|
||||
+ kMessageIdInts;
|
||||
static constexpr auto kSeqNoInts = 1;
|
||||
static constexpr auto kMessageLengthPosition = kSeqNoPosition
|
||||
@ -168,13 +168,19 @@ public:
|
||||
SecureRequestData &operator*() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
void addPadding(bool extended);
|
||||
uint32 messageSize() const;
|
||||
void setMsgId(mtpMsgId msgId);
|
||||
[[nodiscard]] mtpMsgId getMsgId() const;
|
||||
|
||||
void setSeqNo(uint32 seqNo);
|
||||
[[nodiscard]] uint32 getSeqNo() const;
|
||||
|
||||
void addPadding(bool extended, bool old);
|
||||
[[nodiscard]] uint32 messageSize() const;
|
||||
|
||||
// "request-like" wrap for msgIds vector
|
||||
bool isSentContainer() const;
|
||||
bool isStateRequest() const;
|
||||
bool needAck() const;
|
||||
[[nodiscard]] bool isSentContainer() const;
|
||||
[[nodiscard]] bool isStateRequest() const;
|
||||
[[nodiscard]] bool needAck() const;
|
||||
|
||||
using ResponseType = void; // don't know real response type =(
|
||||
|
||||
|
@ -33,6 +33,11 @@ public:
|
||||
void setConnectionInited(bool connectionInited = true) {
|
||||
QMutexLocker lock(&initLock);
|
||||
_connectionInited = connectionInited;
|
||||
lock.unlock();
|
||||
|
||||
if (connectionInited) {
|
||||
emit connectionWasInited();
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
|
@ -8,24 +8,143 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/details/mtproto_dc_key_checker.h"
|
||||
|
||||
#include "mtproto/mtp_instance.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "scheme.h"
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
namespace MTP::details {
|
||||
namespace {
|
||||
|
||||
constexpr auto kBindKeyExpireTimeout = TimeId(3600);
|
||||
|
||||
[[nodiscard]] QByteArray EncryptBindAuthKeyInner(
|
||||
const AuthKeyPtr &persistentKey,
|
||||
mtpMsgId realMsgId,
|
||||
const MTPBindAuthKeyInner &data) {
|
||||
auto serialized = SecureRequest::Serialize(data);
|
||||
serialized.setMsgId(realMsgId);
|
||||
serialized.setSeqNo(0);
|
||||
serialized.addPadding(false, true);
|
||||
|
||||
constexpr auto kMsgIdPosition = SecureRequest::kMessageIdPosition;
|
||||
constexpr auto kMinMessageSize = 5;
|
||||
|
||||
const auto sizeInPrimes = serialized->size();
|
||||
const auto messageSize = serialized.messageSize();
|
||||
Assert(messageSize >= kMinMessageSize);
|
||||
Assert(sizeInPrimes >= kMsgIdPosition + messageSize);
|
||||
|
||||
const auto sizeInBytes = sizeInPrimes * sizeof(mtpPrime);
|
||||
const auto padding = sizeInBytes
|
||||
- (kMsgIdPosition + messageSize) * sizeof(mtpPrime);
|
||||
|
||||
// session_id, salt - just random here.
|
||||
bytes::set_random(bytes::make_span(*serialized).subspan(
|
||||
0,
|
||||
kMsgIdPosition * sizeof(mtpPrime)));
|
||||
|
||||
const auto hash = openssl::Sha1(bytes::make_span(*serialized).subspan(
|
||||
0,
|
||||
sizeInBytes - padding));
|
||||
auto msgKey = MTPint128();
|
||||
bytes::copy(
|
||||
bytes::object_as_span(&msgKey),
|
||||
bytes::make_span(hash).subspan(4));
|
||||
|
||||
constexpr auto kAuthKeyIdBytes = 2 * sizeof(mtpPrime);
|
||||
constexpr auto kMessageKeyPosition = kAuthKeyIdBytes;
|
||||
constexpr auto kMessageKeyBytes = 4 * sizeof(mtpPrime);
|
||||
constexpr auto kPrefix = (kAuthKeyIdBytes + kMessageKeyBytes);
|
||||
auto encrypted = QByteArray(kPrefix + sizeInBytes, Qt::Uninitialized);
|
||||
*reinterpret_cast<uint64*>(encrypted.data()) = persistentKey->keyId();
|
||||
*reinterpret_cast<MTPint128*>(encrypted.data() + kMessageKeyPosition)
|
||||
= msgKey;
|
||||
|
||||
aesIgeEncrypt_oldmtp(
|
||||
serialized->constData(),
|
||||
encrypted.data() + kPrefix,
|
||||
sizeInBytes,
|
||||
persistentKey,
|
||||
msgKey);
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DcKeyChecker::DcKeyChecker(
|
||||
not_null<Instance*> instance,
|
||||
DcId dcId,
|
||||
const AuthKeyPtr &key,
|
||||
FnMut<void()> destroyMe)
|
||||
ShiftedDcId shiftedDcId,
|
||||
const AuthKeyPtr &persistentKey)
|
||||
: _instance(instance)
|
||||
, _dcId(dcId)
|
||||
, _key(key)
|
||||
, _destroyMe(std::move(destroyMe)) {
|
||||
, _shiftedDcId(shiftedDcId)
|
||||
, _persistentKey(persistentKey) {
|
||||
}
|
||||
|
||||
SecureRequest DcKeyChecker::prepareRequest(
|
||||
const AuthKeyPtr &temporaryKey,
|
||||
uint64 sessionId) {
|
||||
Expects(_requestMsgId == 0);
|
||||
|
||||
const auto nonce = openssl::RandomValue<uint64>();
|
||||
_requestMsgId = base::unixtime::mtproto_msg_id();
|
||||
auto result = SecureRequest::Serialize(MTPauth_BindTempAuthKey(
|
||||
MTP_long(_persistentKey->keyId()),
|
||||
MTP_long(nonce),
|
||||
MTP_int(kBindKeyExpireTimeout),
|
||||
MTP_bytes(EncryptBindAuthKeyInner(
|
||||
_persistentKey,
|
||||
_requestMsgId,
|
||||
MTP_bind_auth_key_inner(
|
||||
MTP_long(nonce),
|
||||
MTP_long(temporaryKey->keyId()),
|
||||
MTP_long(_persistentKey->keyId()),
|
||||
MTP_long(sessionId),
|
||||
MTP_int(kBindKeyExpireTimeout))))));
|
||||
result.setMsgId(_requestMsgId);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DcKeyChecker::handleResponse(
|
||||
MTPlong requestMsgId,
|
||||
const mtpBuffer &response) {
|
||||
Expects(!response.isEmpty());
|
||||
|
||||
if (!_requestMsgId || requestMsgId.v != _requestMsgId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto destroyed = [&] {
|
||||
if (response[0] != mtpc_rpc_error) {
|
||||
return false;
|
||||
}
|
||||
auto error = MTPRpcError();
|
||||
auto from = response.begin();
|
||||
const auto end = from + response.size();
|
||||
if (!error.read(from, end)) {
|
||||
return false;
|
||||
}
|
||||
return error.match([&](const MTPDrpc_error &data) {
|
||||
return (data.verror_code().v == 400)
|
||||
&& (data.verror_message().v == "ENCRYPTED_MESSAGE_INVALID");
|
||||
});
|
||||
}();
|
||||
|
||||
const auto instance = _instance;
|
||||
const auto shiftedDcId = _shiftedDcId;
|
||||
const auto keyId = _persistentKey->keyId();
|
||||
_persistentKey->setLastCheckTime(crl::now());
|
||||
crl::on_main(instance, [=] {
|
||||
auto destroy = std::move(_destroyMe);
|
||||
destroy();
|
||||
instance->killSession(shiftedDcId);
|
||||
if (destroyed) {
|
||||
instance->keyDestroyedOnServer(BareDcId(shiftedDcId), keyId);
|
||||
}
|
||||
});
|
||||
|
||||
_requestMsgId = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MTP::details
|
||||
|
@ -16,19 +16,28 @@ class Instance;
|
||||
|
||||
namespace MTP::details {
|
||||
|
||||
enum class DcKeyState {
|
||||
MaybeExisting,
|
||||
DefinitelyDestroyed,
|
||||
};
|
||||
|
||||
class DcKeyChecker final {
|
||||
public:
|
||||
DcKeyChecker(
|
||||
not_null<Instance*> instance,
|
||||
DcId dcId,
|
||||
const AuthKeyPtr &key,
|
||||
FnMut<void()> destroyMe);
|
||||
ShiftedDcId shiftedDcId,
|
||||
const AuthKeyPtr &persistentKey);
|
||||
|
||||
[[nodiscard]] SecureRequest prepareRequest(
|
||||
const AuthKeyPtr &temporaryKey,
|
||||
uint64 sessionId);
|
||||
bool handleResponse(MTPlong requestMsgId, const mtpBuffer &response);
|
||||
|
||||
private:
|
||||
not_null<Instance*> _instance;
|
||||
DcId _dcId = 0;
|
||||
AuthKeyPtr _key;
|
||||
FnMut<void()> _destroyMe;
|
||||
const not_null<Instance*> _instance;
|
||||
const ShiftedDcId _shiftedDcId = 0;
|
||||
const AuthKeyPtr _persistentKey;
|
||||
mtpMsgId _requestMsgId = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -76,12 +76,17 @@ template <typename PQInnerData>
|
||||
constexpr auto kSkipPrimes = 6;
|
||||
constexpr auto kMaxPrimes = 65; // 260 bytes
|
||||
|
||||
const auto p_q_inner_size = tl::count_length(data);
|
||||
using BoxedPQInnerData = std::conditional_t<
|
||||
tl::is_boxed_v<PQInnerData>,
|
||||
PQInnerData,
|
||||
tl::boxed<PQInnerData>>;
|
||||
const auto boxed = BoxedPQInnerData(data);
|
||||
const auto p_q_inner_size = tl::count_length(boxed);
|
||||
const auto sizeInPrimes = (p_q_inner_size >> 2) + kSkipPrimes;
|
||||
if (sizeInPrimes >= kMaxPrimes) {
|
||||
auto tmp = mtpBuffer();
|
||||
tmp.reserve(sizeInPrimes);
|
||||
data.write(tmp);
|
||||
boxed.write(tmp);
|
||||
LOG(("AuthKey Error: too large data for RSA encrypt, size %1").arg(sizeInPrimes * sizeof(mtpPrime)));
|
||||
DEBUG_LOG(("AuthKey Error: bad data for RSA encrypt %1").arg(Logs::mb(&tmp[0], tmp.size() * 4).str()));
|
||||
return {}; // can't be 255-byte string
|
||||
@ -90,7 +95,7 @@ template <typename PQInnerData>
|
||||
auto encBuffer = mtpBuffer();
|
||||
encBuffer.reserve(kMaxPrimes);
|
||||
encBuffer.resize(kSkipPrimes);
|
||||
data.write(encBuffer);
|
||||
boxed.write(encBuffer);
|
||||
encBuffer.resize(kMaxPrimes);
|
||||
const auto bytes = bytes::make_span(encBuffer);
|
||||
|
||||
|
@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "mtproto/mtp_instance.h"
|
||||
|
||||
#include "mtproto/details/mtproto_dc_key_checker.h"
|
||||
#include "mtproto/session.h"
|
||||
#include "mtproto/dc_options.h"
|
||||
#include "mtproto/dcenter.h"
|
||||
@ -34,6 +33,7 @@ namespace {
|
||||
|
||||
constexpr auto kConfigBecomesOldIn = 2 * 60 * crl::time(1000);
|
||||
constexpr auto kConfigBecomesOldForBlockedIn = 8 * crl::time(1000);
|
||||
constexpr auto kCheckKeyEach = 60 * crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -134,6 +134,7 @@ public:
|
||||
void performKeyDestroy(ShiftedDcId shiftedDcId);
|
||||
void completedKeyDestroy(ShiftedDcId shiftedDcId);
|
||||
void checkMainDcKey();
|
||||
void keyDestroyedOnServer(DcId dcId, uint64 keyId);
|
||||
|
||||
void clearKilledSessions();
|
||||
void prepareToDestroy();
|
||||
@ -228,8 +229,6 @@ private:
|
||||
|
||||
base::Timer _checkDelayedTimer;
|
||||
|
||||
std::unique_ptr<details::DcKeyChecker> _mainDcKeyChecker;
|
||||
|
||||
// Debug flag to find out how we end up crashing.
|
||||
bool MustNotCreateSessions = false;
|
||||
|
||||
@ -1509,10 +1508,11 @@ void Instance::Private::completedKeyDestroy(ShiftedDcId shiftedDcId) {
|
||||
}
|
||||
|
||||
void Instance::Private::checkMainDcKey() {
|
||||
if (_mainDcKeyChecker) {
|
||||
const auto id = mainDcId();
|
||||
const auto shiftedDcId = ShiftDcId(id, kCheckKeyDcShift);
|
||||
if (_sessions.find(shiftedDcId) != _sessions.end()) {
|
||||
return;
|
||||
}
|
||||
const auto id = mainDcId();
|
||||
const auto key = [&] {
|
||||
QReadLocker lock(&_keysForWriteLock);
|
||||
const auto i = _keysForWrite.find(id);
|
||||
@ -1521,11 +1521,26 @@ void Instance::Private::checkMainDcKey() {
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
_mainDcKeyChecker = std::make_unique<details::DcKeyChecker>(
|
||||
_instance,
|
||||
id,
|
||||
key,
|
||||
[=] { _mainDcKeyChecker = nullptr; });
|
||||
const auto lastCheckTime = key->lastCheckTime();
|
||||
if (lastCheckTime > 0 && lastCheckTime + kCheckKeyEach >= crl::now()) {
|
||||
return;
|
||||
}
|
||||
_instance->sendDcKeyCheck(shiftedDcId, key);
|
||||
}
|
||||
|
||||
void Instance::Private::keyDestroyedOnServer(DcId dcId, uint64 keyId) {
|
||||
if (dcId == _mainDcId) {
|
||||
for (const auto &[id, dc] : _dcenters) {
|
||||
dc->destroyKey();
|
||||
}
|
||||
restart();
|
||||
} else {
|
||||
const auto i = _dcenters.find(dcId);
|
||||
if (i != end(_dcenters)) {
|
||||
i->second->destroyKey();
|
||||
}
|
||||
restart(dcId);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::Private::setUpdatesHandler(RPCDoneHandlerPtr onDone) {
|
||||
@ -1782,6 +1797,10 @@ void Instance::checkIfKeyWasDestroyed(ShiftedDcId shiftedDcId) {
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::keyDestroyedOnServer(DcId dcId, uint64 keyId) {
|
||||
_private->keyDestroyedOnServer(dcId, keyId);
|
||||
}
|
||||
|
||||
void Instance::sendRequest(
|
||||
mtpRequestId requestId,
|
||||
SecureRequest &&request,
|
||||
@ -1805,6 +1824,11 @@ void Instance::sendAnything(ShiftedDcId shiftedDcId, crl::time msCanWait) {
|
||||
session->sendAnything(msCanWait);
|
||||
}
|
||||
|
||||
void Instance::sendDcKeyCheck(ShiftedDcId shiftedDcId, const AuthKeyPtr &key) {
|
||||
const auto session = _private->getSession(shiftedDcId);
|
||||
session->sendDcKeyCheck(key);
|
||||
}
|
||||
|
||||
Instance::~Instance() {
|
||||
_private->prepareToDestroy();
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ public:
|
||||
}
|
||||
|
||||
void sendAnything(ShiftedDcId shiftedDcId = 0, crl::time msCanWait = 0);
|
||||
void sendDcKeyCheck(ShiftedDcId shiftedDcId, const AuthKeyPtr &key);
|
||||
|
||||
void restart();
|
||||
void restart(ShiftedDcId shiftedDcId);
|
||||
@ -174,6 +175,7 @@ public:
|
||||
bool isKeysDestroyer() const;
|
||||
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
|
||||
void checkIfKeyWasDestroyed(ShiftedDcId shiftedDcId);
|
||||
void keyDestroyedOnServer(DcId dcId, uint64 keyId);
|
||||
|
||||
void requestConfig();
|
||||
void requestConfigIfOld();
|
||||
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "mtproto/session.h"
|
||||
|
||||
#include "mtproto/details/mtproto_dc_key_checker.h"
|
||||
#include "mtproto/connection.h"
|
||||
#include "mtproto/dcenter.h"
|
||||
#include "mtproto/auth_key.h"
|
||||
@ -77,6 +78,10 @@ void SessionData::setKey(const AuthKeyPtr &key) {
|
||||
}
|
||||
}
|
||||
|
||||
void SessionData::setKeyForCheck(const AuthKeyPtr &key) {
|
||||
_dcKeyForCheck = key;
|
||||
}
|
||||
|
||||
void SessionData::notifyConnectionInited(const ConnectionOptions &options) {
|
||||
QWriteLocker locker(&_lock);
|
||||
if (options.cloudLangCode == _options.cloudLangCode
|
||||
@ -157,7 +162,7 @@ void Session::start() {
|
||||
}
|
||||
|
||||
void Session::createDcData() {
|
||||
if (_dc) {
|
||||
if (_dc || GetDcIdShift(_shiftedDcId) == kCheckKeyDcShift) {
|
||||
return;
|
||||
}
|
||||
_dc = _instance->getDcById(_shiftedDcId);
|
||||
@ -212,7 +217,9 @@ void Session::refreshOptions() {
|
||||
}
|
||||
|
||||
void Session::reInitConnection() {
|
||||
_dc->setConnectionInited(false);
|
||||
if (_dc) {
|
||||
_dc->setConnectionInited(false);
|
||||
}
|
||||
_data.setConnectionInited(false);
|
||||
restart();
|
||||
}
|
||||
@ -242,6 +249,11 @@ void Session::unpaused() {
|
||||
}
|
||||
}
|
||||
|
||||
void Session::sendDcKeyCheck(const AuthKeyPtr &key) {
|
||||
_data.setKeyForCheck(key);
|
||||
needToResumeAndSend();
|
||||
}
|
||||
|
||||
void Session::sendAnything(qint64 msCanWait) {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't send anything in a killed session"));
|
||||
@ -550,10 +562,12 @@ void Session::sendPrepared(
|
||||
}
|
||||
|
||||
QReadWriteLock *Session::keyMutex() const {
|
||||
return _dc->keyMutex();
|
||||
return _dc ? _dc->keyMutex() : nullptr;
|
||||
}
|
||||
|
||||
void Session::authKeyCreatedForDC() {
|
||||
Expects(_dc != nullptr);
|
||||
|
||||
DEBUG_LOG(("AuthKey Info: Session::authKeyCreatedForDC slot, emitting authKeyCreated(), dcWithShift %1").arg(_shiftedDcId));
|
||||
_data.setKey(_dc->getKey());
|
||||
emit authKeyCreated();
|
||||
@ -561,31 +575,37 @@ void Session::authKeyCreatedForDC() {
|
||||
|
||||
void Session::notifyKeyCreated(AuthKeyPtr &&key) {
|
||||
DEBUG_LOG(("AuthKey Info: Session::keyCreated(), setting, dcWithShift %1").arg(_shiftedDcId));
|
||||
_dc->setKey(std::move(key));
|
||||
if (_dc) {
|
||||
_dc->setKey(std::move(key));
|
||||
} else {
|
||||
_data.setKey(std::move(key));
|
||||
emit authKeyCreated();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::connectionWasInitedForDC() {
|
||||
Expects(_dc != nullptr);
|
||||
|
||||
DEBUG_LOG(("MTP Info: Session::connectionWasInitedForDC slot, dcWithShift %1").arg(_shiftedDcId));
|
||||
_data.setConnectionInited();
|
||||
}
|
||||
|
||||
void Session::notifyDcConnectionInited() {
|
||||
DEBUG_LOG(("MTP Info: emitting MTProtoDC::connectionWasInited(), dcWithShift %1").arg(_shiftedDcId));
|
||||
_dc->setConnectionInited();
|
||||
emit _dc->connectionWasInited();
|
||||
if (_dc) {
|
||||
_dc->setConnectionInited();
|
||||
} else {
|
||||
_data.setConnectionInited();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::destroyKey() {
|
||||
if (!_dc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_data.getKey()) {
|
||||
if (const auto key = _data.getKey()) {
|
||||
DEBUG_LOG(("MTP Info: destroying auth_key for dcWithShift %1").arg(_shiftedDcId));
|
||||
if (_data.getKey() == _dc->getKey()) {
|
||||
if (_dc && _dc->getKey() == key) {
|
||||
_dc->destroyKey();
|
||||
}
|
||||
_data.setKey(AuthKeyPtr());
|
||||
_data.setKey(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,6 +184,11 @@ public:
|
||||
}
|
||||
void setKey(const AuthKeyPtr &key);
|
||||
|
||||
const AuthKeyPtr &getKeyForCheck() const {
|
||||
return _dcKeyForCheck;
|
||||
}
|
||||
void setKeyForCheck(const AuthKeyPtr &key);
|
||||
|
||||
bool isCheckedKey() const {
|
||||
QReadLocker locker(&_lock);
|
||||
return _keyChecked;
|
||||
@ -193,7 +198,7 @@ public:
|
||||
_keyChecked = checked;
|
||||
}
|
||||
|
||||
not_null<QReadWriteLock*> keyMutex() const;
|
||||
QReadWriteLock *keyMutex() const;
|
||||
|
||||
not_null<QReadWriteLock*> toSendMutex() const {
|
||||
return &_toSendLock;
|
||||
@ -291,6 +296,7 @@ private:
|
||||
not_null<Session*> _owner;
|
||||
|
||||
AuthKeyPtr _authKey;
|
||||
AuthKeyPtr _dcKeyForCheck;
|
||||
bool _keyChecked = false;
|
||||
bool _layerInited = false;
|
||||
ConnectionOptions _options;
|
||||
@ -345,6 +351,8 @@ public:
|
||||
int32 getState() const;
|
||||
QString transport() const;
|
||||
|
||||
void sendDcKeyCheck(const AuthKeyPtr &key);
|
||||
|
||||
// Nulls msgId and seqNo in request, if newRequest = true.
|
||||
void sendPrepared(
|
||||
const SecureRequest &request,
|
||||
@ -393,6 +401,7 @@ private:
|
||||
|
||||
ShiftedDcId _shiftedDcId = 0;
|
||||
std::shared_ptr<Dcenter> _dc;
|
||||
AuthKeyPtr _dcKeyForCheck;
|
||||
|
||||
crl::time _msSendCall = 0;
|
||||
crl::time _msWait = 0;
|
||||
@ -404,9 +413,38 @@ private:
|
||||
|
||||
};
|
||||
|
||||
inline not_null<QReadWriteLock*> SessionData::keyMutex() const {
|
||||
inline QReadWriteLock *SessionData::keyMutex() const {
|
||||
return _owner->keyMutex();
|
||||
}
|
||||
|
||||
class ReadLockerAttempt {
|
||||
public:
|
||||
ReadLockerAttempt(QReadWriteLock *lock) : _lock(lock), _locked(_lock ? _lock->tryLockForRead() : true) {
|
||||
}
|
||||
ReadLockerAttempt(const ReadLockerAttempt &other) = delete;
|
||||
ReadLockerAttempt &operator=(const ReadLockerAttempt &other) = delete;
|
||||
ReadLockerAttempt(ReadLockerAttempt &&other) : _lock(other._lock), _locked(base::take(other._locked)) {
|
||||
}
|
||||
ReadLockerAttempt &operator=(ReadLockerAttempt &&other) {
|
||||
_lock = other._lock;
|
||||
_locked = base::take(other._locked);
|
||||
return *this;
|
||||
}
|
||||
~ReadLockerAttempt() {
|
||||
if (_lock && _locked) {
|
||||
_lock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return _locked;
|
||||
}
|
||||
|
||||
private:
|
||||
QReadWriteLock *_lock = nullptr;
|
||||
bool _locked = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace MTP
|
||||
|
Loading…
Reference in New Issue
Block a user