summaryrefslogtreecommitdiff
path: root/p2p
diff options
context:
space:
mode:
authormallinath@webrtc.org <mallinath@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-02-03 16:57:16 +0000
committermallinath@webrtc.org <mallinath@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-02-03 16:57:16 +0000
commitb881d27f23e9a8f52dc6a60fc66ebd75f9c2f15c (patch)
tree7e476a94dc6bd821fb3452e8021da5a49c3325df /p2p
parentd51e05ddea8c27cfc8f1e33fd4ef068534280bd5 (diff)
downloadtalk-b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15c.tar.gz
Update talk to 60923971
Review URL: https://webrtc-codereview.appspot.com/7909004 git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@5475 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'p2p')
-rw-r--r--p2p/base/dtlstransportchannel.h3
-rw-r--r--p2p/base/fakesession.h4
-rw-r--r--p2p/base/p2ptransportchannel.cc20
-rw-r--r--p2p/base/p2ptransportchannel.h1
-rw-r--r--p2p/base/p2ptransportchannel_unittest.cc57
-rw-r--r--p2p/base/port.cc48
-rw-r--r--p2p/base/port.h19
-rw-r--r--p2p/base/port_unittest.cc111
-rw-r--r--p2p/base/rawtransportchannel.h3
-rw-r--r--p2p/base/relayport.cc8
-rw-r--r--p2p/base/stunport.cc6
-rw-r--r--p2p/base/tcpport.cc8
-rw-r--r--p2p/base/transport.cc30
-rw-r--r--p2p/base/transportchannelimpl.h1
-rw-r--r--p2p/base/turnport.cc18
-rw-r--r--p2p/base/turnport_unittest.cc10
16 files changed, 270 insertions, 77 deletions
diff --git a/p2p/base/dtlstransportchannel.h b/p2p/base/dtlstransportchannel.h
index d6b7346..c977888 100644
--- a/p2p/base/dtlstransportchannel.h
+++ b/p2p/base/dtlstransportchannel.h
@@ -193,6 +193,9 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
virtual void SetIceTiebreaker(uint64 tiebreaker) {
channel_->SetIceTiebreaker(tiebreaker);
}
+ virtual bool GetIceProtocolType(IceProtocolType* type) const {
+ return channel_->GetIceProtocolType(type);
+ }
virtual void SetIceProtocolType(IceProtocolType type) {
channel_->SetIceProtocolType(type);
}
diff --git a/p2p/base/fakesession.h b/p2p/base/fakesession.h
index 2615f50..d199449 100644
--- a/p2p/base/fakesession.h
+++ b/p2p/base/fakesession.h
@@ -101,6 +101,10 @@ class FakeTransportChannel : public TransportChannelImpl,
virtual void SetIceRole(IceRole role) { role_ = role; }
virtual IceRole GetIceRole() const { return role_; }
virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
+ virtual bool GetIceProtocolType(IceProtocolType* type) const {
+ *type = ice_proto_;
+ return true;
+ }
virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; }
virtual void SetIceCredentials(const std::string& ice_ufrag,
const std::string& ice_pwd) {
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
index 38cc354..104b5e6 100644
--- a/p2p/base/p2ptransportchannel.cc
+++ b/p2p/base/p2ptransportchannel.cc
@@ -167,7 +167,7 @@ P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
pending_best_connection_(NULL),
sort_dirty_(false),
was_writable_(false),
- protocol_type_(ICEPROTO_GOOGLE),
+ protocol_type_(ICEPROTO_HYBRID),
remote_ice_mode_(ICEMODE_FULL),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
@@ -237,6 +237,11 @@ void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) {
tiebreaker_ = tiebreaker;
}
+bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const {
+ *type = protocol_type_;
+ return true;
+}
+
void P2PTransportChannel::SetIceProtocolType(IceProtocolType type) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
@@ -467,7 +472,7 @@ void P2PTransportChannel::OnUnknownAddress(
// Create a new candidate with this address.
std::string type;
- if (protocol_type_ == ICEPROTO_RFC5245) {
+ if (port->IceProtocol() == ICEPROTO_RFC5245) {
type = PRFLX_PORT_TYPE;
} else {
// G-ICE doesn't support prflx candidate.
@@ -491,7 +496,7 @@ void P2PTransportChannel::OnUnknownAddress(
new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX));
}
- if (protocol_type_ == ICEPROTO_RFC5245) {
+ if (port->IceProtocol() == ICEPROTO_RFC5245) {
// RFC 5245
// If the source transport address of the request does not match any
// existing remote candidates, it represents a new peer reflexive remote
@@ -884,6 +889,15 @@ void P2PTransportChannel::SortConnections() {
// will be sorted.
UpdateConnectionStates();
+ if (protocol_type_ == ICEPROTO_HYBRID) {
+ // If we are in hybrid mode, we are not sending any ping requests, so there
+ // is no point in sorting the connections. In hybrid state, ports can have
+ // different protocol than hybrid and protocol may differ from one another.
+ // Instead just update the state of this channel
+ UpdateChannelState();
+ return;
+ }
+
// Any changes after this point will require a re-sort.
sort_dirty_ = false;
diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h
index 6f287f3..b7c5929 100644
--- a/p2p/base/p2ptransportchannel.h
+++ b/p2p/base/p2ptransportchannel.h
@@ -79,6 +79,7 @@ class P2PTransportChannel : public TransportChannelImpl,
virtual void SetIceRole(IceRole role);
virtual IceRole GetIceRole() const { return ice_role_; }
virtual void SetIceTiebreaker(uint64 tiebreaker);
+ virtual bool GetIceProtocolType(IceProtocolType* type) const;
virtual void SetIceProtocolType(IceProtocolType type);
virtual void SetIceCredentials(const std::string& ice_ufrag,
const std::string& ice_pwd);
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index 3c24ded..28b7129 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -588,6 +588,46 @@ class P2PTransportChannelTestBase : public testing::Test,
TestSendRecv(1);
}
+ void TestHybridConnectivity(cricket::IceProtocolType proto) {
+ AddAddress(0, kPublicAddrs[0]);
+ AddAddress(1, kPublicAddrs[1]);
+
+ SetAllocationStepDelay(0, kMinimumStepDelay);
+ SetAllocationStepDelay(1, kMinimumStepDelay);
+
+ SetIceRole(0, cricket::ICEROLE_CONTROLLING);
+ SetIceProtocol(0, cricket::ICEPROTO_HYBRID);
+ SetIceTiebreaker(0, kTiebreaker1);
+ SetIceRole(1, cricket::ICEROLE_CONTROLLED);
+ SetIceProtocol(1, proto);
+ SetIceTiebreaker(1, kTiebreaker2);
+
+ CreateChannels(1);
+ // When channel is in hybrid and it's controlling agent, channel will
+ // receive ping request from the remote. Hence connection is readable.
+ // Since channel is in hybrid, it will not send any pings, so no writable
+ // connection. Since channel2 is in controlled state, it will not have
+ // any connections which are readable or writable, as it didn't received
+ // pings (or none) with USE-CANDIDATE attribute.
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable(), 1000);
+
+ // Set real protocol type.
+ ep1_ch1()->SetIceProtocolType(proto);
+
+ // Channel should able to send ping requests and connections become writable
+ // in both directions.
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+ ep2_ch1()->readable() && ep2_ch1()->writable(),
+ 1000);
+ EXPECT_TRUE(
+ ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+ LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
+ RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+
+ TestSendRecv(1);
+ DestroyChannels();
+ }
+
void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) {
channel->OnSignalingReady();
}
@@ -1082,6 +1122,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsIce) {
cricket::ICEPROTO_RFC5245);
CreateChannels(1);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that we restart candidate allocation when local ufrag&pwd changed.
@@ -1097,6 +1138,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsIce) {
CreateChannels(2);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that we restart candidate allocation when local ufrag&pwd changed.
@@ -1109,6 +1151,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsGice) {
cricket::ICEPROTO_GOOGLE);
CreateChannels(1);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test that ICE restart works when bundle is enabled.
@@ -1124,6 +1167,7 @@ TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsGice) {
CreateChannels(2);
TestHandleIceUfragPasswordChanged();
+ DestroyChannels();
}
// Test the operation of GetStats.
@@ -1389,6 +1433,19 @@ TEST_F(P2PTransportChannelTest, TestIceConfigWillPassDownToPort) {
ep2_ch1()->best_connection());
TestSendRecv(1);
+ DestroyChannels();
+}
+
+// This test verifies channel can handle ice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandIce) {
+ TestHybridConnectivity(cricket::ICEPROTO_RFC5245);
+}
+
+// This test verifies channel can handle Gice messages when channel is in
+// hybrid mode.
+TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandGice) {
+ TestHybridConnectivity(cricket::ICEPROTO_GOOGLE);
}
// Verify that we can set DSCP value and retrieve properly from P2PTC.
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 2fc2cb2..b6421ad 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -178,11 +178,10 @@ Port::Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
password_(password),
timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
- ice_protocol_(ICEPROTO_GOOGLE),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
- shared_socket_(true),
- default_dscp_(talk_base::DSCP_NO_CHANGE) {
+ shared_socket_(true) {
Construct();
}
@@ -205,11 +204,10 @@ Port::Port(talk_base::Thread* thread, const std::string& type,
password_(password),
timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
- ice_protocol_(ICEPROTO_GOOGLE),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
- shared_socket_(false),
- default_dscp_(talk_base::DSCP_NO_CHANGE) {
+ shared_socket_(false) {
ASSERT(factory_ != NULL);
Construct();
}
@@ -341,6 +339,10 @@ bool Port::IsGoogleIce() const {
return (ice_protocol_ == ICEPROTO_GOOGLE);
}
+bool Port::IsHybridIce() const {
+ return (ice_protocol_ == ICEPROTO_HYBRID);
+}
+
bool Port::GetStunMessage(const char* data, size_t size,
const talk_base::SocketAddress& addr,
IceMessage** out_msg, std::string* out_username) {
@@ -382,7 +384,9 @@ bool Port::GetStunMessage(const char* data, size_t size,
// If the username is bad or unknown, fail with a 401 Unauthorized.
std::string local_ufrag;
std::string remote_ufrag;
- if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
+ IceProtocolType remote_protocol_type;
+ if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag,
+ &remote_protocol_type) ||
local_ufrag != username_fragment()) {
LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
<< local_ufrag << " from "
@@ -392,6 +396,15 @@ bool Port::GetStunMessage(const char* data, size_t size,
return true;
}
+ // Port is initialized to GOOGLE-ICE protocol type. If pings from remote
+ // are received before the signal message, protocol type may be different.
+ // Based on the STUN username, we can determine what's the remote protocol.
+ // This also enables us to send the response back using the same protocol
+ // as the request.
+ if (IsHybridIce()) {
+ SetIceProtocolType(remote_protocol_type);
+ }
+
// If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
if (IsStandardIce() &&
!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
@@ -453,7 +466,8 @@ bool Port::IsCompatibleAddress(const talk_base::SocketAddress& addr) {
bool Port::ParseStunUsername(const StunMessage* stun_msg,
std::string* local_ufrag,
- std::string* remote_ufrag) const {
+ std::string* remote_ufrag,
+ IceProtocolType* remote_protocol_type) const {
// The packet must include a username that either begins or ends with our
// fragment. It should begin with our fragment if it is a request and it
// should end with our fragment if it is a response.
@@ -465,8 +479,16 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
return false;
const std::string username_attr_str = username_attr->GetString();
- if (IsStandardIce()) {
- size_t colon_pos = username_attr_str.find(":");
+ size_t colon_pos = username_attr_str.find(":");
+ // If we are in hybrid mode set the appropriate ice protocol type based on
+ // the username argument style.
+ if (IsHybridIce()) {
+ *remote_protocol_type = (colon_pos != std::string::npos) ?
+ ICEPROTO_RFC5245 : ICEPROTO_GOOGLE;
+ } else {
+ *remote_protocol_type = ice_protocol_;
+ }
+ if (*remote_protocol_type == ICEPROTO_RFC5245) {
if (colon_pos != std::string::npos) { // RFRAG:LFRAG
*local_ufrag = username_attr_str.substr(0, colon_pos);
*remote_ufrag = username_attr_str.substr(
@@ -474,7 +496,7 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
} else {
return false;
}
- } else if (IsGoogleIce()) {
+ } else if (*remote_protocol_type == ICEPROTO_GOOGLE) {
int remote_frag_len = static_cast<int>(username_attr_str.size());
remote_frag_len -= static_cast<int>(username_fragment().size());
if (remote_frag_len < 0)
@@ -716,7 +738,7 @@ void Port::CheckTimeout() {
}
const std::string Port::username_fragment() const {
- if (IsGoogleIce() &&
+ if (!IsStandardIce() &&
component_ == ICE_CANDIDATE_COMPONENT_RTCP) {
// In GICE mode, we should adjust username fragment for rtcp component.
return GetRtcpUfragFromRtpUfrag(ice_username_fragment_);
@@ -997,7 +1019,7 @@ void Connection::OnReadPacket(
// id's match.
case STUN_BINDING_RESPONSE:
case STUN_BINDING_ERROR_RESPONSE:
- if (port_->IceProtocol() == ICEPROTO_GOOGLE ||
+ if (port_->IsGoogleIce() ||
msg->ValidateMessageIntegrity(
data, size, remote_candidate().password())) {
requests_.CheckResponse(msg.get());
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 21f3d61..1c43c93 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -280,7 +280,8 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// stun username attribute if present.
bool ParseStunUsername(const StunMessage* stun_msg,
std::string* local_username,
- std::string* remote_username) const;
+ std::string* remote_username,
+ IceProtocolType* remote_protocol_type) const;
void CreateStunUsername(const std::string& remote_username,
std::string* stun_username_attr_str) const;
@@ -301,10 +302,8 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Returns if Google ICE protocol is used.
bool IsGoogleIce() const;
- // Returns default DSCP value.
- talk_base::DiffServCodePoint DefaultDscpValue() const {
- return default_dscp_;
- }
+ // Returns if Hybrid ICE protocol is used.
+ bool IsHybridIce() const;
protected:
enum {
@@ -341,9 +340,10 @@ class Port : public PortInterface, public talk_base::MessageHandler,
// Checks if the address in addr is compatible with the port's ip.
bool IsCompatibleAddress(const talk_base::SocketAddress& addr);
- // Default DSCP value for this port. Set by TransportChannel.
- void SetDefaultDscpValue(talk_base::DiffServCodePoint dscp) {
- default_dscp_ = dscp;
+ // Returns default DSCP value.
+ talk_base::DiffServCodePoint DefaultDscpValue() const {
+ // No change from what MediaChannel set.
+ return talk_base::DSCP_NO_CHANGE;
}
private:
@@ -384,9 +384,6 @@ class Port : public PortInterface, public talk_base::MessageHandler,
IceRole ice_role_;
uint64 tiebreaker_;
bool shared_socket_;
- // DSCP value for ICE/STUN messages. Set by the P2PTransportChannel after
- // port becomes ready.
- talk_base::DiffServCodePoint default_dscp_;
// Information to use when going through a proxy.
std::string user_agent_;
talk_base::ProxyInfo proxy_;
diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc
index 3ea6375..000dc5c 100644
--- a/p2p/base/port_unittest.cc
+++ b/p2p/base/port_unittest.cc
@@ -1280,21 +1280,37 @@ TEST_F(PortTest, TestSkipCrossFamilyUdp) {
// This test verifies DSCP value set through SetOption interface can be
// get through DefaultDscpValue.
TEST_F(PortTest, TestDefaultDscpValue) {
+ int dscp;
talk_base::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1));
- udpport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_CS6);
- EXPECT_EQ(talk_base::DSCP_CS6, udpport->DefaultDscpValue());
+ EXPECT_EQ(0, udpport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS6));
+ EXPECT_EQ(0, udpport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
talk_base::scoped_ptr<TCPPort> tcpport(CreateTcpPort(kLocalAddr1));
- tcpport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_AF31);
- EXPECT_EQ(talk_base::DSCP_AF31, tcpport->DefaultDscpValue());
+ EXPECT_EQ(0, tcpport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_AF31));
+ EXPECT_EQ(0, tcpport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_AF31, dscp);
talk_base::scoped_ptr<StunPort> stunport(
CreateStunPort(kLocalAddr1, nat_socket_factory1()));
- stunport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_AF41);
- EXPECT_EQ(talk_base::DSCP_AF41, stunport->DefaultDscpValue());
- talk_base::scoped_ptr<TurnPort> turnport(CreateTurnPort(
+ EXPECT_EQ(0, stunport->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_AF41));
+ EXPECT_EQ(0, stunport->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_AF41, dscp);
+ talk_base::scoped_ptr<TurnPort> turnport1(CreateTurnPort(
kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
- turnport->SetOption(talk_base::Socket::OPT_DSCP, talk_base::DSCP_CS7);
- EXPECT_EQ(talk_base::DSCP_CS7, turnport->DefaultDscpValue());
- // TODO(mallinath) - Test DSCP through GetOption.
+ // Socket is created in PrepareAddress.
+ turnport1->PrepareAddress();
+ EXPECT_EQ(0, turnport1->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS7));
+ EXPECT_EQ(0, turnport1->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_CS7, dscp);
+ // This will verify correct value returned without the socket.
+ talk_base::scoped_ptr<TurnPort> turnport2(CreateTurnPort(
+ kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP));
+ EXPECT_EQ(0, turnport2->SetOption(talk_base::Socket::OPT_DSCP,
+ talk_base::DSCP_CS6));
+ EXPECT_EQ(0, turnport2->GetOption(talk_base::Socket::OPT_DSCP, &dscp));
+ EXPECT_EQ(talk_base::DSCP_CS6, dscp);
}
// Test sending STUN messages in GICE format.
@@ -1665,6 +1681,81 @@ TEST_F(PortTest, TestHandleStunMessageAsIce) {
out_msg->GetErrorCode()->reason());
}
+// This test verifies port can handle ICE messages in Hybrid mode and switches
+// ICEPROTO_RFC5245 mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsIceInHybridMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid ICE username,
+ // MESSAGE-INTEGRITY, and FINGERPRINT.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfrag:lfrag"));
+ in_msg->AddMessageIntegrity("rpass");
+ in_msg->AddFingerprint();
+ WriteStunMessage(in_msg.get(), buf.get());
+ EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_TRUE(out_msg.get() != NULL);
+ EXPECT_EQ("lfrag", username);
+ EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+// This test verifies port can handle GICE messages in Hybrid mode and switches
+// ICEPROTO_GOOGLE mode after successfully handling the message.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInHybridMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_HYBRID);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfraglfrag"));
+ WriteStunMessage(in_msg.get(), buf.get());
+ EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_TRUE(out_msg.get() != NULL); // Succeeds, since this is GICE.
+ EXPECT_EQ("lfrag", username);
+ EXPECT_EQ(ICEPROTO_GOOGLE, port->IceProtocol());
+}
+
+// Verify port is not switched out of RFC5245 mode if GICE message is received
+// in that mode.
+TEST_F(PortTest, TestHandleStunMessageAsGiceInIceMode) {
+ // Our port will act as the "remote" port.
+ talk_base::scoped_ptr<TestPort> port(
+ CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+ port->SetIceProtocolType(ICEPROTO_RFC5245);
+
+ talk_base::scoped_ptr<IceMessage> in_msg, out_msg;
+ talk_base::scoped_ptr<ByteBuffer> buf(new ByteBuffer());
+ talk_base::SocketAddress addr(kLocalAddr1);
+ std::string username;
+
+ // BINDING-REQUEST from local to remote with valid GICE username and no M-I.
+ in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST,
+ "rfraglfrag"));
+ WriteStunMessage(in_msg.get(), buf.get());
+ // Should fail as there is no MI and fingerprint.
+ EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr,
+ out_msg.accept(), &username));
+ EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol());
+}
+
+
// Tests handling of GICE binding requests with missing or incorrect usernames.
TEST_F(PortTest, TestHandleStunMessageAsGiceBadUsername) {
talk_base::scoped_ptr<TestPort> port(
diff --git a/p2p/base/rawtransportchannel.h b/p2p/base/rawtransportchannel.h
index ed38952..2042d5f 100644
--- a/p2p/base/rawtransportchannel.h
+++ b/p2p/base/rawtransportchannel.h
@@ -97,7 +97,10 @@ class RawTransportChannel : public TransportChannelImpl,
virtual IceRole GetIceRole() const { return ICEROLE_UNKNOWN; }
virtual void SetIceRole(IceRole role) {}
virtual void SetIceTiebreaker(uint64 tiebreaker) {}
+
+ virtual bool GetIceProtocolType(IceProtocolType* type) const { return false; }
virtual void SetIceProtocolType(IceProtocolType type) {}
+
virtual void SetIceUfrag(const std::string& ice_ufrag) {}
virtual void SetIcePwd(const std::string& ice_pwd) {}
virtual void SetRemoteIceMode(IceMode mode) {}
diff --git a/p2p/base/relayport.cc b/p2p/base/relayport.cc
index ddfca71..9112b10 100644
--- a/p2p/base/relayport.cc
+++ b/p2p/base/relayport.cc
@@ -359,14 +359,6 @@ int RelayPort::SendTo(const void* data, size_t size,
int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
int result = 0;
- // DSCP option is not passed to the socket.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return result;
- }
-
for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i]->SetSocketOption(opt, value) < 0) {
result = -1;
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index 913f9af..def3c9b 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -230,12 +230,6 @@ int UDPPort::SendTo(const void* data, size_t size,
}
int UDPPort::SetOption(talk_base::Socket::Option opt, int value) {
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
return socket_->SetOption(opt, value);
}
diff --git a/p2p/base/tcpport.cc b/p2p/base/tcpport.cc
index 2cca82f..0981244 100644
--- a/p2p/base/tcpport.cc
+++ b/p2p/base/tcpport.cc
@@ -167,14 +167,6 @@ int TCPPort::GetOption(talk_base::Socket::Option opt, int* value) {
}
int TCPPort::SetOption(talk_base::Socket::Option opt, int value) {
- // If we are setting DSCP value, pass value to base Port and return.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
-
if (socket_) {
return socket_->SetOption(opt, value);
} else {
diff --git a/p2p/base/transport.cc b/p2p/base/transport.cc
index d177833..3781b2a 100644
--- a/p2p/base/transport.cc
+++ b/p2p/base/transport.cc
@@ -208,15 +208,14 @@ TransportChannelImpl* Transport::CreateChannel_w(int component) {
// Push down our transport state to the new channel.
impl->SetIceRole(ice_role_);
impl->SetIceTiebreaker(tiebreaker_);
- if (local_description_) {
- // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
- // below Apply**Description_w calls can fail.
+ // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
+ // below Apply**Description_w calls can fail.
+ if (local_description_)
ApplyLocalTransportDescription_w(impl, NULL);
- if (remote_description_) {
- ApplyRemoteTransportDescription_w(impl, NULL);
- ApplyNegotiatedTransportDescription_w(impl, NULL);
- }
- }
+ if (remote_description_)
+ ApplyRemoteTransportDescription_w(impl, NULL);
+ if (local_description_ && remote_description_)
+ ApplyNegotiatedTransportDescription_w(impl, NULL);
impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
@@ -684,6 +683,21 @@ bool Transport::SetRemoteTransportDescription_w(
bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
std::string* error_desc) {
+ // If existing protocol_type is HYBRID, we may have not chosen the final
+ // protocol type, so update the channel protocol type from the
+ // local description. Otherwise, skip updating the protocol type.
+ // We check for HYBRID to avoid accidental changes; in the case of a
+ // session renegotiation, the new offer will have the google-ice ICE option,
+ // so we need to make sure we don't switch back from ICE mode to HYBRID
+ // when this happens.
+ // There are some other ways we could have solved this, but this is the
+ // simplest. The ultimate solution will be to get rid of GICE altogether.
+ IceProtocolType protocol_type;
+ if (ch->GetIceProtocolType(&protocol_type) &&
+ protocol_type == ICEPROTO_HYBRID) {
+ ch->SetIceProtocolType(
+ TransportProtocolFromDescription(local_description()));
+ }
ch->SetIceCredentials(local_description_->ice_ufrag,
local_description_->ice_pwd);
return true;
diff --git a/p2p/base/transportchannelimpl.h b/p2p/base/transportchannelimpl.h
index d8432b7..c66e0c0 100644
--- a/p2p/base/transportchannelimpl.h
+++ b/p2p/base/transportchannelimpl.h
@@ -54,6 +54,7 @@ class TransportChannelImpl : public TransportChannel {
virtual void SetIceRole(IceRole role) = 0;
virtual void SetIceTiebreaker(uint64 tiebreaker) = 0;
// To toggle G-ICE/ICE.
+ virtual bool GetIceProtocolType(IceProtocolType* type) const = 0;
virtual void SetIceProtocolType(IceProtocolType type) = 0;
// SetIceCredentials only need to be implemented by the ICE
// transport channels. Non-ICE transport channels can just ignore.
diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc
index d8c0cb6..eed7f8d 100644
--- a/p2p/base/turnport.cc
+++ b/p2p/base/turnport.cc
@@ -304,14 +304,6 @@ Connection* TurnPort::CreateConnection(const Candidate& address,
}
int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
- // DSCP option is not passed to the socket.
- // TODO(mallinath) - After we have the support on socket,
- // remove this specialization.
- if (opt == talk_base::Socket::OPT_DSCP) {
- SetDefaultDscpValue(static_cast<talk_base::DiffServCodePoint>(value));
- return 0;
- }
-
if (!socket_) {
// If socket is not created yet, these options will be applied during socket
// creation.
@@ -322,8 +314,14 @@ int TurnPort::SetOption(talk_base::Socket::Option opt, int value) {
}
int TurnPort::GetOption(talk_base::Socket::Option opt, int* value) {
- if (!socket_)
- return -1;
+ if (!socket_) {
+ SocketOptionsMap::const_iterator it = socket_options_.find(opt);
+ if (it == socket_options_.end()) {
+ return -1;
+ }
+ *value = it->second;
+ return 0;
+ }
return socket_->GetOption(opt, value);
}
diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc
index 0284f51..e09c196 100644
--- a/p2p/base/turnport_unittest.cc
+++ b/p2p/base/turnport_unittest.cc
@@ -179,6 +179,12 @@ class TurnPortTest : public testing::Test,
local_address.ipaddr(), 0, 0,
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);
turn_port_->SignalPortComplete.connect(this,
&TurnPortTest::OnTurnPortComplete);
turn_port_->SignalPortError.connect(this,
@@ -192,6 +198,10 @@ class TurnPortTest : public testing::Test,
udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_,
kLocalAddr2.ipaddr(), 0, 0,
kIceUfrag2, kIcePwd2));
+ // Set protocol type to RFC5245, as turn port is also in same mode.
+ // UDP port will be controlled.
+ udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);
+ udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED);
udp_port_->SignalPortComplete.connect(
this, &TurnPortTest::OnUdpPortComplete);
}