diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 8c456aa931..e4c639bcad 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -95,7 +95,7 @@ namespace App { return w ? w->mainWidget() : 0; } - Settings *settings() { + SettingsWidget *settings() { Window *w(wnd()); return w ? w->settingsWidget() : 0; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index be6c374c31..fcccf20b31 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -22,7 +22,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com class Application; class Window; class MainWidget; -class Settings; +class SettingsWidget; class Font; class Color; class FileUploader; @@ -38,7 +38,7 @@ namespace App { Application *app(); Window *wnd(); MainWidget *main(); - Settings *settings(); + SettingsWidget *settings(); FileUploader *uploader(); void showSettings(); diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp index c73f8d3af8..b05198e4b1 100644 --- a/Telegram/SourceFiles/gui/images.cpp +++ b/Telegram/SourceFiles/gui/images.cpp @@ -230,6 +230,7 @@ bool StorageImage::check() const { h = data.height(); invalidateSizeCache(); loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; saved = bytes; @@ -256,6 +257,7 @@ void StorageImage::setData(QByteArray &bytes, const QByteArray &format) { invalidateSizeCache(); if (loader) { loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; } this->saved = bytes; @@ -269,6 +271,7 @@ StorageImage::~StorageImage() { } if (loader) { loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; } } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 152c27706c..a3c3e79fc4 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -227,6 +227,7 @@ struct VideoData { if (l) { l->cancel(); l->deleteLater(); + l->rpcInvalidate(); } fileName = QString(); modDate = QDateTime(); @@ -241,6 +242,7 @@ struct VideoData { modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); } loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; } @@ -328,6 +330,7 @@ struct AudioData { if (l) { l->cancel(); l->deleteLater(); + l->rpcInvalidate(); } fileName = QString(); modDate = QDateTime(); @@ -342,6 +345,7 @@ struct AudioData { modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); } loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; } @@ -427,6 +431,7 @@ struct DocumentData { if (l) { l->cancel(); l->deleteLater(); + l->rpcInvalidate(); } fileName = QString(); modDate = QDateTime(); @@ -441,6 +446,7 @@ struct DocumentData { modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified(); } loader->deleteLater(); + loader->rpcInvalidate(); loader = 0; } diff --git a/Telegram/SourceFiles/intro/intro.cpp b/Telegram/SourceFiles/intro/intro.cpp index 9e9416a641..7b8f49f0a2 100644 --- a/Telegram/SourceFiles/intro/intro.cpp +++ b/Telegram/SourceFiles/intro/intro.cpp @@ -288,6 +288,12 @@ void IntroWidget::keyPressEvent(QKeyEvent *e) { } } +void IntroWidget::rpcInvalidate() { + if (phone) phone->rpcInvalidate(); + if (code) code->rpcInvalidate(); + if (signup) signup->rpcInvalidate(); +} + IntroWidget::~IntroWidget() { delete steps; delete phone; diff --git a/Telegram/SourceFiles/intro/intro.h b/Telegram/SourceFiles/intro/intro.h index c43b0cbb71..0b496e1760 100644 --- a/Telegram/SourceFiles/intro/intro.h +++ b/Telegram/SourceFiles/intro/intro.h @@ -57,6 +57,8 @@ public: void finish(const MTPUser &user, const QImage &photo = QImage()); + void rpcInvalidate(); + ~IntroWidget(); public slots: diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index dc2204b37d..8fbf9ec778 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -756,7 +756,10 @@ void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool for history.showPeer(peerId, msgId, force); if (force || !selectingPeer()) { if (profile) { - if (profile) profile->deleteLater(); + if (profile) { + profile->deleteLater(); + profile->rpcInvalidate(); + } profile = 0; profileStack.clear(); if (!history.peer() || !history.peer()->id) { @@ -811,7 +814,10 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) { profileStack.push_back(history.peer()); } } - if (profile) profile->deleteLater(); + if (profile) { + profile->deleteLater(); + profile->rpcInvalidate(); + } profile = new ProfileWidget(this, peer); _topBar.show(); resizeEvent(0); diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp index ad786002dd..e685714995 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -1034,7 +1034,8 @@ void MTProtoConnectionPrivate::createConn() { MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc) : QObject(0) , _state(MTProtoConnection::Disconnected) - , dc(_dc) + , _needSessionReset(false) + , dc(_dc) , _owner(owner) , conn(0) , retryTimeout(1) @@ -1137,7 +1138,118 @@ bool MTProtoConnectionPrivate::setState(int32 state, int32 ifState) { return true; } -mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request) { +void MTProtoConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno + _needSessionReset = false; + + QWriteLocker locker1(sessionData->haveSentMutex()); + QWriteLocker locker2(sessionData->toResendMutex()); + QWriteLocker locker3(sessionData->toSendMutex()); + QWriteLocker locker4(sessionData->wereAckedMutex()); + mtpRequestMap &haveSent(sessionData->haveSentMap()); + mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpPreRequestMap &toSend(sessionData->toSendMap()); + mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + + mtpMsgId newId = msgid(); + mtpRequestMap setSeqNumbers; + typedef QMap Replaces; + Replaces replaces; + for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + if (!mtpRequestData::isSentContainer(i.value())) { + if (!*(mtpMsgId*)(i.value()->constData() + 4)) continue; + + mtpMsgId id = i.key(); + if (id > newId) { + while (true) { + if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) { + break; + } + mtpMsgId m = msgid(); + if (m <= newId) break; // wtf + + newId = m; + } + + MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId)); + replaces.insert(id, newId); + id = newId; + *(mtpMsgId*)(i.value()->data() + 4) = id; + } + setSeqNumbers.insert(id, i.value()); + } + } + for (mtpRequestIdsMap::const_iterator i = toResend.cbegin(), e = toResend.cend(); i != e; ++i) { // collect all non-container requests + mtpPreRequestMap::const_iterator j = toSend.constFind(i.value()); + if (j == toSend.cend()) continue; + + if (!mtpRequestData::isSentContainer(j.value())) { + if (!*(mtpMsgId*)(j.value()->constData() + 4)) continue; + + mtpMsgId id = i.key(); + if (id > newId) { + while (true) { + if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) { + break; + } + mtpMsgId m = msgid(); + if (m <= newId) break; // wtf + + newId = m; + } + + MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId)); + replaces.insert(id, newId); + id = newId; + *(mtpMsgId*)(j.value()->data() + 4) = id; + } + setSeqNumbers.insert(id, j.value()); + } + } + + uint64 session = MTP::nonce(); + DEBUG_LOG(("MTP Info: creating new session after bad_msg_notification, setting random server_session %1").arg(session)); + sessionData->setSession(session); + + for (mtpRequestMap::const_iterator i = setSeqNumbers.cbegin(), e = setSeqNumbers.cend(); i != e; ++i) { // generate new seq_numbers + bool wasNeedAck = (*(i.value()->data() + 6) & 1); + *(i.value()->data() + 6) = sessionData->nextRequestSeqNumber(wasNeedAck); + } + if (!replaces.isEmpty()) { + for (Replaces::const_iterator i = replaces.cbegin(), e = replaces.cend(); i != e; ++i) { // replace msgIds keys in all data structs + mtpRequestMap::iterator j = haveSent.find(i.key()); + if (j != haveSent.cend()) { + mtpRequest req = j.value(); + haveSent.erase(j); + haveSent.insert(i.value(), req); + } + mtpRequestIdsMap::iterator k = toResend.find(i.key()); + if (k != toResend.cend()) { + mtpRequestId req = k.value(); + toResend.erase(k); + toResend.insert(i.value(), req); + } + k = wereAcked.find(i.key()); + if (k != wereAcked.cend()) { + mtpRequestId req = k.value(); + wereAcked.erase(k); + wereAcked.insert(i.value(), req); + } + } + for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { // replace msgIds in saved containers + if (mtpRequestData::isSentContainer(i.value())) { + mtpMsgId *ids = (mtpMsgId *)(i.value()->data() + 8); + for (uint32 j = 0, l = (i.value()->size() - 8) >> 1; j < l; ++j) { + Replaces::const_iterator k = replaces.constFind(ids[j]); + if (k != replaces.cend()) { + ids[j] = k.value(); + } + } + } + } + } +} + +mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request, mtpMsgId currentLastId) { if (request->size() < 9) return 0; mtpMsgId msgId = *(mtpMsgId*)(request->constData() + 4); if (msgId) { // resending this request @@ -1148,12 +1260,75 @@ mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request) { toResend.erase(i); } } else { - msgId = *(mtpMsgId*)(request->data() + 4) = msgid(); + msgId = *(mtpMsgId*)(request->data() + 4) = currentLastId; *(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request)); } return msgId; } +mtpMsgId MTProtoConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId newId) { + if (request->size() < 9) return 0; + + mtpMsgId oldMsgId = *(mtpMsgId*)(request->constData() + 4); + if (oldMsgId != newId) { + if (oldMsgId) { + QWriteLocker locker(sessionData->toResendMutex()); + // haveSentMutex() and wereAckedMutex() were locked in tryToSend() + + mtpRequestIdsMap &toResend(sessionData->toResendMap()); + mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + mtpRequestMap &haveSent(sessionData->haveSentMap()); + + while (true) { + if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) { + break; + } + mtpMsgId m = msgid(); + if (m <= newId) break; // wtf + + newId = m; + } + + mtpRequestIdsMap::iterator i = toResend.find(oldMsgId); + if (i != toResend.cend()) { + mtpRequestId req = i.value(); + toResend.erase(i); + toResend.insert(newId, req); + } + + mtpRequestIdsMap::iterator j = wereAcked.find(oldMsgId); + if (j != wereAcked.cend()) { + mtpRequestId req = j.value(); + wereAcked.erase(j); + wereAcked.insert(newId, req); + } + + mtpRequestMap::iterator k = haveSent.find(oldMsgId); + if (k != haveSent.cend()) { + mtpRequest req = k.value(); + haveSent.erase(k); + haveSent.insert(newId, req); + } + + for (k = haveSent.begin(); k != haveSent.cend(); ++k) { + mtpRequest req(k.value()); + if (mtpRequestData::isSentContainer(req)) { + mtpMsgId *ids = (mtpMsgId *)(req->data() + 8); + for (uint32 i = 0, l = (req->size() - 8) >> 1; i < l; ++i) { + if (ids[i] == oldMsgId) { + ids[i] = newId; + } + } + } + } + } else { + *(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request)); + } + *(mtpMsgId*)(request->data() + 4) = newId; + } + return newId; +} + void MTProtoConnectionPrivate::tryToSend() { if (!conn) return; @@ -1211,7 +1386,7 @@ void MTProtoConnectionPrivate::tryToSend() { locker1.unlock(); } - mtpMsgId msgId = prepareToSend(toSendRequest); + mtpMsgId msgId = prepareToSend(toSendRequest, msgid()); if (havePrepend) pingMsgId = msgId; if (toSendRequest->requestId) { @@ -1237,10 +1412,12 @@ void MTProtoConnectionPrivate::tryToSend() { toSendRequest->push_back(mtpc_msg_container); toSendRequest->push_back(toSendCount); - QWriteLocker locker2(sessionData->haveSentMutex()); + mtpMsgId bigMsgId = msgid(); // check for a valid container + + QWriteLocker locker2(sessionData->haveSentMutex()); // the fact of this lock is used in replaceMsgId() mtpRequestMap &haveSent(sessionData->haveSentMap()); - QWriteLocker locker3(sessionData->wereAckedMutex()); + QWriteLocker locker3(sessionData->wereAckedMutex()); // the fact of this lock is used in replaceMsgId() mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); mtpRequest haveSentIdsWrap(mtpRequestData::prepare(idsWrapSize)); // prepare "request-like" wrap for msgId vector @@ -1249,7 +1426,9 @@ void MTProtoConnectionPrivate::tryToSend() { mtpMsgId *haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8); if (havePrepend) { - mtpMsgId msgId = prepareToSend(prepend); + mtpMsgId msgId = prepareToSend(prepend, bigMsgId); + if (msgId > bigMsgId) msgId = replaceMsgId(prepend, bigMsgId); + if (msgId >= bigMsgId) bigMsgId = msgid(); *(haveSentArr++) = msgId; if (havePrepend) pingMsgId = msgId; @@ -1261,8 +1440,10 @@ void MTProtoConnectionPrivate::tryToSend() { } for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) { mtpRequest &req(i.value()); - mtpMsgId msgId = prepareToSend(req); - *(haveSentArr++) = msgId; + mtpMsgId msgId = prepareToSend(req, bigMsgId); + if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId); + if (msgId >= bigMsgId) bigMsgId = msgid(); + *(haveSentArr++) = msgId; if (req->requestId) { if (mtpRequestData::needAck(req)) { @@ -1279,7 +1460,7 @@ void MTProtoConnectionPrivate::tryToSend() { memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime)); } - mtpMsgId contMsgId = prepareToSend(toSendRequest); + mtpMsgId contMsgId = prepareToSend(toSendRequest, bigMsgId); *(mtpMsgId*)(haveSentIdsWrap->data() + 4) = contMsgId; (*haveSentIdsWrap)[6] = 0; // for container, msDate = 0, seqNo = 0 haveSent.insert(contMsgId, haveSentIdsWrap); @@ -1372,6 +1553,9 @@ void MTProtoConnectionPrivate::restart(bool maybeBadKey) { } doDisconnect(); + if (_needSessionReset) { + resetSession(); + } restarted = true; if (retryTimer.isActive()) return; @@ -1564,7 +1748,9 @@ void MTProtoConnectionPrivate::handleReceived() { int32 res = 1; // if no need to handle, then succeed end = data + 8 + (msgLen >> 2); const mtpPrime *sfrom(data + 4); - MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end, mtpc_core_message)); + if (cDebug()) { + MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end, mtpc_core_message)); + } bool needToHandle = false; { @@ -1606,6 +1792,7 @@ void MTProtoConnectionPrivate::handleReceived() { } if (res < 0) { + _needSessionReset = (res < -1); return restart(); } @@ -1714,29 +1901,71 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt const MTPDbad_msg_notification &data(msg.c_bad_msg_notification()); LOG(("Message Info: bad message notification received (error_code %3) for msg_id = %1, seq_no = %2").arg(data.vbad_msg_id.v).arg(data.vbad_msg_seqno.v).arg(data.verror_code.v)); - bool needResend = (data.verror_code.v == 16 || data.verror_code.v == 17); // bad msg_id - - mtpMsgId resendId = data.vbad_msg_id.v; - if (!wasSent(resendId)) { - DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); - return (badTime ? 0 : 1); - } + int32 errorCode = data.verror_code.v; + if (errorCode == 16 || errorCode == 17 || errorCode == 32 || errorCode == 33 || errorCode == 64) { // can handle + bool needResend = (errorCode == 16 || errorCode == 17); // bad msg_id + if (errorCode == 64) { // bad container! + needResend = true; + if (cDebug()) { + mtpRequest request; + { + QWriteLocker locker(sessionData->haveSentMutex()); + mtpRequestMap &haveSent(sessionData->haveSentMap()); - if (needResend) { // bad msg_id - if (serverSalt) sessionData->setSalt(serverSalt); - unixtimeSet(serverTime, true); + mtpRequestMap::iterator i = haveSent.find(msgId); + if (i == haveSent.end()) { + LOG(("Message Error: Container not found!")); + } - DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container..").arg(serverTime)); - - resend(resendId, 0, true); - } else { - if (badTime) { - if (serverSalt) sessionData->setSalt(serverSalt); - unixtimeSet(serverTime); - badTime = false; + request = i.value(); + } + if (request) { + if (mtpRequestData::isSentContainer(request)) { + QStringList lst; + const mtpMsgId *ids = (const mtpMsgId *)(request->constData() + 8); + for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) { + lst.push_back(QString::number(ids[i])); + } + LOG(("Message Info: bad container received! messages: %1").arg(lst.join(','))); + } else { + LOG(("Message Error: bad container received, but request is not a container!")); + } + } + } } - LOG(("Message Error: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(data.verror_code.v)); - return -1; + + mtpMsgId resendId = data.vbad_msg_id.v; + if (!wasSent(resendId)) { + DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); + return (badTime ? 0 : 1); + } + + if (needResend) { // bad msg_id + if (serverSalt) sessionData->setSalt(serverSalt); + unixtimeSet(serverTime, true); + + DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container..").arg(serverTime)); + + resend(resendId, 0, true); + } else { // must create new session, because msg_id and msg_seqno are inconsistent + if (badTime) { + if (serverSalt) sessionData->setSalt(serverSalt); + unixtimeSet(serverTime); + badTime = false; + } + LOG(("Message Info: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(errorCode)); + return -2; + } + } else { // fatal (except 48, but it must not get here) + mtpMsgId resendId = data.vbad_msg_id.v; + mtpRequestId requestId = wasSent(resendId); + if (requestId) { + LOG(("Message Error: bad message notification received, msgId %1, error_code %2, fatal: clearing callbacks").arg(data.vbad_msg_id.v).arg(errorCode)); + _mtp_internal::clearCallbacksDelayed(RPCCallbackClears(1, RPCCallbackClear(requestId, -errorCode))); + } else { + DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); + } + return (badTime ? 0 : 1); } } return 1; @@ -1855,8 +2084,13 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt } try { const mtpPrime *rFrom = requestBuffer->constData() + 8, *rEnd = requestBuffer->constData() + requestBuffer->size(); - MTPMsgsStateReq request(rFrom, rEnd); - handleMsgsStates(request.c_msgs_state_req().vmsg_ids.c_vector().v, states, toAck); + if (*rFrom == mtpc_msgs_state_req) { + MTPMsgsStateReq request(rFrom, rEnd); + handleMsgsStates(request.c_msgs_state_req().vmsg_ids.c_vector().v, states, toAck); + } else { + MTPMsgResendReq request(rFrom, rEnd); + handleMsgsStates(request.c_msg_resend_req().vmsg_ids.c_vector().v, states, toAck); + } } catch(Exception &e) { LOG(("Message Error: could not parse sent msgs_state_req")); throw; @@ -2280,7 +2514,6 @@ mtpRequestId MTProtoConnectionPrivate::resend(mtpMsgId msgId, uint64 msCanWait, return sessionData->owner()->resend(msgId, msCanWait, forceContainer, sendMsgStateInfo); } - void MTProtoConnectionPrivate::onConnected() { disconnect(conn, SIGNAL(connected()), this, SLOT(onConnected())); if (!conn->isConnected()) { @@ -2874,7 +3107,9 @@ bool MTProtoConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResp memcpy(request->data() + 2, &session, 2 * sizeof(mtpPrime)); const mtpPrime *from = request->constData() + 4; - MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize, mtpc_core_message)); + if (cDebug()) { + MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize, mtpc_core_message)); + } uchar encryptedSHA[20]; MTPint128 &msgKey(*(MTPint128*)(encryptedSHA + 4)); diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.h b/Telegram/SourceFiles/mtproto/mtpConnection.h index 25fafbc7ee..4c243bc5fa 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.h +++ b/Telegram/SourceFiles/mtproto/mtpConnection.h @@ -332,7 +332,8 @@ private: void createConn(); - mtpMsgId prepareToSend(mtpRequest &request); + mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId); + mtpMsgId replaceMsgId(mtpRequest &request, mtpMsgId newId); bool sendRequest(mtpRequest &request, bool needAnyResponse); mtpRequestId wasSent(mtpMsgId msgId) const; @@ -347,6 +348,9 @@ private: mutable QReadWriteLock stateMutex; int32 _state; + bool _needSessionReset; + void resetSession(); + uint32 dc; MTProtoConnection *_owner; MTPabstractConnection *conn; diff --git a/Telegram/SourceFiles/mtproto/mtpRPC.cpp b/Telegram/SourceFiles/mtproto/mtpRPC.cpp index b2d01e005c..abae4c6585 100644 --- a/Telegram/SourceFiles/mtproto/mtpRPC.cpp +++ b/Telegram/SourceFiles/mtproto/mtpRPC.cpp @@ -19,17 +19,17 @@ Copyright (c) 2014 John Preston, https://tdesktop.com #include "mtproto/mtpRPC.h" RPCOwnedDoneHandler::RPCOwnedDoneHandler(RPCSender *owner) : _owner(owner) { - _owner->regHandler(this); + _owner->_rpcRegHandler(this); } RPCOwnedDoneHandler::~RPCOwnedDoneHandler() { - if (_owner) _owner->unregHandler(this); + if (_owner) _owner->_rpcUnregHandler(this); } RPCOwnedFailHandler::RPCOwnedFailHandler(RPCSender *owner) : _owner(owner) { - _owner->regHandler(this); + _owner->_rpcRegHandler(this); } RPCOwnedFailHandler::~RPCOwnedFailHandler() { - if (_owner) _owner->unregHandler(this); + if (_owner) _owner->_rpcUnregHandler(this); } diff --git a/Telegram/SourceFiles/mtproto/mtpRPC.h b/Telegram/SourceFiles/mtproto/mtpRPC.h index f27438b30c..00a4f977d0 100644 --- a/Telegram/SourceFiles/mtproto/mtpRPC.h +++ b/Telegram/SourceFiles/mtproto/mtpRPC.h @@ -654,9 +654,28 @@ private: class RPCSender { typedef QSet DoneHandlers; - DoneHandlers doneHandlers; + DoneHandlers _rpcDoneHandlers; typedef QSet FailHandlers; - FailHandlers failHandlers; + FailHandlers _rpcFailHandlers; + + void _rpcRegHandler(RPCOwnedDoneHandler *handler) { + _rpcDoneHandlers.insert(handler); + } + + void _rpcUnregHandler(RPCOwnedDoneHandler *handler) { + _rpcDoneHandlers.remove(handler); + } + + void _rpcRegHandler(RPCOwnedFailHandler *handler) { + _rpcFailHandlers.insert(handler); + } + + void _rpcUnregHandler(RPCOwnedFailHandler *handler) { + _rpcFailHandlers.remove(handler); + } + + friend class RPCOwnedDoneHandler; + friend class RPCOwnedFailHandler; public: @@ -760,29 +779,19 @@ public: return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo(b, static_cast(this), onFail)); } - void regHandler(RPCOwnedDoneHandler *handler) { - doneHandlers.insert(handler); - } - - void unregHandler(RPCOwnedDoneHandler *handler) { - doneHandlers.remove(handler); - } - - void regHandler(RPCOwnedFailHandler *handler) { - failHandlers.insert(handler); - } - - void unregHandler(RPCOwnedFailHandler *handler) { - failHandlers.remove(handler); + void rpcInvalidate() { + for (DoneHandlers::iterator i = _rpcDoneHandlers.begin(), e = _rpcDoneHandlers.end(); i != e; ++i) { + (*i)->invalidate(); + } + _rpcDoneHandlers.clear(); + for (FailHandlers::iterator i = _rpcFailHandlers.begin(), e = _rpcFailHandlers.end(); i != e; ++i) { + (*i)->invalidate(); + } + _rpcFailHandlers.clear(); } ~RPCSender() { - for (DoneHandlers::iterator i = doneHandlers.begin(), e = doneHandlers.end(); i != e; ++i) { - (*i)->invalidate(); - } - for (FailHandlers::iterator i = failHandlers.begin(), e = failHandlers.end(); i != e; ++i) { - (*i)->invalidate(); - } + rpcInvalidate(); } }; diff --git a/Telegram/SourceFiles/mtproto/mtpSession.h b/Telegram/SourceFiles/mtproto/mtpSession.h index eb2220f432..bc64026c94 100644 --- a/Telegram/SourceFiles/mtproto/mtpSession.h +++ b/Telegram/SourceFiles/mtproto/mtpSession.h @@ -61,8 +61,7 @@ public: void setKey(const mtpAuthKeyPtr &key) { if (authKey != key) { uint64 session; - memset_rand(&session, sizeof(uint64)); - + memsetrnd(session); 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(session)); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index 2fc51d4de0..1b3fe62c2d 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -95,7 +95,7 @@ bool scaleIs(DBIScale scale) { return cRealScale() == scale || (cRealScale() == dbisAuto && cScreenScale() == scale); } -SettingsInner::SettingsInner(Settings *parent) : QWidget(parent), +SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent), _self(App::self()), // profile @@ -1126,7 +1126,7 @@ void SettingsInner::onPhotoUpdateDone(PeerId peer) { update(); } -Settings::Settings(Window *parent) : QWidget(parent), +SettingsWidget::SettingsWidget(Window *parent) : QWidget(parent), _scroll(this, st::setScroll), _inner(this), _close(this, st::setClose) { _scroll.setWidget(&_inner); @@ -1138,11 +1138,11 @@ Settings::Settings(Window *parent) : QWidget(parent), showAll(); } -void Settings::onParentResize(const QSize &newSize) { +void SettingsWidget::onParentResize(const QSize &newSize) { resize(newSize); } -void Settings::animShow(const QPixmap &bgAnimCache, bool back) { +void SettingsWidget::animShow(const QPixmap &bgAnimCache, bool back) { _bgAnimCache = bgAnimCache; anim::stop(this); @@ -1159,7 +1159,7 @@ void Settings::animShow(const QPixmap &bgAnimCache, bool back) { show(); } -bool Settings::animStep(float64 ms) { +bool SettingsWidget::animStep(float64 ms) { float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration; float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0; bool res = true; @@ -1184,7 +1184,7 @@ bool Settings::animStep(float64 ms) { return res; } -void Settings::paintEvent(QPaintEvent *e) { +void SettingsWidget::paintEvent(QPaintEvent *e) { QRect r(e->rect()); bool trivial = (rect() == r); @@ -1202,32 +1202,32 @@ void Settings::paintEvent(QPaintEvent *e) { } } -void Settings::showAll() { +void SettingsWidget::showAll() { _scroll.show(); _inner.show(); _inner.showAll(); _close.show(); } -void Settings::hideAll() { +void SettingsWidget::hideAll() { _scroll.hide(); _close.hide(); } -void Settings::resizeEvent(QResizeEvent *e) { +void SettingsWidget::resizeEvent(QResizeEvent *e) { _scroll.resize(size()); _inner.updateSize(width()); _close.move(st::setClosePos.x(), st::setClosePos.y()); } -void Settings::dragEnterEvent(QDragEnterEvent *e) { +void SettingsWidget::dragEnterEvent(QDragEnterEvent *e) { } -void Settings::dropEvent(QDropEvent *e) { +void SettingsWidget::dropEvent(QDropEvent *e) { } -bool Settings::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { +bool SettingsWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const { if (_inner.getPhotoCoords(photo, x, y, w)) { x += _inner.x(); y += _inner.y(); @@ -1236,14 +1236,18 @@ bool Settings::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) co return false; } -void Settings::updateOnlineDisplay() { +void SettingsWidget::updateOnlineDisplay() { _inner.updateOnlineDisplay(); } -void Settings::updateConnectionType() { +void SettingsWidget::updateConnectionType() { _inner.updateConnectionType(); } -Settings::~Settings() { +void SettingsWidget::rpcInvalidate() { + _inner.rpcInvalidate(); +} + +SettingsWidget::~SettingsWidget() { if (App::wnd()) App::wnd()->noSettings(this); } diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index 64c114910f..fdf57c9578 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -59,7 +59,7 @@ class SettingsInner : public QWidget, public RPCSender, public Animated { public: - SettingsInner(Settings *parent); + SettingsInner(SettingsWidget *parent); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); @@ -218,12 +218,12 @@ private: }; -class Settings : public QWidget, public Animated { +class SettingsWidget : public QWidget, public Animated { Q_OBJECT public: - Settings(Window *parent); + SettingsWidget(Window *parent); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); @@ -238,7 +238,9 @@ public: void updateOnlineDisplay(); void updateConnectionType(); - ~Settings(); + void rpcInvalidate(); + + ~SettingsWidget(); public slots: diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index 71480ed461..c0f7c7a945 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -129,6 +129,11 @@ inline char *hashMd5Hex(const void *data, uint32 len, void *dest) { // dest = pt void memset_rand(void *data, uint32 len); +template +inline void memsetrnd(T &value) { + memset_rand(&value, sizeof(value)); +} + class ReadLockerAttempt { public: diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 44a3be1ae1..8fedbf2575 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -395,18 +395,21 @@ void Window::clearWidgets() { anim::stop(settings); settings->hide(); settings->deleteLater(); + settings->rpcInvalidate(); settings = 0; } if (main) { anim::stop(main); main->hide(); main->deleteLater(); + main->rpcInvalidate(); main = 0; } if (intro) { anim::stop(intro); intro->hide(); intro->deleteLater(); + intro->rpcInvalidate(); intro = 0; } } @@ -463,7 +466,7 @@ void Window::showSettings() { anim::stop(main); main->hide(); } - settings = new Settings(this); + settings = new SettingsWidget(this); settings->animShow(bg); fixOrder(); @@ -476,6 +479,7 @@ void Window::hideSettings(bool fast) { anim::stop(settings); settings->hide(); settings->deleteLater(); + settings->rpcInvalidate(); settings = 0; if (intro) { intro->show(); @@ -488,6 +492,7 @@ void Window::hideSettings(bool fast) { anim::stop(settings); settings->hide(); settings->deleteLater(); + settings->rpcInvalidate(); settings = 0; if (intro) { intro->animShow(bg, true); @@ -533,7 +538,7 @@ MainWidget *Window::mainWidget() { return main; } -Settings *Window::settingsWidget() { +SettingsWidget *Window::settingsWidget() { return settings; } @@ -798,7 +803,7 @@ void Window::noIntro(IntroWidget *was) { } } -void Window::noSettings(Settings *was) { +void Window::noSettings(SettingsWidget *was) { if (was == settings) { settings = 0; } diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index b4989db4aa..838379a43d 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -25,7 +25,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com class TitleWidget; class IntroWidget; class MainWidget; -class Settings; +class SettingsWidget; class LayerWidget; class BackgroundWidget; class LayeredWidget; @@ -165,7 +165,7 @@ public: IntroWidget *introWidget(); MainWidget *mainWidget(); - Settings *settingsWidget(); + SettingsWidget *settingsWidget(); void showConnecting(const QString &text, const QString &reconnect = QString()); void hideConnecting(); @@ -191,7 +191,7 @@ public: void activate(); void noIntro(IntroWidget *was); - void noSettings(Settings *was); + void noSettings(SettingsWidget *was); void noMain(MainWidget *was); void noLayer(LayerWidget *was); void noBox(BackgroundWidget *was); @@ -259,7 +259,7 @@ private: TitleWidget *title; IntroWidget *intro; MainWidget *main; - Settings *settings; + SettingsWidget *settings; LayerWidget *layer; BackgroundWidget *layerBG;