Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1408)

Unified Diff: webrtc/p2p/base/port.cc

Issue 1336553003: Revert change which removes GICE (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/p2p/base/port.h ('k') | webrtc/p2p/base/port_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/p2p/base/port.cc
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc
index 8048201754b737dabdfa1901e020521cacc4ef84..eb63b02c86dfc5a734eadbbc026d83b3da7b28a1 100644
--- a/webrtc/p2p/base/port.cc
+++ b/webrtc/p2p/base/port.cc
@@ -58,6 +58,27 @@ inline bool TooLongWithoutResponse(
return now > (first.sent_time + maximum_time);
}
+// GICE(ICEPROTO_GOOGLE) requires different username for RTP and RTCP.
+// This function generates a different username by +1 on the last character of
+// the given username (|rtp_ufrag|).
+std::string GetRtcpUfragFromRtpUfrag(const std::string& rtp_ufrag) {
+ ASSERT(!rtp_ufrag.empty());
+ if (rtp_ufrag.empty()) {
+ return rtp_ufrag;
+ }
+ // Change the last character to the one next to it in the base64 table.
+ char new_last_char;
+ if (!rtc::Base64::GetNextBase64Char(rtp_ufrag[rtp_ufrag.size() - 1],
+ &new_last_char)) {
+ // Should not be here.
+ ASSERT(false);
+ }
+ std::string rtcp_ufrag = rtp_ufrag;
+ rtcp_ufrag[rtcp_ufrag.size() - 1] = new_last_char;
+ ASSERT(rtcp_ufrag != rtp_ufrag);
+ return rtcp_ufrag;
+}
+
// We will restrict RTT estimates (when used for determining state) to be
// within a reasonable range.
const uint32 MINIMUM_RTT = 100; // 0.1 seconds
@@ -150,6 +171,7 @@ Port::Port(rtc::Thread* thread,
password_(password),
timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
shared_socket_(true),
@@ -180,6 +202,7 @@ Port::Port(rtc::Thread* thread,
password_(password),
timeout_delay_(kPortTimeoutDelay),
enable_port_packets_(false),
+ ice_protocol_(ICEPROTO_HYBRID),
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
shared_socket_(false),
@@ -189,9 +212,7 @@ Port::Port(rtc::Thread* thread,
}
void Port::Construct() {
- // TODO(pthatcher): Remove this old behavior once we're sure no one
- // relies on it. If the username_fragment and password are empty,
- // we should just create one.
+ // If the username_fragment and password are empty, we should just create one.
if (ice_username_fragment_.empty()) {
ASSERT(password_.empty());
ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
@@ -293,7 +314,8 @@ void Port::OnReadPacket(
<< " from unknown address " << addr.ToSensitiveString();
// Check for role conflicts.
- if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
+ if (IsStandardIce() &&
+ !MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
LOG(LS_INFO) << "Received conflicting role from the peer.";
return;
}
@@ -324,6 +346,18 @@ size_t Port::AddPrflxCandidate(const Candidate& local) {
return (candidates_.size() - 1);
}
+bool Port::IsStandardIce() const {
+ return (ice_protocol_ == ICEPROTO_RFC5245);
+}
+
+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 rtc::SocketAddress& addr,
IceMessage** out_msg, std::string* out_username) {
@@ -337,7 +371,7 @@ bool Port::GetStunMessage(const char* data, size_t size,
// Don't bother parsing the packet if we can tell it's not STUN.
// In ICE mode, all STUN packets will have a valid fingerprint.
- if (!StunMessage::ValidateFingerprint(data, size)) {
+ if (IsStandardIce() && !StunMessage::ValidateFingerprint(data, size)) {
return false;
}
@@ -353,7 +387,8 @@ bool Port::GetStunMessage(const char* data, size_t size,
// Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
// If not present, fail with a 400 Bad Request.
if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
- !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
+ (IsStandardIce() &&
+ !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY))) {
LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
<< "from " << addr.ToSensitiveString();
SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
@@ -364,7 +399,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 "
@@ -374,8 +411,18 @@ 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 (!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
+ if (IsStandardIce() &&
+ !stun_msg->ValidateMessageIntegrity(data, size, password_)) {
LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
<< "from " << addr.ToSensitiveString()
<< ", password_=" << password_;
@@ -436,7 +483,8 @@ bool Port::IsCompatibleAddress(const rtc::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.
@@ -447,15 +495,34 @@ bool Port::ParseStunUsername(const StunMessage* stun_msg,
if (username_attr == NULL)
return false;
- // RFRAG:LFRAG
- const std::string username = username_attr->GetString();
- size_t colon_pos = username.find(":");
- if (colon_pos == std::string::npos) {
- return false;
+ const std::string username_attr_str = username_attr->GetString();
+ 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(
+ colon_pos + 1, username_attr_str.size());
+ } else {
+ return false;
+ }
+ } 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)
+ return false;
+
+ *local_ufrag = username_attr_str.substr(0, username_fragment().size());
+ *remote_ufrag = username_attr_str.substr(
+ username_fragment().size(), username_attr_str.size());
}
-
- *local_ufrag = username.substr(0, colon_pos);
- *remote_ufrag = username.substr(colon_pos + 1, username.size());
return true;
}
@@ -524,7 +591,10 @@ void Port::CreateStunUsername(const std::string& remote_username,
std::string* stun_username_attr_str) const {
stun_username_attr_str->clear();
*stun_username_attr_str = remote_username;
- stun_username_attr_str->append(":");
+ if (IsStandardIce()) {
+ // Connectivity checks from L->R will have username RFRAG:LFRAG.
+ stun_username_attr_str->append(":");
+ }
stun_username_attr_str->append(username_fragment());
}
@@ -560,10 +630,19 @@ void Port::SendBindingResponse(StunMessage* request,
}
}
- response.AddAttribute(
- new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
- response.AddMessageIntegrity(password_);
- response.AddFingerprint();
+ // Only GICE messages have USERNAME and MAPPED-ADDRESS in the response.
+ // ICE messages use XOR-MAPPED-ADDRESS, and add MESSAGE-INTEGRITY.
+ if (IsStandardIce()) {
+ response.AddAttribute(
+ new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
+ response.AddMessageIntegrity(password_);
+ response.AddFingerprint();
+ } else if (IsGoogleIce()) {
+ response.AddAttribute(
+ new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, addr));
+ response.AddAttribute(new StunByteStringAttribute(
+ STUN_ATTR_USERNAME, username_attr->GetString()));
+ }
// The fact that we received a successful request means that this connection
// (if one exists) should now be readable.
@@ -609,16 +688,30 @@ void Port::SendBindingErrorResponse(StunMessage* request,
// When doing GICE, we need to write out the error code incorrectly to
// maintain backwards compatiblility.
StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
- error_attr->SetCode(error_code);
+ if (IsStandardIce()) {
+ error_attr->SetCode(error_code);
+ } else if (IsGoogleIce()) {
+ error_attr->SetClass(error_code / 256);
+ error_attr->SetNumber(error_code % 256);
+ }
error_attr->SetReason(reason);
response.AddAttribute(error_attr);
- // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
- // because we don't have enough information to determine the shared secret.
- if (error_code != STUN_ERROR_BAD_REQUEST &&
- error_code != STUN_ERROR_UNAUTHORIZED)
- response.AddMessageIntegrity(password_);
- response.AddFingerprint();
+ if (IsStandardIce()) {
+ // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
+ // because we don't have enough information to determine the shared secret.
+ if (error_code != STUN_ERROR_BAD_REQUEST &&
+ error_code != STUN_ERROR_UNAUTHORIZED)
+ response.AddMessageIntegrity(password_);
+ response.AddFingerprint();
+ } else if (IsGoogleIce()) {
+ // GICE responses include a username, if one exists.
+ const StunByteStringAttribute* username_attr =
+ request->GetByteString(STUN_ATTR_USERNAME);
+ if (username_attr)
+ response.AddAttribute(new StunByteStringAttribute(
+ STUN_ATTR_USERNAME, username_attr->GetString()));
+ }
// Send the response message.
rtc::ByteBuffer buf;
@@ -678,7 +771,13 @@ void Port::CheckTimeout() {
}
const std::string Port::username_fragment() const {
- return ice_username_fragment_;
+ if (!IsStandardIce() &&
+ component_ == ICE_CANDIDATE_COMPONENT_RTCP) {
+ // In GICE mode, we should adjust username fragment for rtcp component.
+ return GetRtcpUfragFromRtpUfrag(ice_username_fragment_);
+ } else {
+ return ice_username_fragment_;
+ }
}
// A ConnectionRequest is a simple STUN ping used to determine writability.
@@ -708,41 +807,44 @@ class ConnectionRequest : public StunRequest {
connection_->pings_since_last_response_.size() - 1)));
}
- // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
- if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
- request->AddAttribute(new StunUInt64Attribute(
- STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
- // Since we are trying aggressive nomination, sending USE-CANDIDATE
- // attribute in every ping.
- // If we are dealing with a ice-lite end point, nomination flag
- // in Connection will be set to false by default. Once the connection
- // becomes "best connection", nomination flag will be turned on.
- if (connection_->use_candidate_attr()) {
- request->AddAttribute(new StunByteStringAttribute(
- STUN_ATTR_USE_CANDIDATE));
+ // Adding ICE-specific attributes to the STUN request message.
+ if (connection_->port()->IsStandardIce()) {
+ // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
+ if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
+ request->AddAttribute(new StunUInt64Attribute(
+ STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
+ // Since we are trying aggressive nomination, sending USE-CANDIDATE
+ // attribute in every ping.
+ // If we are dealing with a ice-lite end point, nomination flag
+ // in Connection will be set to false by default. Once the connection
+ // becomes "best connection", nomination flag will be turned on.
+ if (connection_->use_candidate_attr()) {
+ request->AddAttribute(new StunByteStringAttribute(
+ STUN_ATTR_USE_CANDIDATE));
+ }
+ } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
+ request->AddAttribute(new StunUInt64Attribute(
+ STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
+ } else {
+ ASSERT(false);
}
- } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
- request->AddAttribute(new StunUInt64Attribute(
- STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
- } else {
- ASSERT(false);
- }
-
- // Adding PRIORITY Attribute.
- // Changing the type preference to Peer Reflexive and local preference
- // and component id information is unchanged from the original priority.
- // priority = (2^24)*(type preference) +
- // (2^8)*(local preference) +
- // (2^0)*(256 - component ID)
- uint32 prflx_priority = ICE_TYPE_PREFERENCE_PRFLX << 24 |
- (connection_->local_candidate().priority() & 0x00FFFFFF);
- request->AddAttribute(
- new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
- // Adding Message Integrity attribute.
- request->AddMessageIntegrity(connection_->remote_candidate().password());
- // Adding Fingerprint.
- request->AddFingerprint();
+ // Adding PRIORITY Attribute.
+ // Changing the type preference to Peer Reflexive and local preference
+ // and component id information is unchanged from the original priority.
+ // priority = (2^24)*(type preference) +
+ // (2^8)*(local preference) +
+ // (2^0)*(256 - component ID)
+ uint32 prflx_priority = ICE_TYPE_PREFERENCE_PRFLX << 24 |
+ (connection_->local_candidate().priority() & 0x00FFFFFF);
+ request->AddAttribute(
+ new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
+
+ // Adding Message Integrity attribute.
+ request->AddMessageIntegrity(connection_->remote_candidate().password());
+ // Adding Fingerprint.
+ request->AddFingerprint();
+ }
}
void OnResponse(StunMessage* response) override {
@@ -938,7 +1040,8 @@ void Connection::OnReadPacket(
if (remote_ufrag == remote_candidate_.username()) {
// Check for role conflicts.
- if (!port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) {
+ if (port_->IsStandardIce() &&
+ !port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) {
// Received conflicting role from the peer.
LOG(LS_INFO) << "Received conflicting role from the peer.";
return;
@@ -952,7 +1055,8 @@ void Connection::OnReadPacket(
if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
set_write_state(STATE_WRITE_INIT);
- if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
+ if ((port_->IsStandardIce()) &&
+ (port_->GetIceRole() == ICEROLE_CONTROLLED)) {
const StunByteStringAttribute* use_candidate_attr =
msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
if (use_candidate_attr) {
@@ -978,7 +1082,8 @@ void Connection::OnReadPacket(
// id's match.
case STUN_BINDING_RESPONSE:
case STUN_BINDING_ERROR_RESPONSE:
- if (msg->ValidateMessageIntegrity(
+ if (port_->IsGoogleIce() ||
+ msg->ValidateMessageIntegrity(
data, size, remote_candidate().password())) {
requests_.CheckResponse(msg.get());
}
@@ -990,7 +1095,7 @@ void Connection::OnReadPacket(
// Otherwise we can mark connection to read timeout. No response will be
// sent in this scenario.
case STUN_BINDING_INDICATION:
- if (read_state_ == STATE_READABLE) {
+ if (port_->IsStandardIce() && read_state_ == STATE_READABLE) {
ReceivedPing();
} else {
LOG_J(LS_WARNING, this) << "Received STUN binding indication "
@@ -1058,6 +1163,30 @@ void Connection::UpdateState(uint32 now) {
<< ", pings_since_last_response=" << pings;
}
+ // Check the readable state.
+ //
+ // Since we don't know how many pings the other side has attempted, the best
+ // test we can do is a simple window.
+ // If other side has not sent ping after connection has become readable, use
+ // |last_data_received_| as the indication.
+ // If remote endpoint is doing RFC 5245, it's not required to send ping
+ // after connection is established. If this connection is serving a data
+ // channel, it may not be in a position to send media continuously. Do not
+ // mark connection timeout if it's in RFC5245 mode.
+ // Below check will be performed with end point if it's doing google-ice.
+ if (port_->IsGoogleIce() && (read_state_ == STATE_READABLE) &&
+ (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now) &&
+ (last_data_received_ + CONNECTION_READ_TIMEOUT <= now)) {
+ LOG_J(LS_INFO, this) << "Unreadable after " << now - last_ping_received_
+ << " ms without a ping,"
+ << " ms since last received response="
+ << now - last_ping_response_received_
+ << " ms since last received data="
+ << now - last_data_received_
+ << " rtt=" << rtt;
+ set_read_state(STATE_READ_TIMEOUT);
+ }
+
// Check the writable state. (The order of these checks is important.)
//
// Before becoming unwritable, we allow for a fixed number of pings to fail
@@ -1216,7 +1345,10 @@ void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
- MaybeAddPrflxCandidate(request, response);
+ // Peer reflexive candidate is only for RFC 5245 ICE.
+ if (port_->IsStandardIce()) {
+ MaybeAddPrflxCandidate(request, response);
+ }
}
void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
@@ -1224,7 +1356,13 @@ void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
int error_code = STUN_ERROR_GLOBAL_FAILURE;
if (error_attr) {
- error_code = error_attr->code();
+ if (port_->IsGoogleIce()) {
+ // When doing GICE, the error code is written out incorrectly, so we need
+ // to unmunge it here.
+ error_code = error_attr->eclass() * 256 + error_attr->number();
+ } else {
+ error_code = error_attr->code();
+ }
}
LOG_J(LS_INFO, this) << "Received STUN error response"
« no previous file with comments | « webrtc/p2p/base/port.h ('k') | webrtc/p2p/base/port_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698