Bug 1217677: increase UDP socket receive buffer for <= Win7. r=jesup,mcmanus
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Tue, 01 Mar 2016 21:46:50 -0800
changeset 323208 bca82ee20a78bcb93c0ae72885e461ded33fbcb0
parent 323207 d2e86ab855bd0b14f381e4505627310c915dd79c
child 323209 2a06c1a146e16a369ab3648e184d9e3311362395
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, mcmanus
bugs1217677
milestone47.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 1217677: increase UDP socket receive buffer for <= Win7. r=jesup,mcmanus MozReview-Commit-ID: A3yCZZ3Pwcu
dom/network/PUDPSocket.ipdl
dom/network/UDPSocket.cpp
dom/network/UDPSocketChild.cpp
dom/network/UDPSocketParent.cpp
dom/network/UDPSocketParent.h
dom/network/interfaces/nsIUDPSocketChild.idl
media/mtransport/nr_socket_prsock.cpp
netwerk/base/nsIUDPSocket.idl
netwerk/base/nsUDPSocket.cpp
--- a/dom/network/PUDPSocket.ipdl
+++ b/dom/network/PUDPSocket.ipdl
@@ -36,17 +36,17 @@ namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PUDPSocket
 {
   manager PNecko or PBackground;
 
 parent:
-  async Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
+  async Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback, uint32_t recvBufferSize);
   async Connect(UDPAddressInfo addressInfo);
 
   async OutgoingData(UDPData data, UDPSocketAddr addr);
 
   async JoinMulticast(nsCString multicastAddress, nsCString iface);
   async LeaveMulticast(nsCString multicastAddress, nsCString iface);
 
   async Close();
--- a/dom/network/UDPSocket.cpp
+++ b/dom/network/UDPSocket.cpp
@@ -498,17 +498,18 @@ UDPSocket::InitRemote(const nsAString& a
     return NS_ERROR_FAILURE;
   }
 
   rv = sock->Bind(mListenerProxy,
                   principal,
                   NS_ConvertUTF16toUTF8(aLocalAddress),
                   aLocalPort,
                   mAddressReuse,
-                  mLoopback);
+                  mLoopback,
+                  0);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mSocketChild = sock;
 
   return NS_OK;
--- a/dom/network/UDPSocketChild.cpp
+++ b/dom/network/UDPSocketChild.cpp
@@ -166,17 +166,18 @@ UDPSocketChild::SetBackgroundSpinsEvents
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
                      nsIPrincipal* aPrincipal,
                      const nsACString& aHost,
                      uint16_t aPort,
                      bool aAddressReuse,
-                     bool aLoopback)
+                     bool aLoopback,
+                     uint32_t recvBufferSize)
 {
   UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
 
   NS_ENSURE_ARG(aSocket);
 
   mSocket = aSocket;
   AddIPDLReference();
 
@@ -185,17 +186,17 @@ UDPSocketChild::Bind(nsIUDPSocketInterna
     // convert it to a PrincipalInfo
     MOZ_ASSERT(!aPrincipal);
     mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName);
   } else {
     gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
                                            mFilterName);
   }
 
-  SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
+  SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback, recvBufferSize);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Connect(nsIUDPSocketInternal* aSocket, const nsACString & aHost, uint16_t aPort)
 {
   UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
 
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -156,21 +156,22 @@ UDPSocketParent::Init(const IPC::Princip
   }
   return true;
 }
 
 // PUDPSocketParent methods
 
 bool
 UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
-                          const bool& aAddressReuse, const bool& aLoopback)
+                          const bool& aAddressReuse, const bool& aLoopback,
+                          const uint32_t& recvBufferSize)
 {
   UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
 
-  if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
+  if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback, recvBufferSize))) {
     FireInternalError(__LINE__);
     return true;
   }
 
   nsCOMPtr<nsINetAddr> localAddr;
   mSocket->GetLocalAddr(getter_AddRefs(localAddr));
 
   nsCString addr;
@@ -188,21 +189,22 @@ UDPSocketParent::RecvBind(const UDPAddre
   UDPSOCKET_LOG(("%s: SendCallbackOpened: %s:%u", __FUNCTION__, addr.get(), port));
   mozilla::Unused << SendCallbackOpened(UDPAddressInfo(addr, port));
 
   return true;
 }
 
 nsresult
 UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
-                              const bool& aAddressReuse, const bool& aLoopback)
+                              const bool& aAddressReuse, const bool& aLoopback,
+                              const uint32_t& recvBufferSize)
 {
   nsresult rv;
 
-  UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d", __FUNCTION__, this, nsCString(aHost).get(), aPort, aAddressReuse, aLoopback));
+  UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d recvBufferSize: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, aAddressReuse, aLoopback, recvBufferSize));
 
   nsCOMPtr<nsIUDPSocket> sock =
       do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -238,16 +240,22 @@ UDPSocketParent::BindInternal(const nsCS
     return rv;
   }
   if (family == nsINetAddr::FAMILY_INET) {
     rv = sock->SetMulticastLoopback(aLoopback);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
+  if (recvBufferSize != 0) {
+    rv = sock->SetRecvBufferSize(recvBufferSize);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set recv buffer size to: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, recvBufferSize));
+    }
+  }
 
   // register listener
   rv = sock->AsyncListen(this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   mSocket = sock;
--- a/dom/network/UDPSocketParent.h
+++ b/dom/network/UDPSocketParent.h
@@ -30,17 +30,18 @@ public:
   NS_DECL_NSIUDPSOCKETLISTENER
 
   explicit UDPSocketParent(PBackgroundParent* aManager);
   explicit UDPSocketParent(PNeckoParent* aManager);
 
   bool Init(const IPC::Principal& aPrincipal, const nsACString& aFilter);
 
   virtual bool RecvBind(const UDPAddressInfo& aAddressInfo,
-                        const bool& aAddressReuse, const bool& aLoopback) override;
+                        const bool& aAddressReuse, const bool& aLoopback,
+                        const uint32_t& recvBufferSize) override;
   virtual bool RecvConnect(const UDPAddressInfo& aAddressInfo) override;
   void DoSendConnectResponse(const UDPAddressInfo& aAddressInfo);
   void SendConnectResponse(nsIEventTarget *aThread,
                            const UDPAddressInfo& aAddressInfo);
   void DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
                  nsCOMPtr<nsIEventTarget>& aReturnThread,
                  const UDPAddressInfo& aAddressInfo);
 
@@ -57,17 +58,18 @@ public:
 
 private:
   virtual ~UDPSocketParent();
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
   void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
   void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
   nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
-                        const bool& aAddressReuse, const bool& aLoopback);
+                        const bool& aAddressReuse, const bool& aLoopback,
+                        const uint32_t& recvBufferSize);
   nsresult ConnectInternal(const nsCString& aHost, const uint16_t& aPort);
   void FireInternalError(uint32_t aLineNo);
   void SendInternalError(nsIEventTarget *aThread,
                          uint32_t aLineNo);
 
   // One of these will be null and the other non-null.
   PBackgroundParent* mBackgroundManager;
   PNeckoParent* mNeckoManager;
--- a/dom/network/interfaces/nsIUDPSocketChild.idl
+++ b/dom/network/interfaces/nsIUDPSocketChild.idl
@@ -27,17 +27,17 @@ interface nsIUDPSocketChild : nsISupport
   attribute AUTF8String filterName;
 
   // Allow hosting this over PBackground instead of PNecko
   [noscript] void setBackgroundSpinsEvents();
 
   // Tell the chrome process to bind the UDP socket to a given local host and port
   void bind(in nsIUDPSocketInternal socket, in nsIPrincipal principal,
             in AUTF8String host, in unsigned short port,
-            in bool addressReuse, in bool loopback);
+            in bool addressReuse, in bool loopback, in uint32_t recvBufferSize);
 
   // Tell the chrome process to connect the UDP socket to a given remote host and port
   void connect(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
 
   // Tell the chrome process to perform equivalent operations to all following methods
   void send(in AUTF8String host, in unsigned short port,
             [const, array, size_is(byteLength)] in uint8_t bytes,
             in unsigned long byteLength);
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -109,16 +109,20 @@ nrappkit copyright:
 #include "runnable_utils.h"
 #include "mozilla/SyncRunnable.h"
 #include "nsTArray.h"
 #include "mozilla/dom/TCPSocketBinding.h"
 #include "nsITCPSocketCallback.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
+#ifdef XP_WIN
+#include "mozilla/WindowsVersion.h"
+#endif
+
 #if defined(MOZILLA_INTERNAL_API)
 // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING
 #ifdef LOG_INFO
 #define LOG_TEMP_INFO LOG_INFO
 #undef LOG_INFO
 #endif
 #ifdef LOG_WARNING
 #define LOG_TEMP_WARNING LOG_WARNING
@@ -595,16 +599,35 @@ int NrSocket::create(nr_transport_addr *
 
   switch (addr->protocol) {
     case IPPROTO_UDP:
       if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
               "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
+#ifdef XP_WIN
+      if (!mozilla::IsWin8OrLater()) {
+        PRSocketOptionData opt_rcvbuf;
+        opt_rcvbuf.option = PR_SockOpt_RecvBufferSize;
+        // Increase default receive buffer size on <= Win7 to be able to
+        // receive an unpaced HD (>= 720p = 1280x720 - I Frame ~ 21K size)
+        // stream without losing packets.
+        // Manual testing showed that 100K buffer size was not enough and the
+        // packet loss dis-appeared with 256K buffer size.
+        // See bug 1252769 for future improvements of this.
+        opt_rcvbuf.value.recv_buffer_size = 256 * 1024;
+        status = PR_SetSocketOption(fd_, &opt_rcvbuf);
+        if (status != PR_SUCCESS) {
+          r_log(LOG_GENERIC, LOG_CRIT,
+            "Couldn't set receive buffer size socket option: %d", status);
+          ABORT(R_INTERNAL);
+        }
+      }
+#endif
       break;
     case IPPROTO_TCP:
       if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
         r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
               "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       // Set ReuseAddr for TCP sockets to enable having several
@@ -1452,16 +1475,17 @@ int NrUdpSocketIpc::accept(nr_transport_
   MOZ_ASSERT(false);
   return R_INTERNAL;
 }
 
 // IO thread executors
 void NrUdpSocketIpc::create_i(const nsACString &host, const uint16_t port) {
   ASSERT_ON_THREAD(io_thread_);
 
+  uint32_t recvBuffSize = 0;
   nsresult rv;
   nsCOMPtr<nsIUDPSocketChild> socketChild = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
   if (NS_FAILED(rv)) {
     ReentrantMonitorAutoEnter mon(monitor_);
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDPSocketChild");
     return;
   }
@@ -1480,20 +1504,32 @@ void NrUdpSocketIpc::create_i(const nsAC
   RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
   rv = proxy->Init(this);
   if (NS_FAILED(rv)) {
     err_ = true;
     mon.NotifyAll();
     return;
   }
 
+#ifdef XP_WIN
+  if (!mozilla::IsWin8OrLater()) {
+    // Increase default receive buffer size on <= Win7 to be able to
+    // receive an unpaced HD (>= 720p = 1280x720 - I Frame ~ 21K size)
+    // stream without losing packets.
+    // Manual testing showed that 100K buffer size was not enough and the
+    // packet loss dis-appeared with 256K buffer size.
+    // See bug 1252769 for future improvements of this.
+    recvBuffSize = 256 * 1024;
+  }
+#endif
   // XXX bug 1126232 - don't use null Principal!
   if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port,
                                     /* reuse = */ false,
-                                    /* loopback = */ false))) {
+                                    /* loopback = */ false,
+                                    /* recv buffer size */ recvBuffSize))) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDP socket");
     mon.NotifyAll();
     return;
   }
 }
 
 void NrUdpSocketIpc::connect_i(const nsACString &host, const uint16_t port) {
--- a/netwerk/base/nsIUDPSocket.idl
+++ b/netwerk/base/nsIUDPSocket.idl
@@ -254,16 +254,23 @@ interface nsIUDPSocket : nsISupports
 
     /**
      * multicastInterfaceAddr
      *
      * The interface that should be used for sending future multicast datagrams.
      * Note: This is currently write-only.
      */
     [noscript] attribute NetAddr multicastInterfaceAddr;
+
+    /**
+     * recvBufferSize
+     *
+     * The size of the receive buffer. Default depends on the OS.
+     */
+    [noscript] attribute long recvBufferSize;
 };
 
 /**
  * nsIUDPSocketListener
  *
  * This interface is notified whenever a UDP socket accepts a new connection.
  * The transport is in the connected state, and read/write streams can be opened
  * using the normal nsITransport API.  The address of the client can be found by
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -1470,16 +1470,43 @@ nsUDPSocket::SetMulticastLoopback(bool a
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsUDPSocket::GetRecvBufferSize(int* size)
+{
+  // Bug 1252759 - missing support for GetSocketOption
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsUDPSocket::SetRecvBufferSize(int size)
+{
+  if (NS_WARN_IF(!mFD)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  PRSocketOptionData opt;
+
+  opt.option = PR_SockOpt_RecvBufferSize;
+  opt.value.recv_buffer_size = size;
+
+  nsresult rv = SetSocketOption(opt);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsUDPSocket::GetMulticastInterface(nsACString& aIface)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsUDPSocket::GetMulticastInterfaceAddr(NetAddr* aIface)
 {