Bug 1215092 - WebSocketEventService and WebSocket discovering - part 2 - Unique Serial number for WebSocketChannel in IPC, r=michal
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 28 Oct 2015 19:10:42 +0000
changeset 270090 684e5160767d3be6eabd10e810869889657df421
parent 270089 0f42f6bc21a8df4a6662e3431a279c1913296a63
child 270091 3fe351a6269628e5b43bdcf981f3677ccabbf0cd
push id29599
push usercbook@mozilla.com
push dateThu, 29 Oct 2015 10:49:48 +0000
treeherdermozilla-central@67a788db9f07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1215092
milestone44.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 1215092 - WebSocketEventService and WebSocket discovering - part 2 - Unique Serial number for WebSocketChannel in IPC, r=michal
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.h
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelParent.cpp
netwerk/protocol/websocket/WebSocketChannelParent.h
netwerk/protocol/websocket/nsIWebSocketChannel.idl
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -140,17 +140,18 @@ NeckoChild::DeallocPWyciwygChannelChild(
 
   WyciwygChannelChild *p = static_cast<WyciwygChannelChild*>(channel);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PWebSocketChild*
 NeckoChild::AllocPWebSocketChild(const PBrowserOrId& browser,
-                                 const SerializedLoadContext& aSerialized)
+                                 const SerializedLoadContext& aSerialized,
+                                 const uint32_t& aSerial)
 {
   NS_NOTREACHED("AllocPWebSocketChild should not be called");
   return nullptr;
 }
 
 bool
 NeckoChild::DeallocPWebSocketChild(PWebSocketChild* child)
 {
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -35,17 +35,18 @@ protected:
   virtual bool DeallocPWyciwygChannelChild(PWyciwygChannelChild*) override;
   virtual PFTPChannelChild*
     AllocPFTPChannelChild(const PBrowserOrId& aBrowser,
                           const SerializedLoadContext& aSerialized,
                           const FTPChannelCreationArgs& aOpenArgs) override;
   virtual bool DeallocPFTPChannelChild(PFTPChannelChild*) override;
   virtual PWebSocketChild*
     AllocPWebSocketChild(const PBrowserOrId&,
-                         const SerializedLoadContext&) override;
+                         const SerializedLoadContext&,
+                         const uint32_t&) override;
   virtual bool DeallocPWebSocketChild(PWebSocketChild*) override;
   virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& host,
                                                 const uint16_t& port) override;
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*) override;
   virtual PTCPServerSocketChild*
     AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                const uint16_t& aBacklog,
                                const bool& aUseArrayBuffers) override;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -315,32 +315,34 @@ NeckoParent::DeallocPWyciwygChannelParen
 {
   WyciwygChannelParent *p = static_cast<WyciwygChannelParent *>(channel);
   p->Release();
   return true;
 }
 
 PWebSocketParent*
 NeckoParent::AllocPWebSocketParent(const PBrowserOrId& browser,
-                                   const SerializedLoadContext& serialized)
+                                   const SerializedLoadContext& serialized,
+                                   const uint32_t& aSerial)
 {
   nsCOMPtr<nsILoadContext> loadContext;
   const char *error = CreateChannelLoadContext(browser, Manager(),
                                                serialized, loadContext);
   if (error) {
     printf_stderr("NeckoParent::AllocPWebSocketParent: "
                   "FATAL error: %s: KILLING CHILD PROCESS\n",
                   error);
     return nullptr;
   }
 
   RefPtr<TabParent> tabParent = TabParent::GetFrom(browser.get_PBrowserParent());
   PBOverrideStatus overrideStatus = PBOverrideStatusFromLoadContext(serialized);
   WebSocketChannelParent* p = new WebSocketChannelParent(tabParent, loadContext,
-                                                         overrideStatus);
+                                                         overrideStatus,
+                                                         aSerial);
   p->AddRef();
   return p;
 }
 
 bool
 NeckoParent::DeallocPWebSocketParent(PWebSocketParent* actor)
 {
   WebSocketChannelParent* p = static_cast<WebSocketChannelParent*>(actor);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -119,17 +119,18 @@ protected:
     RecvPFTPChannelConstructor(
                       PFTPChannelParent* aActor,
                       const PBrowserOrId& aBrowser,
                       const SerializedLoadContext& aSerialized,
                       const FTPChannelCreationArgs& aOpenArgs) override;
   virtual bool DeallocPFTPChannelParent(PFTPChannelParent*) override;
   virtual PWebSocketParent*
     AllocPWebSocketParent(const PBrowserOrId& browser,
-                          const SerializedLoadContext& aSerialized) override;
+                          const SerializedLoadContext& aSerialized,
+                          const uint32_t& aSerial) override;
   virtual bool DeallocPWebSocketParent(PWebSocketParent*) override;
   virtual PTCPSocketParent* AllocPTCPSocketParent(const nsString& host,
                                                   const uint16_t& port) override;
 
   virtual PRemoteOpenFileParent*
     AllocPRemoteOpenFileParent(const SerializedLoadContext& aSerialized,
                                const URIParams& aFileURI,
                                const OptionalURIParams& aAppURI) override;
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -63,17 +63,18 @@ parent:
   prio(urgent) async PCookieService();
   PHttpChannel(PBrowserOrId browser,
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowserOrId browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
-  PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext);
+  PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext,
+             uint32_t aSerialID);
   PTCPServerSocket(uint16_t localPort, uint16_t backlog, bool useArrayBuffers);
   PUDPSocket(Principal principal, nsCString filter);
 
   PDNSRequest(nsCString hostName, uint32_t flags, nsCString networkInterface);
 
   PWebSocketEventListener(uint64_t aInnerWindowID);
 
   /* Predictor Methods */
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -9,33 +9,64 @@
 #include "MainThreadUtils.h"
 #include "nsILoadGroup.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsAutoPtr.h"
 #include "nsProxyRelease.h"
 #include "nsStandardURL.h"
 #include "LoadInfo.h"
 #include "nsIDOMNode.h"
+#include "mozilla/dom/ContentChild.h"
+
+using mozilla::dom::ContentChild;
 
 PRLogModuleInfo *webSocketLog = nullptr;
 
 namespace mozilla {
 namespace net {
 
+static uint64_t gNextWebSocketID = 0;
+
+// We use only 53 bits for the WebSocket serial ID so that it can be converted
+// to and from a JS value without loss of precision. The upper bits of the
+// WebSocket serial ID hold the process ID. The lower bits identify the
+// WebSocket.
+static const uint64_t kWebSocketIDTotalBits = 53;
+static const uint64_t kWebSocketIDProcessBits = 22;
+static const uint64_t kWebSocketIDWebSocketBits = kWebSocketIDTotalBits - kWebSocketIDProcessBits;
+
 BaseWebSocketChannel::BaseWebSocketChannel()
   : mWasOpened(0)
   , mClientSetPingInterval(0)
   , mClientSetPingTimeout(0)
   , mEncrypted(0)
   , mPingForced(0)
   , mPingInterval(0)
   , mPingResponseTimeout(10000)
 {
   if (!webSocketLog)
     webSocketLog = PR_NewLogModule("nsWebSocket");
+
+  // Generation of a unique serial ID.
+  uint64_t processID = 0;
+  if (XRE_IsContentProcess()) {
+    ContentChild* cc = ContentChild::GetSingleton();
+    processID = cc->GetID();
+  }
+
+  uint64_t processBits = processID & ((uint64_t(1) << kWebSocketIDProcessBits) - 1);
+
+  // Make sure no actual webSocket ends up with mWebSocketID == 0 but less then
+  // what the kWebSocketIDProcessBits allows.
+  if (++gNextWebSocketID >= (uint64_t(1) << kWebSocketIDWebSocketBits)) {
+    gNextWebSocketID = 1;
+  }
+
+  uint64_t webSocketBits = gNextWebSocketID & ((uint64_t(1) << kWebSocketIDWebSocketBits) - 1);
+  mSerial = (processBits << kWebSocketIDWebSocketBits) | webSocketBits;
 }
 
 //-----------------------------------------------------------------------------
 // BaseWebSocketChannel::nsIWebSocketChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 BaseWebSocketChannel::GetOriginalURI(nsIURI **aOriginalURI)
@@ -192,16 +223,34 @@ BaseWebSocketChannel::InitLoadInfo(nsIDO
                                    uint32_t aContentPolicyType)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aLoadingNode);
   mLoadInfo = new LoadInfo(aLoadingPrincipal, aTriggeringPrincipal,
                            node, aSecurityFlags, aContentPolicyType);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+BaseWebSocketChannel::GetSerial(uint32_t* aSerial)
+{
+  if (!aSerial) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aSerial = mSerial;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BaseWebSocketChannel::SetSerial(uint32_t aSerial)
+{
+  mSerial = aSerial;
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // BaseWebSocketChannel::nsIProtocolHandler
 //-----------------------------------------------------------------------------
 
 
 NS_IMETHODIMP
 BaseWebSocketChannel::GetScheme(nsACString &aScheme)
 {
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.h
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h
@@ -50,16 +50,18 @@ class BaseWebSocketChannel : public nsIW
   NS_IMETHOD SetProtocol(const nsACString &aProtocol) override;
   NS_IMETHOD GetPingInterval(uint32_t *aSeconds) override;
   NS_IMETHOD SetPingInterval(uint32_t aSeconds) override;
   NS_IMETHOD GetPingTimeout(uint32_t *aSeconds) override;
   NS_IMETHOD SetPingTimeout(uint32_t aSeconds) override;
   NS_IMETHOD InitLoadInfo(nsIDOMNode* aLoadingNode, nsIPrincipal* aLoadingPrincipal,
                           nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags,
                           uint32_t aContentPolicyType) override;
+  NS_IMETHOD GetSerial(uint32_t* aSerial) override;
+  NS_IMETHOD SetSerial(uint32_t aSerial) override;
 
   // Off main thread URI access.
   virtual void GetEffectiveURL(nsAString& aEffectiveURL) const = 0;
   virtual bool IsEncrypted() const = 0;
 
   class ListenerAndContextContainer final
   {
   public:
@@ -93,14 +95,16 @@ class BaseWebSocketChannel : public nsIW
   uint32_t                        mClientSetPingInterval     : 1;
   uint32_t                        mClientSetPingTimeout      : 1;
 
   Atomic<bool>                    mEncrypted;
   bool                            mPingForced;
 
   uint32_t                        mPingInterval;         /* milliseconds */
   uint32_t                        mPingResponseTimeout;  /* milliseconds */
+
+  uint32_t                        mSerial;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_BaseWebSocketChannel_h
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -1133,18 +1133,16 @@ private:
 };
 NS_IMPL_ISUPPORTS(OutboundEnqueuer, nsIRunnable)
 
 
 //-----------------------------------------------------------------------------
 // WebSocketChannel
 //-----------------------------------------------------------------------------
 
-uint32_t WebSocketChannel::sSerialSeed = 0;
-
 WebSocketChannel::WebSocketChannel() :
   mPort(0),
   mCloseTimeout(20000),
   mOpenTimeout(20000),
   mConnecting(NOT_CONNECTING),
   mMaxConcurrentConnections(200),
   mGotUpgradeOK(0),
   mRecvdHttpUpgradeTransport(0),
@@ -1189,18 +1187,16 @@ WebSocketChannel::WebSocketChannel() :
 
   mFramePtr = mBuffer = static_cast<uint8_t *>(moz_xmalloc(mBufferSize));
 
   nsresult rv;
   mConnectionLogService = do_GetService("@mozilla.org/network/dashboard;1",&rv);
   if (NS_FAILED(rv))
     LOG(("Failed to initiate dashboard service."));
 
-  mSerial = sSerialSeed++;
-
   mService = WebSocketEventService::GetOrCreate();
 }
 
 WebSocketChannel::~WebSocketChannel()
 {
   LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this));
 
   if (mWasOpened) {
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -289,18 +289,16 @@ private:
   uint8_t                        *mHdrOut;
   uint8_t                         mOutHeader[kCopyBreak + 16];
   nsAutoPtr<PMCECompression>      mPMCECompressor;
   uint32_t                        mDynamicOutputSize;
   uint8_t                        *mDynamicOutput;
   bool                            mPrivateBrowsing;
 
   nsCOMPtr<nsIDashboardEventNotifier> mConnectionLogService;
-  uint32_t mSerial;
-  static uint32_t sSerialSeed;
 
 // These members are used for network per-app metering (bug 855949)
 // Currently, they are only available on gonk.
   Atomic<uint64_t, Relaxed>       mCountRecv;
   Atomic<uint64_t, Relaxed>       mCountSent;
   uint32_t                        mAppId;
   bool                            mIsInBrowser;
 #ifdef MOZ_WIDGET_GONK
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -484,17 +484,18 @@ WebSocketChannelChild::AsyncOpen(nsIURI 
   // Corresponding release in DeallocPWebSocket
   AddIPDLReference();
 
   OptionalLoadInfoArgs loadInfoArgs;
   nsresult rv = LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs);
   NS_ENSURE_SUCCESS(rv, rv);
 
   gNeckoChild->SendPWebSocketConstructor(this, tabChild,
-                                         IPC::SerializedLoadContext(this));
+                                         IPC::SerializedLoadContext(this),
+                                         mSerial);
   if (!SendAsyncOpen(uri, nsCString(aOrigin), aInnerWindowID, mProtocol,
                      mEncrypted, mPingInterval, mClientSetPingInterval,
                      mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   mOriginalURI = aURI;
   mURI = mOriginalURI;
--- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp
@@ -21,20 +21,22 @@ namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS(WebSocketChannelParent,
                   nsIWebSocketListener,
                   nsIInterfaceRequestor)
 
 WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider,
                                                nsILoadContext* aLoadContext,
-                                               PBOverrideStatus aOverrideStatus)
+                                               PBOverrideStatus aOverrideStatus,
+                                               uint32_t aSerial)
   : mAuthProvider(aAuthProvider)
   , mLoadContext(aLoadContext)
   , mIPCOpen(true)
+  , mSerial(aSerial)
 {
   // Websocket channels can't have a private browsing override
   MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset);
   if (!webSocketLog)
     webSocketLog = PR_NewLogModule("nsWebSocket");
   mObserver = new OfflineObserver(this);
 }
 
@@ -90,16 +92,21 @@ WebSocketChannelParent::RecvAsyncOpen(co
       do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
   } else {
     mChannel =
       do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
   }
   if (NS_FAILED(rv))
     goto fail;
 
+  rv = mChannel->SetSerial(mSerial);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    goto fail;
+  }
+
   rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo));
   if (NS_FAILED(rv))
     goto fail;
 
   rv = mChannel->SetLoadInfo(loadInfo);
   if (NS_FAILED(rv)) {
     goto fail;
   }
--- a/netwerk/protocol/websocket/WebSocketChannelParent.h
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.h
@@ -30,17 +30,18 @@ class WebSocketChannelParent : public PW
   ~WebSocketChannelParent();
  public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIWEBSOCKETLISTENER
   NS_DECL_NSIINTERFACEREQUESTOR
 
   WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider,
                          nsILoadContext* aLoadContext,
-                         PBOverrideStatus aOverrideStatus);
+                         PBOverrideStatus aOverrideStatus,
+                         uint32_t aSerial);
 
  private:
   bool RecvAsyncOpen(const URIParams& aURI,
                      const nsCString& aOrigin,
                      const uint64_t& aInnerWindowID,
                      const nsCString& aProtocol,
                      const bool& aSecure,
                      const uint32_t& aPingInterval,
@@ -61,14 +62,15 @@ class WebSocketChannelParent : public PW
   uint32_t GetAppId() override;
   RefPtr<OfflineObserver> mObserver;
 
   nsCOMPtr<nsIAuthPromptProvider> mAuthProvider;
   nsCOMPtr<nsIWebSocketChannel> mChannel;
   nsCOMPtr<nsILoadContext> mLoadContext;
   bool mIPCOpen;
 
+  uint32_t mSerial;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WebSocketChannelParent_h
--- a/netwerk/protocol/websocket/nsIWebSocketChannel.idl
+++ b/netwerk/protocol/websocket/nsIWebSocketChannel.idl
@@ -17,17 +17,17 @@ interface nsIPrincipal;
 
 /**
  * Low-level websocket API: handles network protocol.  
  *
  * This is primarly intended for use by the higher-level nsIWebSocket.idl.
  * We are also making it scriptable for now, but this may change once we have
  * WebSockets for Workers.
  */
-[scriptable, uuid(352e0c08-f14c-40c8-ad06-2f8bb5d9d9e0)]
+[scriptable, uuid(1bfc252b-ad46-413c-860b-2079bf1399c7)]
 interface nsIWebSocketChannel : nsISupports
 {
     /**
      * The original URI used to construct the protocol connection. This is used
      * in the case of a redirect or URI "resolution" (e.g. resolving a
      * resource: URI to a file: URI) so that the original pre-redirect
      * URI can still be obtained.  This is never null.
      */
@@ -218,9 +218,14 @@ interface nsIWebSocketChannel : nsISuppo
      * the server to reply to a ping that has been sent before considering the
      * connection broken.
      *
      * This value can currently only be set before asyncOpen is called, else 
      * NS_ERROR_IN_PROGRESS is thrown.
      */
     attribute unsigned long pingTimeout;
 
+    /**
+     * Unique ID for this channel. It's not readonly because when the channel is
+     * created via IPC, the serial number is received from the child process.
+     */
+    attribute unsigned long serial;
 };