michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsQtNetworkManager.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsINetworkLinkService.h" michael@0: #include "nsIOService.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIOService.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: nsQtNetworkManager* nsQtNetworkManager::gQtNetworkManager = nullptr; michael@0: michael@0: void nsQtNetworkManager::create() michael@0: { michael@0: if (!gQtNetworkManager) { michael@0: gQtNetworkManager = new nsQtNetworkManager(); michael@0: connect(gQtNetworkManager, SIGNAL(openConnectionSignal()), michael@0: gQtNetworkManager, SLOT(openSession()), michael@0: Qt::BlockingQueuedConnection); michael@0: connect(&gQtNetworkManager->networkConfigurationManager, michael@0: SIGNAL(onlineStateChanged(bool)), gQtNetworkManager, michael@0: SLOT(onlineStateChanged(bool))); michael@0: } michael@0: } michael@0: michael@0: void nsQtNetworkManager::destroy() michael@0: { michael@0: delete gQtNetworkManager; michael@0: gQtNetworkManager = nullptr; michael@0: } michael@0: michael@0: nsQtNetworkManager::nsQtNetworkManager(QObject* parent) michael@0: : QObject(parent), networkSession(0) michael@0: { michael@0: mOnline = networkConfigurationManager.isOnline(); michael@0: NS_ASSERTION(NS_IsMainThread(), "nsQtNetworkManager can only initiated in Main Thread"); michael@0: } michael@0: michael@0: nsQtNetworkManager::~nsQtNetworkManager() michael@0: { michael@0: closeSession(); michael@0: networkSession->deleteLater(); michael@0: } michael@0: michael@0: bool michael@0: nsQtNetworkManager::isOnline() michael@0: { michael@0: static bool sForceOnlineUSB = getenv("MOZ_MEEGO_NET_ONLINE") != 0; michael@0: return sForceOnlineUSB || mOnline; michael@0: } michael@0: michael@0: void michael@0: nsQtNetworkManager::onlineStateChanged(bool online) michael@0: { michael@0: mOnline = online; michael@0: } michael@0: michael@0: /* michael@0: This function is called from different threads, we need to make sure that michael@0: the attempt to create a network connection is done in the mainthread michael@0: michael@0: In case this function is called by another thread than the mainthread michael@0: we emit a signal which is connected through "BlockingQueue"-Connection Type. michael@0: michael@0: This cause that the current thread is blocked and waiting for the result. michael@0: michael@0: Of course, in case this gets called from the mainthread we must not emit the signal, michael@0: but call the slot directly. michael@0: */ michael@0: michael@0: bool michael@0: nsQtNetworkManager::openConnection(const QString& host) michael@0: { michael@0: // we are already online -> return true. michael@0: if (isOnline()) { michael@0: return true; michael@0: } michael@0: michael@0: if (NS_IsMainThread()) { michael@0: openSession(); michael@0: } else { michael@0: // jump to mainthread and do the work there michael@0: Q_EMIT openConnectionSignal(); michael@0: } michael@0: michael@0: // if its claiming its online -> send one resolve request ahead. michael@0: // this is important because on mobile the first request can take up to 10 seconds michael@0: // sending here one will help to avoid trouble and timeouts later michael@0: if (isOnline()) { michael@0: QHostInfo::fromName(host); michael@0: } michael@0: michael@0: return isOnline(); michael@0: } michael@0: michael@0: void michael@0: nsQtNetworkManager::openSession() michael@0: { michael@0: if (mBlockTimer.isActive()) { michael@0: // if openSession is called within 200 ms again, we forget this attempt since michael@0: // its mostlike an automatic connection attempt which was not successful or canceled 200ms ago. michael@0: // we reset the timer and start it again. michael@0: michael@0: // As example: Go in firefox mobile into AwesomeView, see that the icons are not always cached and michael@0: // get loaded on the fly. Not having the 200 ms rule here would mean that instantly michael@0: // after the user dismissed the one connection dialog once another michael@0: // would get opened. The user will never be able to close / leave the view until each such attempt is gone through. michael@0: michael@0: // Basically 200 ms are working fine, its huge enough for automatic attempts to get covered and small enough to michael@0: // still be able to react on direct user request. michael@0: michael@0: mBlockTimer.stop(); michael@0: mBlockTimer.setSingleShot(true); michael@0: mBlockTimer.start(200); michael@0: return; michael@0: } michael@0: michael@0: if (isOnline()) { michael@0: return; michael@0: } michael@0: michael@0: // this only means we did not shutdown before... michael@0: // renew Session every time michael@0: // fix/workaround for prestart bug michael@0: if (networkSession) { michael@0: networkSession->close(); michael@0: networkSession->deleteLater(); michael@0: } michael@0: michael@0: // renew always to react on changed Configurations michael@0: networkConfigurationManager.updateConfigurations(); michael@0: // go always with default configuration michael@0: networkConfiguration = networkConfigurationManager.defaultConfiguration(); michael@0: networkSession = new QNetworkSession(networkConfiguration); michael@0: michael@0: networkSession->open(); michael@0: QTime current; michael@0: current.start(); michael@0: networkSession->waitForOpened(-1); michael@0: michael@0: if (current.elapsed() < 1000) { michael@0: NS_WARNING("Connection Creation was to fast, something is not right."); michael@0: } michael@0: michael@0: mBlockTimer.setSingleShot(true); michael@0: mBlockTimer.start(200); michael@0: } michael@0: michael@0: void michael@0: nsQtNetworkManager::closeSession() michael@0: { michael@0: if (networkSession) { michael@0: networkSession->close(); michael@0: } michael@0: }