Index: webrtc/p2p/base/port.cc |
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc |
index fca4f027f93e9de840faf326aa6d007f19e1b120..98b62c4222e11eac346bfc1991599d833aeb7e70 100644 |
--- a/webrtc/p2p/base/port.cc |
+++ b/webrtc/p2p/base/port.cc |
@@ -775,15 +775,17 @@ class ConnectionRequest : public StunRequest { |
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. |
+ // We should have either USE_CANDIDATE attribute or ICE_NOMINATION |
+ // attribute but not both. That was enforced in p2ptransportchannel. |
if (connection_->use_candidate_attr()) { |
request->AddAttribute(new StunByteStringAttribute( |
STUN_ATTR_USE_CANDIDATE)); |
} |
+ if (connection_->nomination() && |
+ connection_->nomination() != connection_->acked_nomination()) { |
+ request->AddAttribute(new StunUInt32Attribute( |
+ STUN_ATTR_NOMINATION, connection_->nomination())); |
+ } |
} else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) { |
request->AddAttribute(new StunUInt64Attribute( |
STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker())); |
@@ -846,12 +848,13 @@ Connection::Connection(Port* port, |
: port_(port), |
local_candidate_index_(index), |
remote_candidate_(remote_candidate), |
+ recv_rate_tracker_(100, 10u), |
+ send_rate_tracker_(100, 10u), |
write_state_(STATE_WRITE_INIT), |
receiving_(false), |
connected_(true), |
pruned_(false), |
use_candidate_attr_(false), |
- nominated_(false), |
remote_ice_mode_(ICEMODE_FULL), |
requests_(port->thread()), |
rtt_(DEFAULT_RTT), |
@@ -859,8 +862,6 @@ Connection::Connection(Port* port, |
last_ping_received_(0), |
last_data_received_(0), |
last_ping_response_received_(0), |
- recv_rate_tracker_(100, 10u), |
- send_rate_tracker_(100, 10u), |
reported_(false), |
state_(STATE_WAITING), |
receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT), |
@@ -1062,10 +1063,24 @@ void Connection::HandleBindingRequest(IceMessage* msg) { |
} |
if (port_->GetIceRole() == ICEROLE_CONTROLLED) { |
- const StunByteStringAttribute* use_candidate_attr = |
- msg->GetByteString(STUN_ATTR_USE_CANDIDATE); |
- if (use_candidate_attr) { |
- set_nominated(true); |
+ const StunUInt32Attribute* nomination_attr = |
+ msg->GetUInt32(STUN_ATTR_NOMINATION); |
+ uint32_t nomination = 0; |
+ if (nomination_attr) { |
+ nomination = nomination_attr->value(); |
+ if (nomination == 0) { |
+ LOG(LS_ERROR) << "Invalid nomination: " << nomination; |
+ } |
+ } else { |
+ const StunByteStringAttribute* use_candidate_attr = |
+ msg->GetByteString(STUN_ATTR_USE_CANDIDATE); |
+ if (use_candidate_attr) { |
+ nomination = 1; |
+ } |
+ } |
+ // We don't un-nominate a connection, so we only keep a larger nomination. |
+ if (nomination > remote_nomination_) { |
+ set_remote_nomination(nomination); |
SignalNominated(this); |
} |
} |
@@ -1199,9 +1214,10 @@ void Connection::UpdateState(int64_t now) { |
void Connection::Ping(int64_t now) { |
last_ping_sent_ = now; |
ConnectionRequest *req = new ConnectionRequest(this); |
- pings_since_last_response_.push_back(SentPing(req->id(), now)); |
+ pings_since_last_response_.push_back(SentPing(req->id(), now, nomination_)); |
LOG_J(LS_VERBOSE, this) << "Sending STUN ping " |
- << ", id=" << rtc::hex_encode(req->id()); |
+ << ", id=" << rtc::hex_encode(req->id()) |
+ << ", nomination=" << nomination_; |
requests_.Send(req); |
state_ = STATE_INPROGRESS; |
num_pings_sent_++; |
@@ -1212,17 +1228,25 @@ void Connection::ReceivedPing() { |
UpdateReceiving(last_ping_received_); |
} |
-void Connection::ReceivedPingResponse(int rtt) { |
+void Connection::ReceivedPingResponse(int rtt, const std::string& request_id) { |
// We've already validated that this is a STUN binding response with |
// the correct local and remote username for this connection. |
// So if we're not already, become writable. We may be bringing a pruned |
// connection back to life, but if we don't really want it, we can always |
// prune it again. |
+ auto iter = std::find_if( |
+ pings_since_last_response_.begin(), pings_since_last_response_.end(), |
+ [request_id](const SentPing& ping) { return ping.id == request_id; }); |
+ if (iter != pings_since_last_response_.end() && |
+ iter->nomination > acked_nomination_) { |
+ acked_nomination_ = iter->nomination; |
+ } |
+ |
+ pings_since_last_response_.clear(); |
last_ping_response_received_ = rtc::TimeMillis(); |
UpdateReceiving(last_ping_response_received_); |
set_write_state(STATE_WRITABLE); |
set_state(STATE_SUCCEEDED); |
- pings_since_last_response_.clear(); |
rtt_samples_++; |
rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1); |
} |
@@ -1295,21 +1319,16 @@ std::string Connection::ToString() const { |
const Candidate& local = local_candidate(); |
const Candidate& remote = remote_candidate(); |
std::stringstream ss; |
- ss << "Conn[" << ToDebugId() |
- << ":" << port_->content_name() |
- << ":" << local.id() << ":" << local.component() |
- << ":" << local.generation() |
- << ":" << local.type() << ":" << local.protocol() |
- << ":" << local.address().ToSensitiveString() |
- << "->" << remote.id() << ":" << remote.component() |
- << ":" << remote.priority() |
- << ":" << remote.type() << ":" |
- << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|" |
- << CONNECT_STATE_ABBREV[connected()] |
- << RECEIVE_STATE_ABBREV[receiving()] |
- << WRITE_STATE_ABBREV[write_state()] |
- << ICESTATE[state()] << "|" |
- << priority() << "|"; |
+ ss << "Conn[" << ToDebugId() << ":" << port_->content_name() << ":" |
+ << local.id() << ":" << local.component() << ":" << local.generation() |
+ << ":" << local.type() << ":" << local.protocol() << ":" |
+ << local.address().ToSensitiveString() << "->" << remote.id() << ":" |
+ << remote.component() << ":" << remote.priority() << ":" << remote.type() |
+ << ":" << remote.protocol() << ":" << remote.address().ToSensitiveString() |
+ << "|" << CONNECT_STATE_ABBREV[connected()] |
+ << RECEIVE_STATE_ABBREV[receiving()] << WRITE_STATE_ABBREV[write_state()] |
+ << ICESTATE[state()] << "|" << remote_nomination() << "|" << nomination() |
+ << "|" << priority() << "|"; |
if (rtt_ < DEFAULT_RTT) { |
ss << rtt_ << "]"; |
} else { |
@@ -1330,20 +1349,16 @@ void Connection::OnConnectionRequestResponse(ConnectionRequest* request, |
int rtt = request->Elapsed(); |
- ReceivedPingResponse(rtt); |
- |
if (LOG_CHECK_LEVEL_V(sev)) { |
- bool use_candidate = ( |
- response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr); |
std::string pings; |
PrintPingsSinceLastResponse(&pings, 5); |
LOG_JV(sev, this) << "Received STUN ping response" |
<< ", id=" << rtc::hex_encode(request->id()) |
<< ", code=0" // Makes logging easier to parse. |
<< ", rtt=" << rtt |
- << ", use_candidate=" << use_candidate |
<< ", pings_since_last_response=" << pings; |
} |
+ ReceivedPingResponse(rtt, request->id()); |
stats_.recv_ping_responses++; |
@@ -1390,10 +1405,10 @@ void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) { |
void Connection::OnConnectionRequestSent(ConnectionRequest* request) { |
// Log at LS_INFO if we send a ping on an unwritable connection. |
rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE; |
- bool use_candidate = use_candidate_attr(); |
LOG_JV(sev, this) << "Sent STUN ping" |
<< ", id=" << rtc::hex_encode(request->id()) |
- << ", use_candidate=" << use_candidate; |
+ << ", use_candidate=" << use_candidate_attr() |
+ << ", nomination=" << nomination(); |
stats_.sent_ping_requests_total++; |
if (stats_.recv_ping_responses == 0) { |
stats_.sent_ping_requests_before_first_response++; |