Bug 646396 - Update QtNetworkManager to new API useage. r=romaxa
authorJeremias Bosch <jeremias.bosch@gmail.com>
Fri, 08 Apr 2011 11:51:32 -0700
changeset 67672 4f957dd3f9f79e175d7cb78faaf59a4e74fc10bd
parent 67671 0f077c086750bdf13fadb05f1efd08a0d18cbdcf
child 67673 272a7b90280dd5771684342f73f6c6e23893f90d
child 67705 877127eae177507f65bc689347f26e28789524bb
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersromaxa
bugs646396
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 646396 - Update QtNetworkManager to new API useage. r=romaxa
netwerk/base/src/Makefile.in
netwerk/base/src/nsAutodialQt.cpp
netwerk/system/qt/Makefile.in
netwerk/system/qt/nsQtNetworkLinkService.cpp
netwerk/system/qt/nsQtNetworkManager.cpp
netwerk/system/qt/nsQtNetworkManager.h
--- a/netwerk/base/src/Makefile.in
+++ b/netwerk/base/src/Makefile.in
@@ -117,16 +117,17 @@ ifdef MOZ_PLATFORM_MAEMO
 	CPPSRCS += nsNativeConnectionHelper.cpp
 ifdef MOZ_ENABLE_LIBCONIC
 	CPPSRCS += nsAutodialMaemo.cpp
 	LOCAL_INCLUDES += -I$(srcdir)/../../system/maemo
 endif
 ifdef MOZ_ENABLE_QTNETWORK
 	CPPSRCS += nsAutodialQt.cpp
 	LOCAL_INCLUDES += -I$(srcdir)/../../system/qt
+	OS_INCLUDES += $(MOZ_QT_CFLAGS)
 endif
 endif
 
 EXTRA_COMPONENTS = \
 		$(srcdir)/nsProxyAutoConfig.js \
 		$(srcdir)/nsProxyAutoConfig.manifest \
 		$(NULL)
 
--- a/netwerk/base/src/nsAutodialQt.cpp
+++ b/netwerk/base/src/nsAutodialQt.cpp
@@ -30,23 +30,23 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsQtNetworkManager.h"
 #include "nsAutodialQt.h"
 #include "nsNetCID.h"
 #include "nsCOMPtr.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsIServiceManager.h"
-#include "nsQtNetworkManager.h"
 
 
 nsAutodial::nsAutodial()
 {
 }
 
 nsAutodial::~nsAutodial()
 {
@@ -56,22 +56,24 @@ nsresult
 nsAutodial::Init()
 {
   return NS_OK;
 }
 
 nsresult
 nsAutodial::DialDefault(const PRUnichar* hostName)
 {
-  if (nsQtNetworkManager::OpenConnectionSync())
+  if (gQtNetworkManager->openConnection(QString::fromUtf16(hostName))) {
     return NS_OK;
+  }
 
   return NS_ERROR_FAILURE;
 }
 
 PRBool
 nsAutodial::ShouldDialOnNetworkError()
 {
-  if (nsQtNetworkManager::IsConnected())
+  if (gQtNetworkManager->isOnline()) {
     return PR_FALSE;
+  }
 
   return PR_TRUE;
 }
--- a/netwerk/system/qt/Makefile.in
+++ b/netwerk/system/qt/Makefile.in
@@ -43,20 +43,24 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE         = necko
 LIBRARY_NAME   = neckosystem_s
 LIBXUL_LIBRARY = 1
 
 FORCE_STATIC_LIB = 1
+MOCSRCS = \
+		moc_nsQtNetworkManager.cpp \
+		$(NULL)
 
 CPPSRCS += \
+	$(MOCSRCS) \
 	nsQtNetworkLinkService.cpp \
 	nsQtNetworkManager.cpp \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
 
-OS_INCLUDES += $(GLIB_CFLAGS) $(MOZ_QT_CFLAGS)
+OS_INCLUDES += $(MOZ_QT_CFLAGS)
 LOCAL_INCLUDES += -I$(srcdir)/../../base/src
--- a/netwerk/system/qt/nsQtNetworkLinkService.cpp
+++ b/netwerk/system/qt/nsQtNetworkLinkService.cpp
@@ -30,77 +30,93 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "nsQtNetworkManager.h"
 #include "nsQtNetworkLinkService.h"
 #include "nsCOMPtr.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
-#include "nsQtNetworkManager.h"
 #include "mozilla/Services.h"
 
 NS_IMPL_ISUPPORTS2(nsQtNetworkLinkService,
                    nsINetworkLinkService,
                    nsIObserver)
 
 nsQtNetworkLinkService::nsQtNetworkLinkService()
 {
 }
 
 nsQtNetworkLinkService::~nsQtNetworkLinkService()
 {
 }
 
 NS_IMETHODIMP
-nsQtNetworkLinkService::GetIsLinkUp(PRBool *aIsUp)
+nsQtNetworkLinkService::GetIsLinkUp(PRBool* aIsUp)
 {
-  *aIsUp = nsQtNetworkManager::IsConnected();
+  *aIsUp = gQtNetworkManager->isOnline();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsQtNetworkLinkService::GetLinkStatusKnown(PRBool *aIsKnown)
+nsQtNetworkLinkService::GetLinkStatusKnown(PRBool* aIsKnown)
 {
-  *aIsKnown = nsQtNetworkManager::GetLinkStatusKnown();
+  *aIsKnown = gQtNetworkManager->isOnline();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQtNetworkLinkService::Observe(nsISupports* aSubject,
                                 const char* aTopic,
                                 const PRUnichar* aData)
 {
-  if (!strcmp(aTopic, "xpcom-shutdown"))
+  if (!strcmp(aTopic, "xpcom-shutdown")) {
     Shutdown();
+    delete gQtNetworkManager;
+    gQtNetworkManager = 0;
+  }
+
+  if (!strcmp(aTopic, "browser-lastwindow-close-granted")) {
+    Shutdown();
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsQtNetworkLinkService::Init(void)
 {
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
-  if (!observerService)
+  if (!observerService) {
     return NS_ERROR_FAILURE;
+  }
+
+  delete gQtNetworkManager;
+  gQtNetworkManager = new nsQtNetworkManager();
+  nsresult rv;
 
-  nsresult rv = observerService->AddObserver(this, "xpcom-shutdown", PR_FALSE);
-  if (NS_FAILED(rv))
+  rv = observerService->AddObserver(this, "xpcom-shutdown", PR_FALSE);
+  if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
+  }
 
-  if (!nsQtNetworkManager::Startup())
+  rv = observerService->AddObserver(this, "browser-lastwindow-close-granted", PR_FALSE);
+  if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
+  }
+
 
   return NS_OK;
 }
 
 nsresult
 nsQtNetworkLinkService::Shutdown()
 {
-  nsQtNetworkManager::Shutdown();
+  gQtNetworkManager->closeSession();
   return NS_OK;
 }
--- a/netwerk/system/qt/nsQtNetworkManager.cpp
+++ b/netwerk/system/qt/nsQtNetworkManager.cpp
@@ -30,108 +30,145 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-//order is important - mozilla redefine qt macros
-#include <QNetworkConfigurationManager>
-#include <QNetworkConfiguration>
-#include <QNetworkSession>
-
 #include "nsQtNetworkManager.h"
 
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
-
 #include "nsINetworkLinkService.h"
-
 #include "nsIOService.h"
 #include "nsIObserverService.h"
 #include "nsIOService.h"
 
-#include "nsINetworkLinkService.h"
+#include <QHostInfo>
+#include <QHostAddress>
+#include <QTime>
 
-static QNetworkConfigurationManager* sNetworkConfig = 0;
+nsQtNetworkManager::nsQtNetworkManager(QObject* parent)
+  : QObject(parent), networkSession(0)
+{
+    mOnline = networkConfigurationManager.isOnline();
+    NS_ASSERTION(NS_IsMainThread(), "nsQtNetworkManager can only initiated in Main Thread");
+}
+
+nsQtNetworkManager::~nsQtNetworkManager()
+{
+    closeSession();
+    networkSession->deleteLater();
+}
 
 PRBool
-nsQtNetworkManager::OpenConnectionSync()
+nsQtNetworkManager::isOnline()
 {
-    if (!sNetworkConfig)
-        return PR_FALSE;
-
-    //do not request when we are online...
-    if (sNetworkConfig->isOnline())
-        return PR_FALSE;
-
-    if (!(sNetworkConfig->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces))
-        return PR_FALSE;
-
-    // Is there default access point, use it
-    QNetworkConfiguration default_cfg = sNetworkConfig->defaultConfiguration();
-
-    if (!default_cfg.isValid())
-    {
-        NS_WARNING("default configuration is not valid. Looking for any other:");
-        foreach (QNetworkConfiguration cfg, sNetworkConfig->allConfigurations())
-        {
-            if (cfg.isValid())
-                default_cfg = cfg;
-        }
-
-        if (!default_cfg.isValid())
-        {
-            NS_WARNING("No valid configuration found. Giving up.");
-            return PR_FALSE;
-        }
-    }
-
-    //do use pointer here, it will be deleted after connected!
-    //Creation on stack cause appearing issues and segfaults of the connectivity dialog
-    QNetworkSession* session = new QNetworkSession(default_cfg);
-    QObject::connect(session, SIGNAL(opened()),
-                     session, SLOT(deleteLater()));
-    QObject::connect(session, SIGNAL(error(QNetworkSession::SessionError)),
-                     session, SLOT(deleteLater()));
-    session->open();
-    return session->waitForOpened(-1);
+    static PRBool sForceOnlineUSB = getenv("MOZ_MEEGO_NET_ONLINE") != 0;
+    return sForceOnlineUSB || mOnline;
 }
 
 void
-nsQtNetworkManager::CloseConnection()
+nsQtNetworkManager::onlineStateChanged(bool online)
 {
-    NS_WARNING("nsQtNetworkManager::CloseConnection() Not implemented by QtNetwork.");
+    mOnline = online;
 }
 
-PRBool
-nsQtNetworkManager::IsConnected()
-{
-    NS_ASSERTION(sNetworkConfig, "Network not initialized");
-    return sNetworkConfig->isOnline();
-}
+/*
+  This function is called from different threads, we need to make sure that
+  the attempt to create a network connection is done in the mainthread
+
+  In case this function is called by another thread than the mainthread
+  we emit a signal which is connected through "BlockingQueue"-Connection Type.
+
+  This cause that the current thread is blocked and waiting for the result.
+
+  Of course, in case this gets called from the mainthread we must not emit the signal,
+  but call the slot directly.
+*/
 
 PRBool
-nsQtNetworkManager::GetLinkStatusKnown()
-{
-    return IsConnected();
-}
-
-PRBool
-nsQtNetworkManager::Startup()
+nsQtNetworkManager::openConnection(const QString& host)
 {
-    //Dont do it if already there
-    if (sNetworkConfig)
-        return PR_FALSE;
+    // we are already online -> return true.
+    if (isOnline()) {
+        return true;
+    }
 
-    sNetworkConfig = new QNetworkConfigurationManager();
+    if (NS_IsMainThread()) {
+        openSession();
+    } else {
+        // jump to mainthread and do the work there
+        emit openConnectionSignal();
+    }
 
-    return PR_TRUE;
+    // if its claiming its online -> send one resolve request ahead.
+    // this is important because on mobile the first request can take up to 10 seconds
+    // sending here one will help to avoid trouble and timeouts later
+    if (isOnline()) {
+        QHostInfo::fromName(host);
+    }
+
+    return isOnline();
 }
 
 void
-nsQtNetworkManager::Shutdown()
+nsQtNetworkManager::openSession()
 {
-    delete sNetworkConfig;
-    sNetworkConfig = nsnull;
+    if (mBlockTimer.isActive()) {
+        // if openSession is called within 200 ms again, we forget this attempt since
+        // its mostlike an automatic connection attempt which was not successful or canceled 200ms ago.
+        // we reset the timer and start it again.
+
+        // As example: Go in firefox mobile into AwesomeView, see that the icons are not always cached and
+        // get loaded on the fly. Not having the 200 ms rule here would mean that instantly
+        // after the user dismissed the one connection dialog once another
+        // would get opened. The user will never be able to close / leave the view until each such attempt is gone through.
+
+        // Basically 200 ms are working fine, its huge enough for automatic attempts to get covered and small enough to
+        // still be able to react on direct user request.
+
+        mBlockTimer.stop();
+        mBlockTimer.setSingleShot(true);
+        mBlockTimer.start(200);
+        return;
+    }
+
+    if (isOnline()) {
+        return;
+    }
+
+    // this only means we did not shutdown before...
+    // renew Session every time
+    // fix/workaround for prestart bug
+    if (!networkSession) {
+        networkSession->close();
+        networkSession->deleteLater();
+    }
+
+    // renew always to react on changed Configurations
+    networkConfigurationManager.updateConfigurations();
+    // go always with default configuration
+    networkConfiguration = networkConfigurationManager.defaultConfiguration();
+    networkSession = new QNetworkSession(networkConfiguration);
+
+    networkSession->open();
+    QTime current;
+    current.start();
+    networkSession->waitForOpened(-1);
+
+    if (current.elapsed() < 1000) {
+        NS_WARNING("Connection Creation was to fast, something is not right.");
+    }
+
+    mBlockTimer.setSingleShot(true);
+    mBlockTimer.start(200);
 }
+
+void
+nsQtNetworkManager::closeSession()
+{
+    if (!networkSession) {
+        networkSession->close();
+    }
+}
--- a/netwerk/system/qt/nsQtNetworkManager.h
+++ b/netwerk/system/qt/nsQtNetworkManager.h
@@ -33,26 +33,52 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef NSQTNETWORKMANAGER_H_
 #define NSQTNETWORKMANAGER_H_
 
+#include <QNetworkConfigurationManager>
+#include <QObject>
+#include <QTimer>
+#include <QNetworkConfiguration>
+#include <QNetworkSession>
 #include "nscore.h"
 
-class nsQtNetworkManager
+class nsQtNetworkManager;
+
+static nsQtNetworkManager* gQtNetworkManager = nsnull;
+
+class nsQtNetworkManager : public QObject
 {
-public:
-  // Can be called from any thread, most likely the socket transport thread
-  static PRBool OpenConnectionSync();
-  static void CloseConnection();
+  Q_OBJECT
+  public:
+    explicit nsQtNetworkManager(QObject* parent = 0);
+
+    virtual ~nsQtNetworkManager();
 
-  static PRBool IsConnected();
-  static PRBool GetLinkStatusKnown();
+    static PRBool IsConnected();
+    static PRBool GetLinkStatusKnown();
+    static void enableInstance();
+    PRBool openConnection(const QString&);
+    PRBool isOnline();
+  signals:
+    void openConnectionSignal();
 
-  // Called from the nsQtNetworkLinkService (main thread only)
-  static PRBool Startup();
-  static void Shutdown();
+  public slots:
+    void closeSession();
+    void onlineStateChanged(bool);
+
+  private slots:
+    void openSession();
+
+  private:
+    QNetworkSession* networkSession;
+    QNetworkConfiguration networkConfiguration;
+    QNetworkConfigurationManager networkConfigurationManager;
+    QTimer mBlockTimer;
+    bool mOnline;
 };
 
 #endif /* NSQTNETWORKMANAGER_H_ */
+