summaryrefslogtreecommitdiff
path: root/p2p
diff options
context:
space:
mode:
authorbuildbot@webrtc.org <buildbot@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-04-14 16:06:21 +0000
committerbuildbot@webrtc.org <buildbot@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-04-14 16:06:21 +0000
commitafaf4d10603cf012a13d43a62fbc43c0757ec3b9 (patch)
tree6876925c3b5e2608ae3c0861764a85aed6177080 /p2p
parent92ad4370e12c1017bcc1137e738d81957a2d038e (diff)
downloadtalk-afaf4d10603cf012a13d43a62fbc43c0757ec3b9.tar.gz
(Auto)update libjingle 64709629-> 64813990
git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@5897 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'p2p')
-rw-r--r--p2p/base/port.cc3
-rw-r--r--p2p/base/port.h9
-rw-r--r--p2p/base/port_unittest.cc26
-rw-r--r--p2p/base/relayport.cc11
-rw-r--r--p2p/base/stunport.cc12
-rw-r--r--p2p/base/stunport_unittest.cc3
-rw-r--r--p2p/base/tcpport.cc8
-rw-r--r--p2p/base/turnport.cc88
-rw-r--r--p2p/base/turnport.h46
-rw-r--r--p2p/base/turnport_unittest.cc40
-rw-r--r--p2p/client/basicportallocator.cc120
-rw-r--r--p2p/client/basicportallocator.h5
-rw-r--r--p2p/client/connectivitychecker_unittest.cc2
-rw-r--r--p2p/client/portallocator_unittest.cc55
14 files changed, 339 insertions, 89 deletions
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 38157f4..ad692ce 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -248,6 +248,7 @@ Connection* Port::GetConnection(const talk_base::SocketAddress& remote_addr) {
void Port::AddAddress(const talk_base::SocketAddress& address,
const talk_base::SocketAddress& base_address,
+ const talk_base::SocketAddress& related_address,
const std::string& protocol,
const std::string& type,
uint32 type_preference,
@@ -263,7 +264,7 @@ void Port::AddAddress(const talk_base::SocketAddress& address,
c.set_password(password_);
c.set_network_name(network_->name());
c.set_generation(generation_);
- c.set_related_address(related_address_);
+ c.set_related_address(related_address);
c.set_foundation(ComputeFoundation(type, protocol, base_address));
candidates_.push_back(c);
SignalCandidateReady(this, c);
diff --git a/p2p/base/port.h b/p2p/base/port.h
index ff68dd0..6e5c383 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -172,13 +172,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
send_retransmit_count_attribute_ = enable;
}
- const talk_base::SocketAddress& related_address() const {
- return related_address_;
- }
- void set_related_address(const talk_base::SocketAddress& address) {
- related_address_ = address;
- }
-
// Identifies the generation that this port was created in.
uint32 generation() { return generation_; }
void set_generation(uint32 generation) { generation_ = generation; }
@@ -315,6 +308,7 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Fills in the local address of the port.
void AddAddress(const talk_base::SocketAddress& address,
const talk_base::SocketAddress& base_address,
+ const talk_base::SocketAddress& related_address,
const std::string& protocol, const std::string& type,
uint32 type_preference, bool final);
@@ -365,7 +359,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
std::string content_name_;
int component_;
uint32 generation_;
- talk_base::SocketAddress related_address_;
// In order to establish a connection to this Port (so that real data can be
// sent through), the other side must send us a STUN binding request that is
// authenticated with this username_fragment and password.
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
index a6365d5..61a2f4e 100644
--- a/p2p/base/port_unittest.cc
+++ b/p2p/base/port_unittest.cc
@@ -146,19 +146,21 @@ class TestPort : public Port {
virtual void PrepareAddress() {
talk_base::SocketAddress addr(ip(), min_port());
- AddAddress(addr, addr, "udp", Type(), ICE_TYPE_PREFERENCE_HOST, true);
+ AddAddress(addr, addr, talk_base::SocketAddress(), "udp", Type(),
+ ICE_TYPE_PREFERENCE_HOST, true);
}
// Exposed for testing candidate building.
void AddCandidateAddress(const talk_base::SocketAddress& addr) {
- AddAddress(addr, addr, "udp", Type(), type_preference_, false);
+ AddAddress(addr, addr, talk_base::SocketAddress(), "udp", Type(),
+ type_preference_, false);
}
void AddCandidateAddress(const talk_base::SocketAddress& addr,
const talk_base::SocketAddress& base_address,
const std::string& type,
int type_preference,
bool final) {
- AddAddress(addr, base_address, "udp", type,
+ AddAddress(addr, base_address, talk_base::SocketAddress(), "udp", type,
type_preference, final);
}
@@ -2169,12 +2171,16 @@ TEST_F(PortTest, TestCandidateFoundation) {
talk_base::scoped_ptr<Port> turnport(CreateTurnPort(
kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
turnport->PrepareAddress();
- ASSERT_EQ_WAIT(1U, turnport->Candidates().size(), kTimeout);
+ ASSERT_EQ_WAIT(2U, turnport->Candidates().size(), kTimeout);
+ EXPECT_NE(turnport->Candidates()[0].foundation(),
+ turnport->Candidates()[1].foundation());
EXPECT_NE(udpport1->Candidates()[0].foundation(),
- turnport->Candidates()[0].foundation());
+ turnport->Candidates()[1].foundation());
EXPECT_NE(udpport2->Candidates()[0].foundation(),
- turnport->Candidates()[0].foundation());
+ turnport->Candidates()[1].foundation());
EXPECT_NE(stunport->Candidates()[0].foundation(),
+ turnport->Candidates()[1].foundation());
+ EXPECT_EQ(stunport->Candidates()[0].foundation(),
turnport->Candidates()[0].foundation());
}
@@ -2217,11 +2223,13 @@ TEST_F(PortTest, TestCandidateRelatedAddress) {
talk_base::scoped_ptr<Port> turnport(CreateTurnPort(
kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
turnport->PrepareAddress();
- ASSERT_EQ_WAIT(1U, turnport->Candidates().size(), kTimeout);
+ ASSERT_EQ_WAIT(2U, turnport->Candidates().size(), kTimeout);
EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
- turnport->Candidates()[0].address().ipaddr());
- EXPECT_EQ(kNatAddr1.ipaddr(),
+ turnport->Candidates()[1].address().ipaddr());
+ EXPECT_EQ(kLocalAddr1.ipaddr(),
turnport->Candidates()[0].related_address().ipaddr());
+ EXPECT_EQ(kNatAddr1.ipaddr(),
+ turnport->Candidates()[1].related_address().ipaddr());
}
// Test priority value overflow handling when preference is set to 3.
diff --git a/p2p/base/relayport.cc b/p2p/base/relayport.cc
index af768e4..23571ea 100644
--- a/p2p/base/relayport.cc
+++ b/p2p/base/relayport.cc
@@ -240,8 +240,11 @@ void RelayPort::SetReady() {
for (iter = external_addr_.begin();
iter != external_addr_.end(); ++iter) {
std::string proto_name = ProtoToString(iter->proto);
- AddAddress(iter->address, iter->address, proto_name,
- RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
+ // In case of Gturn, related address is set to null socket address.
+ // This is due to as mapped address stun attribute is used for allocated
+ // address.
+ AddAddress(iter->address, iter->address, talk_base::SocketAddress(),
+ proto_name, RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY, false);
}
ready_ = true;
SignalPortComplete(this);
@@ -548,10 +551,6 @@ void RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr,
<< " @ " << mapped_addr.ToSensitiveString();
connected_ = true;
- // In case of Gturn related address is set to null socket address.
- // This is due to mapped address stun attribute is used for allocated
- // address.
- port_->set_related_address(talk_base::SocketAddress());
port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
port_->SetReady();
}
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index 95b26ac..e9a2bb9 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -173,7 +173,7 @@ bool UDPPort::Init() {
UDPPort::~UDPPort() {
if (resolver_) {
- resolver_->Destroy(false);
+ resolver_->Destroy(true);
}
if (!SharedSocket())
delete socket_;
@@ -243,7 +243,8 @@ int UDPPort::GetError() {
void UDPPort::OnLocalAddressReady(talk_base::AsyncPacketSocket* socket,
const talk_base::SocketAddress& address) {
- AddAddress(address, address, UDP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
+ AddAddress(address, address, talk_base::SocketAddress(),
+ UDP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
ICE_TYPE_PREFERENCE_HOST, false);
MaybePrepareStunCandidate();
}
@@ -324,10 +325,9 @@ void UDPPort::OnStunBindingRequestSucceeded(
if (!SharedSocket() || stun_addr != socket_->GetLocalAddress()) {
// If socket is shared and |stun_addr| is equal to local socket
// address then discarding the stun address.
- // Setting related address before STUN candidate is added. For STUN
- // related address is local socket address.
- set_related_address(socket_->GetLocalAddress());
- AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
+ // For STUN related address is local socket address.
+ AddAddress(stun_addr, socket_->GetLocalAddress(),
+ socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, false);
}
SetResult(true);
diff --git a/p2p/base/stunport_unittest.cc b/p2p/base/stunport_unittest.cc
index 2a98a9f..5850027 100644
--- a/p2p/base/stunport_unittest.cc
+++ b/p2p/base/stunport_unittest.cc
@@ -43,6 +43,8 @@ static const SocketAddress kBadAddr("0.0.0.1", 5000);
static const SocketAddress kStunHostnameAddr("localhost", 5000);
static const SocketAddress kBadHostnameAddr("not-a-real-hostname", 5000);
static const int kTimeoutMs = 10000;
+// stun prio = 100 << 24 | 30 (IPV4) << 8 | 256 - 0
+static const uint32 kStunCandidatePriority = 1677729535;
// Tests connecting a StunPort to a fake STUN server (cricket::StunServer)
// TODO: Use a VirtualSocketServer here. We have to use a
@@ -178,6 +180,7 @@ TEST_F(StunPortTest, TestPrepareAddressHostname) {
EXPECT_TRUE_WAIT(done(), kTimeoutMs);
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address()));
+ EXPECT_EQ(kStunCandidatePriority, port()->Candidates()[0].priority());
}
// Test that we handle hostname lookup failures properly.
diff --git a/p2p/base/tcpport.cc b/p2p/base/tcpport.cc
index d83623f..f74ad8b 100644
--- a/p2p/base/tcpport.cc
+++ b/p2p/base/tcpport.cc
@@ -121,6 +121,7 @@ void TCPPort::PrepareAddress() {
if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND ||
socket_->GetState() == talk_base::AsyncPacketSocket::STATE_CLOSED)
AddAddress(socket_->GetLocalAddress(), socket_->GetLocalAddress(),
+ talk_base::SocketAddress(),
TCP_PROTOCOL_NAME, LOCAL_PORT_TYPE,
ICE_TYPE_PREFERENCE_HOST_TCP, true);
} else {
@@ -128,8 +129,9 @@ void TCPPort::PrepareAddress() {
// Note: We still add the address, since otherwise the remote side won't
// recognize our incoming TCP connections.
AddAddress(talk_base::SocketAddress(ip(), 0),
- talk_base::SocketAddress(ip(), 0), TCP_PROTOCOL_NAME,
- LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP, true);
+ talk_base::SocketAddress(ip(), 0), talk_base::SocketAddress(),
+ TCP_PROTOCOL_NAME, LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP,
+ true);
}
}
@@ -221,7 +223,7 @@ void TCPPort::OnReadyToSend(talk_base::AsyncPacketSocket* socket) {
void TCPPort::OnAddressReady(talk_base::AsyncPacketSocket* socket,
const talk_base::SocketAddress& address) {
- AddAddress(address, address, "tcp",
+ AddAddress(address, address, talk_base::SocketAddress(), "tcp",
LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP,
true);
}
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index eeaa3af..b9eba75 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -50,6 +50,7 @@ static const int TURN_CHANNEL_NUMBER_START = 0x4000;
static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
+static const size_t MAX_CANDIDATES_PER_TURNPORT = 2; // A STUN + TURN
inline bool IsTurnChannelData(uint16 msg_type) {
return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
@@ -171,6 +172,27 @@ class TurnEntry : public sigslot::has_slots<> {
TurnPort::TurnPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username,
+ const std::string& password,
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials)
+ : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
+ username, password),
+ server_address_(server_address),
+ credentials_(credentials),
+ socket_(socket),
+ resolver_(NULL),
+ error_(0),
+ request_manager_(thread),
+ next_channel_number_(TURN_CHANNEL_NUMBER_START),
+ connected_(false) {
+ request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
+}
+
+TurnPort::TurnPort(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username,
@@ -181,6 +203,7 @@ TurnPort::TurnPort(talk_base::Thread* thread,
username, password),
server_address_(server_address),
credentials_(credentials),
+ socket_(NULL),
resolver_(NULL),
error_(0),
request_manager_(thread),
@@ -197,6 +220,9 @@ TurnPort::~TurnPort() {
if (resolver_) {
resolver_->Destroy(false);
}
+ if (!SharedSocket()) {
+ delete socket_;
+ }
}
void TurnPort::PrepareAddress() {
@@ -227,19 +253,18 @@ void TurnPort::PrepareAddress() {
LOG_J(LS_INFO, this) << "Trying to connect to TURN server via "
<< ProtoToString(server_address_.proto) << " @ "
<< server_address_.address.ToSensitiveString();
- if (server_address_.proto == PROTO_UDP) {
- socket_.reset(socket_factory()->CreateUdpSocket(
- talk_base::SocketAddress(ip(), 0), min_port(), max_port()));
+ if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
+ socket_ = socket_factory()->CreateUdpSocket(
+ talk_base::SocketAddress(ip(), 0), min_port(), max_port());
} else if (server_address_.proto == PROTO_TCP) {
int opts = talk_base::PacketSocketFactory::OPT_STUN;
// If secure bit is enabled in server address, use TLS over TCP.
if (server_address_.secure) {
opts |= talk_base::PacketSocketFactory::OPT_TLS;
}
-
- socket_.reset(socket_factory()->CreateClientTcpSocket(
+ socket_ = socket_factory()->CreateClientTcpSocket(
talk_base::SocketAddress(ip(), 0), server_address_.address,
- proxy(), user_agent(), opts));
+ proxy(), user_agent(), opts);
}
if (!socket_) {
@@ -253,7 +278,11 @@ void TurnPort::PrepareAddress() {
socket_->SetOption(iter->first, iter->second);
}
- socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
+ if (!SharedSocket()) {
+ // If socket is shared, AllocationSequence will receive the packet.
+ socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
+ }
+
socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
if (server_address_.proto == PROTO_TCP) {
@@ -294,12 +323,18 @@ Connection* TurnPort::CreateConnection(const Candidate& address,
// Create an entry, if needed, so we can get our permissions set up correctly.
CreateEntry(address.address());
- // TODO(juberti): The '0' index will need to change if we start gathering STUN
- // candidates on this port.
- ProxyConnection* conn = new ProxyConnection(this, 0, address);
- conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
- AddConnection(conn);
- return conn;
+ // A TURN port will have two candiates, STUN and TURN. STUN may not
+ // present in all cases. If present stun candidate will be added first
+ // and TURN candidate later.
+ for (size_t index = 0; index < Candidates().size(); ++index) {
+ if (Candidates()[index].type() == RELAY_PORT_TYPE) {
+ ProxyConnection* conn = new ProxyConnection(this, index, address);
+ conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed);
+ AddConnection(conn);
+ return conn;
+ }
+ }
+ return NULL;
}
int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
@@ -360,7 +395,7 @@ void TurnPort::OnReadPacket(
talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
const talk_base::SocketAddress& remote_addr,
const talk_base::PacketTime& packet_time) {
- ASSERT(socket == socket_.get());
+ ASSERT(socket == socket_);
ASSERT(remote_addr == server_address_.address);
// The message must be at least the size of a channel header.
@@ -415,6 +450,8 @@ void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
return;
}
+ SignalResolvedServerAddress(this, server_address_.address,
+ resolver_->address());
PrepareAddress();
}
@@ -428,15 +465,25 @@ void TurnPort::OnSendStunPacket(const void* data, size_t size,
}
void TurnPort::OnStunAddress(const talk_base::SocketAddress& address) {
- // For relay, mapped address is rel-addr.
- set_related_address(address);
+ if (server_address_.proto == PROTO_UDP &&
+ address != socket_->GetLocalAddress()) {
+ AddAddress(address,
+ socket_->GetLocalAddress(),
+ socket_->GetLocalAddress(),
+ UDP_PROTOCOL_NAME,
+ STUN_PORT_TYPE,
+ ICE_TYPE_PREFERENCE_SRFLX,
+ false);
+ }
}
-void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address) {
+void TurnPort::OnAllocateSuccess(const talk_base::SocketAddress& address,
+ const talk_base::SocketAddress& stun_address) {
connected_ = true;
AddAddress(address,
socket_->GetLocalAddress(),
- "udp",
+ stun_address,
+ UDP_PROTOCOL_NAME,
RELAY_PORT_TYPE,
GetRelayPreference(server_address_.proto, server_address_.secure),
true);
@@ -684,7 +731,7 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
return;
}
- // TODO(mallinath) - Use mapped address for STUN candidate.
+ // Using XOR-Mapped-Address for stun.
port_->OnStunAddress(mapped_attr->GetAddress());
const StunAddressAttribute* relayed_attr =
@@ -703,7 +750,8 @@ void TurnAllocateRequest::OnResponse(StunMessage* response) {
return;
}
// Notify the port the allocate succeeded, and schedule a refresh request.
- port_->OnAllocateSuccess(relayed_attr->GetAddress());
+ port_->OnAllocateSuccess(relayed_attr->GetAddress(),
+ mapped_attr->GetAddress());
port_->ScheduleRefresh(lifetime_attr->value());
}
diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h
index efec18b..4745b33 100644
--- a/p2p/base/turnport.h
+++ b/p2p/base/turnport.h
@@ -52,6 +52,18 @@ class TurnPort : public Port {
static TurnPort* Create(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username, // ice username.
+ const std::string& password, // ice password.
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials) {
+ return new TurnPort(thread, factory, network, socket, username, password,
+ server_address, credentials);
+ }
+
+ static TurnPort* Create(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username, // ice username.
@@ -79,10 +91,19 @@ class TurnPort : public Port {
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetOption(talk_base::Socket::Option opt, int* value);
virtual int GetError();
- virtual void OnReadPacket(
+
+ virtual bool HandleIncomingPacket(
talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
const talk_base::SocketAddress& remote_addr,
- const talk_base::PacketTime& packet_time);
+ const talk_base::PacketTime& packet_time) {
+ OnReadPacket(socket, data, size, remote_addr, packet_time);
+ return true;
+ }
+ virtual void OnReadPacket(talk_base::AsyncPacketSocket* socket,
+ const char* data, size_t size,
+ const talk_base::SocketAddress& remote_addr,
+ const talk_base::PacketTime& packet_time);
+
virtual void OnReadyToSend(talk_base::AsyncPacketSocket* socket);
void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
@@ -92,6 +113,13 @@ class TurnPort : public Port {
const std::string& hash() const { return hash_; }
const std::string& nonce() const { return nonce_; }
+ // Signal with resolved server address.
+ // Parameters are port, server address and resolved server address.
+ // This signal will be sent only if server address is resolved successfully.
+ sigslot::signal3<TurnPort*,
+ const talk_base::SocketAddress&,
+ const talk_base::SocketAddress&> SignalResolvedServerAddress;
+
// This signal is only for testing purpose.
sigslot::signal3<TurnPort*, const talk_base::SocketAddress&, int>
SignalCreatePermissionResult;
@@ -100,6 +128,15 @@ class TurnPort : public Port {
TurnPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
+ talk_base::AsyncPacketSocket* socket,
+ const std::string& username,
+ const std::string& password,
+ const ProtocolAddress& server_address,
+ const RelayCredentials& credentials);
+
+ TurnPort(talk_base::Thread* thread,
+ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
const talk_base::IPAddress& ip,
int min_port, int max_port,
const std::string& username,
@@ -131,7 +168,8 @@ class TurnPort : public Port {
// Stun address from allocate success response.
// Currently used only for testing.
void OnStunAddress(const talk_base::SocketAddress& address);
- void OnAllocateSuccess(const talk_base::SocketAddress& address);
+ void OnAllocateSuccess(const talk_base::SocketAddress& address,
+ const talk_base::SocketAddress& stun_address);
void OnAllocateError();
void OnAllocateRequestTimeout();
@@ -160,7 +198,7 @@ class TurnPort : public Port {
ProtocolAddress server_address_;
RelayCredentials credentials_;
- talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
+ talk_base::AsyncPacketSocket* socket_;
SocketOptionsMap socket_options_;
talk_base::AsyncResolverInterface* resolver_;
int error_;
diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc
index 75ac6b5..79ae208 100644
--- a/p2p/base/turnport_unittest.cc
+++ b/p2p/base/turnport_unittest.cc
@@ -157,7 +157,13 @@ class TurnPortTest : public testing::Test,
const talk_base::PacketTime& packet_time) {
udp_packets_.push_back(talk_base::Buffer(data, size));
}
-
+ void OnSocketReadPacket(talk_base::AsyncPacketSocket* socket,
+ const char* data, size_t size,
+ const talk_base::SocketAddress& remote_addr,
+ const talk_base::PacketTime& packet_time) {
+ turn_port_->HandleIncomingPacket(socket, data, size, remote_addr,
+ packet_time);
+ }
talk_base::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
talk_base::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM);
EXPECT_GE(socket->Bind(addr), 0);
@@ -185,6 +191,31 @@ class TurnPortTest : public testing::Test,
// This TURN port will be the controlling.
turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ ConnectSignals();
+ }
+
+ void CreateSharedTurnPort(const std::string& username,
+ const std::string& password,
+ const cricket::ProtocolAddress& server_address) {
+ socket_.reset(socket_factory_.CreateUdpSocket(
+ talk_base::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0));
+ ASSERT_TRUE(socket_ != NULL);
+ socket_->SignalReadPacket.connect(this, &TurnPortTest::OnSocketReadPacket);
+
+ cricket::RelayCredentials credentials(username, password);
+ turn_port_.reset(cricket::TurnPort::Create(
+ main_, &socket_factory_, &network_, socket_.get(), kIceUfrag1, kIcePwd1,
+ server_address, credentials));
+ // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be
+ // in Hybrid mode. Protocol type is necessary to send correct type STUN ping
+ // messages.
+ // This TURN port will be the controlling.
+ turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING);
+ ConnectSignals();
+ }
+
+ void ConnectSignals() {
turn_port_->SignalPortComplete.connect(this,
&TurnPortTest::OnTurnPortComplete);
turn_port_->SignalPortError.connect(this,
@@ -294,6 +325,7 @@ class TurnPortTest : public testing::Test,
talk_base::SocketServerScope ss_scope_;
talk_base::Network network_;
talk_base::BasicPacketSocketFactory socket_factory_;
+ talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
cricket::TestTurnServer turn_server_;
talk_base::scoped_ptr<TurnPort> turn_port_;
talk_base::scoped_ptr<UDPPort> udp_port_;
@@ -349,6 +381,12 @@ TEST_F(TurnPortTest, TestTurnConnection) {
TestTurnConnection();
}
+// Similar to above, except that this test will use the shared socket.
+TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) {
+ CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
+ TestTurnConnection();
+}
+
// Test that we can establish a TCP connection with TURN server.
TEST_F(TurnPortTest, TestTurnTcpConnection) {
turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
index 7c285d1..8338abe 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -148,6 +148,9 @@ class AllocationSequence : public talk_base::MessageHandler,
const talk_base::PacketTime& packet_time);
void OnPortDestroyed(PortInterface* port);
+ void OnResolvedTurnServerAddress(
+ TurnPort* port, const talk_base::SocketAddress& server_address,
+ const talk_base::SocketAddress& resolved_server_address);
BasicPortAllocatorSession* session_;
talk_base::Network* network_;
@@ -157,8 +160,10 @@ class AllocationSequence : public talk_base::MessageHandler,
uint32 flags_;
ProtocolList protocols_;
talk_base::scoped_ptr<talk_base::AsyncPacketSocket> udp_socket_;
- // Keeping a list of all UDP based ports.
- std::deque<Port*> ports;
+ // There will be only one udp port per AllocationSequence.
+ Port* udp_port_;
+ // Keeping a map for turn ports keyed with server addresses.
+ std::map<talk_base::SocketAddress, Port*> turn_ports_;
int phase_;
};
@@ -693,6 +698,7 @@ AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session,
state_(kInit),
flags_(flags),
udp_socket_(),
+ udp_port_(NULL),
phase_(0) {
}
@@ -855,7 +861,6 @@ void AllocationSequence::CreateUDPPorts() {
}
if (port) {
- ports.push_back(port);
// If shared socket is enabled, STUN candidate will be allocated by the
// UDPPort.
if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) &&
@@ -866,7 +871,13 @@ void AllocationSequence::CreateUDPPorts() {
<< "AllocationSequence: No STUN server configured, skipping.";
return;
}
- port->set_server_addr(config_->stun_address);
+ udp_port_ = port;
+ // If there is a TURN UDP server available, then we will use TURN port
+ // to get stun address, otherwise by UDP port.
+ // Shared socket mode is not used in GTURN mode.
+ if (config_ && !config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) {
+ port->set_server_addr(config_->stun_address);
+ }
}
session_->AddAllocatedPort(port, this, true);
@@ -992,15 +1003,40 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
PortList::const_iterator relay_port;
for (relay_port = config.ports.begin();
relay_port != config.ports.end(); ++relay_port) {
- TurnPort* port = TurnPort::Create(session_->network_thread(),
- session_->socket_factory(),
- network_, ip_,
- session_->allocator()->min_port(),
- session_->allocator()->max_port(),
- session_->username(),
- session_->password(),
- *relay_port, config.credentials);
+ TurnPort* port = NULL;
+ if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+ port = TurnPort::Create(session_->network_thread(),
+ session_->socket_factory(),
+ network_, udp_socket_.get(),
+ session_->username(), session_->password(),
+ *relay_port, config.credentials);
+ } else {
+ port = TurnPort::Create(session_->network_thread(),
+ session_->socket_factory(),
+ network_, ip_,
+ session_->allocator()->min_port(),
+ session_->allocator()->max_port(),
+ session_->username(),
+ session_->password(),
+ *relay_port, config.credentials);
+ }
+
if (port) {
+ // If we are using shared socket for TURN and udp ports, we need to
+ // find a way to demux the packets to the correct port when received.
+ // Mapping against server_address is one way of doing this. When packet
+ // is received the remote_address will be checked against the map.
+ // If server address is not resolved, a signal will be sent from the port
+ // after the address is resolved. The map entry will updated with the
+ // resolved address when the signal is received from the port.
+ if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) {
+ // If server address is not resolved then listen for signal from port.
+ if ((*relay_port).address.IsUnresolved()) {
+ port->SignalResolvedServerAddress.connect(
+ this, &AllocationSequence::OnResolvedTurnServerAddress);
+ }
+ turn_ports_[(*relay_port).address] = port;
+ }
session_->AddAllocatedPort(port, this, true);
}
}
@@ -1011,22 +1047,46 @@ void AllocationSequence::OnReadPacket(
const talk_base::SocketAddress& remote_addr,
const talk_base::PacketTime& packet_time) {
ASSERT(socket == udp_socket_.get());
- for (std::deque<Port*>::iterator iter = ports.begin();
- iter != ports.end(); ++iter) {
- // We have only one port in the queue.
- // TODO(mallinath) - Add shared socket support to Relay and Turn ports.
- if ((*iter)->HandleIncomingPacket(
- socket, data, size, remote_addr, packet_time)) {
- break;
- }
+ // If the packet is received from one of the TURN server in the config, then
+ // pass down the packet to that port, otherwise it will be handed down to
+ // the local udp port.
+ Port* port = NULL;
+ std::map<talk_base::SocketAddress, Port*>::iterator iter =
+ turn_ports_.find(remote_addr);
+ if (iter != turn_ports_.end()) {
+ port = iter->second;
+ } else if (udp_port_) {
+ port = udp_port_;
}
+ ASSERT(port != NULL);
+ port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time);
}
void AllocationSequence::OnPortDestroyed(PortInterface* port) {
- std::deque<Port*>::iterator iter =
- std::find(ports.begin(), ports.end(), port);
- ASSERT(iter != ports.end());
- ports.erase(iter);
+ if (udp_port_ == port) {
+ udp_port_ = NULL;
+ } else {
+ std::map<talk_base::SocketAddress, Port*>::iterator iter;
+ for (iter = turn_ports_.begin(); iter != turn_ports_.end(); ++iter) {
+ if (iter->second == port) {
+ turn_ports_.erase(iter);
+ break;
+ }
+ }
+ }
+}
+
+void AllocationSequence::OnResolvedTurnServerAddress(
+ TurnPort* port, const talk_base::SocketAddress& server_address,
+ const talk_base::SocketAddress& resolved_server_address) {
+ std::map<talk_base::SocketAddress, Port*>::iterator iter;
+ iter = turn_ports_.find(server_address);
+
+ ASSERT(iter != turn_ports_.end());
+ ASSERT(iter->second != port);
+ // Remove old entry and then insert using the resolved address as key.
+ turn_ports_.erase(iter);
+ turn_ports_[resolved_server_address] = port;
}
// PortConfiguration
@@ -1044,7 +1104,7 @@ void PortConfiguration::AddRelay(const RelayServerConfig& config) {
}
bool PortConfiguration::SupportsProtocol(
- const RelayServerConfig& relay, ProtocolType type) {
+ const RelayServerConfig& relay, ProtocolType type) const {
PortList::const_iterator relay_port;
for (relay_port = relay.ports.begin();
relay_port != relay.ports.end();
@@ -1055,4 +1115,14 @@ bool PortConfiguration::SupportsProtocol(
return false;
}
+bool PortConfiguration::SupportsProtocol(const RelayType turn_type,
+ ProtocolType type) const {
+ for (size_t i = 0; i < relays.size(); ++i) {
+ if (relays[i].type == turn_type &&
+ SupportsProtocol(relays[i], type))
+ return true;
+ }
+ return false;
+}
+
} // namespace cricket
diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h
index c46c29a..b8660f0 100644
--- a/p2p/client/basicportallocator.h
+++ b/p2p/client/basicportallocator.h
@@ -232,8 +232,9 @@ struct PortConfiguration : public talk_base::MessageData {
void AddRelay(const RelayServerConfig& config);
// Determines whether the given relay server supports the given protocol.
- static bool SupportsProtocol(const RelayServerConfig& relay,
- ProtocolType type);
+ bool SupportsProtocol(const RelayServerConfig& relay,
+ ProtocolType type) const;
+ bool SupportsProtocol(const RelayType turn_type, ProtocolType type) const;
};
} // namespace cricket
diff --git a/p2p/client/connectivitychecker_unittest.cc b/p2p/client/connectivitychecker_unittest.cc
index 59fdfc2..c62120b 100644
--- a/p2p/client/connectivitychecker_unittest.cc
+++ b/p2p/client/connectivitychecker_unittest.cc
@@ -73,7 +73,7 @@ class FakeStunPort : public StunPort {
// Just set external address and signal that we are done.
virtual void PrepareAddress() {
- AddAddress(kExternalAddr, kExternalAddr, "udp",
+ AddAddress(kExternalAddr, kExternalAddr, talk_base::SocketAddress(), "udp",
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, true);
SignalPortComplete(this);
}
diff --git a/p2p/client/portallocator_unittest.cc b/p2p/client/portallocator_unittest.cc
index 0ea8fb5..211c354 100644
--- a/p2p/client/portallocator_unittest.cc
+++ b/p2p/client/portallocator_unittest.cc
@@ -44,6 +44,7 @@
#include "talk/p2p/base/portallocatorsessionproxy.h"
#include "talk/p2p/base/testrelayserver.h"
#include "talk/p2p/base/teststunserver.h"
+#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/client/basicportallocator.h"
#include "talk/p2p/client/httpportallocator.h"
@@ -55,6 +56,7 @@ 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", talk_base::NAT_SERVER_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);
static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
@@ -62,6 +64,8 @@ static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
+static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478);
+static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
// Minimum and maximum port for port range tests.
static const int kMinPort = 10000;
@@ -75,6 +79,8 @@ static const char kIcePwd0[] = "TESTICEPWD00000000000000";
static const char kContentName[] = "test content";
static const int kDefaultAllocationTimeout = 1000;
+static const char kTurnUsername[] = "test";
+static const char kTurnPassword[] = "test";
namespace cricket {
@@ -107,6 +113,7 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
relay_server_(Thread::Current(), kRelayUdpIntAddr, kRelayUdpExtAddr,
kRelayTcpIntAddr, kRelayTcpExtAddr,
kRelaySslTcpIntAddr, kRelaySslTcpExtAddr),
+ turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr),
allocator_(new cricket::BasicPortAllocator(
&network_manager_, kStunAddr,
kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr)),
@@ -245,6 +252,7 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
talk_base::BasicPacketSocketFactory nat_socket_factory_;
cricket::TestStunServer stun_server_;
cricket::TestRelayServer relay_server_;
+ cricket::TestTurnServer turn_server_;
talk_base::FakeNetworkManager network_manager_;
talk_base::scoped_ptr<cricket::BasicPortAllocator> allocator_;
talk_base::scoped_ptr<cricket::PortAllocatorSession> session_;
@@ -653,7 +661,7 @@ TEST_F(PortAllocatorTest, TestDisableSharedUfrag) {
// is allocated for udp and stun. Also verify there is only one candidate
// (local) if stun candidate is same as local candidate, which will be the case
// in a public network like the below test.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketWithoutNat) {
+TEST_F(PortAllocatorTest, TestSharedSocketWithoutNat) {
AddInterface(kClientAddr);
allocator_->set_flags(allocator().flags() |
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
@@ -670,7 +678,7 @@ TEST_F(PortAllocatorTest, TestEnableSharedSocketWithoutNat) {
// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
// is allocated for udp and stun. In this test we should expect both stun and
// local candidates as client behind a nat.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketWithNat) {
+TEST_F(PortAllocatorTest, TestSharedSocketWithNat) {
AddInterface(kClientAddr);
talk_base::scoped_ptr<talk_base::NATServer> nat_server(
CreateNatServer(kNatAddr, talk_base::NAT_OPEN_CONE));
@@ -693,10 +701,51 @@ TEST_F(PortAllocatorTest, TestEnableSharedSocketWithNat) {
EXPECT_EQ(3U, candidates_.size());
}
+// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port
+// is allocated for udp/stun/turn. In this test we should expect all local,
+// stun and turn candidates.
+TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) {
+ AddInterface(kClientAddr);
+ talk_base::scoped_ptr<talk_base::NATServer> nat_server(
+ CreateNatServer(kNatAddr, talk_base::NAT_OPEN_CONE));
+ allocator_.reset(new cricket::BasicPortAllocator(
+ &network_manager_, &nat_socket_factory_, kStunAddr));
+ cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
+ cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword);
+ relay_server.credentials = credentials;
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+ allocator_->AddRelay(relay_server);
+
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
+ 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);
+ 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, "stun", "udp",
+ talk_base::SocketAddress(kNatAddr.ipaddr(), 0));
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
+ talk_base::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_EQ(3U, candidates_.size());
+ // Local port will be created first and then TURN port.
+ // Checking TURN port has two candidates, STUN + TURN.
+ EXPECT_EQ(1U, ports_[0]->Candidates().size());
+ EXPECT_EQ(2U, ports_[1]->Candidates().size());
+}
+
// This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled
// and fail to generate STUN candidate, local UDP candidate is generated
// properly.
-TEST_F(PortAllocatorTest, TestEnableSharedSocketNoUdpAllowed) {
+TEST_F(PortAllocatorTest, TestSharedSocketNoUdpAllowed) {
allocator().set_flags(allocator().flags() |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP |