Bug 1217677: increase UDP socket receive buffer for <= Win7. r=jesup
MozReview-Commit-ID: A3yCZZ3Pwcu
--- 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)
{