Bug 1194259: Make ICE IP restriction to default routes work in E10S r=jesup,mcmanus,drno
authorRandell Jesup <rjesup@jesup.org>
Fri, 22 Jan 2016 02:47:01 -0500
changeset 316328 5c372359d5ba913866e9fc6b4f5f321ad33dc11a
parent 316327 cfeefd4e5ea219f20f7913cd6d0578256081e91f
child 316329 c94ef992148247f672b560380b6b2785f21a8ab1
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, mcmanus, drno
bugs1194259
milestone46.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 1194259: Make ICE IP restriction to default routes work in E10S r=jesup,mcmanus,drno
dom/network/PUDPSocket.ipdl
dom/network/UDPSocket.cpp
dom/network/UDPSocketChild.cpp
dom/network/UDPSocketChild.h
dom/network/UDPSocketParent.cpp
dom/network/UDPSocketParent.h
dom/network/interfaces/nsIUDPSocketChild.idl
media/mtransport/nr_socket_prsock.cpp
media/mtransport/nr_socket_prsock.h
media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
netwerk/base/nsIUDPSocket.idl
netwerk/base/nsUDPSocket.cpp
--- a/dom/network/PUDPSocket.ipdl
+++ b/dom/network/PUDPSocket.ipdl
@@ -37,28 +37,30 @@ namespace net {
 
 //-------------------------------------------------------------------
 protocol PUDPSocket
 {
   manager PNecko or PBackground;
 
 parent:
   Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
+  Connect(UDPAddressInfo addressInfo);
 
   OutgoingData(UDPData data, UDPSocketAddr addr);
 
   JoinMulticast(nsCString multicastAddress, nsCString iface);
   LeaveMulticast(nsCString multicastAddress, nsCString iface);
 
   Close();
 
   RequestDelete();
 
 child:
   CallbackOpened(UDPAddressInfo addressInfo);
+  CallbackConnected(UDPAddressInfo addressInfo);
   CallbackClosed();
   CallbackReceivedData(UDPAddressInfo addressInfo, uint8_t[] data);
   CallbackError(nsCString message, nsCString filename, uint32_t lineNumber);
   __delete__();
 };
 
 
 } // namespace net
--- a/dom/network/UDPSocket.cpp
+++ b/dom/network/UDPSocket.cpp
@@ -735,16 +735,25 @@ UDPSocket::CallListenerOpened()
   }
 
   mOpened->MaybeResolve(JS::UndefinedHandleValue);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+UDPSocket::CallListenerConnected()
+{
+  // This shouldn't be called here.
+  MOZ_CRASH();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 UDPSocket::CallListenerClosed()
 {
   CloseWithReason(NS_OK);
 
   return NS_OK;
 }
 
 } // namespace dom
--- a/dom/network/UDPSocketChild.cpp
+++ b/dom/network/UDPSocketChild.cpp
@@ -190,16 +190,28 @@ UDPSocketChild::Bind(nsIUDPSocketInterna
                                            mFilterName);
   }
 
   SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
   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));
+
+  mSocket = aSocket;
+
+  SendConnect(UDPAddressInfo(nsCString(aHost), aPort));
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 UDPSocketChild::Close()
 {
   SendClose();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Send(const nsACString& aHost,
@@ -339,16 +351,30 @@ UDPSocketChild::RecvCallbackOpened(const
 
   UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
   nsresult rv = mSocket->CallListenerOpened();
   mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
 
   return true;
 }
 
+// PUDPSocketChild Methods
+bool
+UDPSocketChild::RecvCallbackConnected(const UDPAddressInfo& aAddressInfo)
+{
+  mLocalAddress = aAddressInfo.addr();
+  mLocalPort = aAddressInfo.port();
+
+  UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
+  nsresult rv = mSocket->CallListenerConnected();
+  mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
+
+  return true;
+}
+
 bool
 UDPSocketChild::RecvCallbackClosed()
 {
   nsresult rv = mSocket->CallListenerClosed();
   mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
 
   return true;
 }
--- a/dom/network/UDPSocketChild.h
+++ b/dom/network/UDPSocketChild.h
@@ -40,16 +40,17 @@ public:
   NS_IMETHOD_(MozExternalRefCountType) Release() override;
 
   UDPSocketChild();
   virtual ~UDPSocketChild();
 
   nsresult CreatePBackgroundSpinUntilDone();
 
   virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) override;
+  virtual bool RecvCallbackConnected(const UDPAddressInfo& aAddressInfo) override;
   virtual bool RecvCallbackClosed() override;
   virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
                                         InfallibleTArray<uint8_t>&& aData) override;
   virtual bool RecvCallbackError(const nsCString& aMessage,
                                  const nsCString& aFilename,
                                  const uint32_t& aLineNumber) override;
 
 private:
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/PNeckoParent.h"
 #include "nsNetUtil.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/ipc/PBackgroundParent.h"
+#include "mtransport/runnable_utils.h"
 
 //
 // set NSPR_LOG_MODULES=UDPSocket:5
 //
 extern mozilla::LazyLogModule gUDPSocketLog;
 #define UDPSOCKET_LOG(args)     MOZ_LOG(gUDPSocketLog, mozilla::LogLevel::Debug, args)
 #define UDPSOCKET_LOG_ENABLED() MOZ_LOG_TEST(gUDPSocketLog, mozilla::LogLevel::Debug)
 
@@ -95,17 +96,17 @@ UDPSocketParent::GetAppId()
 bool
 UDPSocketParent::Init(const IPC::Principal& aPrincipal,
                       const nsACString& aFilter)
 {
   MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
   // will be used once we move all UDPSocket to PBackground, or
   // if we add in Principal checking for mtransport
   Unused << mBackgroundManager;
-  
+
   mPrincipal = aPrincipal;
   if (net::UsingNeckoIPCSecurity() &&
       mPrincipal &&
       !ContentParent::IgnoreIPCPrincipal()) {
     if (mNeckoManager) {
       if (!AssertAppPrincipal(mNeckoManager->Manager(), mPrincipal)) {
         return false;
       }
@@ -191,17 +192,17 @@ UDPSocketParent::RecvBind(const UDPAddre
 }
 
 nsresult
 UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
                               const bool& aAddressReuse, const bool& aLoopback)
 {
   nsresult rv;
 
-  UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
+  UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d", __FUNCTION__, this, nsCString(aHost).get(), aPort, aAddressReuse, aLoopback));
 
   nsCOMPtr<nsIUDPSocket> sock =
       do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -221,32 +222,148 @@ UDPSocketParent::BindInternal(const nsCS
     rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse,
                                /* optional_argc = */ 1);
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = sock->SetMulticastLoopback(aLoopback);
+  nsCOMPtr<nsINetAddr> laddr;
+  rv = sock->GetLocalAddr(getter_AddRefs(laddr));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
+  uint16_t family;
+  rv = laddr->GetFamily(&family);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (family == nsINetAddr::FAMILY_INET) {
+    rv = sock->SetMulticastLoopback(aLoopback);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
 
   // register listener
   rv = sock->AsyncListen(this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   mSocket = sock;
 
   return NS_OK;
 }
 
+
+static nsCOMPtr<nsIEventTarget> GetSTSThread()
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIEventTarget> sts_thread;
+
+  sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+  return sts_thread;
+}
+
+static void CheckSTSThread()
+{
+  nsCOMPtr<nsIEventTarget> sts_thread = GetSTSThread();
+
+  ASSERT_ON_THREAD(sts_thread);
+}
+
+
+// Proxy the Connect() request to the STS thread, since it may block and
+// should be done there.
+bool
+UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo)
+{
+  nsCOMPtr<nsIEventTarget> thread(NS_GetCurrentThread());
+  NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable(
+                                                  this,
+                                                  &UDPSocketParent::DoConnect,
+                                                  mSocket,
+                                                  thread,
+                                                  aAddressInfo),
+                                                NS_DISPATCH_NORMAL)));
+  return true;
+}
+
+void
+UDPSocketParent::SendConnectResponse(nsIEventTarget *aThread,
+                                     const UDPAddressInfo& aAddressInfo)
+{
+  NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
+                                           this,
+                                           &UDPSocketParent::SendCallbackConnected,
+                                           aAddressInfo),
+                                         NS_DISPATCH_NORMAL)));
+}
+
+// Runs on STS thread
+void
+UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
+                           nsCOMPtr<nsIEventTarget>& aReturnThread,
+                           const UDPAddressInfo& aAddressInfo)
+{
+  UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
+  if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) {
+    SendInternalError(aReturnThread, __LINE__);
+    return;
+  }
+  CheckSTSThread();
+
+  nsCOMPtr<nsINetAddr> localAddr;
+  aSocket->GetLocalAddr(getter_AddRefs(localAddr));
+
+  nsCString addr;
+  if (NS_FAILED(localAddr->GetAddress(addr))) {
+    SendInternalError(aReturnThread, __LINE__);
+    return;
+  }
+
+  uint16_t port;
+  if (NS_FAILED(localAddr->GetPort(&port))) {
+    SendInternalError(aReturnThread, __LINE__);
+    return;
+  }
+
+  UDPSOCKET_LOG(("%s: SendConnectResponse: %s:%u", __FUNCTION__, addr.get(), port));
+  SendConnectResponse(aReturnThread, UDPAddressInfo(addr, port));
+}
+
+nsresult
+UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
+{
+  nsresult rv;
+
+  UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
+  PRNetAddr prAddr;
+  PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
+  PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
+  if (status != PR_SUCCESS) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mozilla::net::NetAddr addr;
+  PRNetAddrToNetAddr(&prAddr, &addr);
+
+  rv = mSocket->Connect(&addr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 bool
 UDPSocketParent::RecvOutgoingData(const UDPData& aData,
                                   const UDPSocketAddr& aAddr)
 {
   MOZ_ASSERT(mSocket);
 
   nsresult rv;
   if (mFilter) {
@@ -480,10 +597,22 @@ UDPSocketParent::FireInternalError(uint3
   if (!mIPCOpen) {
     return;
   }
 
   mozilla::Unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
                                        NS_LITERAL_CSTRING(__FILE__), aLineNo);
 }
 
+void
+UDPSocketParent::SendInternalError(nsIEventTarget *aThread,
+                                   uint32_t aLineNo)
+{
+  UDPSOCKET_LOG(("SendInternalError: %u", aLineNo));
+  NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
+                                           this,
+                                           &UDPSocketParent::FireInternalError,
+                                           aLineNo),
+                                         NS_DISPATCH_NORMAL)));
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/UDPSocketParent.h
+++ b/dom/network/UDPSocketParent.h
@@ -31,16 +31,22 @@ public:
 
   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;
+  virtual bool RecvConnect(const UDPAddressInfo& aAddressInfo) override;
+  void SendConnectResponse(nsIEventTarget *aThread,
+                           const UDPAddressInfo& aAddressInfo);
+  void DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
+                 nsCOMPtr<nsIEventTarget>& aReturnThread,
+                 const UDPAddressInfo& aAddressInfo);
 
   virtual bool RecvOutgoingData(const UDPData& aData, const UDPSocketAddr& aAddr) override;
 
   virtual bool RecvClose() override;
   virtual bool RecvRequestDelete() override;
   virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
                                  const nsCString& aInterface) override;
   virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
@@ -51,18 +57,20 @@ 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);
-
+  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;
 
   bool mIPCOpen;
   nsCOMPtr<nsIUDPSocket> mSocket;
   nsCOMPtr<nsIUDPSocketFilter> mFilter;
--- a/dom/network/interfaces/nsIUDPSocketChild.idl
+++ b/dom/network/interfaces/nsIUDPSocketChild.idl
@@ -14,31 +14,34 @@ namespace mozilla {
 namespace net {
 union NetAddr;
 }
 }
 %}
 native NetAddr(mozilla::net::NetAddr);
 [ptr] native NetAddrPtr(mozilla::net::NetAddr);
 
-[scriptable, uuid(481f15ce-224a-40b6-9927-7effbc326776)]
+[scriptable, uuid(1e6ad73b-6c05-4d78-9a88-2d357b88f58b)]
 interface nsIUDPSocketChild : nsISupports
 {
   readonly attribute unsigned short localPort;
   readonly attribute AUTF8String localAddress;
   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);
 
+  // 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);
   // Send without DNS query
   void sendWithAddr(in nsINetAddr addr,
                     [const, array, size_is(byteLength)] in uint8_t bytes,
                     in unsigned long byteLength);
@@ -51,21 +54,23 @@ interface nsIUDPSocketChild : nsISupport
   void close();
   void joinMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
   void leaveMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
 };
 
 /*
  * Internal interface for callback from chrome process
  */
-[scriptable, uuid(44cd9ad5-d574-4169-baf9-e1af0648a143)]
+[scriptable, uuid(613dd3ad-598b-4da9-ad63-bbda50c20098)]
 interface nsIUDPSocketInternal : nsISupports
 {
   // callback while socket is opened. localPort and localAddress is ready until this time.
   void callListenerOpened();
+  // callback while socket is connected.
+  void callListenerConnected();
   // callback while socket is closed.
   void callListenerClosed();
   // callback while incoming packet is received.
   void callListenerReceivedData(in AUTF8String host, in unsigned short port,
                                 [const, array, size_is(dataLength)] in uint8_t data,
                                 in unsigned long dataLength);
   // callback while any error happened.
   void callListenerError(in AUTF8String message, in AUTF8String filename, in uint32_t lineNumber);
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -493,17 +493,17 @@ int nr_netaddr_to_transport_addr(const n
                                                ntohs(netaddr->inet6.port),
                                                protocol, addr)))
           ABORT(r);
         break;
       default:
         MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
-    _status=0;
+    _status = 0;
   abort:
     return(_status);
   }
 
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr, int protocol,
                                 int keep)
   {
@@ -531,17 +531,17 @@ int nr_praddr_to_transport_addr(const PR
         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
           ABORT(r);
         break;
       default:
         MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
 
-    _status=0;
+    _status = 0;
  abort:
     return(_status);
   }
 
 /*
  * nr_transport_addr_get_addrstring_and_port
  * convert nr_transport_addr to IP address string and port number
  */
@@ -558,17 +558,17 @@ int nr_transport_addr_get_addrstring_and
   }
 
   if ((r=nr_transport_addr_get_port(addr, port))) {
     ABORT(r);
   }
 
   *host = addr_string;
 
-  _status=0;
+  _status = 0;
 abort:
   return(_status);
 }
 
 // nr_socket APIs (as member functions)
 int NrSocket::create(nr_transport_addr *addr) {
   int r,_status;
 
@@ -760,17 +760,17 @@ int NrSocket::sendto(const void *msg, si
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
 
     r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
           to->as_string, PR_GetError());
     ABORT(R_IO_ERROR);
   }
 
-  _status=0;
+  _status = 0;
 abort:
   return(_status);
 }
 
 int NrSocket::recvfrom(void * buf, size_t maxlen,
                        size_t *len, int flags,
                        nr_transport_addr *from) {
   ASSERT_ON_THREAD(ststhread_);
@@ -780,24 +780,24 @@ int NrSocket::recvfrom(void * buf, size_
 
   status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
   if (status <= 0) {
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
     r_log(LOG_GENERIC, LOG_INFO, "Error in recvfrom: %d", (int)PR_GetError());
     ABORT(R_IO_ERROR);
   }
-  *len=status;
+  *len = status;
 
   if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0)))
     ABORT(r);
 
   //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
 
-  _status=0;
+  _status = 0;
 abort:
   return(_status);
 }
 
 int NrSocket::getaddr(nr_transport_addr *addrp) {
   ASSERT_ON_THREAD(ststhread_);
   return nr_transport_addr_copy(addrp, &my_addr_);
 }
@@ -843,17 +843,17 @@ int NrSocket::connect(nr_transport_addr 
       ABORT(r);
   }
 
   // Now return the WOULDBLOCK if needed.
   if (connect_status != PR_SUCCESS) {
     ABORT(R_WOULDBLOCK);
   }
 
-  _status=0;
+  _status = 0;
 abort:
   return(_status);
 }
 
 
 int NrSocket::write(const void *msg, size_t len, size_t *written) {
   ASSERT_ON_THREAD(ststhread_);
   int _status;
@@ -867,17 +867,17 @@ int NrSocket::write(const void *msg, siz
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
     r_log(LOG_GENERIC, LOG_INFO, "Error in write");
     ABORT(R_IO_ERROR);
   }
 
   *written = status;
 
-  _status=0;
+  _status = 0;
 abort:
   return _status;
 }
 
 int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
   ASSERT_ON_THREAD(ststhread_);
   int _status;
   int32_t status;
@@ -907,17 +907,17 @@ int NrSocket::listen(int backlog) {
   int _status;
 
   assert(fd_);
   status = PR_Listen(fd_, backlog);
   if (status != PR_SUCCESS) {
     ABORT(R_IO_ERROR);
   }
 
-  _status=0;
+  _status = 0;
 abort:
   return(_status);
 }
 
 int NrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) {
   ASSERT_ON_THREAD(ststhread_);
   int _status, r;
   PRStatus status;
@@ -985,17 +985,17 @@ int NrSocket::accept(nr_transport_addr *
   if (NS_FAILED(rv)) {
     ABORT(R_INTERNAL);
   }
 
   sock->connect_invoked_ = true;
 
   // Add a reference so that we can delete it in destroy()
   sock->AddRef();
-  _status=0;
+  _status = 0;
 abort:
   if (_status) {
     delete sock;
   }
 
   return(_status);
 }
 
@@ -1039,16 +1039,22 @@ NS_IMETHODIMP NrUdpSocketIpcProxy::CallL
   return socket_->CallListenerReceivedData(host, port, data, data_length);
 }
 
 // callback while UDP socket is opened
 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() {
   return socket_->CallListenerOpened();
 }
 
+// callback while UDP socket is connected
+NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() {
+  return socket_->CallListenerConnected();
+  return NS_OK;
+}
+
 // callback while UDP socket is closed
 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() {
   return socket_->CallListenerClosed();
 }
 
 // NrUdpSocketIpc Implementation
 NrUdpSocketIpc::NrUdpSocketIpc()
   : NrSocketIpc(GetIOThreadAndAddUse_s()),
@@ -1074,18 +1080,18 @@ NrUdpSocketIpc::~NrUdpSocketIpc()
 
 // IUDPSocketInternal interfaces
 // callback while error happened in UDP socket operation
 NS_IMETHODIMP NrUdpSocketIpc::CallListenerError(const nsACString &message,
                                                 const nsACString &filename,
                                                 uint32_t line_number) {
   ASSERT_ON_THREAD(io_thread_);
 
-  r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d",
-        message.BeginReading(), filename.BeginReading(), line_number );
+  r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d this=%p",
+        message.BeginReading(), filename.BeginReading(), line_number, (void*) this );
 
   ReentrantMonitorAutoEnter mon(monitor_);
   err_ = true;
   monitor_.NotifyAll();
 
   return NS_OK;
 }
 
@@ -1122,21 +1128,17 @@ NS_IMETHODIMP NrUdpSocketIpc::CallListen
   RUN_ON_THREAD(sts_thread_,
                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
                                       &NrUdpSocketIpc::recv_callback_s,
                                       msg),
                 NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
-// callback while UDP socket is opened
-NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() {
-  ASSERT_ON_THREAD(io_thread_);
-  ReentrantMonitorAutoEnter mon(monitor_);
-
+NS_IMETHODIMP NrUdpSocketIpc::SetAddress() {
   uint16_t port;
   if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to get local port");
     return NS_OK;
   }
 
   nsAutoCString address;
@@ -1165,33 +1167,70 @@ NS_IMETHODIMP NrUdpSocketIpc::CallListen
     MOZ_ASSERT(false, "Failed to copy my_addr_");
   }
 
   if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
   }
 
-  if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
+  if (!nr_transport_addr_is_wildcard(&expected_addr) &&
+      nr_transport_addr_cmp(&expected_addr, &my_addr_,
                             NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
     err_ = true;
     MOZ_ASSERT(false, "Address of opened socket is not expected");
   }
 
+  return NS_OK;
+}
+
+// callback while UDP socket is opened
+NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() {
+  ASSERT_ON_THREAD(io_thread_);
+  ReentrantMonitorAutoEnter mon(monitor_);
+
+  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket opened this=%p", (void*) this);
+  nsresult rv = SetAddress();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mon.NotifyAll();
+
+  return NS_OK;
+}
+
+// callback while UDP socket is connected
+NS_IMETHODIMP NrUdpSocketIpc::CallListenerConnected() {
+  ASSERT_ON_THREAD(io_thread_);
+
+  ReentrantMonitorAutoEnter mon(monitor_);
+
+  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket connected this=%p", (void*) this);
+  MOZ_ASSERT(state_ == NR_CONNECTED);
+
+  nsresult rv = SetAddress();
+  if (NS_FAILED(rv)) {
+    mon.NotifyAll();
+    return rv;
+  }
+
+  r_log(LOG_GENERIC, LOG_INFO, "Exit UDP socket connected");
   mon.NotifyAll();
 
   return NS_OK;
 }
 
 // callback while UDP socket is closed
 NS_IMETHODIMP NrUdpSocketIpc::CallListenerClosed() {
   ASSERT_ON_THREAD(io_thread_);
 
   ReentrantMonitorAutoEnter mon(monitor_);
 
+  r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket closed this=%p", (void*) this);
   MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
   state_ = NR_CLOSED;
 
   return NS_OK;
 }
 
 //
 // NrSocketBase methods.
@@ -1274,16 +1313,18 @@ int NrUdpSocketIpc::sendto(const void *m
                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
                                       &NrUdpSocketIpc::sendto_i,
                                       addr, buf),
                 NS_DISPATCH_NORMAL);
   return 0;
 }
 
 void NrUdpSocketIpc::close() {
+  r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::close()");
+
   ASSERT_ON_THREAD(sts_thread_);
 
   ReentrantMonitorAutoEnter mon(monitor_);
   state_ = NR_CLOSING;
 
   RUN_ON_THREAD(io_thread_,
                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
                                       &NrUdpSocketIpc::close_i),
@@ -1346,18 +1387,47 @@ int NrUdpSocketIpc::getaddr(nr_transport
   if (state_ != NR_CONNECTED) {
     return R_INTERNAL;
   }
 
   return nr_transport_addr_copy(addrp, &my_addr_);
 }
 
 int NrUdpSocketIpc::connect(nr_transport_addr *addr) {
-  MOZ_ASSERT(false);
-  return R_INTERNAL;
+  int r,_status;
+  int32_t port;
+  nsCString host;
+
+  ReentrantMonitorAutoEnter mon(monitor_);
+  r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect(%s) this=%p", addr->as_string,
+        (void*) this);
+
+  if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
+    ABORT(r);
+  }
+
+  RUN_ON_THREAD(io_thread_,
+                mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
+                                      &NrUdpSocketIpc::connect_i,
+                                      host, static_cast<uint16_t>(port)),
+                NS_DISPATCH_NORMAL);
+
+  // Wait until connect() completes.
+  mon.Wait();
+
+  r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect this=%p completed err_ = %s",
+        (void*) this, err_ ? "true" : "false");
+
+  if (err_) {
+    ABORT(R_INTERNAL);
+  }
+
+  _status = 0;
+abort:
+  return _status;
 }
 
 int NrUdpSocketIpc::write(const void *msg, size_t len, size_t *written) {
   MOZ_ASSERT(false);
   return R_INTERNAL;
 }
 
 int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
@@ -1413,16 +1483,38 @@ void NrUdpSocketIpc::create_i(const nsAC
                                     /* loopback = */ false))) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDP socket");
     mon.NotifyAll();
     return;
   }
 }
 
+void NrUdpSocketIpc::connect_i(const nsACString &host, const uint16_t port) {
+  ASSERT_ON_THREAD(io_thread_);
+  nsresult rv;
+  ReentrantMonitorAutoEnter mon(monitor_);
+
+  RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy);
+  rv = proxy->Init(this);
+  if (NS_FAILED(rv)) {
+    err_ = true;
+    mon.NotifyAll();
+    return;
+  }
+
+  if (NS_FAILED(socket_child_->Connect(proxy, host, port))) {
+    err_ = true;
+    MOZ_ASSERT(false, "Failed to connect UDP socket");
+    mon.NotifyAll();
+    return;
+  }
+}
+
+
 void NrUdpSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
   ASSERT_ON_THREAD(io_thread_);
 
   ReentrantMonitorAutoEnter mon(monitor_);
 
   if (!socket_child_) {
     MOZ_ASSERT(false);
     err_ = true;
@@ -2012,17 +2104,17 @@ abort:
 }
 
 
 static int nr_socket_local_destroy(void **objp) {
   if(!objp || !*objp)
     return 0;
 
   NrSocketBase *sock = static_cast<NrSocketBase *>(*objp);
-  *objp=0;
+  *objp = 0;
 
   sock->close();  // Signal STS that we want not to listen
   sock->Release();  // Decrement the ref count
 
   return 0;
 }
 
 static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -238,16 +238,17 @@ public:
   NS_IMETHODIMP CallListenerError(const nsACString &message,
                                   const nsACString &filename,
                                   uint32_t line_number);
   NS_IMETHODIMP CallListenerReceivedData(const nsACString &host,
                                          uint16_t port,
                                          const uint8_t *data,
                                          uint32_t data_length);
   NS_IMETHODIMP CallListenerOpened();
+  NS_IMETHODIMP CallListenerConnected();
   NS_IMETHODIMP CallListenerClosed();
 
   NrUdpSocketIpc();
 
   // Implementations of the NrSocketBase APIs
   virtual int create(nr_transport_addr *addr) override;
   virtual int sendto(const void *msg, size_t len,
                      int flags, nr_transport_addr *to) override;
@@ -262,18 +263,21 @@ public:
   virtual int listen(int backlog) override;
   virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override;
 
 private:
   virtual ~NrUdpSocketIpc();
 
   DISALLOW_COPY_ASSIGN(NrUdpSocketIpc);
 
+  nsresult SetAddress();  // Set the local address from parent info.
+
   // Main or private thread executors of the NrSocketBase APIs
   void create_i(const nsACString &host, const uint16_t port);
+  void connect_i(const nsACString &host, const uint16_t port);
   void sendto_i(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf);
   void close_i();
 #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
   static void release_child_i(nsIUDPSocketChild* aChild, nsCOMPtr<nsIEventTarget> ststhread);
   static void release_use_s();
 #endif
   // STS thread executor
   void recv_callback_s(RefPtr<nr_udp_message> msg);
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -596,16 +596,18 @@ static int nr_ice_get_default_address(nr
 
     if ((r=nr_socket_factory_create_socket(ctx->socket_factory, &addr, &sock)))
       ABORT(r);
     if ((r=nr_socket_connect(sock, &remote_addr)))
       ABORT(r);
     if ((r=nr_socket_getaddr(sock, addrp)))
       ABORT(r);
 
+    r_log(LOG_GENERIC, LOG_DEBUG, "Default address: %s", addrp->as_string);
+
     _status=0;
   abort:
     nr_socket_destroy(&sock);
     return(_status);
   }
 
 static int nr_ice_get_default_local_address(nr_ice_ctx *ctx, int ip_version, nr_local_addr* addrs, int addr_ct, nr_local_addr *addrp)
   {
--- a/netwerk/base/nsIUDPSocket.idl
+++ b/netwerk/base/nsIUDPSocket.idl
@@ -25,17 +25,17 @@ native NetAddr(mozilla::net::NetAddr);
 [ptr] native NetAddrPtr(mozilla::net::NetAddr);
 [ref] native Uint8TArrayRef(FallibleTArray<uint8_t>);
 
 /**
  * nsIUDPSocket
  *
  * An interface to a UDP socket that can accept incoming connections.
  */
-[scriptable, uuid(e0377f7b-34a9-4d0f-8191-7e0cba77a52f)]
+[scriptable, uuid(d423bf4e-4499-40cf-bc03-153e2bf206d1)]
 interface nsIUDPSocket : nsISupports
 {
     /**
      * init
      *
      * This method initializes a UDP socket.
      *
      * @param aPort
@@ -98,16 +98,26 @@ interface nsIUDPSocket : nsISupports
      * transport (nsISocketTransport).  See below for more details.
      *
      * @param aListener
      *        The listener to be notified when client connections are accepted.
      */
     void asyncListen(in nsIUDPSocketListener aListener);
 
     /**
+     * connect
+     *
+     * This method connects the UDP socket to a remote UDP address.
+     *
+     * @param aRemoteAddr
+     *        The remote address to connect to
+     */
+     void connect([const] in NetAddrPtr aAddr);
+
+    /**
      * Returns the local address of this UDP socket
      */
     readonly attribute nsINetAddr localAddr;
 
     /**
      * Returns the port of this UDP socket.
      */
     readonly attribute long port;
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -671,16 +671,51 @@ nsUDPSocket::InitWithAddress(const NetAd
   return NS_OK;
 
 fail:
   Close();
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
+nsUDPSocket::Connect(const NetAddr *aAddr)
+{
+  UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
+
+  NS_ENSURE_ARG(aAddr);
+
+  bool onSTSThread = false;
+  mSts->IsOnCurrentThread(&onSTSThread);
+  NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
+  if (!onSTSThread) {
+    return NS_ERROR_FAILURE;
+  }
+
+  PRNetAddr prAddr;
+  NetAddrToPRNetAddr(aAddr, &prAddr);
+
+  if (PR_Connect(mFD, &prAddr, PR_INTERVAL_NO_WAIT) != PR_SUCCESS) {
+    NS_WARNING("Cannot PR_Connect");
+    return NS_ERROR_FAILURE;
+  }
+
+  // get the resulting socket address, which may have been updated.
+  PRNetAddr addr;
+  if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
+  {
+    NS_WARNING("cannot get socket name");
+    return NS_ERROR_FAILURE;
+  }
+
+  PRNetAddrToNetAddr(&addr, &mAddr);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsUDPSocket::Close()
 {
   {
     MutexAutoLock lock(mLock);
     // we want to proxy the close operation to the socket thread if a listener
     // has been set.  otherwise, we should just close the socket here...
     if (!mListener)
     {