diff options
author | mallinath@webrtc.org <mallinath@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-02-03 16:57:16 +0000 |
---|---|---|
committer | mallinath@webrtc.org <mallinath@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-02-03 16:57:16 +0000 |
commit | b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15c (patch) | |
tree | 7e476a94dc6bd821fb3452e8021da5a49c3325df /p2p | |
parent | d51e05ddea8c27cfc8f1e33fd4ef068534280bd5 (diff) | |
download | talk-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.h | 3 | ||||
-rw-r--r-- | p2p/base/fakesession.h | 4 | ||||
-rw-r--r-- | p2p/base/p2ptransportchannel.cc | 20 | ||||
-rw-r--r-- | p2p/base/p2ptransportchannel.h | 1 | ||||
-rw-r--r-- | p2p/base/p2ptransportchannel_unittest.cc | 57 | ||||
-rw-r--r-- | p2p/base/port.cc | 48 | ||||
-rw-r--r-- | p2p/base/port.h | 19 | ||||
-rw-r--r-- | p2p/base/port_unittest.cc | 111 | ||||
-rw-r--r-- | p2p/base/rawtransportchannel.h | 3 | ||||
-rw-r--r-- | p2p/base/relayport.cc | 8 | ||||
-rw-r--r-- | p2p/base/stunport.cc | 6 | ||||
-rw-r--r-- | p2p/base/tcpport.cc | 8 | ||||
-rw-r--r-- | p2p/base/transport.cc | 30 | ||||
-rw-r--r-- | p2p/base/transportchannelimpl.h | 1 | ||||
-rw-r--r-- | p2p/base/turnport.cc | 18 | ||||
-rw-r--r-- | p2p/base/turnport_unittest.cc | 10 |
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); } |