Bug 684893 - part1: Start backup TCP SYN timer on primary TCP connection start, r=mcmanus
authorHonza Bambas <honzab.moz@firemni.cz>
Wed, 02 Nov 2011 17:18:53 +0100
changeset 79625 790fff5fd07a4886ceb4cf87c65ab4b4f981b0b8
parent 79624 a47adda7f98a14c9d00ea03ded62951bb8cd4820
child 79626 3af633ba04ab8bcee4277e796a927e9ceefc2865
push id21418
push usermak77@bonardo.net
push dateThu, 03 Nov 2011 14:57:14 +0000
treeherdermozilla-central@6cbeabc07c59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs684893
milestone10.0a1
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 684893 - part1: Start backup TCP SYN timer on primary TCP connection start, r=mcmanus
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -839,17 +839,16 @@ nsHttpConnectionMgr::CreateTransport(nsC
                                      nsHttpTransaction *trans)
 {
     NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
     nsRefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans);
     nsresult rv = sock->SetupPrimaryStreams();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    sock->SetupBackupTimer();
     ent->mHalfOpens.AppendElement(sock);
     return NS_OK;
 }
 
 nsresult
 nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
                                          nsAHttpTransaction *trans,
                                          PRUint8 caps,
@@ -1462,57 +1461,71 @@ nsHttpConnectionMgr::nsHalfOpenSocket::S
         // if we do not get a writable event on the main one.
         // We do this because a lost SYN takes a very long time
         // to repair at the TCP level.
         //
         // Failure to setup the timer is something we can live with,
         // so don't return an error in that case.
         nsresult rv;
         mSynTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
-        if (NS_SUCCEEDED(rv))
+        if (NS_SUCCEEDED(rv)) {
             mSynTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
+            LOG(("nsHalfOpenSocket::SetupBackupTimer()"));
+        }
     }
 }
 
 void
+nsHttpConnectionMgr::nsHalfOpenSocket::CancelBackupTimer()
+{
+    // If the syntimer is still armed, we can cancel it because no backup
+    // socket should be formed at this point
+    if (!mSynTimer)
+        return;
+
+    LOG(("nsHalfOpenSocket::CancelBackupTimer()"));
+    mSynTimer->Cancel();
+    mSynTimer = nsnull;
+}
+
+void
 nsHttpConnectionMgr::nsHalfOpenSocket::Abandon()
 {
     LOG(("nsHalfOpenSocket::Abandon [this=%p ent=%s]",
          this, mEnt->mConnInfo->Host()));
     nsRefPtr<nsHalfOpenSocket> deleteProtector(this);
 
     if (mStreamOut) {
         gHttpHandler->ConnMgr()->RecvdConnect();
         mStreamOut->AsyncWait(nsnull, 0, 0, nsnull);
         mStreamOut = nsnull;
     }
     if (mBackupStreamOut) {
         gHttpHandler->ConnMgr()->RecvdConnect();
         mBackupStreamOut->AsyncWait(nsnull, 0, 0, nsnull);
         mBackupStreamOut = nsnull;
     }
-    if (mSynTimer) {
-        mSynTimer->Cancel();
-        mSynTimer = nsnull;
-    }
+
+    CancelBackupTimer();
 
     mEnt = nsnull;
 }
 
 NS_IMETHODIMP // method for nsITimerCallback
 nsHttpConnectionMgr::nsHalfOpenSocket::Notify(nsITimer *timer)
 {
     NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     NS_ABORT_IF_FALSE(timer == mSynTimer, "wrong timer");
 
-    mSynTimer = nsnull;
     if (!gHttpHandler->ConnMgr()->
         AtActiveConnectionLimit(mEnt, mTransaction->Caps())) {
         SetupBackupStreams();
     }
+
+    mSynTimer = nsnull;
     return NS_OK;
 }
 
 // method for nsIAsyncOutputStreamCallback
 NS_IMETHODIMP
 nsHttpConnectionMgr::
 nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
 {
@@ -1522,25 +1535,17 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
     LOG(("nsHalfOpenSocket::OnOutputStreamReady [this=%p ent=%s %s]\n", 
          this, mEnt->mConnInfo->Host(),
          out == mStreamOut ? "primary" : "backup"));
     PRInt32 index;
     nsresult rv;
     
     gHttpHandler->ConnMgr()->RecvdConnect();
 
-    // If the syntimer is still armed, we can cancel it because no backup
-    // socket should be formed at this point
-    if (mSynTimer) {
-        NS_ABORT_IF_FALSE (out == mStreamOut, "timer for non existant stream");
-        LOG(("nsHalfOpenSocket::OnOutputStreamReady "
-             "Backup connection timer canceled\n"));
-        mSynTimer->Cancel();
-        mSynTimer = nsnull;
-    }
+    CancelBackupTimer();
 
     // assign the new socket to the http connection
     nsRefPtr<nsHttpConnection> conn = new nsHttpConnection();
     LOG(("nsHalfOpenSocket::OnOutputStreamReady "
          "Created new nshttpconnection %p\n", conn.get()));
 
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
     nsCOMPtr<nsIEventTarget>        callbackTarget;
@@ -1609,17 +1614,39 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
 // method for nsITransportEventSink
 NS_IMETHODIMP
 nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
                                                          nsresult status,
                                                          PRUint64 progress,
                                                          PRUint64 progressMax)
 {
     if (mTransaction)
-      mTransaction->OnTransportStatus(trans, status, progress);
+        mTransaction->OnTransportStatus(trans, status, progress);
+
+    if (trans != mSocketTransport)
+        return NS_OK;
+
+    switch (status) {
+    case nsISocketTransport::STATUS_CONNECTING_TO:
+        // Passed DNS resolution, now trying to connect, start the backup timer
+        // only prevent creating another backup transport
+        if (!mBackupTransport && !mSynTimer)
+            SetupBackupTimer();
+        break;
+
+    case nsISocketTransport::STATUS_CONNECTED_TO:
+        // TCP connection's up, now transfer or SSL negotiantion starts,
+        // no need for backup socket
+        CancelBackupTimer();
+        break;
+
+    default:
+        break;
+    }
+
     return NS_OK;
 }
 
 // method for nsIInterfaceRequestor
 NS_IMETHODIMP
 nsHttpConnectionMgr::nsHalfOpenSocket::GetInterface(const nsIID &iid,
                                                     void **result)
 {
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -215,16 +215,17 @@ private:
         
         nsresult SetupStreams(nsISocketTransport **,
                               nsIAsyncInputStream **,
                               nsIAsyncOutputStream **,
                               bool isBackup);
         nsresult SetupPrimaryStreams();
         nsresult SetupBackupStreams();
         void     SetupBackupTimer();
+        void     CancelBackupTimer();
         void     Abandon();
         
         nsHttpTransaction *Transaction() { return mTransaction; }
 
     private:
         nsConnectionEntry              *mEnt;
         nsRefPtr<nsHttpTransaction>    mTransaction;
         nsCOMPtr<nsISocketTransport>   mSocketTransport;