Bug 748766 - Only count connected websockets toward max-websocket limit. r=mcmanus, a=akeybl
authorJason Duell <jduell.mcbugs@gmail.com>
Tue, 29 May 2012 21:58:00 -0700
changeset 95946 173d2921c023501bf1544115dbf12754f6df1403
parent 95945 32787d343859ff00c08034a3b2d35bb371b71d7c
child 95947 1851b8c13061fe22eb15a90a9284ec5b19dec808
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, akeybl
bugs748766
milestone14.0a2
Bug 748766 - Only count connected websockets toward max-websocket limit. r=mcmanus, a=akeybl
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -688,16 +688,18 @@ WebSocketChannel::WebSocketChannel() :
   mPingOutstanding(0),
   mAllowCompression(1),
   mAutoFollowRedirects(0),
   mReleaseOnTransmit(0),
   mTCPClosed(0),
   mOpenBlocked(0),
   mOpenRunning(0),
   mChannelWasOpened(0),
+  mIncrementedSessionCount(0),
+  mDecrementedSessionCount(0),
   mMaxMessageSize(PR_INT32_MAX),
   mStopOnClose(NS_OK),
   mServerCloseCode(CLOSE_ABNORMAL),
   mScriptCloseCode(0),
   mFragmentOpcode(kContinuation),
   mFragmentAccumulator(0),
   mBuffered(0),
   mBufferSize(kIncomingBufferInitialSize),
@@ -709,29 +711,23 @@ WebSocketChannel::WebSocketChannel() :
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
   LOG(("WebSocketChannel::WebSocketChannel() %p\n", this));
 
   if (!sWebSocketAdmissions)
     sWebSocketAdmissions = new nsWSAdmissionManager();
 
-  // The active session limit is enforced in AsyncOpen()
-  sWebSocketAdmissions->IncrementSessionCount();
-
   mFramePtr = mBuffer = static_cast<PRUint8 *>(moz_xmalloc(mBufferSize));
 }
 
 WebSocketChannel::~WebSocketChannel()
 {
   LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this));
 
-  if (sWebSocketAdmissions)
-    sWebSocketAdmissions->DecrementSessionCount();
-
   // this stop is a nop if the normal connect/close is followed
   StopSession(NS_ERROR_UNEXPECTED);
   NS_ABORT_IF_FALSE(!mOpenRunning && !mOpenBlocked, "op");
 
   moz_free(mBuffer);
   moz_free(mDynamicOutput);
   delete mCompressor;
   delete mCurrentOut;
@@ -1550,16 +1546,18 @@ WebSocketChannel::CleanupConnection()
   }
 
   if (mTransport) {
     mTransport->SetSecurityCallbacks(nsnull);
     mTransport->SetEventSink(nsnull, nsnull);
     mTransport->Close(NS_BASE_STREAM_CLOSED);
     mTransport = nsnull;
   }
+
+  DecrementSessionCount();
 }
 
 void
 WebSocketChannel::StopSession(nsresult reason)
 {
   LOG(("WebSocketChannel::StopSession() %p [%x]\n", this, reason));
 
   // normally this should be called on socket thread, but it is ok to call it
@@ -1705,16 +1703,38 @@ WebSocketChannel::ReleaseSession()
        this, mStopped));
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "not socket thread");
 
   if (mStopped)
     return;
   StopSession(NS_OK);
 }
 
+void
+WebSocketChannel::IncrementSessionCount()
+{
+  if (!mIncrementedSessionCount) {
+    sWebSocketAdmissions->IncrementSessionCount();
+    mIncrementedSessionCount = 1;
+  }
+}
+
+void
+WebSocketChannel::DecrementSessionCount()
+{
+  // Make sure we decrement session count only once, and only if we incremented it.
+  // This code is thread-safe: sWebSocketAdmissions->DecrementSessionCount is
+  // atomic, and mIncrementedSessionCount/mDecrementedSessionCount are set at
+  // times when they'll never be a race condition for checking/setting them.
+  if (mIncrementedSessionCount && !mDecrementedSessionCount) {
+    sWebSocketAdmissions->DecrementSessionCount();
+    mDecrementedSessionCount = 1;
+  }
+}
+
 nsresult
 WebSocketChannel::HandleExtensions()
 {
   LOG(("WebSocketChannel::HandleExtensions() %p\n", this));
 
   nsresult rv;
   nsCAutoString extensions;
 
@@ -2294,17 +2314,24 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI
 
   mHttpChannel = do_QueryInterface(localChannel, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetupRequest();
   if (NS_FAILED(rv))
     return rv;
 
-  return ApplyForAdmission();
+  rv = ApplyForAdmission();
+  if (NS_FAILED(rv))
+    return rv;
+
+  // Session setup OK, so count it.
+  IncrementSessionCount();
+
+  return rv;
 }
 
 NS_IMETHODIMP
 WebSocketChannel::Close(PRUint16 code, const nsACString & reason)
 {
   LOG(("WebSocketChannel::Close() %p\n", this));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -157,16 +157,18 @@ private:
   nsresult ApplyForAdmission();
   nsresult StartWebsocketData();
   PRUint16 ResultToCloseCode(nsresult resultCode);
 
   void StopSession(nsresult reason);
   void AbortSession(nsresult reason);
   void ReleaseSession();
   void CleanupConnection();
+  void IncrementSessionCount();
+  void DecrementSessionCount();
 
   void EnsureHdrOut(PRUint32 size);
   void ApplyMask(PRUint32 mask, PRUint8 *data, PRUint64 len);
 
   bool     IsPersistentFramePtr();
   nsresult ProcessInput(PRUint8 *buffer, PRUint32 count);
   bool UpdateReadBuffer(PRUint8 *buffer, PRUint32 count,
                         PRUint32 accumulatedFragments,
@@ -213,16 +215,18 @@ private:
   PRUint32                        mPingOutstanding           : 1;
   PRUint32                        mAllowCompression          : 1;
   PRUint32                        mAutoFollowRedirects       : 1;
   PRUint32                        mReleaseOnTransmit         : 1;
   PRUint32                        mTCPClosed                 : 1;
   PRUint32                        mOpenBlocked               : 1;
   PRUint32                        mOpenRunning               : 1;
   PRUint32                        mChannelWasOpened          : 1;
+  PRUint32                        mIncrementedSessionCount   : 1;
+  PRUint32                        mDecrementedSessionCount   : 1;
 
   PRInt32                         mMaxMessageSize;
   nsresult                        mStopOnClose;
   PRUint16                        mServerCloseCode;
   nsCString                       mServerCloseReason;
   PRUint16                        mScriptCloseCode;
   nsCString                       mScriptCloseReason;