Don't lock whole key creation by a mutex.

This commit is contained in:
John Preston 2019-11-15 16:04:32 +03:00
parent 055b99f5b0
commit be06d68468
12 changed files with 397 additions and 445 deletions

View File

@ -40,7 +40,6 @@ namespace MTP {
namespace internal {
namespace {
constexpr auto kRecreateKeyId = AuthKey::KeyId(0xFFFFFFFFFFFFFFFFULL);
constexpr auto kIntSize = static_cast<int>(sizeof(mtpPrime));
constexpr auto kWaitForBetterTimeout = crl::time(2000);
constexpr auto kMinConnectedTimeout = crl::time(1000);
@ -100,6 +99,14 @@ Connection::Connection(not_null<Instance*> instance)
: _instance(instance) {
}
Connection::~Connection() {
Expects(_private == nullptr);
if (_thread) {
waitTillFinish();
}
}
void Connection::start(SessionData *sessionData, ShiftedDcId shiftedDcId) {
Expects(_thread == nullptr && _private == nullptr);
@ -144,14 +151,6 @@ QString Connection::transport() const {
return _private->transport();
}
Connection::~Connection() {
Expects(_private == nullptr);
if (_thread) {
waitTillFinish();
}
}
void ConnectionPrivate::appendTestConnection(
DcOptions::Variants::Protocol protocol,
const QString &ip,
@ -215,11 +214,14 @@ int16 ConnectionPrivate::getProtocolDcId() const {
}
void ConnectionPrivate::destroyAllConnections() {
{
QReadLocker lockFinished(&_sessionDataMutex);
clearKeyCreatorOnFail();
}
_waitForBetterTimer.cancel();
_waitForReceivedTimer.cancel();
_waitForConnectedTimer.cancel();
_testConnections.clear();
_keyCreator = nullptr;
_connection = nullptr;
}
@ -250,7 +252,7 @@ ConnectionPrivate::ConnectionPrivate(
connect(thread, &QThread::started, this, [=] { connectToServer(); });
connect(thread, &QThread::finished, this, [=] { finishAndDestroy(); });
connect(_sessionData->owner(), SIGNAL(authKeyCreated()), this, SLOT(updateAuthKey()), Qt::QueuedConnection);
connect(_sessionData->owner(), SIGNAL(authKeyChanged()), this, SLOT(updateAuthKey()), Qt::QueuedConnection);
connect(_sessionData->owner(), SIGNAL(needToRestart()), this, SLOT(restartNow()), Qt::QueuedConnection);
connect(this, SIGNAL(needToReceive()), _sessionData->owner(), SLOT(tryToReceive()), Qt::QueuedConnection);
connect(this, SIGNAL(stateChanged(qint32)), _sessionData->owner(), SLOT(onConnectionStateChange(qint32)), Qt::QueuedConnection);
@ -274,6 +276,13 @@ ConnectionPrivate::ConnectionPrivate(
connect(this, SIGNAL(resendAllAsync()), _sessionData->owner(), SLOT(resendAll()), Qt::QueuedConnection);
}
ConnectionPrivate::~ConnectionPrivate() {
Expects(_finished);
Expects(!_connection);
Expects(_testConnections.empty());
Expects(!_keyCreator);
}
void ConnectionPrivate::onConfigLoaded() {
connectToServer(true);
}
@ -562,11 +571,11 @@ mtpMsgId ConnectionPrivate::placeToContainer(SecureRequest &toSendRequest, mtpMs
void ConnectionPrivate::tryToSend() {
QReadLocker lockFinished(&_sessionDataMutex);
if (!_sessionData || !_connection) {
if (!_sessionData || !_connection || !_keyId) {
return;
}
auto needsLayer = !_connectionOptions->inited;
auto needsLayer = !_sessionData->owner()->connectionInited();
auto state = getState();
auto sendOnlyFirstPing = (state != ConnectedState);
if (sendOnlyFirstPing && !_pingIdToSend) {
@ -650,7 +659,7 @@ void ConnectionPrivate::tryToSend() {
_shiftedDcId,
keyForCheck);
checkDcKeyRequest = _keyChecker->prepareRequest(
_sessionData->getKey(),
_key,
_sessionData->getSessionId());
// This is a special request with msgId used inside the message
@ -771,7 +780,9 @@ void ConnectionPrivate::tryToSend() {
auto &haveSent = _sessionData->haveSentMap();
haveSent.insert(msgId, toSendRequest);
if (needsLayer && !toSendRequest->needsLayer) needsLayer = false;
if (needsLayer && !toSendRequest->needsLayer) {
needsLayer = false;
}
if (toSendRequest->after) {
const auto toSendSize = tl::count_length(toSendRequest) >> 2;
auto wrappedRequest = SecureRequest::Prepare(
@ -844,6 +855,7 @@ void ConnectionPrivate::tryToSend() {
// prepare "request-like" wrap for msgId vector
auto haveSentIdsWrap = SecureRequest::Prepare(idsWrapSize);
haveSentIdsWrap->msDate = 0; // Container: msDate = 0, seqNo = 0.
haveSentIdsWrap->requestId = 0;
haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize);
auto haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8);
@ -931,15 +943,6 @@ void ConnectionPrivate::retryByTimer() {
} else if (_retryTimeout < 64000) {
_retryTimeout *= 2;
}
if (_keyId == kRecreateKeyId) {
if (_sessionData->getKey()) {
unlockKey();
QWriteLocker lock(_sessionData->keyMutex());
_sessionData->owner()->destroyKey();
}
_keyId = 0;
}
connectToServer();
}
@ -964,7 +967,8 @@ void ConnectionPrivate::connectToServer(bool afterConfig) {
}
_connectionOptions = std::make_unique<ConnectionOptions>(
_sessionData->connectionOptions());
const auto hasKey = (_sessionData->getKey() != nullptr);
// #TODO race.
const auto hasKey = (_sessionData->owner()->getKey() != nullptr);
lockFinished.unlock();
const auto bareDc = BareDcId(_shiftedDcId);
@ -1212,13 +1216,6 @@ void ConnectionPrivate::connectingTimedOut() {
void ConnectionPrivate::doDisconnect() {
destroyAllConnections();
{
QReadLocker lockFinished(&_sessionDataMutex);
if (_sessionData) {
unlockKey();
}
}
setState(DisconnectedState);
_restarted = false;
}
@ -1257,21 +1254,6 @@ void ConnectionPrivate::handleReceived() {
restart();
};
ReadLockerAttempt lock(_sessionData->keyMutex());
if (!lock) {
DEBUG_LOG(("MTP Error: auth_key for dc %1 busy, cant lock").arg(_shiftedDcId));
clearMessages();
_keyId = 0;
return restartOnError();
}
auto key = _sessionData->getKey();
if (!key || key->keyId() != _keyId) {
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(_shiftedDcId));
return restartOnError();
}
while (!_connection->received().empty()) {
auto intsBuffer = std::move(_connection->received().front());
_connection->received().pop_front();
@ -1302,9 +1284,9 @@ void ConnectionPrivate::handleReceived() {
auto msgKey = *(MTPint128*)(ints + 2);
#ifdef TDESKTOP_MTPROTO_OLD
aesIgeDecrypt_oldmtp(encryptedInts, decryptedBuffer.data(), encryptedBytesCount, key, msgKey);
aesIgeDecrypt_oldmtp(encryptedInts, decryptedBuffer.data(), encryptedBytesCount, _key, msgKey);
#else // TDESKTOP_MTPROTO_OLD
aesIgeDecrypt(encryptedInts, decryptedBuffer.data(), encryptedBytesCount, key, msgKey);
aesIgeDecrypt(encryptedInts, decryptedBuffer.data(), encryptedBytesCount, _key, msgKey);
#endif // TDESKTOP_MTPROTO_OLD
auto decryptedInts = reinterpret_cast<const mtpPrime*>(decryptedBuffer.constData());
@ -1351,7 +1333,7 @@ void ConnectionPrivate::handleReceived() {
SHA256_CTX msgKeyLargeContext;
SHA256_Init(&msgKeyLargeContext);
SHA256_Update(&msgKeyLargeContext, key->partForMsgKey(false), 32);
SHA256_Update(&msgKeyLargeContext, _key->partForMsgKey(false), 32);
SHA256_Update(&msgKeyLargeContext, decryptedInts, encryptedBytesCount);
SHA256_Final(sha256Buffer.data(), &msgKeyLargeContext);
@ -1960,10 +1942,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
// An error could be some RPC_CALL_FAIL or other error inside
// the initConnection, so we're not sure yet that it was inited.
// Wait till a good response is received.
if (!_connectionOptions->inited) {
_connectionOptions->inited = true;
_sessionData->notifyConnectionInited(*_connectionOptions);
}
_sessionData->notifyConnectionInited(*_connectionOptions);
}
if (_keyChecker && _keyChecker->handleResponse(reqMsgId, response)) {
@ -2346,7 +2325,7 @@ void ConnectionPrivate::onConnected(
_testConnections.clear();
lockFinished.unlock();
updateAuthKey();
checkAuthKey();
}
}
@ -2383,7 +2362,7 @@ void ConnectionPrivate::confirmBestConnection() {
_connection = std::move(i->data);
_testConnections.clear();
updateAuthKey();
checkAuthKey();
}
void ConnectionPrivate::removeTestConnection(
@ -2396,51 +2375,58 @@ void ConnectionPrivate::removeTestConnection(
end(_testConnections));
}
void ConnectionPrivate::checkAuthKey() {
if (!_keyId) {
updateAuthKey();
} else {
authKeyChecked();
}
}
void ConnectionPrivate::updateAuthKey() {
QReadLocker lockFinished(&_sessionDataMutex);
if (!_sessionData || !_connection) {
if (!_sessionData || _keyCreator) {
return;
}
DEBUG_LOG(("AuthKey Info: Connection updating key from Session, dc %1").arg(_shiftedDcId));
uint64 newKeyId = 0;
{
ReadLockerAttempt lock(_sessionData->keyMutex());
if (!lock) {
DEBUG_LOG(("MTP Info: could not lock auth_key for read, waiting signal emit"));
clearMessages();
_keyId = newKeyId;
return; // some other connection is getting key
_key = _sessionData->owner()->getKey();
const auto newKeyId = _key ? _key->keyId() : 0;
if (newKeyId) {
if (_keyId == newKeyId) {
return;
}
auto key = _sessionData->getKey();
newKeyId = key ? key->keyId() : 0;
_sessionData->setCurrentKeyId(newKeyId);
}
if (_keyId != newKeyId) {
clearMessages();
_keyId = newKeyId;
_keyId = newKeyId;
if (!_connection) {
return;
}
if (const auto already = _connection->sentEncryptedWithKeyId()) {
Assert(already != newKeyId);
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(_shiftedDcId));
lockFinished.unlock();
restart();
return;
}
DEBUG_LOG(("AuthKey Info: Connection update key from Session, dc %1 result: %2").arg(_shiftedDcId).arg(Logs::mb(&_keyId, sizeof(_keyId)).str()));
if (_keyId) {
return authKeyCreated();
return authKeyChecked();
}
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), will be creating auth_key"));
lockKey();
const auto &key = _sessionData->getKey();
if (key) {
if (_keyId != key->keyId()) clearMessages();
_keyId = key->keyId();
unlockKey();
return authKeyCreated();
} else if (_instance->isKeysDestroyer()) {
if (_instance->isKeysDestroyer()) {
// We are here to destroy an old key, so we're done.
LOG(("MTP Error: No key %1 in updateAuthKey() for destroying.").arg(_shiftedDcId));
_instance->checkIfKeyWasDestroyed(_shiftedDcId);
return;
} else if (!_sessionData->owner()->acquireKeyCreation()) {
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), but someone is creating already."));
return;
}
lockFinished.unlock();
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), creating."));
createDcKey();
}
@ -2449,23 +2435,24 @@ void ConnectionPrivate::createDcKey() {
using Error = DcKeyCreator::Error;
auto delegate = DcKeyCreator::Delegate();
delegate.done = [=](base::expected<Result, Error> result) {
_keyCreator = nullptr;
QReadLocker lockFinished(&_sessionDataMutex);
if (!_sessionData) return;
if (result) {
QReadLocker lockFinished(&_sessionDataMutex);
if (!_sessionData) return;
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(result->key->keyId()).arg(result->serverSalt));
_sessionData->setSalt(result->serverSalt);
_sessionData->clearForNewKey(_instance);
auto authKey = std::move(result->key);
_keyCreator = nullptr;
_sessionData->owner()->releaseKeyCreationOnDone(
std::move(result->key));
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(result->serverSalt));
// slot will call authKeyCreated().
_sessionData->owner()->notifyKeyCreated(std::move(authKey));
_sessionData->clear(_instance);
unlockKey();
} else if (result.error() == Error::UnknownPublicKey) {
updateAuthKey();
return;
}
clearKeyCreatorOnFail();
if (result.error() == Error::UnknownPublicKey) {
if (_dcType == DcType::Cdn) {
LOG(("Warning: CDN public RSA key not found"));
requestCDNConfig();
@ -2489,26 +2476,18 @@ void ConnectionPrivate::createDcKey() {
expireIn);
}
void ConnectionPrivate::clearMessages() {
if (_keyId && _keyId != kRecreateKeyId && _connection) {
_connection->received().clear();
}
}
void ConnectionPrivate::authKeyCreated() {
_keyCreator = nullptr;
void ConnectionPrivate::authKeyChecked() {
connect(_connection, &AbstractConnection::receivedData, [=] {
handleReceived();
});
if (_sessionData->getSalt()) { // else receive salt in bad_server_salt first, then try to send all the requests
if (_sessionData->getSalt()) {
setState(ConnectedState);
if (_restarted) {
emit resendAllAsync();
_restarted = false;
}
}
} // else receive salt in bad_server_salt first, then try to send all the requests
_pingIdToSend = rand_value<uint64>(); // get server_salt
@ -2542,8 +2521,7 @@ void ConnectionPrivate::handleError(int errorCode) {
if (errorCode == -404) {
if (_dcType == DcType::Cdn && !_instance->isKeysDestroyer()) {
LOG(("MTP Info: -404 error received in CDN dc %1, assuming it was destroyed, recreating.").arg(_shiftedDcId));
clearMessages();
_keyId = kRecreateKeyId;
destroyCdnKey();
return restart();
} else {
LOG(("MTP Info: -404 error received, informing instance."));
@ -2557,7 +2535,16 @@ void ConnectionPrivate::handleError(int errorCode) {
return restart();
}
void ConnectionPrivate::onReadyData() {
void ConnectionPrivate::destroyCdnKey() {
if (_key) {
QReadLocker lockFinished(&_sessionDataMutex);
if (_sessionData) {
_sessionData->owner()->destroyCdnKey(_keyId);
}
}
_key = nullptr;
_keyId = 0;
}
bool ConnectionPrivate::sendSecureRequest(
@ -2581,24 +2568,6 @@ bool ConnectionPrivate::sendSecureRequest(
return false;
}
auto lock = ReadLockerAttempt(_sessionData->keyMutex());
if (!lock) {
DEBUG_LOG(("MTP Info: could not lock key for read in sendBuffer(), dc %1, restarting...").arg(_shiftedDcId));
lockFinished.unlock();
restart();
return false;
}
auto key = _sessionData->getKey();
if (!key || key->keyId() != _keyId) {
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(_shiftedDcId));
lockFinished.unlock();
restart();
return false;
}
auto session = _sessionData->getSessionId();
auto salt = _sessionData->getSalt();
@ -2626,7 +2595,7 @@ bool ConnectionPrivate::sendSecureRequest(
request->constData(),
&packet[prefix],
fullSize * sizeof(mtpPrime),
key,
_key,
msgKey);
#else // TDESKTOP_MTPROTO_OLD
uchar encryptedSHA256[32];
@ -2634,7 +2603,7 @@ bool ConnectionPrivate::sendSecureRequest(
SHA256_CTX msgKeyLargeContext;
SHA256_Init(&msgKeyLargeContext);
SHA256_Update(&msgKeyLargeContext, key->partForMsgKey(true), 32);
SHA256_Update(&msgKeyLargeContext, _key->partForMsgKey(true), 32);
SHA256_Update(&msgKeyLargeContext, request->constData(), fullSize * sizeof(mtpPrime));
SHA256_Final(encryptedSHA256, &msgKeyLargeContext);
@ -2646,13 +2615,13 @@ bool ConnectionPrivate::sendSecureRequest(
request->constData(),
&packet[prefix],
fullSize * sizeof(mtpPrime),
key,
_key,
msgKey);
#endif // TDESKTOP_MTPROTO_OLD
DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5]));
_connection->setSentEncrypted();
_connection->setSentEncryptedWithKeyId(_keyId);
_connection->sendData(std::move(packet));
if (needAnyResponse) {
@ -2689,39 +2658,24 @@ mtpRequestId ConnectionPrivate::wasSent(mtpMsgId msgId) const {
return 0;
}
void ConnectionPrivate::lockKey() {
unlockKey();
if (const auto mutex = _sessionData->keyMutex()) {
mutex->lockForWrite();
}
_myKeyLock = true;
}
// _sessionDataMutex must be locked for read.
void ConnectionPrivate::clearKeyCreatorOnFail() {
if (_keyCreator) {
_keyCreator = nullptr;
void ConnectionPrivate::unlockKey() {
if (_myKeyLock) {
_myKeyLock = false;
if (const auto mutex = _sessionData->keyMutex()) {
mutex->unlock();
}
Assert(_sessionData != nullptr);
_sessionData->owner()->releaseKeyCreationOnFail();
}
}
ConnectionPrivate::~ConnectionPrivate() {
Expects(_finished);
Expects(!_connection);
Expects(_testConnections.empty());
Expects(!_keyCreator);
}
void ConnectionPrivate::stop() {
QWriteLocker lockFinished(&_sessionDataMutex);
if (_sessionData) {
if (_myKeyLock) {
_sessionData->owner()->notifyKeyCreated(AuthKeyPtr()); // release key lock, let someone else create it
unlockKey();
}
_sessionData = nullptr;
if (!_sessionData) {
Assert(_keyCreator == nullptr);
return;
}
clearKeyCreatorOnFail();
_sessionData = nullptr;
}
} // namespace internal

View File

@ -41,12 +41,12 @@ public:
};
Connection(not_null<Instance*> instance);
~Connection();
void start(SessionData *data, ShiftedDcId shiftedDcId);
void kill();
void waitTillFinish();
~Connection();
static const int UpdateAlways = 666;
@ -99,14 +99,6 @@ public slots:
void onPingSendForce();
void onSentSome(uint64 size);
void onReceivedSome();
void onReadyData();
// General packet receive slot, connected to conn->receivedData signal
void handleReceived();
// Sessions signals, when we need to send something
void tryToSend();
@ -132,6 +124,10 @@ private:
qint32 errorCode);
void onConnected(not_null<AbstractConnection*> connection);
void onDisconnected(not_null<AbstractConnection*> connection);
void onSentSome(uint64 size);
void onReceivedSome();
void handleReceived();
void retryByTimer();
void waitConnectedFailed();
@ -140,7 +136,9 @@ private:
void markConnectionOld();
void sendPingByTimer();
// Locks _sessionDataMutex.
void destroyAllConnections();
void confirmBestConnection();
void removeTestConnection(not_null<AbstractConnection*> connection);
int16 getProtocolDcId() const;
@ -170,8 +168,6 @@ private:
mtpBuffer ungzip(const mtpPrime *from, const mtpPrime *end) const;
void handleMsgsStates(const QVector<MTPlong> &ids, const QByteArray &states, QVector<MTPlong> &acked);
void clearMessages();
bool setState(int32 state, int32 ifState = Connection::UpdateAlways);
void appendTestConnection(
@ -191,9 +187,12 @@ private:
void createDcKey();
void resetSession();
void lockKey();
void unlockKey();
void authKeyCreated();
void checkAuthKey();
void authKeyChecked();
void destroyCdnKey();
// _sessionDataMutex must be locked for read.
void clearKeyCreatorOnFail();
not_null<Instance*> _instance;
DcType _dcType = DcType::Regular;
@ -235,13 +234,12 @@ private:
bool _restarted = false;
bool _finished = false;
AuthKeyPtr _key;
uint64 _keyId = 0;
QReadWriteLock _sessionDataMutex;
SessionData *_sessionData = nullptr;
std::unique_ptr<ConnectionOptions> _connectionOptions;
bool _myKeyLock = false;
std::unique_ptr<details::DcKeyCreator> _keyCreator;
std::unique_ptr<details::DcKeyChecker> _keyChecker;

View File

@ -100,8 +100,11 @@ public:
[[nodiscard]] virtual QString transport() const = 0;
[[nodiscard]] virtual QString tag() const = 0;
void setSentEncrypted() {
_sentEncrypted = true;
void setSentEncryptedWithKeyId(uint64 keyId) {
_sentEncryptedWithKeyId = keyId;
}
[[nodiscard]] uint64 sentEncryptedWithKeyId() const {
return _sentEncryptedWithKeyId;
}
using BuffersQueue = std::deque<mtpBuffer>;
@ -137,7 +140,6 @@ signals:
protected:
BuffersQueue _receivedQueue; // list of received packets, not processed yet
bool _sentEncrypted = false;
int _pingTime = 0;
ProxyData _proxy;
@ -150,6 +152,8 @@ protected:
private:
[[nodiscard]] uint32 extendedNotSecurePadding() const;
uint64 _sentEncryptedWithKeyId = 0;
};
template <typename Request>

View File

@ -23,53 +23,81 @@ constexpr auto kSpecialRequestTimeoutMs = 6000; // 4 seconds timeout for it to w
} // namespace
Dcenter::Dcenter(not_null<Instance*> instance, DcId dcId, AuthKeyPtr &&key)
: _instance(instance)
, _id(dcId)
Dcenter::Dcenter(DcId dcId, AuthKeyPtr &&key)
: _id(dcId)
, _key(std::move(key)) {
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
}
void Dcenter::authKeyWrite() {
DEBUG_LOG(("AuthKey Info: MTProtoDC::authKeyWrite() slot, dc %1").arg(_id));
if (_key) {
Local::writeMtpData();
}
DcId Dcenter::id() const {
return _id;
}
void Dcenter::setKey(AuthKeyPtr &&key) {
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
_key = std::move(key);
_connectionInited = false;
_instance->setKeyForWrite(_id, _key);
emit authKeyCreated();
}
QReadWriteLock *Dcenter::keyMutex() const {
return &keyLock;
}
const AuthKeyPtr &Dcenter::getKey() const {
AuthKeyPtr Dcenter::getKey() const {
QReadLocker lock(&_mutex);
return _key;
}
void Dcenter::destroyKey() {
setKey(AuthKeyPtr());
void Dcenter::destroyCdnKey(uint64 keyId) {
destroyKey(keyId);
}
bool Dcenter::destroyConfirmedForgottenKey(uint64 keyId) {
return destroyKey(keyId);
}
bool Dcenter::destroyKey(uint64 keyId) {
Expects(!_creatingKey || !_key);
QWriteLocker lock(&_mutex);
if (_key->keyId() != keyId) {
return false;
}
_key = nullptr;
_connectionInited = false;
lock.unlock();
emit authKeyChanged();
return true;
}
bool Dcenter::connectionInited() const {
const auto lock = QMutexLocker(&_initLock);
QReadLocker lock(&_mutex);
return _connectionInited;
}
void Dcenter::setConnectionInited(bool connectionInited) {
auto lock = QMutexLocker(&_initLock);
QWriteLocker lock(&_mutex);
_connectionInited = connectionInited;
}
bool Dcenter::acquireKeyCreation() {
QReadLocker lock(&_mutex);
if (_key != nullptr) {
return false;
}
auto expected = false;
return _creatingKey.compare_exchange_strong(expected, true);
}
void Dcenter::releaseKeyCreationOnFail() {
Expects(_creatingKey);
Expects(_key == nullptr);
_creatingKey = false;
}
void Dcenter::releaseKeyCreationOnDone(AuthKeyPtr &&key) {
Expects(_creatingKey);
Expects(_key == nullptr);
QWriteLocker lock(&_mutex);
DEBUG_LOG(("AuthKey Info: Dcenter::releaseKeyCreationOnDone(%1), emitting authKeyChanged, dc %2").arg(key ? key->keyId() : 0).arg(_id));
_key = std::move(key);
_connectionInited = false;
_creatingKey = false;
lock.unlock();
if (connectionInited) {
emit connectionWasInited();
}
emit authKeyChanged();
}
} // namespace internal

View File

@ -19,30 +19,35 @@ class Dcenter : public QObject {
Q_OBJECT
public:
Dcenter(not_null<Instance*> instance, DcId dcId, AuthKeyPtr &&key);
// Main thread.
Dcenter(DcId dcId, AuthKeyPtr &&key);
QReadWriteLock *keyMutex() const;
const AuthKeyPtr &getKey() const;
void setKey(AuthKeyPtr &&key);
void destroyKey();
// Thread-safe.
[[nodiscard]] DcId id() const;
[[nodiscard]] AuthKeyPtr getKey() const;
void destroyCdnKey(uint64 keyId);
bool destroyConfirmedForgottenKey(uint64 keyId);
void releaseKeyCreationOnDone(AuthKeyPtr &&key);
[[nodiscard]] bool connectionInited() const;
void setConnectionInited(bool connectionInited = true);
signals:
void authKeyCreated();
void connectionWasInited();
[[nodiscard]] bool acquireKeyCreation();
void releaseKeyCreationOnFail();
private slots:
void authKeyWrite();
signals:
void authKeyChanged();
private:
mutable QReadWriteLock keyLock;
mutable QMutex _initLock;
not_null<Instance*> _instance;
DcId _id = 0;
bool destroyKey(uint64 keyId);
const DcId _id = 0;
mutable QReadWriteLock _mutex;
AuthKeyPtr _key;
bool _connectionInited = false;
std::atomic<bool> _creatingKey = false;
};

View File

@ -172,6 +172,9 @@ DcKeyCreator::DcKeyCreator(
}
DcKeyCreator::~DcKeyCreator() {
if (_delegate.done) {
stopReceiving();
}
const auto clearBytes = [](bytes::span bytes) {
OPENSSL_cleanse(bytes.data(), bytes.size());
};
@ -191,11 +194,7 @@ void DcKeyCreator::pqSend() {
}
void DcKeyCreator::pqAnswered() {
QObject::disconnect(
_connection,
&AbstractConnection::receivedData,
nullptr,
nullptr);
stopReceiving();
DEBUG_LOG(("AuthKey Info: receiving Req_pq answer..."));
MTPReq_pq::ResponseType res_pq;
@ -272,11 +271,7 @@ void DcKeyCreator::pqAnswered() {
}
void DcKeyCreator::dhParamsAnswered() {
QObject::disconnect(
_connection,
&AbstractConnection::receivedData,
nullptr,
nullptr);
stopReceiving();
DEBUG_LOG(("AuthKey Info: receiving Req_DH_params answer..."));
MTPReq_DH_params::ResponseType res_DH_params;
@ -450,11 +445,7 @@ void DcKeyCreator::dhClientParamsSend() {
}
void DcKeyCreator::dhClientParamsAnswered() {
QObject::disconnect(
_connection,
&AbstractConnection::receivedData,
nullptr,
nullptr);
stopReceiving();
DEBUG_LOG(("AuthKey Info: receiving Req_client_DH_params answer..."));
MTPSet_client_DH_params::ResponseType res_client_DH_params;
@ -578,7 +569,8 @@ bool DcKeyCreator::readNotSecureResponse(Response &response) {
}
void DcKeyCreator::failed(Error error) {
auto onstack = std::move(_delegate.done);
stopReceiving();
auto onstack = base::take(_delegate.done);
onstack(tl::unexpected(error));
}
@ -589,8 +581,18 @@ void DcKeyCreator::done(uint64 serverSalt) {
_dcId,
_authKey);
result.serverSalt = serverSalt;
auto onstack = std::move(_delegate.done);
stopReceiving();
auto onstack = base::take(_delegate.done);
onstack(std::move(result));
}
void DcKeyCreator::stopReceiving() {
QObject::disconnect(
_connection,
&AbstractConnection::receivedData,
nullptr,
nullptr);
}
} // namespace MTP::details

View File

@ -83,6 +83,7 @@ private:
void dhClientParamsSend();
void dhClientParamsAnswered();
void stopReceiving();
void failed(Error error = Error::Other);
void done(uint64 serverSalt);

View File

@ -645,7 +645,7 @@ not_null<Dcenter*> Instance::Private::addDc(
const auto dcId = BareDcId(shiftedDcId);
return _dcenters.emplace(
shiftedDcId,
std::make_unique<Dcenter>(_instance, dcId, std::move(key))
std::make_unique<Dcenter>(dcId, std::move(key))
).first->second.get();
}
@ -690,6 +690,10 @@ void Instance::Private::setKeyForWrite(DcId dcId, const AuthKeyPtr &key) {
} else {
_keysForWrite.erase(dcId);
}
crl::on_main(_instance, [=] {
DEBUG_LOG(("AuthKey Info: writing auth keys, called by dc %1").arg(dcId));
Local::writeMtpData();
});
}
AuthKeysList Instance::Private::getKeysForWrite() const {
@ -1578,17 +1582,16 @@ void Instance::Private::checkMainDcKey() {
}
void Instance::Private::keyDestroyedOnServer(DcId dcId, uint64 keyId) {
if (dcId == _mainDcId) {
for (const auto &[id, dc] : _dcenters) {
dc->destroyKey();
LOG(("Destroying key for dc: %1").arg(dcId));
if (const auto dc = findDc(dcId)) {
if (dc->destroyConfirmedForgottenKey(keyId)) {
LOG(("Key destroyed!"));
setKeyForWrite(dcId, nullptr);
} else {
LOG(("Key already is different."));
}
restart();
} else {
if (const auto dc = findDc(dcId)) {
return dc->destroyKey();
}
restart(dcId);
}
restart(dcId);
}
void Instance::Private::setUpdatesHandler(RPCDoneHandlerPtr onDone) {
@ -1737,7 +1740,9 @@ void Instance::logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) {
}
void Instance::setKeyForWrite(DcId dcId, const AuthKeyPtr &key) {
_private->setKeyForWrite(dcId, key);
InvokeQueued(this, [=] {
_private->setKeyForWrite(dcId, key);
});
}
AuthKeysList Instance::getKeysForWrite() const {

View File

@ -38,14 +38,16 @@ public:
QString deviceModel;
QString systemVersion;
};
enum class Mode {
Normal,
KeysDestroyer,
};
Instance(not_null<DcOptions*> options, Mode mode, Config &&config);
Instance(not_null<DcOptions*> options, Mode mode, Config &&config);
Instance(const Instance &other) = delete;
Instance &operator=(const Instance &other) = delete;
~Instance();
void resolveProxyDomain(const QString &host);
void setGoodProxyDomain(const QString &host, const QString &ip);
@ -56,16 +58,71 @@ public:
[[nodiscard]] QString cloudLangCode() const;
[[nodiscard]] QString langPackName() const;
// Thread safe.
// Thread-safe.
[[nodiscard]] QString deviceModel() const;
[[nodiscard]] QString systemVersion() const;
void setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
// Main thread.
[[nodiscard]] AuthKeysList getKeysForWrite() const;
void addKeysForDestroy(AuthKeysList &&keys);
[[nodiscard]] not_null<DcOptions*> dcOptions();
void restart();
void restart(ShiftedDcId shiftedDcId);
int32 dcstate(ShiftedDcId shiftedDcId = 0);
QString dctransport(ShiftedDcId shiftedDcId = 0);
void ping();
void cancel(mtpRequestId requestId);
int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
// Main thread.
void killSession(ShiftedDcId shiftedDcId);
void stopSession(ShiftedDcId shiftedDcId);
void reInitConnection(DcId dcId);
void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
void unpaused();
void queueQuittingConnection(std::unique_ptr<internal::Connection> &&connection);
void setUpdatesHandler(RPCDoneHandlerPtr onDone);
void setGlobalFailHandler(RPCFailHandlerPtr onFail);
void setStateChangedHandler(Fn<void(ShiftedDcId shiftedDcId, int32 state)> handler);
void setSessionResetHandler(Fn<void(ShiftedDcId shiftedDcId)> handler);
void clearGlobalHandlers();
void onStateChange(ShiftedDcId shiftedDcId, int32 state);
void onSessionReset(ShiftedDcId shiftedDcId);
void clearCallbacksDelayed(std::vector<RPCCallbackClear> &&ids);
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
bool hasCallbacks(mtpRequestId requestId);
void globalCallback(const mtpPrime *from, const mtpPrime *end);
// return true if need to clean request data
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
bool isKeysDestroyer() const;
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
void checkIfKeyWasDestroyed(ShiftedDcId shiftedDcId);
void keyDestroyedOnServer(DcId dcId, uint64 keyId);
void requestConfig();
void requestConfigIfOld();
void requestCDNConfig();
void setUserPhone(const QString &phone);
void badConfigurationError();
void syncHttpUnixtime();
void connectionFinished(not_null<internal::Connection*> connection);
void sendAnything(ShiftedDcId shiftedDcId = 0, crl::time msCanWait = 0);
void sendDcKeyCheck(ShiftedDcId shiftedDcId, const AuthKeyPtr &key);
template <typename Request>
mtpRequestId send(
const Request &request,
@ -134,60 +191,6 @@ public:
afterRequestId);
}
void sendAnything(ShiftedDcId shiftedDcId = 0, crl::time msCanWait = 0);
void sendDcKeyCheck(ShiftedDcId shiftedDcId, const AuthKeyPtr &key);
void restart();
void restart(ShiftedDcId shiftedDcId);
int32 dcstate(ShiftedDcId shiftedDcId = 0);
QString dctransport(ShiftedDcId shiftedDcId = 0);
void ping();
void cancel(mtpRequestId requestId);
int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
void killSession(ShiftedDcId shiftedDcId);
void stopSession(ShiftedDcId shiftedDcId);
void reInitConnection(DcId dcId);
void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
void unpaused();
void queueQuittingConnection(std::unique_ptr<internal::Connection> &&connection);
void setUpdatesHandler(RPCDoneHandlerPtr onDone);
void setGlobalFailHandler(RPCFailHandlerPtr onFail);
void setStateChangedHandler(Fn<void(ShiftedDcId shiftedDcId, int32 state)> handler);
void setSessionResetHandler(Fn<void(ShiftedDcId shiftedDcId)> handler);
void clearGlobalHandlers();
void onStateChange(ShiftedDcId shiftedDcId, int32 state);
void onSessionReset(ShiftedDcId shiftedDcId);
void clearCallbacksDelayed(std::vector<RPCCallbackClear> &&ids);
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
bool hasCallbacks(mtpRequestId requestId);
void globalCallback(const mtpPrime *from, const mtpPrime *end);
// return true if need to clean request data
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
bool isKeysDestroyer() const;
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
void checkIfKeyWasDestroyed(ShiftedDcId shiftedDcId);
void keyDestroyedOnServer(DcId dcId, uint64 keyId);
void requestConfig();
void requestConfigIfOld();
void requestCDNConfig();
void setUserPhone(const QString &phone);
void badConfigurationError();
void syncHttpUnixtime();
void connectionFinished(not_null<internal::Connection*> connection);
~Instance();
signals:
void configLoaded();
void cdnConfigLoaded();

View File

@ -261,13 +261,13 @@ private:
};
struct RPCCallbackClear {
RPCCallbackClear(mtpRequestId id , int32 code = RPCError::NoError)
RPCCallbackClear(mtpRequestId id, int32 code = RPCError::NoError)
: requestId(id)
, errorCode(code) {
}
mtpRequestId requestId;
int32 errorCode;
mtpRequestId requestId = 0;
int32 errorCode = 0;
};

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/dcenter.h"
#include "mtproto/auth_key.h"
#include "base/unixtime.h"
#include "base/openssl_help.h"
#include "core/crash_reports.h"
#include "facades.h"
@ -63,19 +64,15 @@ ConnectionOptions::ConnectionOptions(
, useTcp(useTcp) {
}
void SessionData::setKey(const AuthKeyPtr &key) {
if (_authKey != key) {
const auto sessionId = rand_value<uint64>();
_authKey = key;
DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(key ? key->keyId() : 0).arg(sessionId));
QWriteLocker locker(&_lock);
if (_sessionId != sessionId) {
_sessionId = sessionId;
_messagesSent = 0;
}
_layerInited = false;
void SessionData::setCurrentKeyId(uint64 keyId) {
QWriteLocker locker(&_lock);
if (_keyId == keyId) {
return;
}
_keyId = keyId;
_sessionId = openssl::RandomValue<uint64>();
_messagesSent = 0;
DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(_keyId).arg(_sessionId));
}
void SessionData::setKeyForCheck(const AuthKeyPtr &key) {
@ -83,25 +80,24 @@ void SessionData::setKeyForCheck(const AuthKeyPtr &key) {
}
void SessionData::notifyConnectionInited(const ConnectionOptions &options) {
QWriteLocker locker(&_lock);
if (options.cloudLangCode == _options.cloudLangCode
&& options.systemLangCode == _options.systemLangCode
&& options.langPackName == _options.langPackName
&& options.proxy == _options.proxy
&& !_options.inited) {
_options.inited = true;
locker.unlock();
// #TODO race
const auto current = connectionOptions();
if (current.cloudLangCode == _options.cloudLangCode
&& current.systemLangCode == _options.systemLangCode
&& current.langPackName == _options.langPackName
&& current.proxy == _options.proxy) {
owner()->notifyDcConnectionInited();
}
}
void SessionData::clear(Instance *instance) {
void SessionData::clearForNewKey(not_null<Instance*> instance) {
auto clearCallbacks = std::vector<RPCCallbackClear>();
{
QReadLocker locker1(haveSentMutex()), locker2(toResendMutex()), locker3(haveReceivedMutex()), locker4(wereAckedMutex());
auto receivedResponsesEnd = _receivedResponses.cend();
clearCallbacks.reserve(_haveSent.size() + _wereAcked.size());
QReadLocker locker1(haveSentMutex());
QReadLocker locker2(toResendMutex());
QReadLocker locker3(haveReceivedMutex());
QReadLocker locker4(wereAckedMutex());
clearCallbacks.reserve(_haveSent.size() + _toResend.size() + _wereAcked.size());
for (auto i = _haveSent.cbegin(), e = _haveSent.cend(); i != e; ++i) {
auto requestId = i.value()->requestId;
if (!_receivedResponses.contains(requestId)) {
@ -147,21 +143,15 @@ Session::Session(
: QObject()
, _instance(instance)
, _shiftedDcId(shiftedDcId)
, _dc(dc)
, _ownedDc(dc ? nullptr : std::make_unique<Dcenter>(shiftedDcId, nullptr))
, _dc(dc ? dc : _ownedDc.get())
, _data(this)
, _timeouter([=] { checkRequestsByTimer(); })
, _sender([=] { needToResumeAndSend(); }) {
_timeouter.callEach(1000);
refreshOptions();
if (_dc) {
if (const auto lock = ReadLockerAttempt(keyMutex())) {
_data.setKey(_dc->getKey());
if (_dc->connectionInited()) {
_data.setConnectionInited();
}
}
connect(_dc, SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()), Qt::QueuedConnection);
connect(_dc, SIGNAL(connectionWasInited()), this, SLOT(connectionWasInitedForDC()), Qt::QueuedConnection);
if (sharedDc()) {
connect(_dc, SIGNAL(authKeyChanged()), this, SLOT(authKeyChangedForDC()), Qt::QueuedConnection);
}
}
@ -199,7 +189,7 @@ void Session::refreshOptions() {
const auto useHttp = (proxyType != ProxyData::Type::Mtproto);
const auto useIPv4 = true;
const auto useIPv6 = Global::TryIPv6();
_data.applyConnectionOptions(ConnectionOptions(
_data.setConnectionOptions(ConnectionOptions(
_instance->systemLangCode(),
_instance->cloudLangCode(),
_instance->langPackName(),
@ -213,10 +203,7 @@ void Session::refreshOptions() {
}
void Session::reInitConnection() {
if (_dc) {
_dc->setConnectionInited(false);
}
_data.setConnectionInited(false);
_dc->setConnectionInited(false);
restart();
}
@ -315,6 +302,10 @@ void Session::sendMsgsStateInfo(quint64 msgId, QByteArray data) {
MTP_msgs_state_info(MTP_long(msgId), MTP_bytes(data))));
}
bool Session::sharedDc() const {
return (_ownedDc == nullptr);
}
void Session::checkRequestsByTimer() {
QVector<mtpMsgId> resendingIds;
QVector<mtpMsgId> removingIds; // remove very old (10 minutes) containers and resend requests
@ -555,51 +546,44 @@ void Session::sendPrepared(
sendAnything(msCanWait);
}
QReadWriteLock *Session::keyMutex() const {
return _dc ? _dc->keyMutex() : nullptr;
void Session::authKeyChangedForDC() {
DEBUG_LOG(("AuthKey Info: Session::authKeyCreatedForDC slot, emitting authKeyChanged(), dcWithShift %1").arg(_shiftedDcId));
emit authKeyChanged();
}
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();
bool Session::acquireKeyCreation() {
return _dc->acquireKeyCreation();
}
void Session::notifyKeyCreated(AuthKeyPtr &&key) {
DEBUG_LOG(("AuthKey Info: Session::keyCreated(), setting, dcWithShift %1").arg(_shiftedDcId));
if (_dc) {
_dc->setKey(std::move(key));
} else {
_data.setKey(std::move(key));
emit authKeyCreated();
void Session::releaseKeyCreationOnFail() {
_dc->releaseKeyCreationOnFail();
}
void Session::releaseKeyCreationOnDone(AuthKeyPtr &&key) {
DEBUG_LOG(("AuthKey Info: Session key created, setting, dcWithShift %1").arg(_shiftedDcId));
if (sharedDc()) {
const auto dcId = _dc->id();
const auto instance = _instance;
InvokeQueued(instance, [=] {
instance->setKeyForWrite(dcId, key);
});
}
}
void Session::connectionWasInitedForDC() {
Expects(_dc != nullptr);
DEBUG_LOG(("MTP Info: Session::connectionWasInitedForDC slot, dcWithShift %1").arg(_shiftedDcId));
_data.setConnectionInited();
_dc->releaseKeyCreationOnDone(std::move(key));
}
void Session::notifyDcConnectionInited() {
DEBUG_LOG(("MTP Info: emitting MTProtoDC::connectionWasInited(), dcWithShift %1").arg(_shiftedDcId));
if (_dc) {
_dc->setConnectionInited();
} else {
_data.setConnectionInited();
}
_dc->setConnectionInited();
}
void Session::destroyKey() {
if (const auto key = _data.getKey()) {
DEBUG_LOG(("MTP Info: destroying auth_key for dcWithShift %1").arg(_shiftedDcId));
if (_dc && _dc->getKey() == key) {
_dc->destroyKey();
}
_data.setKey(nullptr);
void Session::destroyCdnKey(uint64 keyId) {
_dc->destroyCdnKey(keyId);
if (sharedDc()) {
const auto dcId = _dc->id();
const auto instance = _instance;
InvokeQueued(instance, [=] {
instance->setKeyForWrite(dcId, nullptr);
});
}
}
@ -607,6 +591,14 @@ int32 Session::getDcWithShift() const {
return _shiftedDcId;
}
AuthKeyPtr Session::getKey() const {
return _dc->getKey();
}
bool Session::connectionInited() const {
return _dc->connectionInited();
}
void Session::tryToReceive() {
if (_killed) {
DEBUG_LOG(("Session Error: can't receive in a killed session"));

View File

@ -131,7 +131,6 @@ struct ConnectionOptions {
bool useIPv6 = true;
bool useHttp = true;
bool useTcp = true;
bool inited = false;
};
@ -141,6 +140,7 @@ public:
SessionData(not_null<Session*> creator) : _owner(creator) {
}
void setCurrentKeyId(uint64 keyId);
void setSessionId(uint64 sessionId) {
DEBUG_LOG(("MTP Info: setting server_session: %1").arg(sessionId));
@ -150,22 +150,16 @@ public:
_messagesSent = 0;
}
}
uint64 getSessionId() const {
[[nodiscard]] uint64 getSessionId() const {
QReadLocker locker(&_lock);
return _sessionId;
}
void setConnectionInited(bool inited = true) {
QWriteLocker locker(&_lock);
_options.inited = inited;
}
void notifyConnectionInited(const ConnectionOptions &options);
void applyConnectionOptions(ConnectionOptions options) {
void setConnectionOptions(ConnectionOptions options) {
QWriteLocker locker(&_lock);
const auto inited = _options.inited;
_options = options;
_options.inited = inited;
}
ConnectionOptions connectionOptions() const {
[[nodiscard]] ConnectionOptions connectionOptions() const {
QReadLocker locker(&_lock);
return _options;
}
@ -174,23 +168,16 @@ public:
QWriteLocker locker(&_lock);
_salt = salt;
}
uint64 getSalt() const {
[[nodiscard]] uint64 getSalt() const {
QReadLocker locker(&_lock);
return _salt;
}
const AuthKeyPtr &getKey() const {
return _authKey;
}
void setKey(const AuthKeyPtr &key);
const AuthKeyPtr &getKeyForCheck() const {
[[nodiscard]] const AuthKeyPtr &getKeyForCheck() const {
return _dcKeyForCheck;
}
void setKeyForCheck(const AuthKeyPtr &key);
QReadWriteLock *keyMutex() const;
not_null<QReadWriteLock*> toSendMutex() const {
return &_toSendLock;
}
@ -276,19 +263,17 @@ public:
return result * 2 + (needAck ? 1 : 0);
}
void clear(Instance *instance);
void clearForNewKey(not_null<Instance*> instance);
private:
uint64 _keyId = 0;
uint64 _sessionId = 0;
uint64 _salt = 0;
uint32 _messagesSent = 0;
not_null<Session*> _owner;
AuthKeyPtr _authKey;
AuthKeyPtr _dcKeyForCheck;
bool _layerInited = false;
ConnectionOptions _options;
PreRequestMap _toSend; // map of request_id -> request, that is waiting to be sent
@ -317,25 +302,34 @@ class Session : public QObject {
Q_OBJECT
public:
// Main thread.
Session(
not_null<Instance*> instance,
ShiftedDcId shiftedDcId,
Dcenter *dc);
~Session();
void start();
void reInitConnection();
void restart();
void refreshOptions();
void reInitConnection();
void stop();
void kill();
void unpaused();
ShiftedDcId getDcWithShift() const;
// Thread-safe.
[[nodiscard]] ShiftedDcId getDcWithShift() const;
[[nodiscard]] AuthKeyPtr getKey() const;
[[nodiscard]] bool connectionInited() const;
// Connection thread.
[[nodiscard]] bool acquireKeyCreation();
void releaseKeyCreationOnFail();
void releaseKeyCreationOnDone(AuthKeyPtr &&key);
void destroyCdnKey(uint64 keyId);
QReadWriteLock *keyMutex() const;
void notifyKeyCreated(AuthKeyPtr &&key);
void destroyKey();
void notifyDcConnectionInited();
void ping();
@ -352,10 +346,8 @@ public:
crl::time msCanWait = 0,
bool newRequest = true);
~Session();
signals:
void authKeyCreated();
void authKeyChanged();
void needToSend();
void needToPing();
void needToRestart();
@ -367,8 +359,7 @@ public slots:
void resendMany(QVector<quint64> msgIds, qint64 msCanWait, bool forceContainer, bool sendMsgStateInfo);
void resendAll(); // after connection restart
void authKeyCreatedForDC();
void connectionWasInitedForDC();
void authKeyChangedForDC();
void tryToReceive();
void onConnectionStateChange(qint32 newState);
@ -379,13 +370,15 @@ public slots:
void sendMsgsStateInfo(quint64 msgId, QByteArray data);
private:
[[nodiscard]] bool sharedDc() const;
void checkRequestsByTimer();
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
const not_null<Instance*> _instance;
const ShiftedDcId _shiftedDcId = 0;
Dcenter *_dc = nullptr;
const std::unique_ptr<Dcenter> _ownedDc;
const not_null<Dcenter*> _dc;
std::unique_ptr<Connection> _connection;
@ -406,38 +399,5 @@ private:
};
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