diff --git a/Telegram/Build.bat b/Telegram/Build.bat index 6f83a43f27..788f9c7668 100644 --- a/Telegram/Build.bat +++ b/Telegram/Build.bat @@ -1,4 +1,5 @@ @echo OFF +setlocal FOR /F "tokens=1,2* delims= " %%i in (Version) do set "%%i=%%j" diff --git a/Telegram/SourceFiles/_other/updater.cpp b/Telegram/SourceFiles/_other/updater.cpp index d89efcd950..7050e9bf30 100644 --- a/Telegram/SourceFiles/_other/updater.cpp +++ b/Telegram/SourceFiles/_other/updater.cpp @@ -255,7 +255,7 @@ bool update() { } else { break; } - } while (copyTries < 30); + } while (copyTries < 100); if (!copyResult) { writeLog(L"Error: failed to copy, asking to retry.."); WCHAR errMsg[2048]; diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index e128cb5eb8..fca1d7df40 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -110,6 +110,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) connect(&_localSocket, SIGNAL(readyRead()), this, SLOT(socketReading())); connect(&_localServer, SIGNAL(newConnection()), this, SLOT(newInstanceConnected())); + QTimer::singleShot(0, this, SLOT(startApplication())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication())); #ifndef TDESKTOP_DISABLE_AUTOUPDATE @@ -127,27 +128,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) } } -Application::~Application() { - App::setQuiting(); - - Sandbox::finish(); - - delete AppObject; - - _localSocket.close(); - closeApplication(); - -#ifndef TDESKTOP_DISABLE_AUTOUPDATE - delete _updateReply; - _updateReply = 0; - if (_updateChecker) _updateChecker->deleteLater(); - _updateChecker = 0; - if (_updateThread) _updateThread->quit(); - _updateThread = 0; -#endif -} - - void Application::socketConnected() { LOG(("Socket connected, this is not the first application instance, sending show command..")); _secondInstance = true; @@ -333,13 +313,54 @@ void Application::removeClients() { } } +void Application::startApplication() { + if (App::quiting()) { + quit(); + } +} + void Application::closeApplication() { + App::quit(); + + delete AppObject; + AppObject = 0; + + Sandbox::finish(); + _localServer.close(); for (LocalClients::iterator i = _localClients.begin(), e = _localClients.end(); i != e; ++i) { disconnect(i->first, SIGNAL(disconnected()), this, SLOT(removeClients())); i->first->close(); } _localClients.clear(); + + _localSocket.close(); + +#ifndef TDESKTOP_DISABLE_AUTOUPDATE + delete _updateReply; + _updateReply = 0; + if (_updateChecker) _updateChecker->deleteLater(); + _updateChecker = 0; + if (_updateThread) _updateThread->quit(); + _updateThread = 0; +#endif + + DEBUG_LOG(("Telegram finished, result: %1").arg("unknown")); + +#ifndef TDESKTOP_DISABLE_AUTOUPDATE + if (cRestartingUpdate()) { + DEBUG_LOG(("Application Info: executing updater to install update..")); + psExecUpdater(); + } else +#endif + if (cRestarting()) { + DEBUG_LOG(("Application Info: executing Telegram, because of restart..")); + psExecTelegram(); + } + + SignalHandlers::finish(); + PlatformSpecific::finish(); + Logs::finish(); } #ifndef TDESKTOP_DISABLE_AUTOUPDATE @@ -899,7 +920,7 @@ void AppClass::killDownloadSessions() { for (QMap::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) { if (i.value() <= ms) { for (int j = 0; j < MTPDownloadSessionsCount; ++j) { - MTP::stopSession(MTP::dld[j] + i.key()); + MTP::stopSession(MTP::dld(j) + i.key()); } i = killDownloadSessionTimes.erase(i); } else { diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index acae496077..1f69aaaa43 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -30,7 +30,6 @@ class Application : public QApplication { public: Application(int &argc, char **argv); - ~Application(); // Single instance application public slots: @@ -41,11 +40,13 @@ public slots: void socketWritten(qint64 bytes); void socketReading(); void newInstanceConnected(); - void closeApplication(); void readClients(); void removeClients(); + void startApplication(); // will be done in exec() + void closeApplication(); // will be done in aboutToQuit() + private: typedef QPair LocalClient; diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 1bffe5ad4b..5e68c9995f 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org static const int32 AppVersion = 9028; static const wchar_t *AppVersionStr = L"0.9.28"; static const bool DevVersion = false; -#define BETA_VERSION (9028001ULL) // just comment this line to build public version +#define BETA_VERSION (9028002ULL) // just comment this line to build public version static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppName = L"Telegram Desktop"; diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index 4a90c14aa1..67c1e55afe 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -292,7 +292,7 @@ namespace SignalHandlers { namespace Logs { - Initializer::Initializer() { + void start() { t_assert(LogsData == 0); if (!Sandbox::CheckBetaVersionDir()) { @@ -378,7 +378,7 @@ namespace Logs { LOG(("Logs started")); } - Initializer::~Initializer() { + void finish() { delete LogsData; LogsData = 0; diff --git a/Telegram/SourceFiles/logs.h b/Telegram/SourceFiles/logs.h index 451fb81795..df23981171 100644 --- a/Telegram/SourceFiles/logs.h +++ b/Telegram/SourceFiles/logs.h @@ -23,11 +23,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org class MTPlong; namespace Logs { - struct Initializer { - Initializer(); - ~Initializer(); - }; + void start(); bool started(); + void finish(); bool instanceChecked(); void multipleInstances(); diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp index 508fb9052e..2cbe3e078d 100644 --- a/Telegram/SourceFiles/main.cpp +++ b/Telegram/SourceFiles/main.cpp @@ -25,8 +25,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" int main(int argc, char *argv[]) { - int result = 0; - settingsParseArgs(argc, argv); if (cLaunchMode() == LaunchModeFixPrevious) { return psFixPrevious(); @@ -36,34 +34,15 @@ int main(int argc, char *argv[]) { return showCrashReportWindow(QFileInfo(cStartUrl()).absoluteFilePath()); } - Logs::Initializer _logs; - { - PlatformSpecific::Initializer _ps; + // both are finished in Application::closeApplication + Logs::start(); // must be started before PlatformSpecific is started + PlatformSpecific::start(); // must be started before QApplication is created - QByteArray args[] = { "-style=0" }; // prepare fake args to disable QT_STYLE_OVERRIDE env variable - static const int a_cnt = sizeof(args) / sizeof(args[0]); - int a_argc = a_cnt + 1; - char *a_argv[a_cnt + 1] = { argv[0], args[0].data() }; + //QByteArray args[] = { "-style=0" }; // prepare fake args to disable QT_STYLE_OVERRIDE env variable + //static const int a_cnt = sizeof(args) / sizeof(args[0]); + //int a_argc = a_cnt + 1; + //char *a_argv[a_cnt + 1] = { argv[0], args[0].data() }; - Application app(a_argc, a_argv); - if (!App::quiting()) { - result = app.exec(); - } - } - - DEBUG_LOG(("Telegram finished, result: %1").arg(result)); - - #ifndef TDESKTOP_DISABLE_AUTOUPDATE - if (cRestartingUpdate()) { - DEBUG_LOG(("Application Info: executing updater to install update..")); - psExecUpdater(); - } else - #endif - if (cRestarting()) { - DEBUG_LOG(("Application Info: executing Telegram, because of restart..")); - psExecTelegram(); - } - - SignalHandlers::finish(); - return result; + Application app(argc, argv); + return app.exec(); } diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp index 1770bcef1e..4c2ce87fb2 100644 --- a/Telegram/SourceFiles/mtproto/mtp.cpp +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -24,10 +24,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" namespace { - typedef QMap Sessions; + typedef QMap Sessions; Sessions sessions; - QVector sessionsToKill; - MTProtoSessionPtr mainSession; + MTProtoSession *mainSession; typedef QMap RequestsByDC; // holds dcWithShift for request to this dc or -dc for request to main dc RequestsByDC requestsByDC; @@ -62,13 +61,16 @@ namespace { typedef QMap AuthWaiters; // holds request ids waiting for auth import to specific dc AuthWaiters authWaiters; + typedef OrderedSet MTPQuittingConnections; + MTPQuittingConnections quittingConnections; + QMutex toClearLock; RPCCallbackClears toClear; RPCResponseHandler globalHandler; MTPStateChangedHandler stateChangedHandler = 0; MTPSessionResetHandler sessionResetHandler = 0; - _mtp_internal::RequestResender *resender = 0; + _mtp_internal::GlobalSlotCarrier *_globalSlotCarrier = 0; void importDone(const MTPauth_Authorization &result, mtpRequestId req) { QMutexLocker locker1(&requestByDCLock); @@ -111,7 +113,7 @@ namespace { } DEBUG_LOG(("MTP Info: resending request %1 to dc %2 after import auth").arg(requestId).arg(k.value())); } - if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift)) { + if (MTProtoSession *session = _mtp_internal::getSession(dcWithShift)) { session->sendPrepared(j.value()); } } @@ -202,7 +204,7 @@ namespace { } req = i.value(); } - if (MTProtoSessionPtr session = _mtp_internal::getSession(newdcWithShift)) { + if (MTProtoSession *session = _mtp_internal::getSession(newdcWithShift)) { _mtp_internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift); session->sendPrepared(req); } @@ -230,7 +232,7 @@ namespace { } delayedRequests.insert(i, DelayedRequest(requestId, sendAt)); - if (resender) resender->checkDelayed(); + if (_globalSlotCarrier) _globalSlotCarrier->checkDelayed(); return true; } else if (code == 401 || (badGuestDC && badGuestDCRequests.constFind(requestId) == badGuestDCRequests.cend())) { @@ -281,7 +283,7 @@ namespace { } if (!dcWithShift) return false; - if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { + if (MTProtoSession *session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { req->needsLayer = true; session->sendPrepared(req); } @@ -319,7 +321,7 @@ namespace { if (!dcWithShift) return false; if (!req->after) { - if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { + if (MTProtoSession *session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { req->needsLayer = true; session->sendPrepared(req); } @@ -346,7 +348,7 @@ namespace { delayedRequests.insert(i, DelayedRequest(requestId, i->second)); } - if (resender) resender->checkDelayed(); + if (_globalSlotCarrier) _globalSlotCarrier->checkDelayed(); } } return true; @@ -360,21 +362,18 @@ namespace { } namespace _mtp_internal { - MTProtoSessionPtr getSession(int32 dcWithShift) { - if (!_started) return MTProtoSessionPtr(); + MTProtoSession *getSession(int32 dcWithShift) { + if (!_started) return 0; if (!dcWithShift) return mainSession; if (!(dcWithShift % _mtp_internal::dcShift)) { dcWithShift += (mainSession->getDcWithShift() % _mtp_internal::dcShift); } Sessions::const_iterator i = sessions.constFind(dcWithShift); - if (i != sessions.cend()) return *i; - - MTProtoSessionPtr result(new MTProtoSession()); - result->start(dcWithShift); - - sessions.insert(dcWithShift, result); - return result; + if (i == sessions.cend()) { + i = sessions.insert(dcWithShift, new MTProtoSession(dcWithShift)); + } + return i.value(); } bool paused() { @@ -580,11 +579,11 @@ namespace _mtp_internal { return true; } - RequestResender::RequestResender() { + GlobalSlotCarrier::GlobalSlotCarrier() { connect(&_timer, SIGNAL(timeout()), this, SLOT(checkDelayed())); } - void RequestResender::checkDelayed() { + void GlobalSlotCarrier::checkDelayed() { uint64 now = getms(true); while (!delayedRequests.isEmpty() && now >= delayedRequests.front().second) { mtpRequestId requestId = delayedRequests.front().first; @@ -612,7 +611,7 @@ namespace _mtp_internal { } req = j.value(); } - if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { + if (MTProtoSession *session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) { session->sendPrepared(req); } } @@ -621,6 +620,25 @@ namespace _mtp_internal { _timer.start(delayedRequests.front().second - now); } } + + void GlobalSlotCarrier::connectionFinished(MTProtoConnection *connection) { + MTPQuittingConnections::iterator i = quittingConnections.find(connection); + if (i != quittingConnections.cend()) { + quittingConnections.erase(i); + } + + connection->waitTillFinish(); + delete connection; + } + + GlobalSlotCarrier *globalSlotCarrier() { + return _globalSlotCarrier; + } + + void queueQuittingConnection(MTProtoConnection *connection) { + quittingConnections.insert(connection); + } + }; namespace MTP { @@ -637,12 +655,12 @@ namespace MTP { MTProtoDCMap &dcs(mtpDCMap()); - mainSession = MTProtoSessionPtr(new MTProtoSession()); - mainSession->start(mtpMainDC()); - sessions[mainSession->getDcWithShift()] = mainSession; + _globalSlotCarrier = new _mtp_internal::GlobalSlotCarrier(); + + mainSession = new MTProtoSession(mtpMainDC()); + sessions.insert(mainSession->getDcWithShift(), mainSession); _started = true; - resender = new _mtp_internal::RequestResender(); if (mtpNeedConfig()) { mtpConfigLoader()->load(); @@ -657,7 +675,7 @@ namespace MTP { if (!_started) return; for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) { - (*i)->restart(); + i.value()->restart(); } } @@ -666,8 +684,8 @@ namespace MTP { dcMask %= _mtp_internal::dcShift; for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) { - if (((*i)->getDcWithShift() % int(_mtp_internal::dcShift)) == dcMask) { - (*i)->restart(); + if ((i.value()->getDcWithShift() % int(_mtp_internal::dcShift)) == dcMask) { + i.value()->restart(); } } } @@ -681,7 +699,7 @@ namespace MTP { if (!_started) return; _paused = false; for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) { - (*i)->unpaused(); + i.value()->unpaused(); } } @@ -714,7 +732,7 @@ namespace MTP { } Sessions::const_iterator i = sessions.constFind(dc); - if (i != sessions.cend()) return (*i)->getState(); + if (i != sessions.cend()) return i.value()->getState(); return MTProtoConnection::Disconnected; } @@ -728,13 +746,13 @@ namespace MTP { } Sessions::const_iterator i = sessions.constFind(dc); - if (i != sessions.cend()) return (*i)->transport(); + if (i != sessions.cend()) return i.value()->transport(); return QString(); } void ping() { - if (MTProtoSessionPtr session = _mtp_internal::getSession(0)) { + if (MTProtoSession *session = _mtp_internal::getSession(0)) { session->ping(); } } @@ -754,7 +772,7 @@ namespace MTP { QMutexLocker locker(&requestByDCLock); RequestsByDC::iterator i = requestsByDC.find(requestId); if (i != requestsByDC.end()) { - if (MTProtoSessionPtr session = _mtp_internal::getSession(abs(i.value()))) { + if (MTProtoSession *session = _mtp_internal::getSession(abs(i.value()))) { session->cancel(requestId, msgId); } requestsByDC.erase(i); @@ -763,26 +781,25 @@ namespace MTP { _mtp_internal::clearCallbacks(requestId); } - void killSessionsDelayed() { - if (!sessionsToKill.isEmpty()) { - sessionsToKill.clear(); - } - } - void killSession(int32 dc) { Sessions::iterator i = sessions.find(dc); - if (i != sessions.end()) { + if (i != sessions.cend()) { bool wasMain = (i.value() == mainSession); i.value()->kill(); - if (sessionsToKill.isEmpty()) QTimer::singleShot(0, killSessionsDelayed); - sessionsToKill.push_back(i.value()); + i.value()->deleteLater(); sessions.erase(i); if (wasMain) { - mainSession = MTProtoSessionPtr(new MTProtoSession()); - mainSession->start(mtpMainDC()); - sessions[mainSession->getDcWithShift()] = mainSession; + mainSession = new MTProtoSession(mtpMainDC()); + int32 newdc = mainSession->getDcWithShift(); + i = sessions.find(newdc); + if (i != sessions.cend()) { + i.value()->kill(); + i.value()->deleteLater(); + sessions.erase(i); + } + sessions.insert(newdc, mainSession); } } } @@ -801,14 +818,14 @@ namespace MTP { QMutexLocker locker(&requestByDCLock); RequestsByDC::iterator i = requestsByDC.find(requestId); if (i != requestsByDC.end()) { - if (MTProtoSessionPtr session = _mtp_internal::getSession(abs(i.value()))) { + if (MTProtoSession *session = _mtp_internal::getSession(abs(i.value()))) { return session->requestState(requestId); } return MTP::RequestConnecting; } return MTP::RequestSent; } - if (MTProtoSessionPtr session = _mtp_internal::getSession(-requestId)) { + if (MTProtoSession *session = _mtp_internal::getSession(-requestId)) { return session->requestState(0); } return MTP::RequestConnecting; @@ -817,11 +834,20 @@ namespace MTP { void stop() { for (Sessions::iterator i = sessions.begin(), e = sessions.end(); i != e; ++i) { i.value()->kill(); + delete i.value(); } sessions.clear(); - mainSession = MTProtoSessionPtr(); - delete resender; - resender = 0; + mainSession = nullptr; + + for (MTPQuittingConnections::const_iterator i = quittingConnections.cbegin(), e = quittingConnections.cend(); i != e; ++i) { + i.key()->waitTillFinish(); + delete i.key(); + } + quittingConnections.clear(); + + delete _globalSlotCarrier; + _globalSlotCarrier = nullptr; + mtpDestroyConfigLoader(); _started = false; diff --git a/Telegram/SourceFiles/mtproto/mtp.h b/Telegram/SourceFiles/mtproto/mtp.h index ac79f5e3c3..a59c092b97 100644 --- a/Telegram/SourceFiles/mtproto/mtp.h +++ b/Telegram/SourceFiles/mtproto/mtp.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/mtpFileLoader.h" namespace _mtp_internal { - MTProtoSessionPtr getSession(int32 dc = 0); // 0 - current set dc + MTProtoSession *getSession(int32 dc); // 0 - current set dc bool paused(); @@ -49,21 +49,28 @@ namespace _mtp_internal { return rpcErrorOccured(requestId, handler.onFail, err); } - class RequestResender : public QObject { + // used for: + // - resending requests by timer which were postponed by flood delay + // - destroying MTProtoConnections whose thread has finished + class GlobalSlotCarrier : public QObject { Q_OBJECT public: - RequestResender(); + GlobalSlotCarrier(); public slots: void checkDelayed(); + void connectionFinished(MTProtoConnection *connection); private: SingleTimer _timer; }; + + GlobalSlotCarrier *globalSlotCarrier(); + void queueQuittingConnection(MTProtoConnection *connection); }; namespace MTP { @@ -99,7 +106,7 @@ namespace MTP { template inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) { - if (MTProtoSessionPtr session = _mtp_internal::getSession(dc)) { + if (MTProtoSession *session = _mtp_internal::getSession(dc)) { return session->send(request, callbacks, msCanWait, true, !dc, after); } return 0; @@ -109,7 +116,7 @@ namespace MTP { return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait, after); } inline void sendAnything(int32 dc = 0, uint64 msCanWait = 0) { - if (MTProtoSessionPtr session = _mtp_internal::getSession(dc)) { + if (MTProtoSession *session = _mtp_internal::getSession(dc)) { return session->sendAnything(msCanWait); } } diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp index e5959811b1..ae2fd23731 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -252,8 +252,6 @@ namespace { typedef QMap PublicRSAKeys; PublicRSAKeys gPublicRSA; - MTProtoConnection gMainConnection; - bool gConfigInited = false; void initRSAConfig() { if (gConfigInited) return; @@ -277,66 +275,75 @@ namespace { } } -MTPThread::MTPThread(QObject *parent) : QThread(parent) { - static uint32 gThreadId = 0; - threadId = ++gThreadId; +uint32 MTPThreadIdIncrement = 0; + +MTPThread::MTPThread() : QThread(0) +, _threadId(++MTPThreadIdIncrement) { } uint32 MTPThread::getThreadId() const { - return threadId; + return _threadId; } -MTProtoConnection::MTProtoConnection() : thread(0), data(0) { +MTPThread::~MTPThread() { +} + +MTProtoConnection::MTProtoConnection() : thread(nullptr), data(nullptr) { } int32 MTProtoConnection::start(MTPSessionData *sessionData, int32 dc) { + t_assert(thread == nullptr && data == nullptr); + initRSAConfig(); - if (thread) { - DEBUG_LOG(("MTP Info: MTP start called for already working connection")); - return dc; - } - - thread = new MTPThread(QApplication::instance()); + thread = new MTPThread(); data = new MTProtoConnectionPrivate(thread, this, sessionData, dc); dc = data->getDC(); if (!dc) { delete data; + data = nullptr; delete thread; - data = 0; - thread = 0; + thread = nullptr; return 0; } + thread->start(); return dc; } -void MTProtoConnection::stop() { - if (data) data->stop(); - if (thread) thread->quit(); +void MTProtoConnection::kill() { + t_assert(data != nullptr && thread != nullptr); + data->stop(); + data = nullptr; // will be deleted in thread::finished signal + thread->quit(); + _mtp_internal::queueQuittingConnection(this); } -void MTProtoConnection::stopped() { - if (thread) thread->deleteLater(); - if (data) data->deleteLater(); - thread = 0; - data = 0; - delete this; +void MTProtoConnection::waitTillFinish() { + t_assert(data == nullptr && thread != nullptr); + + thread->wait(); + delete thread; + thread = nullptr; } int32 MTProtoConnection::state() const { - if (!data) return Disconnected; + t_assert(data != nullptr && thread != nullptr); return data->getState(); } QString MTProtoConnection::transport() const { - if (!data) return QString(); + t_assert(data != nullptr && thread != nullptr); return data->transport(); } +MTProtoConnection::~MTProtoConnection() { + t_assert(data == nullptr && thread == nullptr); +} + namespace { mtpBuffer _handleHttpResponse(QNetworkReply *reply) { QByteArray response = reply->readAll(); @@ -1311,30 +1318,31 @@ void MTProtoConnectionPrivate::destroyConn(MTPabstractConnection **conn) { } } -MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc) - : QObject(0) - , _state(MTProtoConnection::Disconnected) - , _needSessionReset(false) - , dc(_dc) - , _owner(owner) - , _conn(0), _conn4(0), _conn6(0) - , retryTimeout(1) - , oldConnection(true) - , _waitForReceived(MTPMinReceiveDelay) - , _waitForConnected(MTPMinConnectDelay) - , firstSentAt(-1) - , _pingId(0) - , _pingIdToSend(0) - , _pingSendAt(0) - , _pingMsgId(0) - , restarted(false) - , keyId(0) +MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc) : QObject(0) +, _state(MTProtoConnection::Disconnected) +, _needSessionReset(false) +, dc(_dc) +, _owner(owner) +, _conn(0) +, _conn4(0) +, _conn6(0) +, retryTimeout(1) +, oldConnection(true) +, _waitForReceived(MTPMinReceiveDelay) +, _waitForConnected(MTPMinConnectDelay) +, firstSentAt(-1) +, _pingId(0) +, _pingIdToSend(0) +, _pingSendAt(0) +, _pingMsgId(0) +, restarted(false) +, _finished(false) +, keyId(0) // , sessionDataMutex(QReadWriteLock::Recursive) - , sessionData(data) - , myKeyLock(false) - , authKeyData(0) - , authKeyStrings(0) { - +, sessionData(data) +, myKeyLock(false) +, authKeyData(0) +, authKeyStrings(0) { oldConnectionTimer.moveToThread(thread); _waitForConnectedTimer.moveToThread(thread); _waitForReceivedTimer.moveToThread(thread); @@ -1357,6 +1365,7 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne connect(thread, SIGNAL(started()), this, SLOT(socketStart())); connect(thread, SIGNAL(finished()), this, SLOT(doFinish())); + connect(this, SIGNAL(finished(MTProtoConnection*)), _mtp_internal::globalSlotCarrier(), SLOT(connectionFinished(MTProtoConnection*)), Qt::QueuedConnection); connect(&retryTimer, SIGNAL(timeout()), this, SLOT(retryByTimer())); connect(&_waitForConnectedTimer, SIGNAL(timeout()), this, SLOT(onWaitConnectedFailed())); @@ -1966,6 +1975,10 @@ void MTProtoConnectionPrivate::restartNow() { } void MTProtoConnectionPrivate::socketStart(bool afterConfig) { + if (_finished) { + DEBUG_LOG(("MTP Error: socketStart() called for finished connection!")); + return; + } bool isDldDc = (dc >= MTP::dldStart) && (dc < MTP::dldEnd); if (isDldDc) { // using media_only addresses only if key for this dc is already created QReadLocker lockFinished(&sessionDataMutex); @@ -2231,7 +2244,9 @@ void MTProtoConnectionPrivate::doDisconnect() { void MTProtoConnectionPrivate::doFinish() { doDisconnect(); - _owner->stopped(); + _finished = true; + emit finished(_owner); + deleteLater(); } void MTProtoConnectionPrivate::handleReceived() { @@ -3928,7 +3943,7 @@ void MTProtoConnectionPrivate::unlockKey() { } MTProtoConnectionPrivate::~MTProtoConnectionPrivate() { - doDisconnect(); + t_assert(_finished && _conn == nullptr && _conn4 == nullptr && _conn6 == nullptr); } void MTProtoConnectionPrivate::stop() { @@ -3939,9 +3954,6 @@ void MTProtoConnectionPrivate::stop() { sessionData->keyMutex()->unlock(); myKeyLock = false; } - sessionData = 0; + sessionData = nullptr; } } - -MTProtoConnection::~MTProtoConnection() { -} diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.h b/Telegram/SourceFiles/mtproto/mtpConnection.h index 1d2d684cf7..8ac08b94bd 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.h +++ b/Telegram/SourceFiles/mtproto/mtpConnection.h @@ -58,11 +58,13 @@ class MTPThread : public QThread { Q_OBJECT public: - MTPThread(QObject *parent = 0); + MTPThread(); uint32 getThreadId() const; + ~MTPThread(); private: - uint32 threadId; + uint32 _threadId; + }; class MTProtoConnection { @@ -75,8 +77,8 @@ public: MTProtoConnection(); int32 start(MTPSessionData *data, int32 dc = 0); // return dc - void stop(); - void stopped(); + void kill(); + void waitTillFinish(); ~MTProtoConnection(); enum { @@ -358,6 +360,8 @@ signals: void resendManyAsync(QVector msgIds, quint64 msCanWait, bool forceContainer, bool sendMsgStateInfo); void resendAllAsync(); + void finished(MTProtoConnection *connection); + public slots: void retryByTimer(); @@ -466,7 +470,7 @@ private: template bool readResponseNotSecure(TResponse &response); - bool restarted; + bool restarted, _finished; uint64 keyId; QReadWriteLock sessionDataMutex; diff --git a/Telegram/SourceFiles/mtproto/mtpSession.cpp b/Telegram/SourceFiles/mtproto/mtpSession.cpp index 54ed49cb91..a6d6d918cf 100644 --- a/Telegram/SourceFiles/mtproto/mtpSession.cpp +++ b/Telegram/SourceFiles/mtproto/mtpSession.cpp @@ -66,7 +66,8 @@ void MTPSessionData::clear() { } -MTProtoSession::MTProtoSession() : QObject() +MTProtoSession::MTProtoSession(int32 dcenter) : QObject() +, _connection(0) , _killed(false) , _needToReceive(false) , data(this) @@ -75,9 +76,6 @@ MTProtoSession::MTProtoSession() : QObject() , msSendCall(0) , msWait(0) , _ping(false) { -} - -void MTProtoSession::start(int32 dcenter) { if (_killed) { DEBUG_LOG(("Session Error: can't start a killed session")); return; @@ -96,37 +94,32 @@ void MTProtoSession::start(int32 dcenter) { MTProtoDCMap &dcs(mtpDCMap()); - connections.reserve(cConnectionsInSession()); - for (uint32 i = 0; i < cConnectionsInSession(); ++i) { - connections.push_back(new MTProtoConnection()); - dcWithShift = connections.back()->start(&data, dcenter); - if (!dcWithShift) { - for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) { - delete *j; - } - connections.clear(); - DEBUG_LOG(("Session Info: could not start connection %1 to dc %2").arg(i).arg(dcenter)); - return; + _connection = new MTProtoConnection(); + dcWithShift = _connection->start(&data, dcenter); + if (!dcWithShift) { + delete _connection; + _connection = 0; + DEBUG_LOG(("Session Info: could not start connection to dc %1").arg(dcenter)); + return; + } + if (!dc) { + dcenter = dcWithShift; + int32 dcId = dcWithShift % _mtp_internal::dcShift; + MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId); + if (dcIndex == dcs.cend()) { + dc = MTProtoDCPtr(new MTProtoDC(dcId, mtpAuthKeyPtr())); + dcs.insert(dcWithShift % _mtp_internal::dcShift, dc); + } else { + dc = dcIndex.value(); } - if (!dc) { - dcenter = dcWithShift; - int32 dcId = dcWithShift % _mtp_internal::dcShift; - MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId); - if (dcIndex == dcs.cend()) { - dc = MTProtoDCPtr(new MTProtoDC(dcId, mtpAuthKeyPtr())); - dcs.insert(dcWithShift % _mtp_internal::dcShift, dc); - } else { - dc = dcIndex.value(); - } - ReadLockerAttempt lock(keyMutex()); - data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0)); - if (lock && dc->connectionInited()) { - data.setLayerWasInited(true); - } - connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()), Qt::QueuedConnection); - connect(dc.data(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)), Qt::QueuedConnection); + ReadLockerAttempt lock(keyMutex()); + data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0)); + if (lock && dc->connectionInited()) { + data.setLayerWasInited(true); } + connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()), Qt::QueuedConnection); + connect(dc.data(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)), Qt::QueuedConnection); } } @@ -139,10 +132,14 @@ void MTProtoSession::restart() { } void MTProtoSession::stop() { + if (_killed) { + DEBUG_LOG(("Session Error: can't kill a killed session")); + return; + } DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(dcWithShift)); - while (!connections.isEmpty()) { - connections.back()->stop(); - connections.pop_back(); + if (_connection) { + _connection->kill(); + _connection = 0; } } @@ -194,22 +191,17 @@ void MTProtoSession::needToResumeAndSend() { DEBUG_LOG(("Session Info: can't resume a killed session")); return; } - if (connections.isEmpty()) { + if (!_connection) { DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift)); MTProtoDCMap &dcs(mtpDCMap()); - connections.reserve(cConnectionsInSession()); - for (uint32 i = 0; i < cConnectionsInSession(); ++i) { - connections.push_back(new MTProtoConnection()); - if (!connections.back()->start(&data, dcWithShift)) { - for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) { - delete *j; - } - connections.clear(); - DEBUG_LOG(("Session Info: could not start connection %1 to dcWithShift %2").arg(i).arg(dcWithShift)); - dcWithShift = 0; - return; - } + _connection = new MTProtoConnection(); + if (!_connection->start(&data, dcWithShift)) { + delete _connection; + _connection = 0; + DEBUG_LOG(("Session Info: could not start connection to dcWithShift %1").arg(dcWithShift)); + dcWithShift = 0; + return; } } if (_ping) { @@ -324,12 +316,13 @@ void MTProtoSession::ping() { } int32 MTProtoSession::requestState(mtpRequestId requestId) const { - MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); int32 result = MTP::RequestSent; - for (; j != e; ++j) { - int32 s = (*j)->state(); + + bool connected = false; + if (_connection) { + int32 s = _connection->state(); if (s == MTProtoConnection::Connected) { - break; + connected = true; } else if (s == MTProtoConnection::Connecting || s == MTProtoConnection::Disconnected) { if (result < 0 || result == MTP::RequestSent) { result = MTP::RequestConnecting; @@ -340,7 +333,7 @@ int32 MTProtoSession::requestState(mtpRequestId requestId) const { } } } - if (j == e) { // no one is connected + if (!connected) { return result; } if (!requestId) return MTP::RequestSent; @@ -356,10 +349,10 @@ int32 MTProtoSession::requestState(mtpRequestId requestId) const { } int32 MTProtoSession::getState() const { - MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); int32 result = -86400000; - for (; j != e; ++j) { - int32 s = (*j)->state(); + + if (_connection) { + int32 s = _connection->state(); if (s == MTProtoConnection::Connected) { return s; } else if (s == MTProtoConnection::Connecting || s == MTProtoConnection::Disconnected) { @@ -379,12 +372,7 @@ int32 MTProtoSession::getState() const { } QString MTProtoSession::transport() const { - MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); - for (; j != e; ++j) { - QString s = (*j)->transport(); - if (!s.isEmpty()) return s; - } - return QString(); + return _connection ? _connection->transport() : QString(); } mtpRequestId MTProtoSession::resend(quint64 msgId, quint64 msCanWait, bool forceContainer, bool sendMsgStateInfo) { @@ -507,6 +495,10 @@ int32 MTProtoSession::getDcWithShift() const { } void MTProtoSession::tryToReceive() { + if (_killed) { + DEBUG_LOG(("Session Error: can't receive in a killed session")); + return; + } if (_mtp_internal::paused()) { _needToReceive = true; return; @@ -537,9 +529,7 @@ void MTProtoSession::tryToReceive() { } MTProtoSession::~MTProtoSession() { - for (MTProtoConnections::const_iterator i = connections.cbegin(), e = connections.cend(); i != e; ++i) { - delete *i; - } + t_assert(_connection == 0); } MTPrpcError rpcClientError(const QString &type, const QString &description) { diff --git a/Telegram/SourceFiles/mtproto/mtpSession.h b/Telegram/SourceFiles/mtproto/mtpSession.h index 23db4fba38..a635372f12 100644 --- a/Telegram/SourceFiles/mtproto/mtpSession.h +++ b/Telegram/SourceFiles/mtproto/mtpSession.h @@ -28,7 +28,7 @@ class MTProtoSession; class MTPSessionData { public: - + MTPSessionData(MTProtoSession *creator) : _session(0), _salt(0) , _messagesSent(0), _fakeRequestId(-2000000000) @@ -222,9 +222,8 @@ class MTProtoSession : public QObject { public: - MTProtoSession(); + MTProtoSession(int32 dcenter); - void start(int32 dcenter = 0); void restart(); void stop(); void kill(); @@ -278,13 +277,12 @@ public slots: void sendMsgsStateInfo(quint64 msgId, QByteArray data); private: - - typedef QList MTProtoConnections; - MTProtoConnections connections; + + MTProtoConnection *_connection; bool _killed; bool _needToReceive; - + MTPSessionData data; int32 dcWithShift; @@ -304,7 +302,3 @@ inline QReadWriteLock *MTPSessionData::keyMutex() const { } MTPrpcError rpcClientError(const QString &type, const QString &description = QString()); - -// here - -typedef QSharedPointer MTProtoSessionPtr; diff --git a/Telegram/SourceFiles/pspecific.h b/Telegram/SourceFiles/pspecific.h index 7362f15da0..7003daa426 100644 --- a/Telegram/SourceFiles/pspecific.h +++ b/Telegram/SourceFiles/pspecific.h @@ -38,10 +38,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace PlatformSpecific { - struct Initializer { - Initializer(); - ~Initializer(); - }; + void start(); + void finish(); namespace ThirdParty { void start(); diff --git a/Telegram/SourceFiles/pspecific_linux.cpp b/Telegram/SourceFiles/pspecific_linux.cpp index 650c51f10a..2134e97dd1 100644 --- a/Telegram/SourceFiles/pspecific_linux.cpp +++ b/Telegram/SourceFiles/pspecific_linux.cpp @@ -1237,10 +1237,10 @@ void psShowInFolder(const QString &name) { namespace PlatformSpecific { - Initializer::Initializer() { + void start() { } - Initializer::~Initializer() { + void finish() { delete _psEventFilter; _psEventFilter = 0; } diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index 854ff00d28..f674e84e65 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -850,11 +850,11 @@ void psShowInFolder(const QString &name) { namespace PlatformSpecific { - Initializer::Initializer() { + void start() { objc_start(); } - Initializer::~Initializer() { + void finish() { delete _psEventFilter; _psEventFilter = 0; diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 1a2e461400..3dc358887b 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -2159,10 +2159,10 @@ void psShowInFolder(const QString &name) { namespace PlatformSpecific { - Initializer::Initializer() { + void start() { } - Initializer::~Initializer() { + void finish() { delete _psEventFilter; _psEventFilter = 0; diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h index b57a6b4f15..93524bba88 100644 --- a/Telegram/SourceFiles/settings.h +++ b/Telegram/SourceFiles/settings.h @@ -77,7 +77,6 @@ inline QString cInlineGifBotUsername() { return cTestMode() ? qstr("contextbot") : qstr("gif"); } DeclareSetting(QString, LoggedPhoneNumber); -DeclareReadSetting(uint32, ConnectionsInSession); DeclareSetting(bool, AutoStart); DeclareSetting(bool, StartMinimized); DeclareSetting(bool, StartInTray); diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc index 6ad208fd05..f82064666b 100644 --- a/Telegram/Telegram.rc +++ b/Telegram/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,28,1 - PRODUCTVERSION 0,9,28,1 + FILEVERSION 0,9,28,2 + PRODUCTVERSION 0,9,28,2 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.28.1" + VALUE "FileVersion", "0.9.28.2" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.28.1" + VALUE "ProductVersion", "0.9.28.2" END END BLOCK "VarFileInfo" diff --git a/Telegram/Version b/Telegram/Version index e3f6eee41c..c6c53f35a0 100644 --- a/Telegram/Version +++ b/Telegram/Version @@ -3,4 +3,4 @@ AppVersionStrMajor 0.9 AppVersionStrSmall 0.9.28 AppVersionStr 0.9.28 DevChannel 0 -BetaVersion 9028001 +BetaVersion 9028002