Bug 1266667: socket reuse option for TCPSocket. r?mcmanus
MozReview-Commit-ID: CJEK714ruLl
--- a/dom/network/PTCPSocket.ipdl
+++ b/dom/network/PTCPSocket.ipdl
@@ -40,17 +40,18 @@ parent:
// is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
// |binaryType| (from TCPOption.binaryType).
async Open(nsString host, uint16_t port, bool useSSL, bool useArrayBuffers);
// Ask parent to open a socket and bind the newly-opened socket to a local
// address specified in |localAddr| and |localPort|.
async OpenBind(nsCString host, uint16_t port,
nsCString localAddr, uint16_t localPort,
- bool useSSL, bool aUseArrayBuffers, nsCString aFilter);
+ bool useSSL, bool reuseAddrPort,
+ bool aUseArrayBuffers, nsCString aFilter);
// When child's send() is called, this message requrests parent to send
// data and update it's trackingNumber.
async Data(SendableData data, uint32_t trackingNumber);
// Forward calling to child's upgradeToSecure() method to parent.
async StartTLS();
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -105,26 +105,27 @@ TCPSocketChild::SendOpen(nsITCPSocketCal
MOZ_ASSERT(mFilterName.IsEmpty()); // Currently nobody should use this
PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers);
}
void
TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort,
- bool aUseSSL)
+ bool aUseSSL, bool aReuseAddrPort)
{
mSocket = aSocket;
AddIPDLReference();
gNeckoChild->SendPTCPSocketConstructor(this,
NS_ConvertUTF8toUTF16(aRemoteHost),
aRemotePort);
PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort,
nsCString(aLocalHost), aLocalPort,
- aUseSSL, true, mFilterName);
+ aUseSSL, aReuseAddrPort,
+ true, mFilterName);
}
void
TCPSocketChildBase::ReleaseIPDLReference()
{
MOZ_ASSERT(mIPCOpen);
mIPCOpen = false;
mSocket = nullptr;
--- a/dom/network/TCPSocketChild.h
+++ b/dom/network/TCPSocketChild.h
@@ -51,17 +51,17 @@ public:
TCPSocketChild(const nsAString& aHost, const uint16_t& aPort);
~TCPSocketChild();
void SendOpen(nsITCPSocketCallback* aSocket, bool aUseSSL, bool aUseArrayBuffers);
void SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
const nsACString& aRemoteHost, uint16_t aRemotePort,
const nsACString& aLocalHost, uint16_t aLocalPort,
- bool aUseSSL);
+ bool aUseSSL, bool aUseRealtimeOptions);
NS_IMETHOD SendSendArray(nsTArray<uint8_t>& aArray,
uint32_t aTrackingNumber);
void SendSend(const nsACString& aData, uint32_t aTrackingNumber);
nsresult SendSend(const ArrayBuffer& aData,
uint32_t aByteOffset,
uint32_t aByteLength,
uint32_t aTrackingNumber);
void SendSendArray(nsTArray<uint8_t>* arr,
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -129,16 +129,17 @@ TCPSocketParent::RecvOpen(const nsString
}
mozilla::ipc::IPCResult
TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
const uint16_t& aRemotePort,
const nsCString& aLocalAddr,
const uint16_t& aLocalPort,
const bool& aUseSSL,
+ const bool& aReuseAddrPort,
const bool& aUseArrayBuffers,
const nsCString& aFilter)
{
nsresult rv;
nsCOMPtr<nsISocketTransportService> sts =
do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__);
@@ -149,16 +150,20 @@ TCPSocketParent::RecvOpenBind(const nsCS
rv = sts->CreateTransport(nullptr, 0,
aRemoteHost, aRemotePort,
nullptr, getter_AddRefs(socketTransport));
if (NS_FAILED(rv)) {
FireInteralError(this, __LINE__);
return IPC_OK();
}
+ // in most cases aReuseAddrPort is false, but ICE TCP needs
+ // sockets options set that allow addr/port reuse
+ socketTransport->SetReuseAddrPort(aReuseAddrPort);
+
PRNetAddr prAddr;
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) {
FireInteralError(this, __LINE__);
return IPC_OK();
}
if (PR_SUCCESS != PR_StringToNetAddr(aLocalAddr.BeginReading(), &prAddr)) {
FireInteralError(this, __LINE__);
return IPC_OK();
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -50,16 +50,17 @@ public:
virtual mozilla::ipc::IPCResult RecvOpen(const nsString& aHost, const uint16_t& aPort,
const bool& useSSL, const bool& aUseArrayBuffers) override;
virtual mozilla::ipc::IPCResult RecvOpenBind(const nsCString& aRemoteHost,
const uint16_t& aRemotePort,
const nsCString& aLocalAddr,
const uint16_t& aLocalPort,
const bool& aUseSSL,
+ const bool& aReuseAddrPort,
const bool& aUseArrayBuffers,
const nsCString& aFilter) override;
virtual mozilla::ipc::IPCResult RecvStartTLS() override;
virtual mozilla::ipc::IPCResult RecvSuspend() override;
virtual mozilla::ipc::IPCResult RecvResume() override;
virtual mozilla::ipc::IPCResult RecvClose() override;
virtual mozilla::ipc::IPCResult RecvData(const SendableData& aData,
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -1963,17 +1963,18 @@ void NrTcpSocketIpc::connect_i(const nsA
socket_child_ = child;
// Bug 1285330: put filtering back in here
// XXX remove remote!
socket_child_->SendWindowlessOpenBind(this,
remote_addr, remote_port,
local_addr, local_port,
- /* use ssl */ false);
+ /* use ssl */ false,
+ /* reuse addr port */ true);
}
void NrTcpSocketIpc::write_i(nsAutoPtr<InfallibleTArray<uint8_t>> arr,
uint32_t tracking_number) {
ASSERT_ON_THREAD(io_thread_);
if (!socket_child_) {
return;
}
--- a/netwerk/base/nsISocketTransport.idl
+++ b/netwerk/base/nsISocketTransport.idl
@@ -125,16 +125,21 @@ interface nsISocketTransport : nsITransp
* Socket timeouts in seconds. To specify no timeout, pass UINT32_MAX
* as aValue to setTimeout. The implementation may truncate timeout values
* to a smaller range of values (e.g., 0 to 0xFFFF).
*/
unsigned long getTimeout(in unsigned long aType);
void setTimeout(in unsigned long aType, in unsigned long aValue);
/**
+ * True to set addr and port reuse socket options.
+ */
+ void setReuseAddrPort(in bool reuseAddrPort);
+
+ /**
* Values for the aType parameter passed to get/setTimeout.
*/
const unsigned long TIMEOUT_CONNECT = 0;
const unsigned long TIMEOUT_READ_WRITE = 1;
/**
* nsITransportEventSink status codes.
*
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -735,16 +735,17 @@ nsSocketTransport::nsSocketTransport()
, mTypeCount(0)
, mPort(0)
, mProxyPort(0)
, mOriginPort(0)
, mProxyTransparent(false)
, mProxyTransparentResolvesHost(false)
, mHttpsProxy(false)
, mConnectionFlags(0)
+ , mReuseAddrPort(false)
, mState(STATE_CLOSED)
, mAttached(false)
, mInputClosed(true)
, mOutputClosed(true)
, mResolving(false)
, mNetAddrIsSet(false)
, mSelfAddrIsSet(false)
, mNetAddrPreResolved(false)
@@ -1349,16 +1350,42 @@ nsSocketTransport::InitiateSocket()
// Make the socket non-blocking...
PRSocketOptionData opt;
opt.option = PR_SockOpt_Nonblocking;
opt.value.non_blocking = true;
status = PR_SetSocketOption(fd, &opt);
NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
+ if (mReuseAddrPort) {
+ SOCKET_LOG((" Setting port/addr reuse socket options\n"));
+
+ // Set ReuseAddr for TCP sockets to enable having several
+ // sockets bound to same local IP and port
+ PRSocketOptionData opt_reuseaddr;
+ opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
+ opt_reuseaddr.value.reuse_addr = PR_TRUE;
+ status = PR_SetSocketOption(fd, &opt_reuseaddr);
+ if (status != PR_SUCCESS) {
+ SOCKET_LOG((" Couldn't set reuse addr socket option: %d\n",
+ status));
+ }
+
+ // And also set ReusePort for platforms supporting this socket option
+ PRSocketOptionData opt_reuseport;
+ opt_reuseport.option = PR_SockOpt_Reuseport;
+ opt_reuseport.value.reuse_port = PR_TRUE;
+ status = PR_SetSocketOption(fd, &opt_reuseport);
+ if (status != PR_SUCCESS
+ && PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
+ SOCKET_LOG((" Couldn't set reuse port socket option: %d\n",
+ status));
+ }
+ }
+
// disable the nagle algorithm - if we rely on it to coalesce writes into
// full packets the final packet of a multi segment POST/PUT or pipeline
// sequence is delayed a full rtt
opt.option = PR_SockOpt_NoDelay;
opt.value.no_delay = true;
PR_SetSocketOption(fd, &opt);
// if the network.tcp.sendbuffer preference is set, use it to size SO_SNDBUF
@@ -2534,16 +2561,23 @@ nsSocketTransport::SetTimeout(uint32_t t
NS_ENSURE_ARG_MAX(type, nsISocketTransport::TIMEOUT_READ_WRITE);
// truncate overly large timeout values.
mTimeouts[type] = (uint16_t) std::min<uint32_t>(value, UINT16_MAX);
PostEvent(MSG_TIMEOUT_CHANGED);
return NS_OK;
}
NS_IMETHODIMP
+nsSocketTransport::SetReuseAddrPort(bool reuseAddrPort)
+{
+ mReuseAddrPort = reuseAddrPort;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsSocketTransport::SetQoSBits(uint8_t aQoSBits)
{
// Don't do any checking here of bits. Why? Because as of RFC-4594
// several different Class Selector and Assured Forwarding values
// have been defined, but that isn't to say more won't be added later.
// In that case, any checking would be an impediment to interoperating
// with newer QoS definitions.
--- a/netwerk/base/nsSocketTransport2.h
+++ b/netwerk/base/nsSocketTransport2.h
@@ -297,16 +297,17 @@ private:
uint16_t mPort;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
uint16_t mProxyPort;
uint16_t mOriginPort;
bool mProxyTransparent;
bool mProxyTransparentResolvesHost;
bool mHttpsProxy;
uint32_t mConnectionFlags;
+ bool mReuseAddrPort;
// The origin attributes are used to create sockets. The first party domain
// will eventually be used to isolate OCSP cache and is only non-empty when
// "privacy.firstparty.isolate" is enabled. Setting this is the only way to
// carry origin attributes down to NSPR layers which are final consumers.
// It must be set before the socket transport is built.
NeckoOriginAttributes mOriginAttributes;
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -1647,16 +1647,22 @@ SocketTransportShim::SetNetworkInterface
NS_IMETHODIMP
SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue)
{
return mWrapped->SetTimeout(aType, aValue);
}
NS_IMETHODIMP
+SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort)
+{
+ return mWrapped->SetReuseAddrPort(aReuseAddrPort);
+}
+
+NS_IMETHODIMP
SocketTransportShim::GetQoSBits(uint8_t *aQoSBits)
{
return mWrapped->GetQoSBits(aQoSBits);
}
NS_IMETHODIMP
SocketTransportShim::SetQoSBits(uint8_t aQoSBits)
{