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