WebRTC Bug 4865

Bug 4865: even without STUN/TURN, as long as the peer is on the open internet, the connectivity should work. This is actually a regression even for hangouts.

We need to issue the 0.0.0.0 candidate into Port::candidates_ and filter it out later. The reason is that when we create connection, we need a local candidate to match the remote candidate.

The same connection later will be updated with the prflx local candidate once the STUN ping response is received.

BUG=webrtc:4865
R=juberti@webrtc.org

Review URL: https://codereview.webrtc.org/1274013002 .

Cr-Commit-Position: refs/heads/master@{#9708}
diff --git a/webrtc/base/virtualsocket_unittest.cc b/webrtc/base/virtualsocket_unittest.cc
index e9d57f8..a656691 100644
--- a/webrtc/base/virtualsocket_unittest.cc
+++ b/webrtc/base/virtualsocket_unittest.cc
@@ -149,6 +149,41 @@
     }
   }
 
+  // Test a client can bind to the any address, and all sent packets will have
+  // the default route as the source address. Also, it can receive packets sent
+  // to the default route.
+  void TestDefaultRoute(const IPAddress& default_route) {
+    ss_->SetDefaultRoute(default_route);
+
+    // Create client1 bound to the any address.
+    AsyncSocket* socket =
+        ss_->CreateAsyncSocket(default_route.family(), SOCK_DGRAM);
+    socket->Bind(EmptySocketAddressWithFamily(default_route.family()));
+    SocketAddress client1_any_addr = socket->GetLocalAddress();
+    EXPECT_TRUE(client1_any_addr.IsAnyIP());
+    TestClient* client1 = new TestClient(new AsyncUDPSocket(socket));
+
+    // Create client2 bound to the default route.
+    AsyncSocket* socket2 =
+        ss_->CreateAsyncSocket(default_route.family(), SOCK_DGRAM);
+    socket2->Bind(SocketAddress(default_route, 0));
+    SocketAddress client2_addr = socket2->GetLocalAddress();
+    EXPECT_FALSE(client2_addr.IsAnyIP());
+    TestClient* client2 = new TestClient(new AsyncUDPSocket(socket2));
+
+    // Client1 sends to client2, client2 should see the default route as
+    // client1's address.
+    SocketAddress client1_addr;
+    EXPECT_EQ(6, client1->SendTo("bizbaz", 6, client2_addr));
+    EXPECT_TRUE(client2->CheckNextPacket("bizbaz", 6, &client1_addr));
+    EXPECT_EQ(client1_addr,
+              SocketAddress(default_route, client1_any_addr.port()));
+
+    // Client2 can send back to client1's default route address.
+    EXPECT_EQ(3, client2->SendTo("foo", 3, client1_addr));
+    EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &client2_addr));
+  }
+
   void BasicTest(const SocketAddress& initial_addr) {
     AsyncSocket* socket = ss_->CreateAsyncSocket(initial_addr.family(),
                                                  SOCK_DGRAM);
@@ -791,6 +826,18 @@
   BasicTest(ipv6_test_addr);
 }
 
+TEST_F(VirtualSocketServerTest, TestDefaultRoute_v4) {
+  IPAddress ipv4_default_addr(0x01020304);
+  TestDefaultRoute(ipv4_default_addr);
+}
+
+TEST_F(VirtualSocketServerTest, TestDefaultRoute_v6) {
+  IPAddress ipv6_default_addr;
+  EXPECT_TRUE(
+      IPFromString("2401:fa00:4:1000:be30:5bff:fee5:c3", &ipv6_default_addr));
+  TestDefaultRoute(ipv6_default_addr);
+}
+
 TEST_F(VirtualSocketServerTest, connect_v4) {
   ConnectTest(kIPv4AnyAddress);
 }
diff --git a/webrtc/base/virtualsocketserver.cc b/webrtc/base/virtualsocketserver.cc
index 9b0e48d..c2f0e01 100644
--- a/webrtc/base/virtualsocketserver.cc
+++ b/webrtc/base/virtualsocketserver.cc
@@ -17,6 +17,7 @@
 #include <map>
 #include <vector>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/base/common.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/physicalsocketserver.h"
@@ -661,7 +662,22 @@
   SocketAddress normalized(addr.ipaddr().Normalized(),
                            addr.port());
   AddressMap::iterator it = bindings_->find(normalized);
-  return (bindings_->end() != it) ? it->second : NULL;
+  if (it != bindings_->end()) {
+    return it->second;
+  }
+
+  IPAddress default_ip = GetDefaultRoute(addr.ipaddr().family());
+  if (!IPIsUnspec(default_ip) && addr.ipaddr() == default_ip) {
+    // If we can't find a binding for the packet which is sent to the interface
+    // corresponding to the default route, it should match a binding with the
+    // correct port to the any address.
+    SocketAddress sock_addr =
+        EmptySocketAddressWithFamily(addr.ipaddr().family());
+    sock_addr.SetPort(addr.port());
+    return LookupBinding(sock_addr);
+  }
+
+  return nullptr;
 }
 
 int VirtualSocketServer::Unbind(const SocketAddress& addr,
@@ -866,8 +882,18 @@
   // Find the delay for crossing the many virtual hops of the network.
   uint32 transit_delay = GetRandomTransitDelay();
 
+  // When the incoming packet is from a binding of the any address, translate it
+  // to the default route here such that the recipient will see the default
+  // route.
+  SocketAddress sender_addr = sender->local_addr_;
+  IPAddress default_ip = GetDefaultRoute(sender_addr.ipaddr().family());
+  if (sender_addr.IsAnyIP() && !IPIsUnspec(default_ip)) {
+    sender_addr.SetIP(default_ip);
+  }
+
   // Post the packet as a message to be delivered (on our own thread)
-  Packet* p = new Packet(data, data_size, sender->local_addr_);
+  Packet* p = new Packet(data, data_size, sender_addr);
+
   uint32 ts = TimeAfter(send_delay + transit_delay);
   if (ordered) {
     // Ensure that new packets arrive after previous ones
@@ -1080,4 +1106,22 @@
   return false;
 }
 
+IPAddress VirtualSocketServer::GetDefaultRoute(int family) {
+  if (family == AF_INET) {
+    return default_route_v4_;
+  }
+  if (family == AF_INET6) {
+    return default_route_v6_;
+  }
+  return IPAddress();
+}
+void VirtualSocketServer::SetDefaultRoute(const IPAddress& from_addr) {
+  DCHECK(!IPIsAny(from_addr));
+  if (from_addr.family() == AF_INET) {
+    default_route_v4_ = from_addr;
+  } else if (from_addr.family() == AF_INET6) {
+    default_route_v6_ = from_addr;
+  }
+}
+
 }  // namespace rtc
diff --git a/webrtc/base/virtualsocketserver.h b/webrtc/base/virtualsocketserver.h
index b96269c..c708bb4 100644
--- a/webrtc/base/virtualsocketserver.h
+++ b/webrtc/base/virtualsocketserver.h
@@ -38,6 +38,11 @@
 
   SocketServer* socketserver() { return server_; }
 
+  // The default route indicates which local address to use when a socket is
+  // bound to the 'any' address, e.g. 0.0.0.0.
+  IPAddress GetDefaultRoute(int family);
+  void SetDefaultRoute(const IPAddress& from_addr);
+
   // Limits the network bandwidth (maximum bytes per second).  Zero means that
   // all sends occur instantly.  Defaults to 0.
   uint32 bandwidth() const { return bandwidth_; }
@@ -224,6 +229,9 @@
   AddressMap* bindings_;
   ConnectionMap* connections_;
 
+  IPAddress default_route_v4_;
+  IPAddress default_route_v6_;
+
   uint32 bandwidth_;
   uint32 network_capacity_;
   uint32 send_buffer_capacity_;
@@ -248,9 +256,6 @@
   SocketAddress GetLocalAddress() const override;
   SocketAddress GetRemoteAddress() const override;
 
-  // Used by server sockets to set the local address without binding.
-  void SetLocalAddress(const SocketAddress& addr);
-
   // Used by TurnPortTest to mimic a case where proxy returns local host address
   // instead of the original one TurnPort was bound against. Please see WebRTC
   // issue 3927 for more detail.
@@ -297,6 +302,9 @@
   int SendUdp(const void* pv, size_t cb, const SocketAddress& addr);
   int SendTcp(const void* pv, size_t cb);
 
+  // Used by server sockets to set the local address without binding.
+  void SetLocalAddress(const SocketAddress& addr);
+
   VirtualSocketServer* server_;
   int family_;
   int type_;