• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "p2p/base/connection.h"
12 
13 #include <math.h>
14 
15 #include <algorithm>
16 #include <memory>
17 #include <utility>
18 #include <vector>
19 
20 #include "absl/algorithm/container.h"
21 #include "absl/strings/match.h"
22 #include "p2p/base/port_allocator.h"
23 #include "rtc_base/checks.h"
24 #include "rtc_base/crc32.h"
25 #include "rtc_base/helpers.h"
26 #include "rtc_base/logging.h"
27 #include "rtc_base/mdns_responder_interface.h"
28 #include "rtc_base/message_digest.h"
29 #include "rtc_base/network.h"
30 #include "rtc_base/numerics/safe_minmax.h"
31 #include "rtc_base/string_encode.h"
32 #include "rtc_base/string_utils.h"
33 #include "rtc_base/strings/string_builder.h"
34 #include "rtc_base/third_party/base64/base64.h"
35 #include "system_wrappers/include/field_trial.h"
36 
37 namespace {
38 
39 // Determines whether we have seen at least the given maximum number of
40 // pings fail to have a response.
TooManyFailures(const std::vector<cricket::Connection::SentPing> & pings_since_last_response,uint32_t maximum_failures,int rtt_estimate,int64_t now)41 inline bool TooManyFailures(
42     const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
43     uint32_t maximum_failures,
44     int rtt_estimate,
45     int64_t now) {
46   // If we haven't sent that many pings, then we can't have failed that many.
47   if (pings_since_last_response.size() < maximum_failures)
48     return false;
49 
50   // Check if the window in which we would expect a response to the ping has
51   // already elapsed.
52   int64_t expected_response_time =
53       pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
54   return now > expected_response_time;
55 }
56 
57 // Determines whether we have gone too long without seeing any response.
TooLongWithoutResponse(const std::vector<cricket::Connection::SentPing> & pings_since_last_response,int64_t maximum_time,int64_t now)58 inline bool TooLongWithoutResponse(
59     const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
60     int64_t maximum_time,
61     int64_t now) {
62   if (pings_since_last_response.size() == 0)
63     return false;
64 
65   auto first = pings_since_last_response[0];
66   return now > (first.sent_time + maximum_time);
67 }
68 
69 // Helper methods for converting string values of log description fields to
70 // enum.
GetCandidateTypeByString(const std::string & type)71 webrtc::IceCandidateType GetCandidateTypeByString(const std::string& type) {
72   if (type == cricket::LOCAL_PORT_TYPE) {
73     return webrtc::IceCandidateType::kLocal;
74   } else if (type == cricket::STUN_PORT_TYPE) {
75     return webrtc::IceCandidateType::kStun;
76   } else if (type == cricket::PRFLX_PORT_TYPE) {
77     return webrtc::IceCandidateType::kPrflx;
78   } else if (type == cricket::RELAY_PORT_TYPE) {
79     return webrtc::IceCandidateType::kRelay;
80   }
81   return webrtc::IceCandidateType::kUnknown;
82 }
83 
GetProtocolByString(const std::string & protocol)84 webrtc::IceCandidatePairProtocol GetProtocolByString(
85     const std::string& protocol) {
86   if (protocol == cricket::UDP_PROTOCOL_NAME) {
87     return webrtc::IceCandidatePairProtocol::kUdp;
88   } else if (protocol == cricket::TCP_PROTOCOL_NAME) {
89     return webrtc::IceCandidatePairProtocol::kTcp;
90   } else if (protocol == cricket::SSLTCP_PROTOCOL_NAME) {
91     return webrtc::IceCandidatePairProtocol::kSsltcp;
92   } else if (protocol == cricket::TLS_PROTOCOL_NAME) {
93     return webrtc::IceCandidatePairProtocol::kTls;
94   }
95   return webrtc::IceCandidatePairProtocol::kUnknown;
96 }
97 
GetAddressFamilyByInt(int address_family)98 webrtc::IceCandidatePairAddressFamily GetAddressFamilyByInt(
99     int address_family) {
100   if (address_family == AF_INET) {
101     return webrtc::IceCandidatePairAddressFamily::kIpv4;
102   } else if (address_family == AF_INET6) {
103     return webrtc::IceCandidatePairAddressFamily::kIpv6;
104   }
105   return webrtc::IceCandidatePairAddressFamily::kUnknown;
106 }
107 
ConvertNetworkType(rtc::AdapterType type)108 webrtc::IceCandidateNetworkType ConvertNetworkType(rtc::AdapterType type) {
109   switch (type) {
110     case rtc::ADAPTER_TYPE_ETHERNET:
111       return webrtc::IceCandidateNetworkType::kEthernet;
112     case rtc::ADAPTER_TYPE_LOOPBACK:
113       return webrtc::IceCandidateNetworkType::kLoopback;
114     case rtc::ADAPTER_TYPE_WIFI:
115       return webrtc::IceCandidateNetworkType::kWifi;
116     case rtc::ADAPTER_TYPE_VPN:
117       return webrtc::IceCandidateNetworkType::kVpn;
118     case rtc::ADAPTER_TYPE_CELLULAR:
119     case rtc::ADAPTER_TYPE_CELLULAR_2G:
120     case rtc::ADAPTER_TYPE_CELLULAR_3G:
121     case rtc::ADAPTER_TYPE_CELLULAR_4G:
122     case rtc::ADAPTER_TYPE_CELLULAR_5G:
123       return webrtc::IceCandidateNetworkType::kCellular;
124     default:
125       return webrtc::IceCandidateNetworkType::kUnknown;
126   }
127 }
128 
129 // When we don't have any RTT data, we have to pick something reasonable.  We
130 // use a large value just in case the connection is really slow.
131 const int DEFAULT_RTT = 3000;  // 3 seconds
132 
133 // We will restrict RTT estimates (when used for determining state) to be
134 // within a reasonable range.
135 const int MINIMUM_RTT = 100;    // 0.1 seconds
136 const int MAXIMUM_RTT = 60000;  // 60 seconds
137 
138 const int DEFAULT_RTT_ESTIMATE_HALF_TIME_MS = 500;
139 
140 // Computes our estimate of the RTT given the current estimate.
ConservativeRTTEstimate(int rtt)141 inline int ConservativeRTTEstimate(int rtt) {
142   return rtc::SafeClamp(2 * rtt, MINIMUM_RTT, MAXIMUM_RTT);
143 }
144 
145 // Weighting of the old rtt value to new data.
146 const int RTT_RATIO = 3;  // 3 : 1
147 
148 constexpr int64_t kMinExtraPingDelayMs = 100;
149 
150 // Default field trials.
151 const cricket::IceFieldTrials kDefaultFieldTrials;
152 
153 constexpr int kSupportGoogPingVersionRequestIndex =
154     static_cast<int>(cricket::IceGoogMiscInfoBindingRequestAttributeIndex::
155                          SUPPORT_GOOG_PING_VERSION);
156 
157 constexpr int kSupportGoogPingVersionResponseIndex =
158     static_cast<int>(cricket::IceGoogMiscInfoBindingResponseAttributeIndex::
159                          SUPPORT_GOOG_PING_VERSION);
160 
161 }  // namespace
162 
163 namespace cricket {
164 
165 // A ConnectionRequest is a STUN binding used to determine writability.
ConnectionRequest(Connection * connection)166 ConnectionRequest::ConnectionRequest(Connection* connection)
167     : StunRequest(new IceMessage()), connection_(connection) {}
168 
Prepare(StunMessage * request)169 void ConnectionRequest::Prepare(StunMessage* request) {
170   request->SetType(STUN_BINDING_REQUEST);
171   std::string username;
172   connection_->port()->CreateStunUsername(
173       connection_->remote_candidate().username(), &username);
174   // Note that the order of attributes does not impact the parsing on the
175   // receiver side. The attribute is retrieved then by iterating and matching
176   // over all parsed attributes. See StunMessage::GetAttribute.
177   request->AddAttribute(
178       std::make_unique<StunByteStringAttribute>(STUN_ATTR_USERNAME, username));
179 
180   // connection_ already holds this ping, so subtract one from count.
181   if (connection_->port()->send_retransmit_count_attribute()) {
182     request->AddAttribute(std::make_unique<StunUInt32Attribute>(
183         STUN_ATTR_RETRANSMIT_COUNT,
184         static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
185                               1)));
186   }
187   uint32_t network_info = connection_->port()->Network()->id();
188   network_info = (network_info << 16) | connection_->port()->network_cost();
189   request->AddAttribute(std::make_unique<StunUInt32Attribute>(
190       STUN_ATTR_NETWORK_INFO, network_info));
191 
192   if (webrtc::field_trial::IsEnabled(
193           "WebRTC-PiggybackIceCheckAcknowledgement") &&
194       connection_->last_ping_id_received()) {
195     request->AddAttribute(std::make_unique<StunByteStringAttribute>(
196         STUN_ATTR_LAST_ICE_CHECK_RECEIVED,
197         connection_->last_ping_id_received().value()));
198   }
199 
200   // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
201   if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
202     request->AddAttribute(std::make_unique<StunUInt64Attribute>(
203         STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
204     // We should have either USE_CANDIDATE attribute or ICE_NOMINATION
205     // attribute but not both. That was enforced in p2ptransportchannel.
206     if (connection_->use_candidate_attr()) {
207       request->AddAttribute(
208           std::make_unique<StunByteStringAttribute>(STUN_ATTR_USE_CANDIDATE));
209     }
210     if (connection_->nomination() &&
211         connection_->nomination() != connection_->acked_nomination()) {
212       request->AddAttribute(std::make_unique<StunUInt32Attribute>(
213           STUN_ATTR_NOMINATION, connection_->nomination()));
214     }
215   } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
216     request->AddAttribute(std::make_unique<StunUInt64Attribute>(
217         STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
218   } else {
219     RTC_NOTREACHED();
220   }
221 
222   // Adding PRIORITY Attribute.
223   // Changing the type preference to Peer Reflexive and local preference
224   // and component id information is unchanged from the original priority.
225   // priority = (2^24)*(type preference) +
226   //           (2^8)*(local preference) +
227   //           (2^0)*(256 - component ID)
228   uint32_t type_preference =
229       (connection_->local_candidate().protocol() == TCP_PROTOCOL_NAME)
230           ? ICE_TYPE_PREFERENCE_PRFLX_TCP
231           : ICE_TYPE_PREFERENCE_PRFLX;
232   uint32_t prflx_priority =
233       type_preference << 24 |
234       (connection_->local_candidate().priority() & 0x00FFFFFF);
235   request->AddAttribute(std::make_unique<StunUInt32Attribute>(
236       STUN_ATTR_PRIORITY, prflx_priority));
237 
238   if (connection_->field_trials_->enable_goog_ping &&
239       !connection_->remote_support_goog_ping_.has_value()) {
240     // Check if remote supports GOOG PING by announcing which version we
241     // support. This is sent on all STUN_BINDING_REQUEST until we get a
242     // STUN_BINDING_RESPONSE.
243     auto list =
244         StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
245     list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
246     request->AddAttribute(std::move(list));
247   }
248 
249   if (connection_->ShouldSendGoogPing(request)) {
250     request->SetType(GOOG_PING_REQUEST);
251     request->ClearAttributes();
252     request->AddMessageIntegrity32(connection_->remote_candidate().password());
253   } else {
254     request->AddMessageIntegrity(connection_->remote_candidate().password());
255     request->AddFingerprint();
256   }
257 }
258 
OnResponse(StunMessage * response)259 void ConnectionRequest::OnResponse(StunMessage* response) {
260   connection_->OnConnectionRequestResponse(this, response);
261 }
262 
OnErrorResponse(StunMessage * response)263 void ConnectionRequest::OnErrorResponse(StunMessage* response) {
264   connection_->OnConnectionRequestErrorResponse(this, response);
265 }
266 
OnTimeout()267 void ConnectionRequest::OnTimeout() {
268   connection_->OnConnectionRequestTimeout(this);
269 }
270 
OnSent()271 void ConnectionRequest::OnSent() {
272   connection_->OnConnectionRequestSent(this);
273   // Each request is sent only once.  After a single delay , the request will
274   // time out.
275   timeout_ = true;
276 }
277 
resend_delay()278 int ConnectionRequest::resend_delay() {
279   return CONNECTION_RESPONSE_TIMEOUT;
280 }
281 
Connection(Port * port,size_t index,const Candidate & remote_candidate)282 Connection::Connection(Port* port,
283                        size_t index,
284                        const Candidate& remote_candidate)
285     : id_(rtc::CreateRandomId()),
286       port_(port),
287       local_candidate_index_(index),
288       remote_candidate_(remote_candidate),
289       recv_rate_tracker_(100, 10u),
290       send_rate_tracker_(100, 10u),
291       write_state_(STATE_WRITE_INIT),
292       receiving_(false),
293       connected_(true),
294       pruned_(false),
295       use_candidate_attr_(false),
296       remote_ice_mode_(ICEMODE_FULL),
297       requests_(port->thread()),
298       rtt_(DEFAULT_RTT),
299       last_ping_sent_(0),
300       last_ping_received_(0),
301       last_data_received_(0),
302       last_ping_response_received_(0),
303       reported_(false),
304       state_(IceCandidatePairState::WAITING),
305       time_created_ms_(rtc::TimeMillis()),
306       field_trials_(&kDefaultFieldTrials),
307       rtt_estimate_(DEFAULT_RTT_ESTIMATE_HALF_TIME_MS) {
308   // All of our connections start in WAITING state.
309   // TODO(mallinath) - Start connections from STATE_FROZEN.
310   // Wire up to send stun packets
311   requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
312   RTC_LOG(LS_INFO) << ToString() << ": Connection created";
313 }
314 
~Connection()315 Connection::~Connection() {}
316 
local_candidate() const317 const Candidate& Connection::local_candidate() const {
318   RTC_DCHECK(local_candidate_index_ < port_->Candidates().size());
319   return port_->Candidates()[local_candidate_index_];
320 }
321 
remote_candidate() const322 const Candidate& Connection::remote_candidate() const {
323   return remote_candidate_;
324 }
325 
network() const326 const rtc::Network* Connection::network() const {
327   return port()->Network();
328 }
329 
generation() const330 int Connection::generation() const {
331   return port()->generation();
332 }
333 
priority() const334 uint64_t Connection::priority() const {
335   uint64_t priority = 0;
336   // RFC 5245 - 5.7.2.  Computing Pair Priority and Ordering Pairs
337   // Let G be the priority for the candidate provided by the controlling
338   // agent.  Let D be the priority for the candidate provided by the
339   // controlled agent.
340   // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
341   IceRole role = port_->GetIceRole();
342   if (role != ICEROLE_UNKNOWN) {
343     uint32_t g = 0;
344     uint32_t d = 0;
345     if (role == ICEROLE_CONTROLLING) {
346       g = local_candidate().priority();
347       d = remote_candidate_.priority();
348     } else {
349       g = remote_candidate_.priority();
350       d = local_candidate().priority();
351     }
352     priority = std::min(g, d);
353     priority = priority << 32;
354     priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
355   }
356   return priority;
357 }
358 
set_write_state(WriteState value)359 void Connection::set_write_state(WriteState value) {
360   WriteState old_value = write_state_;
361   write_state_ = value;
362   if (value != old_value) {
363     RTC_LOG(LS_VERBOSE) << ToString() << ": set_write_state from: " << old_value
364                         << " to " << value;
365     SignalStateChange(this);
366   }
367 }
368 
UpdateReceiving(int64_t now)369 void Connection::UpdateReceiving(int64_t now) {
370   bool receiving;
371   if (last_ping_sent() < last_ping_response_received()) {
372     // We consider any candidate pair that has its last connectivity check
373     // acknowledged by a response as receiving, particularly for backup
374     // candidate pairs that send checks at a much slower pace than the selected
375     // one. Otherwise, a backup candidate pair constantly becomes not receiving
376     // as a side effect of a long ping interval, since we do not have a separate
377     // receiving timeout for backup candidate pairs. See
378     // IceConfig.ice_backup_candidate_pair_ping_interval,
379     // IceConfig.ice_connection_receiving_timeout and their default value.
380     receiving = true;
381   } else {
382     receiving =
383         last_received() > 0 && now <= last_received() + receiving_timeout();
384   }
385   if (receiving_ == receiving) {
386     return;
387   }
388   RTC_LOG(LS_VERBOSE) << ToString() << ": set_receiving to " << receiving;
389   receiving_ = receiving;
390   receiving_unchanged_since_ = now;
391   SignalStateChange(this);
392 }
393 
set_state(IceCandidatePairState state)394 void Connection::set_state(IceCandidatePairState state) {
395   IceCandidatePairState old_state = state_;
396   state_ = state;
397   if (state != old_state) {
398     RTC_LOG(LS_VERBOSE) << ToString() << ": set_state";
399   }
400 }
401 
set_connected(bool value)402 void Connection::set_connected(bool value) {
403   bool old_value = connected_;
404   connected_ = value;
405   if (value != old_value) {
406     RTC_LOG(LS_VERBOSE) << ToString() << ": Change connected_ to " << value;
407     SignalStateChange(this);
408   }
409 }
410 
set_use_candidate_attr(bool enable)411 void Connection::set_use_candidate_attr(bool enable) {
412   use_candidate_attr_ = enable;
413 }
414 
unwritable_timeout() const415 int Connection::unwritable_timeout() const {
416   return unwritable_timeout_.value_or(CONNECTION_WRITE_CONNECT_TIMEOUT);
417 }
418 
unwritable_min_checks() const419 int Connection::unwritable_min_checks() const {
420   return unwritable_min_checks_.value_or(CONNECTION_WRITE_CONNECT_FAILURES);
421 }
422 
inactive_timeout() const423 int Connection::inactive_timeout() const {
424   return inactive_timeout_.value_or(CONNECTION_WRITE_TIMEOUT);
425 }
426 
receiving_timeout() const427 int Connection::receiving_timeout() const {
428   return receiving_timeout_.value_or(WEAK_CONNECTION_RECEIVE_TIMEOUT);
429 }
430 
SetIceFieldTrials(const IceFieldTrials * field_trials)431 void Connection::SetIceFieldTrials(const IceFieldTrials* field_trials) {
432   field_trials_ = field_trials;
433   rtt_estimate_.SetHalfTime(field_trials->rtt_estimate_halftime_ms);
434 }
435 
OnSendStunPacket(const void * data,size_t size,StunRequest * req)436 void Connection::OnSendStunPacket(const void* data,
437                                   size_t size,
438                                   StunRequest* req) {
439   rtc::PacketOptions options(port_->StunDscpValue());
440   options.info_signaled_after_sent.packet_type =
441       rtc::PacketType::kIceConnectivityCheck;
442   auto err =
443       port_->SendTo(data, size, remote_candidate_.address(), options, false);
444   if (err < 0) {
445     RTC_LOG(LS_WARNING) << ToString()
446                         << ": Failed to send STUN ping "
447                            " err="
448                         << err << " id=" << rtc::hex_encode(req->id());
449   }
450 }
451 
OnReadPacket(const char * data,size_t size,int64_t packet_time_us)452 void Connection::OnReadPacket(const char* data,
453                               size_t size,
454                               int64_t packet_time_us) {
455   std::unique_ptr<IceMessage> msg;
456   std::string remote_ufrag;
457   const rtc::SocketAddress& addr(remote_candidate_.address());
458   if (!port_->GetStunMessage(data, size, addr, &msg, &remote_ufrag)) {
459     // The packet did not parse as a valid STUN message
460     // This is a data packet, pass it along.
461     last_data_received_ = rtc::TimeMillis();
462     UpdateReceiving(last_data_received_);
463     recv_rate_tracker_.AddSamples(size);
464     stats_.packets_received++;
465     SignalReadPacket(this, data, size, packet_time_us);
466 
467     // If timed out sending writability checks, start up again
468     if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
469       RTC_LOG(LS_WARNING)
470           << "Received a data packet on a timed-out Connection. "
471              "Resetting state to STATE_WRITE_INIT.";
472       set_write_state(STATE_WRITE_INIT);
473     }
474   } else if (!msg) {
475     // The packet was STUN, but failed a check and was handled internally.
476   } else {
477     // The packet is STUN and passed the Port checks.
478     // Perform our own checks to ensure this packet is valid.
479     // If this is a STUN request, then update the receiving bit and respond.
480     // If this is a STUN response, then update the writable bit.
481     // Log at LS_INFO if we receive a ping on an unwritable connection.
482     rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
483     switch (msg->type()) {
484       case STUN_BINDING_REQUEST:
485         RTC_LOG_V(sev) << ToString() << ": Received "
486                        << StunMethodToString(msg->type())
487                        << ", id=" << rtc::hex_encode(msg->transaction_id());
488         if (remote_ufrag == remote_candidate_.username()) {
489           HandleStunBindingOrGoogPingRequest(msg.get());
490         } else {
491           // The packet had the right local username, but the remote username
492           // was not the right one for the remote address.
493           RTC_LOG(LS_ERROR)
494               << ToString()
495               << ": Received STUN request with bad remote username "
496               << remote_ufrag;
497           port_->SendBindingErrorResponse(msg.get(), addr,
498                                           STUN_ERROR_UNAUTHORIZED,
499                                           STUN_ERROR_REASON_UNAUTHORIZED);
500         }
501         break;
502 
503       // Response from remote peer. Does it match request sent?
504       // This doesn't just check, it makes callbacks if transaction
505       // id's match.
506       case STUN_BINDING_RESPONSE:
507       case STUN_BINDING_ERROR_RESPONSE:
508         if (msg->ValidateMessageIntegrity(data, size,
509                                           remote_candidate().password())) {
510           requests_.CheckResponse(msg.get());
511         }
512         // Otherwise silently discard the response message.
513         break;
514 
515       // Remote end point sent an STUN indication instead of regular binding
516       // request. In this case |last_ping_received_| will be updated but no
517       // response will be sent.
518       case STUN_BINDING_INDICATION:
519         ReceivedPing(msg->transaction_id());
520         break;
521       case GOOG_PING_REQUEST:
522         HandleStunBindingOrGoogPingRequest(msg.get());
523         break;
524       case GOOG_PING_RESPONSE:
525       case GOOG_PING_ERROR_RESPONSE:
526         if (msg->ValidateMessageIntegrity32(data, size,
527                                             remote_candidate().password())) {
528           requests_.CheckResponse(msg.get());
529         }
530         break;
531       default:
532         RTC_NOTREACHED();
533         break;
534     }
535   }
536 }
537 
HandleStunBindingOrGoogPingRequest(IceMessage * msg)538 void Connection::HandleStunBindingOrGoogPingRequest(IceMessage* msg) {
539   // This connection should now be receiving.
540   ReceivedPing(msg->transaction_id());
541   if (webrtc::field_trial::IsEnabled("WebRTC-ExtraICEPing") &&
542       last_ping_response_received_ == 0) {
543     if (local_candidate().type() == RELAY_PORT_TYPE ||
544         local_candidate().type() == PRFLX_PORT_TYPE ||
545         remote_candidate().type() == RELAY_PORT_TYPE ||
546         remote_candidate().type() == PRFLX_PORT_TYPE) {
547       const int64_t now = rtc::TimeMillis();
548       if (last_ping_sent_ + kMinExtraPingDelayMs <= now) {
549         RTC_LOG(LS_INFO) << ToString()
550                          << "WebRTC-ExtraICEPing/Sending extra ping"
551                             " last_ping_sent_: "
552                          << last_ping_sent_ << " now: " << now
553                          << " (diff: " << (now - last_ping_sent_) << ")";
554         Ping(now);
555       } else {
556         RTC_LOG(LS_INFO) << ToString()
557                          << "WebRTC-ExtraICEPing/Not sending extra ping"
558                             " last_ping_sent_: "
559                          << last_ping_sent_ << " now: " << now
560                          << " (diff: " << (now - last_ping_sent_) << ")";
561       }
562     }
563   }
564 
565   const rtc::SocketAddress& remote_addr = remote_candidate_.address();
566   if (msg->type() == STUN_BINDING_REQUEST) {
567     // Check for role conflicts.
568     const std::string& remote_ufrag = remote_candidate_.username();
569     if (!port_->MaybeIceRoleConflict(remote_addr, msg, remote_ufrag)) {
570       // Received conflicting role from the peer.
571       RTC_LOG(LS_INFO) << "Received conflicting role from the peer.";
572       return;
573     }
574   }
575 
576   stats_.recv_ping_requests++;
577   LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckReceived,
578                         msg->reduced_transaction_id());
579 
580   // This is a validated stun request from remote peer.
581   if (msg->type() == STUN_BINDING_REQUEST) {
582     SendStunBindingResponse(msg);
583   } else {
584     RTC_DCHECK(msg->type() == GOOG_PING_REQUEST);
585     SendGoogPingResponse(msg);
586   }
587 
588   // If it timed out on writing check, start up again
589   if (!pruned_ && write_state_ == STATE_WRITE_TIMEOUT) {
590     set_write_state(STATE_WRITE_INIT);
591   }
592 
593   if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
594     const StunUInt32Attribute* nomination_attr =
595         msg->GetUInt32(STUN_ATTR_NOMINATION);
596     uint32_t nomination = 0;
597     if (nomination_attr) {
598       nomination = nomination_attr->value();
599       if (nomination == 0) {
600         RTC_LOG(LS_ERROR) << "Invalid nomination: " << nomination;
601       }
602     } else {
603       const StunByteStringAttribute* use_candidate_attr =
604           msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
605       if (use_candidate_attr) {
606         nomination = 1;
607       }
608     }
609     // We don't un-nominate a connection, so we only keep a larger nomination.
610     if (nomination > remote_nomination_) {
611       set_remote_nomination(nomination);
612       SignalNominated(this);
613     }
614   }
615   // Set the remote cost if the network_info attribute is available.
616   // Note: If packets are re-ordered, we may get incorrect network cost
617   // temporarily, but it should get the correct value shortly after that.
618   const StunUInt32Attribute* network_attr =
619       msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
620   if (network_attr) {
621     uint32_t network_info = network_attr->value();
622     uint16_t network_cost = static_cast<uint16_t>(network_info);
623     if (network_cost != remote_candidate_.network_cost()) {
624       remote_candidate_.set_network_cost(network_cost);
625       // Network cost change will affect the connection ranking, so signal
626       // state change to force a re-sort in P2PTransportChannel.
627       SignalStateChange(this);
628     }
629   }
630 
631   if (webrtc::field_trial::IsEnabled(
632           "WebRTC-PiggybackIceCheckAcknowledgement")) {
633     HandlePiggybackCheckAcknowledgementIfAny(msg);
634   }
635 }
636 
SendStunBindingResponse(const StunMessage * request)637 void Connection::SendStunBindingResponse(const StunMessage* request) {
638   RTC_DCHECK(request->type() == STUN_BINDING_REQUEST);
639 
640   // Retrieve the username from the request.
641   const StunByteStringAttribute* username_attr =
642       request->GetByteString(STUN_ATTR_USERNAME);
643   RTC_DCHECK(username_attr != NULL);
644   if (username_attr == NULL) {
645     // No valid username, skip the response.
646     return;
647   }
648 
649   // Fill in the response message.
650   StunMessage response;
651   response.SetType(STUN_BINDING_RESPONSE);
652   response.SetTransactionID(request->transaction_id());
653   const StunUInt32Attribute* retransmit_attr =
654       request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
655   if (retransmit_attr) {
656     // Inherit the incoming retransmit value in the response so the other side
657     // can see our view of lost pings.
658     response.AddAttribute(std::make_unique<StunUInt32Attribute>(
659         STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
660 
661     if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
662       RTC_LOG(LS_INFO)
663           << ToString()
664           << ": Received a remote ping with high retransmit count: "
665           << retransmit_attr->value();
666     }
667   }
668 
669   response.AddAttribute(std::make_unique<StunXorAddressAttribute>(
670       STUN_ATTR_XOR_MAPPED_ADDRESS, remote_candidate_.address()));
671 
672   if (field_trials_->announce_goog_ping) {
673     // Check if request contains a announce-request.
674     auto goog_misc = request->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO);
675     if (goog_misc != nullptr &&
676         goog_misc->Size() >= kSupportGoogPingVersionRequestIndex &&
677         // Which version can we handle...currently any >= 1
678         goog_misc->GetType(kSupportGoogPingVersionRequestIndex) >= 1) {
679       auto list =
680           StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
681       list->AddTypeAtIndex(kSupportGoogPingVersionResponseIndex,
682                            kGoogPingVersion);
683       response.AddAttribute(std::move(list));
684     }
685   }
686 
687   response.AddMessageIntegrity(local_candidate().password());
688   response.AddFingerprint();
689 
690   SendResponseMessage(response);
691 }
692 
SendGoogPingResponse(const StunMessage * request)693 void Connection::SendGoogPingResponse(const StunMessage* request) {
694   RTC_DCHECK(request->type() == GOOG_PING_REQUEST);
695 
696   // Fill in the response message.
697   StunMessage response;
698   response.SetType(GOOG_PING_RESPONSE);
699   response.SetTransactionID(request->transaction_id());
700   response.AddMessageIntegrity32(local_candidate().password());
701   SendResponseMessage(response);
702 }
703 
SendResponseMessage(const StunMessage & response)704 void Connection::SendResponseMessage(const StunMessage& response) {
705   // Where I send the response.
706   const rtc::SocketAddress& addr = remote_candidate_.address();
707 
708   // Send the response message.
709   rtc::ByteBufferWriter buf;
710   response.Write(&buf);
711   rtc::PacketOptions options(port_->StunDscpValue());
712   options.info_signaled_after_sent.packet_type =
713       rtc::PacketType::kIceConnectivityCheckResponse;
714   auto err = port_->SendTo(buf.Data(), buf.Length(), addr, options, false);
715   if (err < 0) {
716     RTC_LOG(LS_ERROR) << ToString() << ": Failed to send "
717                       << StunMethodToString(response.type())
718                       << ", to=" << addr.ToSensitiveString() << ", err=" << err
719                       << ", id=" << rtc::hex_encode(response.transaction_id());
720   } else {
721     // Log at LS_INFO if we send a stun ping response on an unwritable
722     // connection.
723     rtc::LoggingSeverity sev = (!writable()) ? rtc::LS_INFO : rtc::LS_VERBOSE;
724     RTC_LOG_V(sev) << ToString() << ": Sent "
725                    << StunMethodToString(response.type())
726                    << ", to=" << addr.ToSensitiveString()
727                    << ", id=" << rtc::hex_encode(response.transaction_id());
728 
729     stats_.sent_ping_responses++;
730     LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckResponseSent,
731                           response.reduced_transaction_id());
732   }
733 }
734 
OnReadyToSend()735 void Connection::OnReadyToSend() {
736   SignalReadyToSend(this);
737 }
738 
Prune()739 void Connection::Prune() {
740   if (!pruned_ || active()) {
741     RTC_LOG(LS_INFO) << ToString() << ": Connection pruned";
742     pruned_ = true;
743     requests_.Clear();
744     set_write_state(STATE_WRITE_TIMEOUT);
745   }
746 }
747 
Destroy()748 void Connection::Destroy() {
749   // TODO(deadbeef, nisse): This may leak if an application closes a
750   // PeerConnection and then quickly destroys the PeerConnectionFactory (along
751   // with the networking thread on which this message is posted). Also affects
752   // tests, with a workaround in
753   // AutoSocketServerThread::~AutoSocketServerThread.
754   RTC_LOG(LS_VERBOSE) << ToString() << ": Connection destroyed";
755   port_->thread()->Post(RTC_FROM_HERE, this, MSG_DELETE);
756   LogCandidatePairConfig(webrtc::IceCandidatePairConfigType::kDestroyed);
757 }
758 
FailAndDestroy()759 void Connection::FailAndDestroy() {
760   set_state(IceCandidatePairState::FAILED);
761   Destroy();
762 }
763 
FailAndPrune()764 void Connection::FailAndPrune() {
765   set_state(IceCandidatePairState::FAILED);
766   Prune();
767 }
768 
PrintPingsSinceLastResponse(std::string * s,size_t max)769 void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
770   rtc::StringBuilder oss;
771   if (pings_since_last_response_.size() > max) {
772     for (size_t i = 0; i < max; i++) {
773       const SentPing& ping = pings_since_last_response_[i];
774       oss << rtc::hex_encode(ping.id) << " ";
775     }
776     oss << "... " << (pings_since_last_response_.size() - max) << " more";
777   } else {
778     for (const SentPing& ping : pings_since_last_response_) {
779       oss << rtc::hex_encode(ping.id) << " ";
780     }
781   }
782   *s = oss.str();
783 }
784 
UpdateState(int64_t now)785 void Connection::UpdateState(int64_t now) {
786   int rtt = ConservativeRTTEstimate(rtt_);
787 
788   if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE)) {
789     std::string pings;
790     PrintPingsSinceLastResponse(&pings, 5);
791     RTC_LOG(LS_VERBOSE) << ToString()
792                         << ": UpdateState()"
793                            ", ms since last received response="
794                         << now - last_ping_response_received_
795                         << ", ms since last received data="
796                         << now - last_data_received_ << ", rtt=" << rtt
797                         << ", pings_since_last_response=" << pings;
798   }
799 
800   // Check the writable state.  (The order of these checks is important.)
801   //
802   // Before becoming unwritable, we allow for a fixed number of pings to fail
803   // (i.e., receive no response).  We also have to give the response time to
804   // get back, so we include a conservative estimate of this.
805   //
806   // Before timing out writability, we give a fixed amount of time.  This is to
807   // allow for changes in network conditions.
808 
809   if ((write_state_ == STATE_WRITABLE) &&
810       TooManyFailures(pings_since_last_response_, unwritable_min_checks(), rtt,
811                       now) &&
812       TooLongWithoutResponse(pings_since_last_response_, unwritable_timeout(),
813                              now)) {
814     uint32_t max_pings = unwritable_min_checks();
815     RTC_LOG(LS_INFO) << ToString() << ": Unwritable after " << max_pings
816                      << " ping failures and "
817                      << now - pings_since_last_response_[0].sent_time
818                      << " ms without a response,"
819                         " ms since last received ping="
820                      << now - last_ping_received_
821                      << " ms since last received data="
822                      << now - last_data_received_ << " rtt=" << rtt;
823     set_write_state(STATE_WRITE_UNRELIABLE);
824   }
825   if ((write_state_ == STATE_WRITE_UNRELIABLE ||
826        write_state_ == STATE_WRITE_INIT) &&
827       TooLongWithoutResponse(pings_since_last_response_, inactive_timeout(),
828                              now)) {
829     RTC_LOG(LS_INFO) << ToString() << ": Timed out after "
830                      << now - pings_since_last_response_[0].sent_time
831                      << " ms without a response, rtt=" << rtt;
832     set_write_state(STATE_WRITE_TIMEOUT);
833   }
834 
835   // Update the receiving state.
836   UpdateReceiving(now);
837   if (dead(now)) {
838     Destroy();
839   }
840 }
841 
Ping(int64_t now)842 void Connection::Ping(int64_t now) {
843   last_ping_sent_ = now;
844   ConnectionRequest* req = new ConnectionRequest(this);
845   // If not using renomination, we use "1" to mean "nominated" and "0" to mean
846   // "not nominated". If using renomination, values greater than 1 are used for
847   // re-nominated pairs.
848   int nomination = use_candidate_attr_ ? 1 : 0;
849   if (nomination_ > 0) {
850     nomination = nomination_;
851   }
852   pings_since_last_response_.push_back(SentPing(req->id(), now, nomination));
853   RTC_LOG(LS_VERBOSE) << ToString() << ": Sending STUN ping, id="
854                       << rtc::hex_encode(req->id())
855                       << ", nomination=" << nomination_;
856   requests_.Send(req);
857   state_ = IceCandidatePairState::IN_PROGRESS;
858   num_pings_sent_++;
859 }
860 
ReceivedPing(const absl::optional<std::string> & request_id)861 void Connection::ReceivedPing(const absl::optional<std::string>& request_id) {
862   last_ping_received_ = rtc::TimeMillis();
863   last_ping_id_received_ = request_id;
864   UpdateReceiving(last_ping_received_);
865 }
866 
HandlePiggybackCheckAcknowledgementIfAny(StunMessage * msg)867 void Connection::HandlePiggybackCheckAcknowledgementIfAny(StunMessage* msg) {
868   RTC_DCHECK(msg->type() == STUN_BINDING_REQUEST ||
869              msg->type() == GOOG_PING_REQUEST);
870   const StunByteStringAttribute* last_ice_check_received_attr =
871       msg->GetByteString(STUN_ATTR_LAST_ICE_CHECK_RECEIVED);
872   if (last_ice_check_received_attr) {
873     const std::string request_id = last_ice_check_received_attr->GetString();
874     auto iter = absl::c_find_if(
875         pings_since_last_response_,
876         [&request_id](const SentPing& ping) { return ping.id == request_id; });
877     if (iter != pings_since_last_response_.end()) {
878       rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
879       RTC_LOG_V(sev) << ToString()
880                      << ": Received piggyback STUN ping response, id="
881                      << rtc::hex_encode(request_id);
882       const int64_t rtt = rtc::TimeMillis() - iter->sent_time;
883       ReceivedPingResponse(rtt, request_id, iter->nomination);
884     }
885   }
886 }
887 
ReceivedPingResponse(int rtt,const std::string & request_id,const absl::optional<uint32_t> & nomination)888 void Connection::ReceivedPingResponse(
889     int rtt,
890     const std::string& request_id,
891     const absl::optional<uint32_t>& nomination) {
892   RTC_DCHECK_GE(rtt, 0);
893   // We've already validated that this is a STUN binding response with
894   // the correct local and remote username for this connection.
895   // So if we're not already, become writable. We may be bringing a pruned
896   // connection back to life, but if we don't really want it, we can always
897   // prune it again.
898   if (nomination && nomination.value() > acked_nomination_) {
899     acked_nomination_ = nomination.value();
900   }
901 
902   int64_t now = rtc::TimeMillis();
903   total_round_trip_time_ms_ += rtt;
904   current_round_trip_time_ms_ = static_cast<uint32_t>(rtt);
905   rtt_estimate_.AddSample(now, rtt);
906 
907   pings_since_last_response_.clear();
908   last_ping_response_received_ = now;
909   UpdateReceiving(last_ping_response_received_);
910   set_write_state(STATE_WRITABLE);
911   set_state(IceCandidatePairState::SUCCEEDED);
912   if (rtt_samples_ > 0) {
913     rtt_ = rtc::GetNextMovingAverage(rtt_, rtt, RTT_RATIO);
914   } else {
915     rtt_ = rtt;
916   }
917   rtt_samples_++;
918 }
919 
dead(int64_t now) const920 bool Connection::dead(int64_t now) const {
921   if (last_received() > 0) {
922     // If it has ever received anything, we keep it alive
923     // - if it has recevied last DEAD_CONNECTION_RECEIVE_TIMEOUT (30s)
924     // - if it has a ping outstanding shorter than
925     // DEAD_CONNECTION_RECEIVE_TIMEOUT (30s)
926     // - else if IDLE let it live field_trials_->dead_connection_timeout_ms
927     //
928     // This covers the normal case of a successfully used connection that stops
929     // working. This also allows a remote peer to continue pinging over a
930     // locally inactive (pruned) connection. This also allows the local agent to
931     // ping with longer interval than 30s as long as it shorter than
932     // |dead_connection_timeout_ms|.
933     if (now <= (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT)) {
934       // Not dead since we have received the last 30s.
935       return false;
936     }
937     if (!pings_since_last_response_.empty()) {
938       // Outstanding pings: let it live until the ping is unreplied for
939       // DEAD_CONNECTION_RECEIVE_TIMEOUT.
940       return now > (pings_since_last_response_[0].sent_time +
941                     DEAD_CONNECTION_RECEIVE_TIMEOUT);
942     }
943 
944     // No outstanding pings: let it live until
945     // field_trials_->dead_connection_timeout_ms has passed.
946     return now > (last_received() + field_trials_->dead_connection_timeout_ms);
947   }
948 
949   if (active()) {
950     // If it has never received anything, keep it alive as long as it is
951     // actively pinging and not pruned. Otherwise, the connection might be
952     // deleted before it has a chance to ping. This is the normal case for a
953     // new connection that is pinging but hasn't received anything yet.
954     return false;
955   }
956 
957   // If it has never received anything and is not actively pinging (pruned), we
958   // keep it around for at least MIN_CONNECTION_LIFETIME to prevent connections
959   // from being pruned too quickly during a network change event when two
960   // networks would be up simultaneously but only for a brief period.
961   return now > (time_created_ms_ + MIN_CONNECTION_LIFETIME);
962 }
963 
stable(int64_t now) const964 bool Connection::stable(int64_t now) const {
965   // A connection is stable if it's RTT has converged and it isn't missing any
966   // responses.  We should send pings at a higher rate until the RTT converges
967   // and whenever a ping response is missing (so that we can detect
968   // unwritability faster)
969   return rtt_converged() && !missing_responses(now);
970 }
971 
ToDebugId() const972 std::string Connection::ToDebugId() const {
973   return rtc::ToHex(reinterpret_cast<uintptr_t>(this));
974 }
975 
ComputeNetworkCost() const976 uint32_t Connection::ComputeNetworkCost() const {
977   // TODO(honghaiz): Will add rtt as part of the network cost.
978   return port()->network_cost() + remote_candidate_.network_cost();
979 }
980 
ToString() const981 std::string Connection::ToString() const {
982   const absl::string_view CONNECT_STATE_ABBREV[2] = {
983       "-",  // not connected (false)
984       "C",  // connected (true)
985   };
986   const absl::string_view RECEIVE_STATE_ABBREV[2] = {
987       "-",  // not receiving (false)
988       "R",  // receiving (true)
989   };
990   const absl::string_view WRITE_STATE_ABBREV[4] = {
991       "W",  // STATE_WRITABLE
992       "w",  // STATE_WRITE_UNRELIABLE
993       "-",  // STATE_WRITE_INIT
994       "x",  // STATE_WRITE_TIMEOUT
995   };
996   const absl::string_view ICESTATE[4] = {
997       "W",  // STATE_WAITING
998       "I",  // STATE_INPROGRESS
999       "S",  // STATE_SUCCEEDED
1000       "F"   // STATE_FAILED
1001   };
1002   const absl::string_view SELECTED_STATE_ABBREV[2] = {
1003       "-",  // candidate pair not selected (false)
1004       "S",  // selected (true)
1005   };
1006   const Candidate& local = local_candidate();
1007   const Candidate& remote = remote_candidate();
1008   rtc::StringBuilder ss;
1009   ss << "Conn[" << ToDebugId() << ":" << port_->content_name() << ":"
1010      << port_->Network()->ToString() << ":" << local.id() << ":"
1011      << local.component() << ":" << local.generation() << ":" << local.type()
1012      << ":" << local.protocol() << ":" << local.address().ToSensitiveString()
1013      << "->" << remote.id() << ":" << remote.component() << ":"
1014      << remote.priority() << ":" << remote.type() << ":" << remote.protocol()
1015      << ":" << remote.address().ToSensitiveString() << "|"
1016      << CONNECT_STATE_ABBREV[connected()] << RECEIVE_STATE_ABBREV[receiving()]
1017      << WRITE_STATE_ABBREV[write_state()] << ICESTATE[static_cast<int>(state())]
1018      << "|" << SELECTED_STATE_ABBREV[selected()] << "|" << remote_nomination()
1019      << "|" << nomination() << "|" << priority() << "|";
1020   if (rtt_ < DEFAULT_RTT) {
1021     ss << rtt_ << "]";
1022   } else {
1023     ss << "-]";
1024   }
1025   return ss.Release();
1026 }
1027 
ToSensitiveString() const1028 std::string Connection::ToSensitiveString() const {
1029   return ToString();
1030 }
1031 
ToLogDescription()1032 const webrtc::IceCandidatePairDescription& Connection::ToLogDescription() {
1033   if (log_description_.has_value()) {
1034     return log_description_.value();
1035   }
1036   const Candidate& local = local_candidate();
1037   const Candidate& remote = remote_candidate();
1038   const rtc::Network* network = port()->Network();
1039   log_description_ = webrtc::IceCandidatePairDescription();
1040   log_description_->local_candidate_type =
1041       GetCandidateTypeByString(local.type());
1042   log_description_->local_relay_protocol =
1043       GetProtocolByString(local.relay_protocol());
1044   log_description_->local_network_type = ConvertNetworkType(network->type());
1045   log_description_->local_address_family =
1046       GetAddressFamilyByInt(local.address().family());
1047   log_description_->remote_candidate_type =
1048       GetCandidateTypeByString(remote.type());
1049   log_description_->remote_address_family =
1050       GetAddressFamilyByInt(remote.address().family());
1051   log_description_->candidate_pair_protocol =
1052       GetProtocolByString(local.protocol());
1053   return log_description_.value();
1054 }
1055 
LogCandidatePairConfig(webrtc::IceCandidatePairConfigType type)1056 void Connection::LogCandidatePairConfig(
1057     webrtc::IceCandidatePairConfigType type) {
1058   if (ice_event_log_ == nullptr) {
1059     return;
1060   }
1061   ice_event_log_->LogCandidatePairConfig(type, id(), ToLogDescription());
1062 }
1063 
LogCandidatePairEvent(webrtc::IceCandidatePairEventType type,uint32_t transaction_id)1064 void Connection::LogCandidatePairEvent(webrtc::IceCandidatePairEventType type,
1065                                        uint32_t transaction_id) {
1066   if (ice_event_log_ == nullptr) {
1067     return;
1068   }
1069   ice_event_log_->LogCandidatePairEvent(type, id(), transaction_id);
1070 }
1071 
OnConnectionRequestResponse(ConnectionRequest * request,StunMessage * response)1072 void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1073                                              StunMessage* response) {
1074   // Log at LS_INFO if we receive a ping response on an unwritable
1075   // connection.
1076   rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1077 
1078   int rtt = request->Elapsed();
1079 
1080   if (RTC_LOG_CHECK_LEVEL_V(sev)) {
1081     std::string pings;
1082     PrintPingsSinceLastResponse(&pings, 5);
1083     RTC_LOG_V(sev) << ToString() << ": Received "
1084                    << StunMethodToString(response->type())
1085                    << ", id=" << rtc::hex_encode(request->id())
1086                    << ", code=0"  // Makes logging easier to parse.
1087                       ", rtt="
1088                    << rtt << ", pings_since_last_response=" << pings;
1089   }
1090   absl::optional<uint32_t> nomination;
1091   const std::string request_id = request->id();
1092   auto iter = absl::c_find_if(
1093       pings_since_last_response_,
1094       [&request_id](const SentPing& ping) { return ping.id == request_id; });
1095   if (iter != pings_since_last_response_.end()) {
1096     nomination.emplace(iter->nomination);
1097   }
1098   ReceivedPingResponse(rtt, request_id, nomination);
1099 
1100   stats_.recv_ping_responses++;
1101   LogCandidatePairEvent(
1102       webrtc::IceCandidatePairEventType::kCheckResponseReceived,
1103       response->reduced_transaction_id());
1104 
1105   if (request->msg()->type() == STUN_BINDING_REQUEST) {
1106     if (!remote_support_goog_ping_.has_value()) {
1107       auto goog_misc = response->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO);
1108       if (goog_misc != nullptr &&
1109           goog_misc->Size() >= kSupportGoogPingVersionResponseIndex) {
1110         // The remote peer has indicated that it {does/does not} supports
1111         // GOOG_PING.
1112         remote_support_goog_ping_ =
1113             goog_misc->GetType(kSupportGoogPingVersionResponseIndex) >=
1114             kGoogPingVersion;
1115       } else {
1116         remote_support_goog_ping_ = false;
1117       }
1118     }
1119 
1120     MaybeUpdateLocalCandidate(request, response);
1121 
1122     if (field_trials_->enable_goog_ping && remote_support_goog_ping_) {
1123       cached_stun_binding_ = request->msg()->Clone();
1124     }
1125   }
1126 }
1127 
OnConnectionRequestErrorResponse(ConnectionRequest * request,StunMessage * response)1128 void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1129                                                   StunMessage* response) {
1130   int error_code = response->GetErrorCodeValue();
1131   RTC_LOG(LS_WARNING) << ToString() << ": Received "
1132                       << StunMethodToString(response->type())
1133                       << " id=" << rtc::hex_encode(request->id())
1134                       << " code=" << error_code
1135                       << " rtt=" << request->Elapsed();
1136 
1137   cached_stun_binding_.reset();
1138   if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1139       error_code == STUN_ERROR_SERVER_ERROR ||
1140       error_code == STUN_ERROR_UNAUTHORIZED) {
1141     // Recoverable error, retry
1142   } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1143     // Race failure, retry
1144   } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1145     HandleRoleConflictFromPeer();
1146   } else if (request->msg()->type() == GOOG_PING_REQUEST) {
1147     // Race, retry.
1148   } else {
1149     // This is not a valid connection.
1150     RTC_LOG(LS_ERROR) << ToString()
1151                       << ": Received STUN error response, code=" << error_code
1152                       << "; killing connection";
1153     FailAndDestroy();
1154   }
1155 }
1156 
OnConnectionRequestTimeout(ConnectionRequest * request)1157 void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1158   // Log at LS_INFO if we miss a ping on a writable connection.
1159   rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1160   RTC_LOG_V(sev) << ToString() << ": Timing-out STUN ping "
1161                  << rtc::hex_encode(request->id()) << " after "
1162                  << request->Elapsed() << " ms";
1163 }
1164 
OnConnectionRequestSent(ConnectionRequest * request)1165 void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1166   // Log at LS_INFO if we send a ping on an unwritable connection.
1167   rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1168   RTC_LOG_V(sev) << ToString() << ": Sent "
1169                  << StunMethodToString(request->msg()->type())
1170                  << ", id=" << rtc::hex_encode(request->id())
1171                  << ", use_candidate=" << use_candidate_attr()
1172                  << ", nomination=" << nomination();
1173   stats_.sent_ping_requests_total++;
1174   LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckSent,
1175                         request->reduced_transaction_id());
1176   if (stats_.recv_ping_responses == 0) {
1177     stats_.sent_ping_requests_before_first_response++;
1178   }
1179 }
1180 
HandleRoleConflictFromPeer()1181 void Connection::HandleRoleConflictFromPeer() {
1182   port_->SignalRoleConflict(port_);
1183 }
1184 
MaybeSetRemoteIceParametersAndGeneration(const IceParameters & ice_params,int generation)1185 void Connection::MaybeSetRemoteIceParametersAndGeneration(
1186     const IceParameters& ice_params,
1187     int generation) {
1188   if (remote_candidate_.username() == ice_params.ufrag &&
1189       remote_candidate_.password().empty()) {
1190     remote_candidate_.set_password(ice_params.pwd);
1191   }
1192   // TODO(deadbeef): A value of '0' for the generation is used for both
1193   // generation 0 and "generation unknown". It should be changed to an
1194   // absl::optional to fix this.
1195   if (remote_candidate_.username() == ice_params.ufrag &&
1196       remote_candidate_.password() == ice_params.pwd &&
1197       remote_candidate_.generation() == 0) {
1198     remote_candidate_.set_generation(generation);
1199   }
1200 }
1201 
MaybeUpdatePeerReflexiveCandidate(const Candidate & new_candidate)1202 void Connection::MaybeUpdatePeerReflexiveCandidate(
1203     const Candidate& new_candidate) {
1204   if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1205       new_candidate.type() != PRFLX_PORT_TYPE &&
1206       remote_candidate_.protocol() == new_candidate.protocol() &&
1207       remote_candidate_.address() == new_candidate.address() &&
1208       remote_candidate_.username() == new_candidate.username() &&
1209       remote_candidate_.password() == new_candidate.password() &&
1210       remote_candidate_.generation() == new_candidate.generation()) {
1211     remote_candidate_ = new_candidate;
1212   }
1213 }
1214 
OnMessage(rtc::Message * pmsg)1215 void Connection::OnMessage(rtc::Message* pmsg) {
1216   RTC_DCHECK(pmsg->message_id == MSG_DELETE);
1217   RTC_LOG(LS_INFO) << "Connection deleted with number of pings sent: "
1218                    << num_pings_sent_;
1219   SignalDestroyed(this);
1220   delete this;
1221 }
1222 
last_received() const1223 int64_t Connection::last_received() const {
1224   return std::max(last_data_received_,
1225                   std::max(last_ping_received_, last_ping_response_received_));
1226 }
1227 
stats()1228 ConnectionInfo Connection::stats() {
1229   stats_.recv_bytes_second = round(recv_rate_tracker_.ComputeRate());
1230   stats_.recv_total_bytes = recv_rate_tracker_.TotalSampleCount();
1231   stats_.sent_bytes_second = round(send_rate_tracker_.ComputeRate());
1232   stats_.sent_total_bytes = send_rate_tracker_.TotalSampleCount();
1233   stats_.receiving = receiving_;
1234   stats_.writable = write_state_ == STATE_WRITABLE;
1235   stats_.timeout = write_state_ == STATE_WRITE_TIMEOUT;
1236   stats_.new_connection = !reported_;
1237   stats_.rtt = rtt_;
1238   stats_.key = this;
1239   stats_.state = state_;
1240   stats_.priority = priority();
1241   stats_.nominated = nominated();
1242   stats_.total_round_trip_time_ms = total_round_trip_time_ms_;
1243   stats_.current_round_trip_time_ms = current_round_trip_time_ms_;
1244   stats_.local_candidate = local_candidate();
1245   stats_.remote_candidate = remote_candidate();
1246   return stats_;
1247 }
1248 
MaybeUpdateLocalCandidate(ConnectionRequest * request,StunMessage * response)1249 void Connection::MaybeUpdateLocalCandidate(ConnectionRequest* request,
1250                                            StunMessage* response) {
1251   // RFC 5245
1252   // The agent checks the mapped address from the STUN response.  If the
1253   // transport address does not match any of the local candidates that the
1254   // agent knows about, the mapped address represents a new candidate -- a
1255   // peer reflexive candidate.
1256   const StunAddressAttribute* addr =
1257       response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1258   if (!addr) {
1259     RTC_LOG(LS_WARNING)
1260         << "Connection::OnConnectionRequestResponse - "
1261            "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1262            "stun response message";
1263     return;
1264   }
1265 
1266   for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1267     if (port_->Candidates()[i].address() == addr->GetAddress()) {
1268       if (local_candidate_index_ != i) {
1269         RTC_LOG(LS_INFO) << ToString()
1270                          << ": Updating local candidate type to srflx.";
1271         local_candidate_index_ = i;
1272         // SignalStateChange to force a re-sort in P2PTransportChannel as this
1273         // Connection's local candidate has changed.
1274         SignalStateChange(this);
1275       }
1276       return;
1277     }
1278   }
1279 
1280   // RFC 5245
1281   // Its priority is set equal to the value of the PRIORITY attribute
1282   // in the Binding request.
1283   const StunUInt32Attribute* priority_attr =
1284       request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1285   if (!priority_attr) {
1286     RTC_LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1287                            "No STUN_ATTR_PRIORITY found in the "
1288                            "stun response message";
1289     return;
1290   }
1291   const uint32_t priority = priority_attr->value();
1292   std::string id = rtc::CreateRandomString(8);
1293 
1294   // Create a peer-reflexive candidate based on the local candidate.
1295   Candidate new_local_candidate(local_candidate());
1296   new_local_candidate.set_id(id);
1297   new_local_candidate.set_type(PRFLX_PORT_TYPE);
1298   new_local_candidate.set_address(addr->GetAddress());
1299   new_local_candidate.set_priority(priority);
1300   new_local_candidate.set_related_address(local_candidate().address());
1301   new_local_candidate.set_foundation(Port::ComputeFoundation(
1302       PRFLX_PORT_TYPE, local_candidate().protocol(),
1303       local_candidate().relay_protocol(), local_candidate().address()));
1304 
1305   // Change the local candidate of this Connection to the new prflx candidate.
1306   RTC_LOG(LS_INFO) << ToString() << ": Updating local candidate type to prflx.";
1307   local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1308 
1309   // SignalStateChange to force a re-sort in P2PTransportChannel as this
1310   // Connection's local candidate has changed.
1311   SignalStateChange(this);
1312 }
1313 
rtt_converged() const1314 bool Connection::rtt_converged() const {
1315   return rtt_samples_ > (RTT_RATIO + 1);
1316 }
1317 
missing_responses(int64_t now) const1318 bool Connection::missing_responses(int64_t now) const {
1319   if (pings_since_last_response_.empty()) {
1320     return false;
1321   }
1322 
1323   int64_t waiting = now - pings_since_last_response_[0].sent_time;
1324   return waiting > 2 * rtt();
1325 }
1326 
TooManyOutstandingPings(const absl::optional<int> & max_outstanding_pings) const1327 bool Connection::TooManyOutstandingPings(
1328     const absl::optional<int>& max_outstanding_pings) const {
1329   if (!max_outstanding_pings.has_value()) {
1330     return false;
1331   }
1332   if (static_cast<int>(pings_since_last_response_.size()) <
1333       *max_outstanding_pings) {
1334     return false;
1335   }
1336   return true;
1337 }
1338 
ShouldSendGoogPing(const StunMessage * message)1339 bool Connection::ShouldSendGoogPing(const StunMessage* message) {
1340   if (remote_support_goog_ping_ == true && cached_stun_binding_ &&
1341       cached_stun_binding_->EqualAttributes(message, [](int type) {
1342         // Ignore these attributes.
1343         // NOTE: Consider what to do if adding more content to
1344         // STUN_ATTR_GOOG_MISC_INFO
1345         return type != STUN_ATTR_FINGERPRINT &&
1346                type != STUN_ATTR_MESSAGE_INTEGRITY &&
1347                type != STUN_ATTR_RETRANSMIT_COUNT &&
1348                type != STUN_ATTR_GOOG_MISC_INFO;
1349       })) {
1350     return true;
1351   }
1352   return false;
1353 }
1354 
ForgetLearnedState()1355 void Connection::ForgetLearnedState() {
1356   RTC_LOG(LS_INFO) << ToString() << ": Connection forget learned state";
1357   requests_.Clear();
1358   receiving_ = false;
1359   write_state_ = STATE_WRITE_INIT;
1360   rtt_estimate_.Reset();
1361   pings_since_last_response_.clear();
1362 }
1363 
ProxyConnection(Port * port,size_t index,const Candidate & remote_candidate)1364 ProxyConnection::ProxyConnection(Port* port,
1365                                  size_t index,
1366                                  const Candidate& remote_candidate)
1367     : Connection(port, index, remote_candidate) {}
1368 
Send(const void * data,size_t size,const rtc::PacketOptions & options)1369 int ProxyConnection::Send(const void* data,
1370                           size_t size,
1371                           const rtc::PacketOptions& options) {
1372   stats_.sent_total_packets++;
1373   int sent =
1374       port_->SendTo(data, size, remote_candidate_.address(), options, true);
1375   if (sent <= 0) {
1376     RTC_DCHECK(sent < 0);
1377     error_ = port_->GetError();
1378     stats_.sent_discarded_packets++;
1379   } else {
1380     send_rate_tracker_.AddSamples(sent);
1381   }
1382   return sent;
1383 }
1384 
GetError()1385 int ProxyConnection::GetError() {
1386   return error_;
1387 }
1388 
1389 }  // namespace cricket
1390