Ensuring that UDP TURN servers are always used as STUN servers.
This was already working in most cases, but not for some corner cases:
* If the PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is not set
* If both a STUN server and TURN server are configured
I added unit tests for these cases, and centralized the code that gets
STUN server addresses in order to fix these and any related issues.
BUG=webrtc:4215
Review URL: https://codereview.webrtc.org/1215713003
Cr-Original-Commit-Position: refs/heads/master@{#9596}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: c5d0d95fd8957a7a6645b1196e5f1e9cee33525c
diff --git a/base/nat_unittest.cc b/base/nat_unittest.cc
index 36b9327..af691e4 100644
--- a/base/nat_unittest.cc
+++ b/base/nat_unittest.cc
@@ -18,6 +18,7 @@
#include "webrtc/base/network.h"
#include "webrtc/base/physicalsocketserver.h"
#include "webrtc/base/testclient.h"
+#include "webrtc/base/asynctcpsocket.h"
#include "webrtc/base/virtualsocketserver.h"
#include "webrtc/test/testsupport/gtest_disable.h"
@@ -36,6 +37,11 @@
return new TestClient(socket);
}
+TestClient* CreateTCPTestClient(AsyncSocket* socket) {
+ AsyncTCPSocket* packet_socket = new AsyncTCPSocket(socket, false);
+ return new TestClient(packet_socket);
+}
+
// Tests that when sending from internal_addr to external_addrs through the
// NAT type specified by nat_type, all external addrs receive the sent packet
// and, if exp_same is true, all use the same mapped-address on the NAT.
@@ -48,10 +54,11 @@
SocketAddress server_addr = internal_addr;
server_addr.SetPort(0); // Auto-select a port
- NATServer* nat = new NATServer(
- nat_type, internal, server_addr, external, external_addrs[0]);
+ NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr,
+ external, external_addrs[0]);
NATSocketFactory* natsf = new NATSocketFactory(internal,
- nat->internal_address());
+ nat->internal_udp_address(),
+ nat->internal_tcp_address());
TestClient* in = CreateTestClient(natsf, internal_addr);
TestClient* out[4];
@@ -99,10 +106,11 @@
SocketAddress server_addr = internal_addr;
server_addr.SetPort(0); // Auto-select a port
- NATServer* nat = new NATServer(
- nat_type, internal, server_addr, external, external_addrs[0]);
+ NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr,
+ external, external_addrs[0]);
NATSocketFactory* natsf = new NATSocketFactory(internal,
- nat->internal_address());
+ nat->internal_udp_address(),
+ nat->internal_tcp_address());
TestClient* in = CreateTestClient(natsf, internal_addr);
TestClient* out[4];
@@ -295,56 +303,86 @@
}
}
-// TODO: Finish this test
class NatTcpTest : public testing::Test, public sigslot::has_slots<> {
public:
- NatTcpTest() : connected_(false) {}
- virtual void SetUp() {
- int_vss_ = new TestVirtualSocketServer(new PhysicalSocketServer());
- ext_vss_ = new TestVirtualSocketServer(new PhysicalSocketServer());
- nat_ = new NATServer(NAT_OPEN_CONE, int_vss_, SocketAddress(),
- ext_vss_, SocketAddress());
- natsf_ = new NATSocketFactory(int_vss_, nat_->internal_address());
+ NatTcpTest()
+ : int_addr_("192.168.0.1", 0),
+ ext_addr_("10.0.0.1", 0),
+ connected_(false),
+ int_pss_(new PhysicalSocketServer()),
+ ext_pss_(new PhysicalSocketServer()),
+ int_vss_(new TestVirtualSocketServer(int_pss_)),
+ ext_vss_(new TestVirtualSocketServer(ext_pss_)),
+ int_thread_(new Thread(int_vss_.get())),
+ ext_thread_(new Thread(ext_vss_.get())),
+ nat_(new NATServer(NAT_OPEN_CONE, int_vss_.get(), int_addr_, int_addr_,
+ ext_vss_.get(), ext_addr_)),
+ natsf_(new NATSocketFactory(int_vss_.get(),
+ nat_->internal_udp_address(),
+ nat_->internal_tcp_address())) {
+ int_thread_->Start();
+ ext_thread_->Start();
}
+
void OnConnectEvent(AsyncSocket* socket) {
connected_ = true;
}
+
void OnAcceptEvent(AsyncSocket* socket) {
- accepted_ = server_->Accept(NULL);
+ accepted_.reset(server_->Accept(NULL));
}
+
void OnCloseEvent(AsyncSocket* socket, int error) {
}
+
void ConnectEvents() {
server_->SignalReadEvent.connect(this, &NatTcpTest::OnAcceptEvent);
client_->SignalConnectEvent.connect(this, &NatTcpTest::OnConnectEvent);
}
- TestVirtualSocketServer* int_vss_;
- TestVirtualSocketServer* ext_vss_;
- NATServer* nat_;
- NATSocketFactory* natsf_;
- AsyncSocket* client_;
- AsyncSocket* server_;
- AsyncSocket* accepted_;
+
+ SocketAddress int_addr_;
+ SocketAddress ext_addr_;
bool connected_;
+ PhysicalSocketServer* int_pss_;
+ PhysicalSocketServer* ext_pss_;
+ rtc::scoped_ptr<TestVirtualSocketServer> int_vss_;
+ rtc::scoped_ptr<TestVirtualSocketServer> ext_vss_;
+ rtc::scoped_ptr<Thread> int_thread_;
+ rtc::scoped_ptr<Thread> ext_thread_;
+ rtc::scoped_ptr<NATServer> nat_;
+ rtc::scoped_ptr<NATSocketFactory> natsf_;
+ rtc::scoped_ptr<AsyncSocket> client_;
+ rtc::scoped_ptr<AsyncSocket> server_;
+ rtc::scoped_ptr<AsyncSocket> accepted_;
};
-TEST_F(NatTcpTest, DISABLED_TestConnectOut) {
- server_ = ext_vss_->CreateAsyncSocket(SOCK_STREAM);
- server_->Bind(SocketAddress());
+TEST_F(NatTcpTest, TestConnectOut) {
+ server_.reset(ext_vss_->CreateAsyncSocket(SOCK_STREAM));
+ server_->Bind(ext_addr_);
server_->Listen(5);
- client_ = int_vss_->CreateAsyncSocket(SOCK_STREAM);
- EXPECT_GE(0, client_->Bind(SocketAddress()));
+ client_.reset(natsf_->CreateAsyncSocket(SOCK_STREAM));
+ EXPECT_GE(0, client_->Bind(int_addr_));
EXPECT_GE(0, client_->Connect(server_->GetLocalAddress()));
-
ConnectEvents();
EXPECT_TRUE_WAIT(connected_, 1000);
EXPECT_EQ(client_->GetRemoteAddress(), server_->GetLocalAddress());
- EXPECT_EQ(client_->GetRemoteAddress(), accepted_->GetLocalAddress());
- EXPECT_EQ(client_->GetLocalAddress(), accepted_->GetRemoteAddress());
+ EXPECT_EQ(accepted_->GetRemoteAddress().ipaddr(), ext_addr_.ipaddr());
- client_->Close();
+ rtc::scoped_ptr<rtc::TestClient> in(CreateTCPTestClient(client_.release()));
+ rtc::scoped_ptr<rtc::TestClient> out(
+ CreateTCPTestClient(accepted_.release()));
+
+ const char* buf = "test_packet";
+ size_t len = strlen(buf);
+
+ in->Send(buf, len);
+ SocketAddress trans_addr;
+ EXPECT_TRUE(out->CheckNextPacket(buf, len, &trans_addr));
+
+ out->Send(buf, len);
+ EXPECT_TRUE(in->CheckNextPacket(buf, len, &trans_addr));
}
-//#endif
+// #endif
diff --git a/base/natserver.cc b/base/natserver.cc
index 0ce04d7..b071e01 100644
--- a/base/natserver.cc
+++ b/base/natserver.cc
@@ -11,6 +11,7 @@
#include "webrtc/base/natsocketfactory.h"
#include "webrtc/base/natserver.h"
#include "webrtc/base/logging.h"
+#include "webrtc/base/socketadapters.h"
namespace rtc {
@@ -63,14 +64,77 @@
return false;
}
+// Proxy socket that will capture the external destination address intended for
+// a TCP connection to the NAT server.
+class NATProxyServerSocket : public AsyncProxyServerSocket {
+ public:
+ NATProxyServerSocket(AsyncSocket* socket)
+ : AsyncProxyServerSocket(socket, kNATEncodedIPv6AddressSize) {
+ BufferInput(true);
+ }
+
+ void SendConnectResult(int err, const SocketAddress& addr) override {
+ char code = err ? 1 : 0;
+ BufferedReadAdapter::DirectSend(&code, sizeof(char));
+ }
+
+ protected:
+ void ProcessInput(char* data, size_t* len) override {
+ if (*len < 2) {
+ return;
+ }
+
+ int family = data[1];
+ ASSERT(family == AF_INET || family == AF_INET6);
+ if ((family == AF_INET && *len < kNATEncodedIPv4AddressSize) ||
+ (family == AF_INET6 && *len < kNATEncodedIPv6AddressSize)) {
+ return;
+ }
+
+ SocketAddress dest_addr;
+ size_t address_length = UnpackAddressFromNAT(data, *len, &dest_addr);
+
+ *len -= address_length;
+ if (*len > 0) {
+ memmove(data, data + address_length, *len);
+ }
+
+ bool remainder = (*len > 0);
+ BufferInput(false);
+ SignalConnectRequest(this, dest_addr);
+ if (remainder) {
+ SignalReadEvent(this);
+ }
+ }
+
+};
+
+class NATProxyServer : public ProxyServer {
+ public:
+ NATProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
+ SocketFactory* ext_factory, const SocketAddress& ext_ip)
+ : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {
+ }
+
+ protected:
+ AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override {
+ return new NATProxyServerSocket(socket);
+ }
+};
+
NATServer::NATServer(
- NATType type, SocketFactory* internal, const SocketAddress& internal_addr,
+ NATType type, SocketFactory* internal,
+ const SocketAddress& internal_udp_addr,
+ const SocketAddress& internal_tcp_addr,
SocketFactory* external, const SocketAddress& external_ip)
: external_(external), external_ip_(external_ip.ipaddr(), 0) {
nat_ = NAT::Create(type);
- server_socket_ = AsyncUDPSocket::Create(internal, internal_addr);
- server_socket_->SignalReadPacket.connect(this, &NATServer::OnInternalPacket);
+ udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr);
+ udp_server_socket_->SignalReadPacket.connect(this,
+ &NATServer::OnInternalUDPPacket);
+ tcp_proxy_server_ = new NATProxyServer(internal, internal_tcp_addr, external,
+ external_ip);
int_map_ = new InternalMap(RouteCmp(nat_));
ext_map_ = new ExternalMap();
@@ -83,15 +147,15 @@
delete iter->second;
delete nat_;
- delete server_socket_;
+ delete udp_server_socket_;
+ delete tcp_proxy_server_;
delete int_map_;
delete ext_map_;
}
-void NATServer::OnInternalPacket(
+void NATServer::OnInternalUDPPacket(
AsyncPacketSocket* socket, const char* buf, size_t size,
const SocketAddress& addr, const PacketTime& packet_time) {
-
// Read the intended destination from the wire.
SocketAddress dest_addr;
size_t length = UnpackAddressFromNAT(buf, size, &dest_addr);
@@ -113,10 +177,9 @@
iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
}
-void NATServer::OnExternalPacket(
+void NATServer::OnExternalUDPPacket(
AsyncPacketSocket* socket, const char* buf, size_t size,
const SocketAddress& remote_addr, const PacketTime& packet_time) {
-
SocketAddress local_addr = socket->GetLocalAddress();
// Find the translation for this addresses.
@@ -139,8 +202,8 @@
// Copy the data part after the address.
rtc::PacketOptions options;
memcpy(real_buf.get() + addrlength, buf, size);
- server_socket_->SendTo(real_buf.get(), size + addrlength,
- iter->second->route.source(), options);
+ udp_server_socket_->SendTo(real_buf.get(), size + addrlength,
+ iter->second->route.source(), options);
}
void NATServer::Translate(const SocketAddressPair& route) {
@@ -154,7 +217,7 @@
TransEntry* entry = new TransEntry(route, socket, nat_);
(*int_map_)[route] = entry;
(*ext_map_)[socket->GetLocalAddress()] = entry;
- socket->SignalReadPacket.connect(this, &NATServer::OnExternalPacket);
+ socket->SignalReadPacket.connect(this, &NATServer::OnExternalUDPPacket);
}
bool NATServer::ShouldFilterOut(TransEntry* entry,
diff --git a/base/natserver.h b/base/natserver.h
index 5975620..e987021 100644
--- a/base/natserver.h
+++ b/base/natserver.h
@@ -19,6 +19,7 @@
#include "webrtc/base/thread.h"
#include "webrtc/base/socketfactory.h"
#include "webrtc/base/nattypes.h"
+#include "webrtc/base/proxyserver.h"
namespace rtc {
@@ -46,27 +47,40 @@
// Implements the NAT device. It listens for packets on the internal network,
// translates them, and sends them out over the external network.
+//
+// TCP connections initiated from the internal side of the NAT server are
+// also supported, by making a connection to the NAT server's TCP address and
+// then sending the remote address in quasi-STUN format. The connection status
+// will be indicated back to the client as a 1 byte status code, where '0'
+// indicates success.
-const int NAT_SERVER_PORT = 4237;
+const int NAT_SERVER_UDP_PORT = 4237;
+const int NAT_SERVER_TCP_PORT = 4238;
class NATServer : public sigslot::has_slots<> {
public:
NATServer(
- NATType type, SocketFactory* internal, const SocketAddress& internal_addr,
+ NATType type, SocketFactory* internal,
+ const SocketAddress& internal_udp_addr,
+ const SocketAddress& internal_tcp_addr,
SocketFactory* external, const SocketAddress& external_ip);
~NATServer() override;
- SocketAddress internal_address() const {
- return server_socket_->GetLocalAddress();
+ SocketAddress internal_udp_address() const {
+ return udp_server_socket_->GetLocalAddress();
+ }
+
+ SocketAddress internal_tcp_address() const {
+ return tcp_proxy_server_->GetServerAddress();
}
// Packets received on one of the networks.
- void OnInternalPacket(AsyncPacketSocket* socket, const char* buf,
- size_t size, const SocketAddress& addr,
- const PacketTime& packet_time);
- void OnExternalPacket(AsyncPacketSocket* socket, const char* buf,
- size_t size, const SocketAddress& remote_addr,
- const PacketTime& packet_time);
+ void OnInternalUDPPacket(AsyncPacketSocket* socket, const char* buf,
+ size_t size, const SocketAddress& addr,
+ const PacketTime& packet_time);
+ void OnExternalUDPPacket(AsyncPacketSocket* socket, const char* buf,
+ size_t size, const SocketAddress& remote_addr,
+ const PacketTime& packet_time);
private:
typedef std::set<SocketAddress, AddrCmp> AddressSet;
@@ -98,8 +112,8 @@
SocketFactory* internal_;
SocketFactory* external_;
SocketAddress external_ip_;
- AsyncUDPSocket* server_socket_;
- AsyncSocket* tcp_server_socket_;
+ AsyncUDPSocket* udp_server_socket_;
+ ProxyServer* tcp_proxy_server_;
InternalMap* int_map_;
ExternalMap* ext_map_;
DISALLOW_COPY_AND_ASSIGN(NATServer);
diff --git a/base/natsocketfactory.cc b/base/natsocketfactory.cc
index 9c6756b..a23a7e8 100644
--- a/base/natsocketfactory.cc
+++ b/base/natsocketfactory.cc
@@ -179,8 +179,7 @@
// Decode the wire packet into the actual results.
SocketAddress real_remote_addr;
- size_t addrlength =
- UnpackAddressFromNAT(buf_, result, &real_remote_addr);
+ size_t addrlength = UnpackAddressFromNAT(buf_, result, &real_remote_addr);
memcpy(data, buf_ + addrlength, result - addrlength);
// Make sure this packet should be delivered before returning it.
@@ -230,7 +229,7 @@
}
void OnConnectEvent(AsyncSocket* socket) {
- // If we're NATed, we need to send a request with the real addr to use.
+ // If we're NATed, we need to send a message with the real addr to use.
ASSERT(socket == socket_);
if (server_addr_.IsNil()) {
connected_ = true;
@@ -269,7 +268,7 @@
// Sends the destination address to the server to tell it to connect.
void SendConnectRequest() {
- char buf[256];
+ char buf[kNATEncodedIPv6AddressSize];
size_t length = PackAddressForNAT(buf, ARRAY_SIZE(buf), remote_addr_);
socket_->Send(buf, length);
}
@@ -279,6 +278,7 @@
char code;
socket_->Recv(&code, sizeof(code));
if (code == 0) {
+ connected_ = true;
SignalConnectEvent(this);
} else {
Close();
@@ -299,8 +299,10 @@
// NATSocketFactory
NATSocketFactory::NATSocketFactory(SocketFactory* factory,
- const SocketAddress& nat_addr)
- : factory_(factory), nat_addr_(nat_addr) {
+ const SocketAddress& nat_udp_addr,
+ const SocketAddress& nat_tcp_addr)
+ : factory_(factory), nat_udp_addr_(nat_udp_addr),
+ nat_tcp_addr_(nat_tcp_addr) {
}
Socket* NATSocketFactory::CreateSocket(int type) {
@@ -321,7 +323,11 @@
AsyncSocket* NATSocketFactory::CreateInternalSocket(int family, int type,
const SocketAddress& local_addr, SocketAddress* nat_addr) {
- *nat_addr = nat_addr_;
+ if (type == SOCK_STREAM) {
+ *nat_addr = nat_tcp_addr_;
+ } else {
+ *nat_addr = nat_udp_addr_;
+ }
return factory_->CreateAsyncSocket(family, type);
}
@@ -385,7 +391,7 @@
if (nat) {
socket = nat->internal_factory()->CreateAsyncSocket(family, type);
*nat_addr = (type == SOCK_STREAM) ?
- nat->internal_tcp_address() : nat->internal_address();
+ nat->internal_tcp_address() : nat->internal_udp_address();
} else {
socket = server_->CreateAsyncSocket(family, type);
}
@@ -403,7 +409,7 @@
VirtualSocketServer* internal_server = new VirtualSocketServer(server_);
internal_server->SetMessageQueue(server_->queue());
internal_factory_.reset(internal_server);
- nat_server_.reset(new NATServer(type, internal_server, int_ip,
+ nat_server_.reset(new NATServer(type, internal_server, int_ip, int_ip,
ext_factory, ext_ip));
}
diff --git a/base/natsocketfactory.h b/base/natsocketfactory.h
index 9a189d8..3519cf0 100644
--- a/base/natsocketfactory.h
+++ b/base/natsocketfactory.h
@@ -37,7 +37,8 @@
// from a socket factory, given to the constructor.
class NATSocketFactory : public SocketFactory, public NATInternalSocketFactory {
public:
- NATSocketFactory(SocketFactory* factory, const SocketAddress& nat_addr);
+ NATSocketFactory(SocketFactory* factory, const SocketAddress& nat_udp_addr,
+ const SocketAddress& nat_tcp_addr);
// SocketFactory implementation
Socket* CreateSocket(int type) override;
@@ -53,7 +54,8 @@
private:
SocketFactory* factory_;
- SocketAddress nat_addr_;
+ SocketAddress nat_udp_addr_;
+ SocketAddress nat_tcp_addr_;
DISALLOW_COPY_AND_ASSIGN(NATSocketFactory);
};
@@ -94,8 +96,8 @@
~Translator();
SocketFactory* internal_factory() { return internal_factory_.get(); }
- SocketAddress internal_address() const {
- return nat_server_->internal_address();
+ SocketAddress internal_udp_address() const {
+ return nat_server_->internal_udp_address();
}
SocketAddress internal_tcp_address() const {
return SocketAddress(); // nat_server_->internal_tcp_address();
diff --git a/base/proxyserver.cc b/base/proxyserver.cc
index 8f12a99..d91a92f 100644
--- a/base/proxyserver.cc
+++ b/base/proxyserver.cc
@@ -36,6 +36,10 @@
}
}
+SocketAddress ProxyServer::GetServerAddress() {
+ return server_socket_->GetLocalAddress();
+}
+
void ProxyServer::OnAcceptEvent(AsyncSocket* socket) {
ASSERT(socket != NULL && socket == server_socket_.get());
AsyncSocket* int_socket = socket->Accept(NULL);
diff --git a/base/proxyserver.h b/base/proxyserver.h
index 83fe6c2..711ed55 100644
--- a/base/proxyserver.h
+++ b/base/proxyserver.h
@@ -64,6 +64,9 @@
SocketFactory* ext_factory, const SocketAddress& ext_ip);
~ProxyServer() override;
+ // Returns the address to which the proxy server is bound
+ SocketAddress GetServerAddress();
+
protected:
void OnAcceptEvent(AsyncSocket* socket);
virtual AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) = 0;
diff --git a/base/socketadapters.cc b/base/socketadapters.cc
index 4a2da0a..b1c2a87 100644
--- a/base/socketadapters.cc
+++ b/base/socketadapters.cc
@@ -81,10 +81,18 @@
// FIX: If cb == 0, we won't generate another read event
int res = AsyncSocketAdapter::Recv(pv, cb);
- if (res < 0)
- return res;
+ if (res >= 0) {
+ // Read from socket and possibly buffer; return combined length
+ return res + static_cast<int>(read);
+ }
- return res + static_cast<int>(read);
+ if (read > 0) {
+ // Failed to read from socket, but still read something from buffer
+ return static_cast<int>(read);
+ }
+
+ // Didn't read anything; return error from socket
+ return res;
}
void BufferedReadAdapter::BufferInput(bool on) {
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
index 57618b7..4877af3 100644
--- a/p2p/base/port_unittest.cc
+++ b/p2p/base/port_unittest.cc
@@ -47,8 +47,8 @@
static const int kTimeout = 1000;
static const SocketAddress kLocalAddr1("192.168.1.2", 0);
static const SocketAddress kLocalAddr2("192.168.1.3", 0);
-static const SocketAddress kNatAddr1("77.77.77.77", rtc::NAT_SERVER_PORT);
-static const SocketAddress kNatAddr2("88.88.88.88", rtc::NAT_SERVER_PORT);
+static const SocketAddress kNatAddr1("77.77.77.77", rtc::NAT_SERVER_UDP_PORT);
+static const SocketAddress kNatAddr2("88.88.88.88", rtc::NAT_SERVER_UDP_PORT);
static const SocketAddress kStunAddr("99.99.99.1", STUN_SERVER_PORT);
static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
@@ -343,8 +343,8 @@
ss_scope_(ss_.get()),
network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32),
socket_factory_(rtc::Thread::Current()),
- nat_factory1_(ss_.get(), kNatAddr1),
- nat_factory2_(ss_.get(), kNatAddr2),
+ nat_factory1_(ss_.get(), kNatAddr1, SocketAddress()),
+ nat_factory2_(ss_.get(), kNatAddr2, SocketAddress()),
nat_socket_factory1_(&nat_factory1_),
nat_socket_factory2_(&nat_factory2_),
stun_server_(TestStunServer::Create(main_, kStunAddr)),
@@ -507,7 +507,7 @@
}
rtc::NATServer* CreateNatServer(const SocketAddress& addr,
rtc::NATType type) {
- return new rtc::NATServer(type, ss_.get(), addr, ss_.get(), addr);
+ return new rtc::NATServer(type, ss_.get(), addr, addr, ss_.get(), addr);
}
static const char* StunName(NATType type) {
switch (type) {
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
index bdafe35..1965ad9 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -208,7 +208,7 @@
BasicPortAllocator::~BasicPortAllocator() {
}
-PortAllocatorSession *BasicPortAllocator::CreateSessionInternal(
+PortAllocatorSession* BasicPortAllocator::CreateSessionInternal(
const std::string& content_name, int component,
const std::string& ice_ufrag, const std::string& ice_pwd) {
return new BasicPortAllocatorSession(
@@ -927,18 +927,10 @@
// If STUN is not disabled, setting stun server address to port.
if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) {
- // If config has stun_servers, use it to get server reflexive candidate
- // otherwise use first TURN server which supports UDP.
if (config_ && !config_->StunServers().empty()) {
LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the "
<< "STUN candidate generation.";
port->set_server_addresses(config_->StunServers());
- } else if (config_ &&
- config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) {
- port->set_server_addresses(config_->GetRelayServerAddresses(
- RELAY_TURN, PROTO_UDP));
- LOG(LS_INFO) << "AllocationSequence: TURN Server address will be "
- << " used for generating STUN candidate.";
}
}
}
@@ -1171,6 +1163,13 @@
stun_servers.find(stun_address) == stun_servers.end()) {
stun_servers.insert(stun_address);
}
+ // Every UDP TURN server should also be used as a STUN server.
+ ServerAddresses turn_servers = GetRelayServerAddresses(RELAY_TURN, PROTO_UDP);
+ for (const rtc::SocketAddress& turn_server : turn_servers) {
+ if (stun_servers.find(turn_server) == stun_servers.end()) {
+ stun_servers.insert(turn_server);
+ }
+ }
return stun_servers;
}
diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h
index 96468d3..f2d92ef 100644
--- a/p2p/client/basicportallocator.h
+++ b/p2p/client/basicportallocator.h
@@ -220,7 +220,8 @@
const std::string& username,
const std::string& password);
- // TODO(jiayl): remove when |stun_address| is removed.
+ // Returns addresses of both the explicitly configured STUN servers,
+ // and TURN servers that should be used as STUN servers.
ServerAddresses StunServers();
// Adds another relay server, with the given ports and modifier, to the list.
diff --git a/p2p/client/portallocator_unittest.cc b/p2p/client/portallocator_unittest.cc
index 017c37a..6940ea1 100644
--- a/p2p/client/portallocator_unittest.cc
+++ b/p2p/client/portallocator_unittest.cc
@@ -40,7 +40,8 @@
static const SocketAddress kClientIPv6Addr(
"2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
static const SocketAddress kClientAddr2("22.22.22.22", 0);
-static const SocketAddress kNatAddr("77.77.77.77", rtc::NAT_SERVER_PORT);
+static const SocketAddress kNatUdpAddr("77.77.77.77", rtc::NAT_SERVER_UDP_PORT);
+static const SocketAddress kNatTcpAddr("77.77.77.77", rtc::NAT_SERVER_TCP_PORT);
static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
@@ -85,7 +86,7 @@
vss_(new rtc::VirtualSocketServer(pss_.get())),
fss_(new rtc::FirewallSocketServer(vss_.get())),
ss_scope_(fss_.get()),
- nat_factory_(vss_.get(), kNatAddr),
+ nat_factory_(vss_.get(), kNatUdpAddr, kNatTcpAddr),
nat_socket_factory_(&nat_factory_),
stun_server_(cricket::TestStunServer::Create(Thread::Current(),
kStunAddr)),
@@ -113,7 +114,8 @@
}
void ResetWithNatServer(const rtc::SocketAddress& stun_server) {
nat_server_.reset(new rtc::NATServer(
- rtc::NAT_OPEN_CONE, vss_.get(), kNatAddr, vss_.get(), kNatAddr));
+ rtc::NAT_OPEN_CONE, vss_.get(), kNatUdpAddr, kNatTcpAddr, vss_.get(),
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0)));
ServerAddresses stun_servers;
if (!stun_server.IsNil()) {
@@ -241,7 +243,7 @@
EXPECT_PRED5(CheckCandidate, candidates_[0],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
- rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
EXPECT_EQ(
rtc::EmptySocketAddressWithFamily(candidates_[0].address().family()),
candidates_[0].related_address());
@@ -249,7 +251,7 @@
EXPECT_PRED5(CheckCandidate, candidates_[1],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
- EXPECT_EQ(kNatAddr.ipaddr(), candidates_[1].related_address().ipaddr());
+ EXPECT_EQ(kNatUdpAddr.ipaddr(), candidates_[1].related_address().ipaddr());
}
protected:
@@ -779,12 +781,12 @@
cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
EXPECT_PRED5(CheckCandidate, candidates_[1],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
- rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
EXPECT_EQ(3U, candidates_.size());
}
-// Test TURN port in shared socket mode with UDP and TCP TURN server adderesses.
+// Test TURN port in shared socket mode with UDP and TCP TURN server addresses.
TEST_F(PortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) {
turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
AddInterface(kClientAddr);
@@ -865,7 +867,7 @@
cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
EXPECT_PRED5(CheckCandidate, candidates_[1],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
- rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
EXPECT_PRED5(CheckCandidate, candidates_[2],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
@@ -903,7 +905,7 @@
cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr);
EXPECT_PRED5(CheckCandidate, candidates_[1],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
- rtc::SocketAddress(kNatAddr.ipaddr(), 0));
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
EXPECT_PRED5(CheckCandidate, candidates_[2],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
@@ -916,6 +918,111 @@
EXPECT_EQ(1U, ports_[1]->Candidates().size());
}
+// Test that when only a TCP TURN server is available, we do NOT use it as
+// a UDP STUN server, as this could leak our IP address. Thus we should only
+// expect two ports, a UDPPort and TurnPort.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurnTcpOnly) {
+ turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
+ AddInterface(kClientAddr);
+ ResetWithNatServer(rtc::SocketAddress());
+ AddTurnServers(rtc::SocketAddress(), kTurnTcpIntAddr);
+
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ ASSERT_EQ_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout);
+ ASSERT_EQ(2U, ports_.size());
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+ kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_EQ(2U, candidates_.size());
+ EXPECT_EQ(1U, ports_[0]->Candidates().size());
+ EXPECT_EQ(1U, ports_[1]->Candidates().size());
+}
+
+// Test that even when PORTALLOCATOR_ENABLE_SHARED_SOCKET is NOT enabled, the
+// TURN server is used as the STUN server and we get 'local', 'stun', and
+// 'relay' candidates.
+// TODO(deadbeef): Remove this test when support for non-shared socket mode
+// is removed.
+TEST_F(PortAllocatorTest, TestNonSharedSocketWithNatUsingTurnAsStun) {
+ AddInterface(kClientAddr);
+ // Use an empty SocketAddress to add a NAT without STUN server.
+ ResetWithNatServer(SocketAddress());
+ AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
+
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+ ASSERT_EQ(3U, ports_.size());
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+ kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ // Not using shared socket, so the STUN request's server reflexive address
+ // should be different than the TURN request's server reflexive address.
+ EXPECT_NE(candidates_[2].related_address(), candidates_[1].address());
+
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_EQ(3U, candidates_.size());
+ EXPECT_EQ(1U, ports_[0]->Candidates().size());
+ EXPECT_EQ(1U, ports_[1]->Candidates().size());
+ EXPECT_EQ(1U, ports_[2]->Candidates().size());
+}
+
+// Test that even when both a STUN and TURN server are configured, the TURN
+// server is used as a STUN server and we get a 'stun' candidate.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurnAndStun) {
+ AddInterface(kClientAddr);
+ // Configure with STUN server but destroy it, so we can ensure that it's
+ // the TURN server actually being used as a STUN server.
+ ResetWithNatServer(kStunAddr);
+ stun_server_.reset();
+ AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
+
+ allocator_->set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
+ cricket::PORTALLOCATOR_DISABLE_TCP);
+
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+
+ ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout);
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+ kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
+ rtc::SocketAddress(kNatUdpAddr.ipaddr(), 0));
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_EQ(candidates_[2].related_address(), candidates_[1].address());
+
+ // Don't bother waiting for STUN timeout, since we already verified
+ // that we got a STUN candidate from the TURN server.
+}
+
// This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled
// and fail to generate STUN candidate, local UDP candidate is generated
// properly.