Bug 1194259: Make ICE IP restriction to default routes work in E10S r?jesup,mcmanus,billm draft
authorRandell Jesup <rjesup@jesup.org>
Wed, 20 Jan 2016 02:13:01 -0500
changeset 323382 f8423823acd5b185097078b21e0a86bca07502c8
parent 322296 0b9c06478275bf9a4fe37d660ea37514afd10e4c
child 323383 200b99340ad9503529f236ea615bca97c6692083
push id9713
push userrjesup@wgate.com
push dateWed, 20 Jan 2016 07:13:39 +0000
reviewersjesup, mcmanus, billm
bugs1194259
milestone46.0a1
Bug 1194259: Make ICE IP restriction to default routes work in E10S r?jesup,mcmanus,billm
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
@@ -95,17 +95,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 +191,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,33 +221,89 @@ UDPSocketParent::BindInternal(const nsCS
     rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse,
                                /* optional_argc = */ 1);
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  /*
+  // TODO drno: Fails on IPv6 sockets?!
   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;
 }
 
 bool
+UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo) {
+  UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
+  if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  nsCOMPtr<nsINetAddr> localAddr;
+  mSocket->GetLocalAddr(getter_AddRefs(localAddr));
+
+  nsCString addr;
+  if (NS_FAILED(localAddr->GetAddress(addr))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  uint16_t port;
+  if (NS_FAILED(localAddr->GetPort(&port))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  UDPSOCKET_LOG(("%s: SendCallbackConnected: %s:%u", __FUNCTION__, addr.get(), port));
+  mozilla::Unused << SendCallbackConnected(UDPAddressInfo(addr, port));
+
+  return true;
+}
+
+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) {
     // TODO, Bug 933102, filter packets that are sent with hostname.
--- a/dom/network/UDPSocketParent.h
+++ b/dom/network/UDPSocketParent.h
@@ -31,16 +31,17 @@ 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;
 
   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,17 +52,17 @@ 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);
 
   // One of these will be null and the other non-null.
   PBackgroundParent* mBackgroundManager;
   PNeckoParent* mNeckoManager;
 
   bool mIPCOpen;
   nsCOMPtr<nsIUDPSocket> mSocket;
--- 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
@@ -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()),
@@ -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,22 +1167,56 @@ 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_);
+
+  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_);
+
+  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_);
@@ -1274,16 +1310,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 +1384,46 @@ 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)", addr->as_string);
+
+  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 completed err_ = %s",
+        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 +1479,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;
--- 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
@@ -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
@@ -664,16 +664,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);
+
+  PRNetAddr prAddr;
+  NetAddrToPRNetAddr(aAddr, &prAddr);
+
+  bool onSTSThread = false;
+  mSts->IsOnCurrentThread(&onSTSThread);
+  if (!onSTSThread) {
+    // TODO turn this into ASSERT
+    UDPSOCKET_LOG(("NOT ON STS THREAD"));
+  }
+
+  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)
     {