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/escaping.h"
22 #include "absl/strings/match.h"
23 #include "absl/strings/string_view.h"
24 #include "p2p/base/port_allocator.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/crc32.h"
27 #include "rtc_base/helpers.h"
28 #include "rtc_base/logging.h"
29 #include "rtc_base/mdns_responder_interface.h"
30 #include "rtc_base/message_digest.h"
31 #include "rtc_base/network.h"
32 #include "rtc_base/numerics/safe_minmax.h"
33 #include "rtc_base/string_encode.h"
34 #include "rtc_base/string_utils.h"
35 #include "rtc_base/strings/string_builder.h"
36 #include "rtc_base/third_party/base64/base64.h"
37
38 namespace cricket {
39 namespace {
40
41 // Determines whether we have seen at least the given maximum number of
42 // pings fail to have a response.
TooManyFailures(const std::vector<Connection::SentPing> & pings_since_last_response,uint32_t maximum_failures,int rtt_estimate,int64_t now)43 inline bool TooManyFailures(
44 const std::vector<Connection::SentPing>& pings_since_last_response,
45 uint32_t maximum_failures,
46 int rtt_estimate,
47 int64_t now) {
48 // If we haven't sent that many pings, then we can't have failed that many.
49 if (pings_since_last_response.size() < maximum_failures)
50 return false;
51
52 // Check if the window in which we would expect a response to the ping has
53 // already elapsed.
54 int64_t expected_response_time =
55 pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
56 return now > expected_response_time;
57 }
58
59 // Determines whether we have gone too long without seeing any response.
TooLongWithoutResponse(const std::vector<Connection::SentPing> & pings_since_last_response,int64_t maximum_time,int64_t now)60 inline bool TooLongWithoutResponse(
61 const std::vector<Connection::SentPing>& pings_since_last_response,
62 int64_t maximum_time,
63 int64_t now) {
64 if (pings_since_last_response.size() == 0)
65 return false;
66
67 auto first = pings_since_last_response[0];
68 return now > (first.sent_time + maximum_time);
69 }
70
71 // Helper methods for converting string values of log description fields to
72 // enum.
GetCandidateTypeByString(absl::string_view type)73 webrtc::IceCandidateType GetCandidateTypeByString(absl::string_view type) {
74 if (type == LOCAL_PORT_TYPE) {
75 return webrtc::IceCandidateType::kLocal;
76 } else if (type == STUN_PORT_TYPE) {
77 return webrtc::IceCandidateType::kStun;
78 } else if (type == PRFLX_PORT_TYPE) {
79 return webrtc::IceCandidateType::kPrflx;
80 } else if (type == RELAY_PORT_TYPE) {
81 return webrtc::IceCandidateType::kRelay;
82 }
83 return webrtc::IceCandidateType::kUnknown;
84 }
85
GetProtocolByString(absl::string_view protocol)86 webrtc::IceCandidatePairProtocol GetProtocolByString(
87 absl::string_view protocol) {
88 if (protocol == UDP_PROTOCOL_NAME) {
89 return webrtc::IceCandidatePairProtocol::kUdp;
90 } else if (protocol == TCP_PROTOCOL_NAME) {
91 return webrtc::IceCandidatePairProtocol::kTcp;
92 } else if (protocol == SSLTCP_PROTOCOL_NAME) {
93 return webrtc::IceCandidatePairProtocol::kSsltcp;
94 } else if (protocol == TLS_PROTOCOL_NAME) {
95 return webrtc::IceCandidatePairProtocol::kTls;
96 }
97 return webrtc::IceCandidatePairProtocol::kUnknown;
98 }
99
GetAddressFamilyByInt(int address_family)100 webrtc::IceCandidatePairAddressFamily GetAddressFamilyByInt(
101 int address_family) {
102 if (address_family == AF_INET) {
103 return webrtc::IceCandidatePairAddressFamily::kIpv4;
104 } else if (address_family == AF_INET6) {
105 return webrtc::IceCandidatePairAddressFamily::kIpv6;
106 }
107 return webrtc::IceCandidatePairAddressFamily::kUnknown;
108 }
109
ConvertNetworkType(rtc::AdapterType type)110 webrtc::IceCandidateNetworkType ConvertNetworkType(rtc::AdapterType type) {
111 switch (type) {
112 case rtc::ADAPTER_TYPE_ETHERNET:
113 return webrtc::IceCandidateNetworkType::kEthernet;
114 case rtc::ADAPTER_TYPE_LOOPBACK:
115 return webrtc::IceCandidateNetworkType::kLoopback;
116 case rtc::ADAPTER_TYPE_WIFI:
117 return webrtc::IceCandidateNetworkType::kWifi;
118 case rtc::ADAPTER_TYPE_VPN:
119 return webrtc::IceCandidateNetworkType::kVpn;
120 case rtc::ADAPTER_TYPE_CELLULAR:
121 case rtc::ADAPTER_TYPE_CELLULAR_2G:
122 case rtc::ADAPTER_TYPE_CELLULAR_3G:
123 case rtc::ADAPTER_TYPE_CELLULAR_4G:
124 case rtc::ADAPTER_TYPE_CELLULAR_5G:
125 return webrtc::IceCandidateNetworkType::kCellular;
126 default:
127 return webrtc::IceCandidateNetworkType::kUnknown;
128 }
129 }
130
131 // When we don't have any RTT data, we have to pick something reasonable. We
132 // use a large value just in case the connection is really slow.
133 const int DEFAULT_RTT = 3000; // 3 seconds
134
135 // We will restrict RTT estimates (when used for determining state) to be
136 // within a reasonable range.
137 const int MINIMUM_RTT = 100; // 0.1 seconds
138 const int MAXIMUM_RTT = 60000; // 60 seconds
139
140 const int DEFAULT_RTT_ESTIMATE_HALF_TIME_MS = 500;
141
142 // Computes our estimate of the RTT given the current estimate.
ConservativeRTTEstimate(int rtt)143 inline int ConservativeRTTEstimate(int rtt) {
144 return rtc::SafeClamp(2 * rtt, MINIMUM_RTT, MAXIMUM_RTT);
145 }
146
147 // Weighting of the old rtt value to new data.
148 const int RTT_RATIO = 3; // 3 : 1
149
150 constexpr int64_t kMinExtraPingDelayMs = 100;
151
152 // Default field trials.
153 const IceFieldTrials kDefaultFieldTrials;
154
155 constexpr int kSupportGoogPingVersionRequestIndex = static_cast<int>(
156 IceGoogMiscInfoBindingRequestAttributeIndex::SUPPORT_GOOG_PING_VERSION);
157
158 constexpr int kSupportGoogPingVersionResponseIndex = static_cast<int>(
159 IceGoogMiscInfoBindingResponseAttributeIndex::SUPPORT_GOOG_PING_VERSION);
160
161 } // namespace
162
163 // A ConnectionRequest is a STUN binding used to determine writability.
164 class Connection::ConnectionRequest : public StunRequest {
165 public:
166 ConnectionRequest(StunRequestManager& manager,
167 Connection* connection,
168 std::unique_ptr<IceMessage> message);
169 void OnResponse(StunMessage* response) override;
170 void OnErrorResponse(StunMessage* response) override;
171 void OnTimeout() override;
172 void OnSent() override;
173 int resend_delay() override;
174
175 private:
176 Connection* const connection_;
177 };
178
ConnectionRequest(StunRequestManager & manager,Connection * connection,std::unique_ptr<IceMessage> message)179 Connection::ConnectionRequest::ConnectionRequest(
180 StunRequestManager& manager,
181 Connection* connection,
182 std::unique_ptr<IceMessage> message)
183 : StunRequest(manager, std::move(message)), connection_(connection) {}
184
OnResponse(StunMessage * response)185 void Connection::ConnectionRequest::OnResponse(StunMessage* response) {
186 RTC_DCHECK_RUN_ON(connection_->network_thread_);
187 connection_->OnConnectionRequestResponse(this, response);
188 }
189
OnErrorResponse(StunMessage * response)190 void Connection::ConnectionRequest::OnErrorResponse(StunMessage* response) {
191 RTC_DCHECK_RUN_ON(connection_->network_thread_);
192 connection_->OnConnectionRequestErrorResponse(this, response);
193 }
194
OnTimeout()195 void Connection::ConnectionRequest::OnTimeout() {
196 RTC_DCHECK_RUN_ON(connection_->network_thread_);
197 connection_->OnConnectionRequestTimeout(this);
198 }
199
OnSent()200 void Connection::ConnectionRequest::OnSent() {
201 RTC_DCHECK_RUN_ON(connection_->network_thread_);
202 connection_->OnConnectionRequestSent(this);
203 // Each request is sent only once. After a single delay , the request will
204 // time out.
205 set_timed_out();
206 }
207
resend_delay()208 int Connection::ConnectionRequest::resend_delay() {
209 return CONNECTION_RESPONSE_TIMEOUT;
210 }
211
Connection(rtc::WeakPtr<Port> port,size_t index,const Candidate & remote_candidate)212 Connection::Connection(rtc::WeakPtr<Port> port,
213 size_t index,
214 const Candidate& remote_candidate)
215 : network_thread_(port->thread()),
216 id_(rtc::CreateRandomId()),
217 port_(std::move(port)),
218 local_candidate_(port_->Candidates()[index]),
219 remote_candidate_(remote_candidate),
220 recv_rate_tracker_(100, 10u),
221 send_rate_tracker_(100, 10u),
222 write_state_(STATE_WRITE_INIT),
223 receiving_(false),
224 connected_(true),
225 pruned_(false),
226 use_candidate_attr_(false),
227 requests_(port_->thread(),
228 [this](const void* data, size_t size, StunRequest* request) {
229 OnSendStunPacket(data, size, request);
230 }),
231 rtt_(DEFAULT_RTT),
232 last_ping_sent_(0),
233 last_ping_received_(0),
234 last_data_received_(0),
235 last_ping_response_received_(0),
236 state_(IceCandidatePairState::WAITING),
237 time_created_ms_(rtc::TimeMillis()),
238 delta_internal_unix_epoch_ms_(rtc::TimeUTCMillis() - rtc::TimeMillis()),
239 field_trials_(&kDefaultFieldTrials),
240 rtt_estimate_(DEFAULT_RTT_ESTIMATE_HALF_TIME_MS) {
241 RTC_DCHECK_RUN_ON(network_thread_);
242 RTC_DCHECK(port_);
243 RTC_LOG(LS_INFO) << ToString() << ": Connection created";
244 }
245
~Connection()246 Connection::~Connection() {
247 RTC_DCHECK_RUN_ON(network_thread_);
248 RTC_DCHECK(!port_);
249 }
250
network_thread() const251 webrtc::TaskQueueBase* Connection::network_thread() const {
252 return network_thread_;
253 }
254
local_candidate() const255 const Candidate& Connection::local_candidate() const {
256 RTC_DCHECK_RUN_ON(network_thread_);
257 return local_candidate_;
258 }
259
remote_candidate() const260 const Candidate& Connection::remote_candidate() const {
261 return remote_candidate_;
262 }
263
network() const264 const rtc::Network* Connection::network() const {
265 return port()->Network();
266 }
267
generation() const268 int Connection::generation() const {
269 return port()->generation();
270 }
271
priority() const272 uint64_t Connection::priority() const {
273 if (!port_)
274 return 0;
275
276 uint64_t priority = 0;
277 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
278 // Let G be the priority for the candidate provided by the controlling
279 // agent. Let D be the priority for the candidate provided by the
280 // controlled agent.
281 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
282 IceRole role = port_->GetIceRole();
283 if (role != ICEROLE_UNKNOWN) {
284 uint32_t g = 0;
285 uint32_t d = 0;
286 if (role == ICEROLE_CONTROLLING) {
287 g = local_candidate().priority();
288 d = remote_candidate_.priority();
289 } else {
290 g = remote_candidate_.priority();
291 d = local_candidate().priority();
292 }
293 priority = std::min(g, d);
294 priority = priority << 32;
295 priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
296 }
297 return priority;
298 }
299
set_write_state(WriteState value)300 void Connection::set_write_state(WriteState value) {
301 RTC_DCHECK_RUN_ON(network_thread_);
302 WriteState old_value = write_state_;
303 write_state_ = value;
304 if (value != old_value) {
305 RTC_LOG(LS_VERBOSE) << ToString() << ": set_write_state from: " << old_value
306 << " to " << value;
307 SignalStateChange(this);
308 }
309 }
310
UpdateReceiving(int64_t now)311 void Connection::UpdateReceiving(int64_t now) {
312 RTC_DCHECK_RUN_ON(network_thread_);
313 bool receiving;
314 if (last_ping_sent() < last_ping_response_received()) {
315 // We consider any candidate pair that has its last connectivity check
316 // acknowledged by a response as receiving, particularly for backup
317 // candidate pairs that send checks at a much slower pace than the selected
318 // one. Otherwise, a backup candidate pair constantly becomes not receiving
319 // as a side effect of a long ping interval, since we do not have a separate
320 // receiving timeout for backup candidate pairs. See
321 // IceConfig.ice_backup_candidate_pair_ping_interval,
322 // IceConfig.ice_connection_receiving_timeout and their default value.
323 receiving = true;
324 } else {
325 receiving =
326 last_received() > 0 && now <= last_received() + receiving_timeout();
327 }
328 if (receiving_ == receiving) {
329 return;
330 }
331 RTC_LOG(LS_VERBOSE) << ToString() << ": set_receiving to " << receiving;
332 receiving_ = receiving;
333 receiving_unchanged_since_ = now;
334 SignalStateChange(this);
335 }
336
set_state(IceCandidatePairState state)337 void Connection::set_state(IceCandidatePairState state) {
338 RTC_DCHECK_RUN_ON(network_thread_);
339 IceCandidatePairState old_state = state_;
340 state_ = state;
341 if (state != old_state) {
342 RTC_LOG(LS_VERBOSE) << ToString() << ": set_state";
343 }
344 }
345
set_connected(bool value)346 void Connection::set_connected(bool value) {
347 RTC_DCHECK_RUN_ON(network_thread_);
348 bool old_value = connected_;
349 connected_ = value;
350 if (value != old_value) {
351 RTC_LOG(LS_VERBOSE) << ToString() << ": Change connected_ to " << value;
352 SignalStateChange(this);
353 }
354 }
355
use_candidate_attr() const356 bool Connection::use_candidate_attr() const {
357 RTC_DCHECK_RUN_ON(network_thread_);
358 return use_candidate_attr_;
359 }
360
set_use_candidate_attr(bool enable)361 void Connection::set_use_candidate_attr(bool enable) {
362 RTC_DCHECK_RUN_ON(network_thread_);
363 use_candidate_attr_ = enable;
364 }
365
set_nomination(uint32_t value)366 void Connection::set_nomination(uint32_t value) {
367 RTC_DCHECK_RUN_ON(network_thread_);
368 nomination_ = value;
369 }
370
remote_nomination() const371 uint32_t Connection::remote_nomination() const {
372 RTC_DCHECK_RUN_ON(network_thread_);
373 return remote_nomination_;
374 }
375
nominated() const376 bool Connection::nominated() const {
377 RTC_DCHECK_RUN_ON(network_thread_);
378 return acked_nomination_ || remote_nomination_;
379 }
380
unwritable_timeout() const381 int Connection::unwritable_timeout() const {
382 RTC_DCHECK_RUN_ON(network_thread_);
383 return unwritable_timeout_.value_or(CONNECTION_WRITE_CONNECT_TIMEOUT);
384 }
385
set_unwritable_timeout(const absl::optional<int> & value_ms)386 void Connection::set_unwritable_timeout(const absl::optional<int>& value_ms) {
387 RTC_DCHECK_RUN_ON(network_thread_);
388 unwritable_timeout_ = value_ms;
389 }
390
unwritable_min_checks() const391 int Connection::unwritable_min_checks() const {
392 RTC_DCHECK_RUN_ON(network_thread_);
393 return unwritable_min_checks_.value_or(CONNECTION_WRITE_CONNECT_FAILURES);
394 }
395
set_unwritable_min_checks(const absl::optional<int> & value)396 void Connection::set_unwritable_min_checks(const absl::optional<int>& value) {
397 RTC_DCHECK_RUN_ON(network_thread_);
398 unwritable_min_checks_ = value;
399 }
400
inactive_timeout() const401 int Connection::inactive_timeout() const {
402 RTC_DCHECK_RUN_ON(network_thread_);
403 return inactive_timeout_.value_or(CONNECTION_WRITE_TIMEOUT);
404 }
405
set_inactive_timeout(const absl::optional<int> & value)406 void Connection::set_inactive_timeout(const absl::optional<int>& value) {
407 RTC_DCHECK_RUN_ON(network_thread_);
408 inactive_timeout_ = value;
409 }
410
receiving_timeout() const411 int Connection::receiving_timeout() const {
412 RTC_DCHECK_RUN_ON(network_thread_);
413 return receiving_timeout_.value_or(WEAK_CONNECTION_RECEIVE_TIMEOUT);
414 }
415
set_receiving_timeout(absl::optional<int> receiving_timeout_ms)416 void Connection::set_receiving_timeout(
417 absl::optional<int> receiving_timeout_ms) {
418 RTC_DCHECK_RUN_ON(network_thread_);
419 receiving_timeout_ = receiving_timeout_ms;
420 }
421
SetIceFieldTrials(const IceFieldTrials * field_trials)422 void Connection::SetIceFieldTrials(const IceFieldTrials* field_trials) {
423 RTC_DCHECK_RUN_ON(network_thread_);
424 field_trials_ = field_trials;
425 rtt_estimate_.SetHalfTime(field_trials->rtt_estimate_halftime_ms);
426 }
427
OnSendStunPacket(const void * data,size_t size,StunRequest * req)428 void Connection::OnSendStunPacket(const void* data,
429 size_t size,
430 StunRequest* req) {
431 RTC_DCHECK_RUN_ON(network_thread_);
432 rtc::PacketOptions options(port_->StunDscpValue());
433 options.info_signaled_after_sent.packet_type =
434 rtc::PacketType::kIceConnectivityCheck;
435 auto err =
436 port_->SendTo(data, size, remote_candidate_.address(), options, false);
437 if (err < 0) {
438 RTC_LOG(LS_WARNING) << ToString()
439 << ": Failed to send STUN ping "
440 " err="
441 << err << " id=" << rtc::hex_encode(req->id());
442 }
443 }
444
OnReadPacket(const char * data,size_t size,int64_t packet_time_us)445 void Connection::OnReadPacket(const char* data,
446 size_t size,
447 int64_t packet_time_us) {
448 RTC_DCHECK_RUN_ON(network_thread_);
449 std::unique_ptr<IceMessage> msg;
450 std::string remote_ufrag;
451 const rtc::SocketAddress& addr(remote_candidate_.address());
452 if (!port_->GetStunMessage(data, size, addr, &msg, &remote_ufrag)) {
453 // The packet did not parse as a valid STUN message
454 // This is a data packet, pass it along.
455 last_data_received_ = rtc::TimeMillis();
456 UpdateReceiving(last_data_received_);
457 recv_rate_tracker_.AddSamples(size);
458 stats_.packets_received++;
459 SignalReadPacket(this, data, size, packet_time_us);
460
461 // If timed out sending writability checks, start up again
462 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
463 RTC_LOG(LS_WARNING)
464 << "Received a data packet on a timed-out Connection. "
465 "Resetting state to STATE_WRITE_INIT.";
466 set_write_state(STATE_WRITE_INIT);
467 }
468 } else if (!msg) {
469 // The packet was STUN, but failed a check and was handled internally.
470 } else {
471 // The packet is STUN and passed the Port checks.
472 // Perform our own checks to ensure this packet is valid.
473 // If this is a STUN request, then update the receiving bit and respond.
474 // If this is a STUN response, then update the writable bit.
475 // Log at LS_INFO if we receive a ping on an unwritable connection.
476 rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
477 switch (msg->integrity()) {
478 case StunMessage::IntegrityStatus::kNotSet:
479 // This packet did not come through Port processing?
480 // TODO(bugs.webrtc.org/14578): Clean up this situation.
481 msg->ValidateMessageIntegrity(remote_candidate().password());
482 break;
483 case StunMessage::IntegrityStatus::kIntegrityOk:
484 if (remote_candidate().password() != msg->password()) {
485 // TODO(bugs.webrtc.org/14578): Do a better thing
486 RTC_LOG(LS_INFO) << "STUN code error - Different passwords, old = "
487 << absl::CHexEscape(msg->password()) << ", new "
488 << absl::CHexEscape(remote_candidate().password());
489 }
490 break;
491 default:
492 // kIntegrityBad and kNoIntegrity.
493 // This shouldn't happen.
494 RTC_DCHECK_NOTREACHED();
495 break;
496 }
497 switch (msg->type()) {
498 case STUN_BINDING_REQUEST:
499 RTC_LOG_V(sev) << ToString() << ": Received "
500 << StunMethodToString(msg->type())
501 << ", id=" << rtc::hex_encode(msg->transaction_id());
502 if (remote_ufrag == remote_candidate_.username()) {
503 HandleStunBindingOrGoogPingRequest(msg.get());
504 } else {
505 // The packet had the right local username, but the remote username
506 // was not the right one for the remote address.
507 RTC_LOG(LS_ERROR)
508 << ToString()
509 << ": Received STUN request with bad remote username "
510 << remote_ufrag;
511 port_->SendBindingErrorResponse(msg.get(), addr,
512 STUN_ERROR_UNAUTHORIZED,
513 STUN_ERROR_REASON_UNAUTHORIZED);
514 }
515 break;
516
517 // Response from remote peer. Does it match request sent?
518 // This doesn't just check, it makes callbacks if transaction
519 // id's match.
520 case STUN_BINDING_RESPONSE:
521 case STUN_BINDING_ERROR_RESPONSE:
522 if (msg->IntegrityOk()) {
523 requests_.CheckResponse(msg.get());
524 }
525 // Otherwise silently discard the response.
526 break;
527
528 // Remote end point sent an STUN indication instead of regular binding
529 // request. In this case `last_ping_received_` will be updated but no
530 // response will be sent.
531 case STUN_BINDING_INDICATION:
532 ReceivedPing(msg->transaction_id());
533 break;
534 case GOOG_PING_REQUEST:
535 HandleStunBindingOrGoogPingRequest(msg.get());
536 break;
537 case GOOG_PING_RESPONSE:
538 case GOOG_PING_ERROR_RESPONSE:
539 if (msg->IntegrityOk()) {
540 requests_.CheckResponse(msg.get());
541 }
542 break;
543 default:
544 RTC_DCHECK_NOTREACHED();
545 break;
546 }
547 }
548 }
549
HandleStunBindingOrGoogPingRequest(IceMessage * msg)550 void Connection::HandleStunBindingOrGoogPingRequest(IceMessage* msg) {
551 RTC_DCHECK_RUN_ON(network_thread_);
552 // This connection should now be receiving.
553 ReceivedPing(msg->transaction_id());
554 if (field_trials_->extra_ice_ping && last_ping_response_received_ == 0) {
555 if (local_candidate().type() == RELAY_PORT_TYPE ||
556 local_candidate().type() == PRFLX_PORT_TYPE ||
557 remote_candidate().type() == RELAY_PORT_TYPE ||
558 remote_candidate().type() == PRFLX_PORT_TYPE) {
559 const int64_t now = rtc::TimeMillis();
560 if (last_ping_sent_ + kMinExtraPingDelayMs <= now) {
561 RTC_LOG(LS_INFO) << ToString()
562 << "WebRTC-ExtraICEPing/Sending extra ping"
563 " last_ping_sent_: "
564 << last_ping_sent_ << " now: " << now
565 << " (diff: " << (now - last_ping_sent_) << ")";
566 Ping(now);
567 } else {
568 RTC_LOG(LS_INFO) << ToString()
569 << "WebRTC-ExtraICEPing/Not sending extra ping"
570 " last_ping_sent_: "
571 << last_ping_sent_ << " now: " << now
572 << " (diff: " << (now - last_ping_sent_) << ")";
573 }
574 }
575 }
576
577 const rtc::SocketAddress& remote_addr = remote_candidate_.address();
578 if (msg->type() == STUN_BINDING_REQUEST) {
579 // Check for role conflicts.
580 const std::string& remote_ufrag = remote_candidate_.username();
581 if (!port_->MaybeIceRoleConflict(remote_addr, msg, remote_ufrag)) {
582 // Received conflicting role from the peer.
583 RTC_LOG(LS_INFO) << "Received conflicting role from the peer.";
584 return;
585 }
586 }
587
588 stats_.recv_ping_requests++;
589 LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckReceived,
590 msg->reduced_transaction_id());
591
592 // This is a validated stun request from remote peer.
593 if (msg->type() == STUN_BINDING_REQUEST) {
594 SendStunBindingResponse(msg);
595 } else {
596 RTC_DCHECK(msg->type() == GOOG_PING_REQUEST);
597 SendGoogPingResponse(msg);
598 }
599
600 // If it timed out on writing check, start up again
601 if (!pruned_ && write_state_ == STATE_WRITE_TIMEOUT) {
602 set_write_state(STATE_WRITE_INIT);
603 }
604
605 if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
606 const StunUInt32Attribute* nomination_attr =
607 msg->GetUInt32(STUN_ATTR_NOMINATION);
608 uint32_t nomination = 0;
609 if (nomination_attr) {
610 nomination = nomination_attr->value();
611 if (nomination == 0) {
612 RTC_LOG(LS_ERROR) << "Invalid nomination: " << nomination;
613 }
614 } else {
615 const StunByteStringAttribute* use_candidate_attr =
616 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
617 if (use_candidate_attr) {
618 nomination = 1;
619 }
620 }
621 // We don't un-nominate a connection, so we only keep a larger nomination.
622 if (nomination > remote_nomination_) {
623 set_remote_nomination(nomination);
624 SignalNominated(this);
625 }
626 }
627 // Set the remote cost if the network_info attribute is available.
628 // Note: If packets are re-ordered, we may get incorrect network cost
629 // temporarily, but it should get the correct value shortly after that.
630 const StunUInt32Attribute* network_attr =
631 msg->GetUInt32(STUN_ATTR_GOOG_NETWORK_INFO);
632 if (network_attr) {
633 uint32_t network_info = network_attr->value();
634 uint16_t network_cost = static_cast<uint16_t>(network_info);
635 if (network_cost != remote_candidate_.network_cost()) {
636 remote_candidate_.set_network_cost(network_cost);
637 // Network cost change will affect the connection ranking, so signal
638 // state change to force a re-sort in P2PTransportChannel.
639 SignalStateChange(this);
640 }
641 }
642
643 if (field_trials_->piggyback_ice_check_acknowledgement) {
644 HandlePiggybackCheckAcknowledgementIfAny(msg);
645 }
646 }
647
SendStunBindingResponse(const StunMessage * message)648 void Connection::SendStunBindingResponse(const StunMessage* message) {
649 RTC_DCHECK_RUN_ON(network_thread_);
650 RTC_DCHECK_EQ(message->type(), STUN_BINDING_REQUEST);
651
652 // Retrieve the username from the `message`.
653 const StunByteStringAttribute* username_attr =
654 message->GetByteString(STUN_ATTR_USERNAME);
655 RTC_DCHECK(username_attr != NULL);
656 if (username_attr == NULL) {
657 // No valid username, skip the response.
658 return;
659 }
660
661 // Fill in the response.
662 StunMessage response(STUN_BINDING_RESPONSE, message->transaction_id());
663 const StunUInt32Attribute* retransmit_attr =
664 message->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
665 if (retransmit_attr) {
666 // Inherit the incoming retransmit value in the response so the other side
667 // can see our view of lost pings.
668 response.AddAttribute(std::make_unique<StunUInt32Attribute>(
669 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
670
671 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
672 RTC_LOG(LS_INFO)
673 << ToString()
674 << ": Received a remote ping with high retransmit count: "
675 << retransmit_attr->value();
676 }
677 }
678
679 response.AddAttribute(std::make_unique<StunXorAddressAttribute>(
680 STUN_ATTR_XOR_MAPPED_ADDRESS, remote_candidate_.address()));
681
682 if (field_trials_->announce_goog_ping) {
683 // Check if message contains a announce-request.
684 auto goog_misc = message->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO);
685 if (goog_misc != nullptr &&
686 goog_misc->Size() >= kSupportGoogPingVersionRequestIndex &&
687 // Which version can we handle...currently any >= 1
688 goog_misc->GetType(kSupportGoogPingVersionRequestIndex) >= 1) {
689 auto list =
690 StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
691 list->AddTypeAtIndex(kSupportGoogPingVersionResponseIndex,
692 kGoogPingVersion);
693 response.AddAttribute(std::move(list));
694 }
695 }
696
697 response.AddMessageIntegrity(local_candidate().password());
698 response.AddFingerprint();
699
700 SendResponseMessage(response);
701 }
702
SendGoogPingResponse(const StunMessage * message)703 void Connection::SendGoogPingResponse(const StunMessage* message) {
704 RTC_DCHECK_RUN_ON(network_thread_);
705 RTC_DCHECK(message->type() == GOOG_PING_REQUEST);
706
707 // Fill in the response.
708 StunMessage response(GOOG_PING_RESPONSE, message->transaction_id());
709 response.AddMessageIntegrity32(local_candidate().password());
710 SendResponseMessage(response);
711 }
712
SendResponseMessage(const StunMessage & response)713 void Connection::SendResponseMessage(const StunMessage& response) {
714 RTC_DCHECK_RUN_ON(network_thread_);
715 // Where I send the response.
716 const rtc::SocketAddress& addr = remote_candidate_.address();
717
718 // Send the response.
719 rtc::ByteBufferWriter buf;
720 response.Write(&buf);
721 rtc::PacketOptions options(port_->StunDscpValue());
722 options.info_signaled_after_sent.packet_type =
723 rtc::PacketType::kIceConnectivityCheckResponse;
724 auto err = port_->SendTo(buf.Data(), buf.Length(), addr, options, false);
725 if (err < 0) {
726 RTC_LOG(LS_ERROR) << ToString() << ": Failed to send "
727 << StunMethodToString(response.type())
728 << ", to=" << addr.ToSensitiveString() << ", err=" << err
729 << ", id=" << rtc::hex_encode(response.transaction_id());
730 } else {
731 // Log at LS_INFO if we send a stun ping response on an unwritable
732 // connection.
733 rtc::LoggingSeverity sev = (!writable()) ? rtc::LS_INFO : rtc::LS_VERBOSE;
734 RTC_LOG_V(sev) << ToString() << ": Sent "
735 << StunMethodToString(response.type())
736 << ", to=" << addr.ToSensitiveString()
737 << ", id=" << rtc::hex_encode(response.transaction_id());
738
739 stats_.sent_ping_responses++;
740 LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckResponseSent,
741 response.reduced_transaction_id());
742 }
743 }
744
acked_nomination() const745 uint32_t Connection::acked_nomination() const {
746 RTC_DCHECK_RUN_ON(network_thread_);
747 return acked_nomination_;
748 }
749
set_remote_nomination(uint32_t remote_nomination)750 void Connection::set_remote_nomination(uint32_t remote_nomination) {
751 RTC_DCHECK_RUN_ON(network_thread_);
752 remote_nomination_ = remote_nomination;
753 }
754
OnReadyToSend()755 void Connection::OnReadyToSend() {
756 RTC_DCHECK_RUN_ON(network_thread_);
757 SignalReadyToSend(this);
758 }
759
pruned() const760 bool Connection::pruned() const {
761 RTC_DCHECK_RUN_ON(network_thread_);
762 return pruned_;
763 }
764
Prune()765 void Connection::Prune() {
766 RTC_DCHECK_RUN_ON(network_thread_);
767 if (!pruned_ || active()) {
768 RTC_LOG(LS_INFO) << ToString() << ": Connection pruned";
769 pruned_ = true;
770 requests_.Clear();
771 set_write_state(STATE_WRITE_TIMEOUT);
772 }
773 }
774
Destroy()775 void Connection::Destroy() {
776 RTC_DCHECK_RUN_ON(network_thread_);
777 RTC_DCHECK(port_) << "Calling Destroy() twice?";
778 if (port_)
779 port_->DestroyConnection(this);
780 }
781
Shutdown()782 bool Connection::Shutdown() {
783 RTC_DCHECK_RUN_ON(network_thread_);
784 if (!port_)
785 return false; // already shut down.
786
787 RTC_DLOG(LS_VERBOSE) << ToString() << ": Connection destroyed";
788
789 // Fire the 'destroyed' event before deleting the object. This is done
790 // intentionally to avoid a situation whereby the signal might have dangling
791 // pointers to objects that have been deleted by the time the async task
792 // that deletes the connection object runs.
793 auto destroyed_signals = SignalDestroyed;
794 SignalDestroyed.disconnect_all();
795 destroyed_signals(this);
796
797 LogCandidatePairConfig(webrtc::IceCandidatePairConfigType::kDestroyed);
798
799 // Reset the `port_` after logging and firing the destroyed signal since
800 // information required for logging needs access to `port_`.
801 port_.reset();
802
803 return true;
804 }
805
FailAndPrune()806 void Connection::FailAndPrune() {
807 RTC_DCHECK_RUN_ON(network_thread_);
808
809 // TODO(bugs.webrtc.org/13865): There's a circular dependency between Port
810 // and Connection. In some cases (Port dtor), a Connection object is deleted
811 // without using the `Destroy` method (port_ won't be nulled and some
812 // functionality won't run as expected), while in other cases
813 // the Connection object is deleted asynchronously and in that case `port_`
814 // will be nulled.
815 // In such a case, there's a chance that the Port object gets
816 // deleted before the Connection object ends up being deleted.
817 if (!port_)
818 return;
819
820 set_state(IceCandidatePairState::FAILED);
821 Prune();
822 }
823
PrintPingsSinceLastResponse(std::string * s,size_t max)824 void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
825 RTC_DCHECK_RUN_ON(network_thread_);
826 rtc::StringBuilder oss;
827 if (pings_since_last_response_.size() > max) {
828 for (size_t i = 0; i < max; i++) {
829 const SentPing& ping = pings_since_last_response_[i];
830 oss << rtc::hex_encode(ping.id) << " ";
831 }
832 oss << "... " << (pings_since_last_response_.size() - max) << " more";
833 } else {
834 for (const SentPing& ping : pings_since_last_response_) {
835 oss << rtc::hex_encode(ping.id) << " ";
836 }
837 }
838 *s = oss.str();
839 }
840
selected() const841 bool Connection::selected() const {
842 RTC_DCHECK_RUN_ON(network_thread_);
843 return selected_;
844 }
845
set_selected(bool selected)846 void Connection::set_selected(bool selected) {
847 RTC_DCHECK_RUN_ON(network_thread_);
848 selected_ = selected;
849 }
850
UpdateState(int64_t now)851 void Connection::UpdateState(int64_t now) {
852 RTC_DCHECK_RUN_ON(network_thread_);
853 if (!port_)
854 return;
855
856 int rtt = ConservativeRTTEstimate(rtt_);
857
858 if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE)) {
859 std::string pings;
860 PrintPingsSinceLastResponse(&pings, 5);
861 RTC_LOG(LS_VERBOSE) << ToString()
862 << ": UpdateState()"
863 ", ms since last received response="
864 << now - last_ping_response_received_
865 << ", ms since last received data="
866 << now - last_data_received_ << ", rtt=" << rtt
867 << ", pings_since_last_response=" << pings;
868 }
869
870 // Check the writable state. (The order of these checks is important.)
871 //
872 // Before becoming unwritable, we allow for a fixed number of pings to fail
873 // (i.e., receive no response). We also have to give the response time to
874 // get back, so we include a conservative estimate of this.
875 //
876 // Before timing out writability, we give a fixed amount of time. This is to
877 // allow for changes in network conditions.
878
879 if ((write_state_ == STATE_WRITABLE) &&
880 TooManyFailures(pings_since_last_response_, unwritable_min_checks(), rtt,
881 now) &&
882 TooLongWithoutResponse(pings_since_last_response_, unwritable_timeout(),
883 now)) {
884 uint32_t max_pings = unwritable_min_checks();
885 RTC_LOG(LS_INFO) << ToString() << ": Unwritable after " << max_pings
886 << " ping failures and "
887 << now - pings_since_last_response_[0].sent_time
888 << " ms without a response,"
889 " ms since last received ping="
890 << now - last_ping_received_
891 << " ms since last received data="
892 << now - last_data_received_ << " rtt=" << rtt;
893 set_write_state(STATE_WRITE_UNRELIABLE);
894 }
895 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
896 write_state_ == STATE_WRITE_INIT) &&
897 TooLongWithoutResponse(pings_since_last_response_, inactive_timeout(),
898 now)) {
899 RTC_LOG(LS_INFO) << ToString() << ": Timed out after "
900 << now - pings_since_last_response_[0].sent_time
901 << " ms without a response, rtt=" << rtt;
902 set_write_state(STATE_WRITE_TIMEOUT);
903 }
904
905 // Update the receiving state.
906 UpdateReceiving(now);
907 if (dead(now)) {
908 port_->DestroyConnectionAsync(this);
909 }
910 }
911
UpdateLocalIceParameters(int component,absl::string_view username_fragment,absl::string_view password)912 void Connection::UpdateLocalIceParameters(int component,
913 absl::string_view username_fragment,
914 absl::string_view password) {
915 RTC_DCHECK_RUN_ON(network_thread_);
916 local_candidate_.set_component(component);
917 local_candidate_.set_username(username_fragment);
918 local_candidate_.set_password(password);
919 }
920
last_ping_sent() const921 int64_t Connection::last_ping_sent() const {
922 RTC_DCHECK_RUN_ON(network_thread_);
923 return last_ping_sent_;
924 }
925
Ping(int64_t now)926 void Connection::Ping(int64_t now) {
927 RTC_DCHECK_RUN_ON(network_thread_);
928 if (!port_)
929 return;
930
931 last_ping_sent_ = now;
932
933 // If not using renomination, we use "1" to mean "nominated" and "0" to mean
934 // "not nominated". If using renomination, values greater than 1 are used for
935 // re-nominated pairs.
936 int nomination = use_candidate_attr_ ? 1 : 0;
937 if (nomination_ > 0) {
938 nomination = nomination_;
939 }
940
941 auto req =
942 std::make_unique<ConnectionRequest>(requests_, this, BuildPingRequest());
943
944 if (ShouldSendGoogPing(req->msg())) {
945 auto message = std::make_unique<IceMessage>(GOOG_PING_REQUEST, req->id());
946 message->AddMessageIntegrity32(remote_candidate_.password());
947 req.reset(new ConnectionRequest(requests_, this, std::move(message)));
948 }
949
950 pings_since_last_response_.push_back(SentPing(req->id(), now, nomination));
951 RTC_LOG(LS_VERBOSE) << ToString() << ": Sending STUN ping, id="
952 << rtc::hex_encode(req->id())
953 << ", nomination=" << nomination_;
954 requests_.Send(req.release());
955 state_ = IceCandidatePairState::IN_PROGRESS;
956 num_pings_sent_++;
957 }
958
BuildPingRequest()959 std::unique_ptr<IceMessage> Connection::BuildPingRequest() {
960 auto message = std::make_unique<IceMessage>(STUN_BINDING_REQUEST);
961 // Note that the order of attributes does not impact the parsing on the
962 // receiver side. The attribute is retrieved then by iterating and matching
963 // over all parsed attributes. See StunMessage::GetAttribute.
964 message->AddAttribute(std::make_unique<StunByteStringAttribute>(
965 STUN_ATTR_USERNAME,
966 port()->CreateStunUsername(remote_candidate_.username())));
967 message->AddAttribute(std::make_unique<StunUInt32Attribute>(
968 STUN_ATTR_GOOG_NETWORK_INFO,
969 (port_->Network()->id() << 16) | port_->network_cost()));
970
971 if (field_trials_->piggyback_ice_check_acknowledgement &&
972 last_ping_id_received_) {
973 message->AddAttribute(std::make_unique<StunByteStringAttribute>(
974 STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED, *last_ping_id_received_));
975 }
976
977 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
978 IceRole ice_role = port_->GetIceRole();
979 RTC_DCHECK(ice_role == ICEROLE_CONTROLLING || ice_role == ICEROLE_CONTROLLED);
980 message->AddAttribute(std::make_unique<StunUInt64Attribute>(
981 ice_role == ICEROLE_CONTROLLING ? STUN_ATTR_ICE_CONTROLLING
982 : STUN_ATTR_ICE_CONTROLLED,
983 port_->IceTiebreaker()));
984
985 if (ice_role == ICEROLE_CONTROLLING) {
986 // We should have either USE_CANDIDATE attribute or ICE_NOMINATION
987 // attribute but not both. That was enforced in p2ptransportchannel.
988 if (use_candidate_attr()) {
989 message->AddAttribute(
990 std::make_unique<StunByteStringAttribute>(STUN_ATTR_USE_CANDIDATE));
991 }
992 if (nomination_ && nomination_ != acked_nomination()) {
993 message->AddAttribute(std::make_unique<StunUInt32Attribute>(
994 STUN_ATTR_NOMINATION, nomination_));
995 }
996 }
997
998 message->AddAttribute(std::make_unique<StunUInt32Attribute>(
999 STUN_ATTR_PRIORITY, prflx_priority()));
1000
1001 if (port()->send_retransmit_count_attribute()) {
1002 message->AddAttribute(std::make_unique<StunUInt32Attribute>(
1003 STUN_ATTR_RETRANSMIT_COUNT, pings_since_last_response_.size()));
1004 }
1005 if (field_trials_->enable_goog_ping &&
1006 !remote_support_goog_ping_.has_value()) {
1007 // Check if remote supports GOOG PING by announcing which version we
1008 // support. This is sent on all STUN_BINDING_REQUEST until we get a
1009 // STUN_BINDING_RESPONSE.
1010 auto list =
1011 StunAttribute::CreateUInt16ListAttribute(STUN_ATTR_GOOG_MISC_INFO);
1012 list->AddTypeAtIndex(kSupportGoogPingVersionRequestIndex, kGoogPingVersion);
1013 message->AddAttribute(std::move(list));
1014 }
1015 message->AddMessageIntegrity(remote_candidate_.password());
1016 message->AddFingerprint();
1017
1018 return message;
1019 }
1020
last_ping_response_received() const1021 int64_t Connection::last_ping_response_received() const {
1022 RTC_DCHECK_RUN_ON(network_thread_);
1023 return last_ping_response_received_;
1024 }
1025
last_ping_id_received() const1026 const absl::optional<std::string>& Connection::last_ping_id_received() const {
1027 RTC_DCHECK_RUN_ON(network_thread_);
1028 return last_ping_id_received_;
1029 }
1030
1031 // Used to check if any STUN ping response has been received.
rtt_samples() const1032 int Connection::rtt_samples() const {
1033 RTC_DCHECK_RUN_ON(network_thread_);
1034 return rtt_samples_;
1035 }
1036
1037 // Called whenever a valid ping is received on this connection. This is
1038 // public because the connection intercepts the first ping for us.
last_ping_received() const1039 int64_t Connection::last_ping_received() const {
1040 RTC_DCHECK_RUN_ON(network_thread_);
1041 return last_ping_received_;
1042 }
1043
ReceivedPing(const absl::optional<std::string> & request_id)1044 void Connection::ReceivedPing(const absl::optional<std::string>& request_id) {
1045 RTC_DCHECK_RUN_ON(network_thread_);
1046 last_ping_received_ = rtc::TimeMillis();
1047 last_ping_id_received_ = request_id;
1048 UpdateReceiving(last_ping_received_);
1049 }
1050
HandlePiggybackCheckAcknowledgementIfAny(StunMessage * msg)1051 void Connection::HandlePiggybackCheckAcknowledgementIfAny(StunMessage* msg) {
1052 RTC_DCHECK_RUN_ON(network_thread_);
1053 RTC_DCHECK(msg->type() == STUN_BINDING_REQUEST ||
1054 msg->type() == GOOG_PING_REQUEST);
1055 const StunByteStringAttribute* last_ice_check_received_attr =
1056 msg->GetByteString(STUN_ATTR_GOOG_LAST_ICE_CHECK_RECEIVED);
1057 if (last_ice_check_received_attr) {
1058 const absl::string_view request_id =
1059 last_ice_check_received_attr->string_view();
1060 auto iter = absl::c_find_if(
1061 pings_since_last_response_,
1062 [&request_id](const SentPing& ping) { return ping.id == request_id; });
1063 if (iter != pings_since_last_response_.end()) {
1064 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1065 RTC_LOG_V(sev) << ToString()
1066 << ": Received piggyback STUN ping response, id="
1067 << rtc::hex_encode(request_id);
1068 const int64_t rtt = rtc::TimeMillis() - iter->sent_time;
1069 ReceivedPingResponse(rtt, request_id, iter->nomination);
1070 }
1071 }
1072 }
1073
last_send_data() const1074 int64_t Connection::last_send_data() const {
1075 RTC_DCHECK_RUN_ON(network_thread_);
1076 return last_send_data_;
1077 }
1078
last_data_received() const1079 int64_t Connection::last_data_received() const {
1080 RTC_DCHECK_RUN_ON(network_thread_);
1081 return last_data_received_;
1082 }
1083
ReceivedPingResponse(int rtt,absl::string_view request_id,const absl::optional<uint32_t> & nomination)1084 void Connection::ReceivedPingResponse(
1085 int rtt,
1086 absl::string_view request_id,
1087 const absl::optional<uint32_t>& nomination) {
1088 RTC_DCHECK_RUN_ON(network_thread_);
1089 RTC_DCHECK_GE(rtt, 0);
1090 // We've already validated that this is a STUN binding response with
1091 // the correct local and remote username for this connection.
1092 // So if we're not already, become writable. We may be bringing a pruned
1093 // connection back to life, but if we don't really want it, we can always
1094 // prune it again.
1095 if (nomination && nomination.value() > acked_nomination_) {
1096 acked_nomination_ = nomination.value();
1097 }
1098
1099 int64_t now = rtc::TimeMillis();
1100 total_round_trip_time_ms_ += rtt;
1101 current_round_trip_time_ms_ = static_cast<uint32_t>(rtt);
1102 rtt_estimate_.AddSample(now, rtt);
1103
1104 pings_since_last_response_.clear();
1105 last_ping_response_received_ = now;
1106 UpdateReceiving(last_ping_response_received_);
1107 set_write_state(STATE_WRITABLE);
1108 set_state(IceCandidatePairState::SUCCEEDED);
1109 if (rtt_samples_ > 0) {
1110 rtt_ = rtc::GetNextMovingAverage(rtt_, rtt, RTT_RATIO);
1111 } else {
1112 rtt_ = rtt;
1113 }
1114 rtt_samples_++;
1115 }
1116
write_state() const1117 Connection::WriteState Connection::write_state() const {
1118 RTC_DCHECK_RUN_ON(network_thread_);
1119 return write_state_;
1120 }
1121
writable() const1122 bool Connection::writable() const {
1123 RTC_DCHECK_RUN_ON(network_thread_);
1124 return write_state_ == STATE_WRITABLE;
1125 }
1126
receiving() const1127 bool Connection::receiving() const {
1128 RTC_DCHECK_RUN_ON(network_thread_);
1129 return receiving_;
1130 }
1131
1132 // Determines whether the connection has finished connecting. This can only
1133 // be false for TCP connections.
connected() const1134 bool Connection::connected() const {
1135 RTC_DCHECK_RUN_ON(network_thread_);
1136 return connected_;
1137 }
1138
weak() const1139 bool Connection::weak() const {
1140 return !(writable() && receiving() && connected());
1141 }
1142
active() const1143 bool Connection::active() const {
1144 RTC_DCHECK_RUN_ON(network_thread_);
1145 return write_state_ != STATE_WRITE_TIMEOUT;
1146 }
1147
dead(int64_t now) const1148 bool Connection::dead(int64_t now) const {
1149 RTC_DCHECK_RUN_ON(network_thread_);
1150 if (last_received() > 0) {
1151 // If it has ever received anything, we keep it alive
1152 // - if it has recevied last DEAD_CONNECTION_RECEIVE_TIMEOUT (30s)
1153 // - if it has a ping outstanding shorter than
1154 // DEAD_CONNECTION_RECEIVE_TIMEOUT (30s)
1155 // - else if IDLE let it live field_trials_->dead_connection_timeout_ms
1156 //
1157 // This covers the normal case of a successfully used connection that stops
1158 // working. This also allows a remote peer to continue pinging over a
1159 // locally inactive (pruned) connection. This also allows the local agent to
1160 // ping with longer interval than 30s as long as it shorter than
1161 // `dead_connection_timeout_ms`.
1162 if (now <= (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT)) {
1163 // Not dead since we have received the last 30s.
1164 return false;
1165 }
1166 if (!pings_since_last_response_.empty()) {
1167 // Outstanding pings: let it live until the ping is unreplied for
1168 // DEAD_CONNECTION_RECEIVE_TIMEOUT.
1169 return now > (pings_since_last_response_[0].sent_time +
1170 DEAD_CONNECTION_RECEIVE_TIMEOUT);
1171 }
1172
1173 // No outstanding pings: let it live until
1174 // field_trials_->dead_connection_timeout_ms has passed.
1175 return now > (last_received() + field_trials_->dead_connection_timeout_ms);
1176 }
1177
1178 if (active()) {
1179 // If it has never received anything, keep it alive as long as it is
1180 // actively pinging and not pruned. Otherwise, the connection might be
1181 // deleted before it has a chance to ping. This is the normal case for a
1182 // new connection that is pinging but hasn't received anything yet.
1183 return false;
1184 }
1185
1186 // If it has never received anything and is not actively pinging (pruned), we
1187 // keep it around for at least MIN_CONNECTION_LIFETIME to prevent connections
1188 // from being pruned too quickly during a network change event when two
1189 // networks would be up simultaneously but only for a brief period.
1190 return now > (time_created_ms_ + MIN_CONNECTION_LIFETIME);
1191 }
1192
rtt() const1193 int Connection::rtt() const {
1194 RTC_DCHECK_RUN_ON(network_thread_);
1195 return rtt_;
1196 }
1197
stable(int64_t now) const1198 bool Connection::stable(int64_t now) const {
1199 // A connection is stable if it's RTT has converged and it isn't missing any
1200 // responses. We should send pings at a higher rate until the RTT converges
1201 // and whenever a ping response is missing (so that we can detect
1202 // unwritability faster)
1203 return rtt_converged() && !missing_responses(now);
1204 }
1205
ToDebugId() const1206 std::string Connection::ToDebugId() const {
1207 return rtc::ToHex(reinterpret_cast<uintptr_t>(this));
1208 }
1209
ComputeNetworkCost() const1210 uint32_t Connection::ComputeNetworkCost() const {
1211 // TODO(honghaiz): Will add rtt as part of the network cost.
1212 return port()->network_cost() + remote_candidate_.network_cost();
1213 }
1214
ToString() const1215 std::string Connection::ToString() const {
1216 RTC_DCHECK_RUN_ON(network_thread_);
1217 constexpr absl::string_view CONNECT_STATE_ABBREV[2] = {
1218 "-", // not connected (false)
1219 "C", // connected (true)
1220 };
1221 constexpr absl::string_view RECEIVE_STATE_ABBREV[2] = {
1222 "-", // not receiving (false)
1223 "R", // receiving (true)
1224 };
1225 constexpr absl::string_view WRITE_STATE_ABBREV[4] = {
1226 "W", // STATE_WRITABLE
1227 "w", // STATE_WRITE_UNRELIABLE
1228 "-", // STATE_WRITE_INIT
1229 "x", // STATE_WRITE_TIMEOUT
1230 };
1231 constexpr absl::string_view ICESTATE[4] = {
1232 "W", // STATE_WAITING
1233 "I", // STATE_INPROGRESS
1234 "S", // STATE_SUCCEEDED
1235 "F" // STATE_FAILED
1236 };
1237 constexpr absl::string_view SELECTED_STATE_ABBREV[2] = {
1238 "-", // candidate pair not selected (false)
1239 "S", // selected (true)
1240 };
1241 rtc::StringBuilder ss;
1242 ss << "Conn[" << ToDebugId();
1243
1244 if (!port_) {
1245 // No content or network names for pending delete. Temporarily substitute
1246 // the names with a hash (rhyming with trash).
1247 ss << ":#:#:";
1248 } else {
1249 ss << ":" << port_->content_name() << ":" << port_->Network()->ToString()
1250 << ":";
1251 }
1252
1253 const Candidate& local = local_candidate();
1254 const Candidate& remote = remote_candidate();
1255 ss << local.id() << ":" << local.component() << ":" << local.generation()
1256 << ":" << local.type() << ":" << local.protocol() << ":"
1257 << local.address().ToSensitiveString() << "->" << remote.id() << ":"
1258 << remote.component() << ":" << remote.priority() << ":" << remote.type()
1259 << ":" << remote.protocol() << ":" << remote.address().ToSensitiveString()
1260 << "|";
1261
1262 ss << CONNECT_STATE_ABBREV[connected_] << RECEIVE_STATE_ABBREV[receiving_]
1263 << WRITE_STATE_ABBREV[write_state_] << ICESTATE[static_cast<int>(state_)]
1264 << "|" << SELECTED_STATE_ABBREV[selected_] << "|" << remote_nomination_
1265 << "|" << nomination_ << "|";
1266
1267 if (port_)
1268 ss << priority() << "|";
1269
1270 if (rtt_ < DEFAULT_RTT) {
1271 ss << rtt_ << "]";
1272 } else {
1273 ss << "-]";
1274 }
1275
1276 return ss.Release();
1277 }
1278
ToSensitiveString() const1279 std::string Connection::ToSensitiveString() const {
1280 return ToString();
1281 }
1282
ToLogDescription()1283 const webrtc::IceCandidatePairDescription& Connection::ToLogDescription() {
1284 RTC_DCHECK_RUN_ON(network_thread_);
1285 if (log_description_.has_value()) {
1286 return log_description_.value();
1287 }
1288 const Candidate& local = local_candidate();
1289 const Candidate& remote = remote_candidate();
1290 const rtc::Network* network = port()->Network();
1291 log_description_ = webrtc::IceCandidatePairDescription();
1292 log_description_->local_candidate_type =
1293 GetCandidateTypeByString(local.type());
1294 log_description_->local_relay_protocol =
1295 GetProtocolByString(local.relay_protocol());
1296 log_description_->local_network_type = ConvertNetworkType(network->type());
1297 log_description_->local_address_family =
1298 GetAddressFamilyByInt(local.address().family());
1299 log_description_->remote_candidate_type =
1300 GetCandidateTypeByString(remote.type());
1301 log_description_->remote_address_family =
1302 GetAddressFamilyByInt(remote.address().family());
1303 log_description_->candidate_pair_protocol =
1304 GetProtocolByString(local.protocol());
1305 return log_description_.value();
1306 }
1307
set_ice_event_log(webrtc::IceEventLog * ice_event_log)1308 void Connection::set_ice_event_log(webrtc::IceEventLog* ice_event_log) {
1309 RTC_DCHECK_RUN_ON(network_thread_);
1310 ice_event_log_ = ice_event_log;
1311 }
1312
LogCandidatePairConfig(webrtc::IceCandidatePairConfigType type)1313 void Connection::LogCandidatePairConfig(
1314 webrtc::IceCandidatePairConfigType type) {
1315 RTC_DCHECK_RUN_ON(network_thread_);
1316 if (ice_event_log_ == nullptr) {
1317 return;
1318 }
1319 ice_event_log_->LogCandidatePairConfig(type, id(), ToLogDescription());
1320 }
1321
LogCandidatePairEvent(webrtc::IceCandidatePairEventType type,uint32_t transaction_id)1322 void Connection::LogCandidatePairEvent(webrtc::IceCandidatePairEventType type,
1323 uint32_t transaction_id) {
1324 RTC_DCHECK_RUN_ON(network_thread_);
1325 if (ice_event_log_ == nullptr) {
1326 return;
1327 }
1328 ice_event_log_->LogCandidatePairEvent(type, id(), transaction_id);
1329 }
1330
OnConnectionRequestResponse(StunRequest * request,StunMessage * response)1331 void Connection::OnConnectionRequestResponse(StunRequest* request,
1332 StunMessage* response) {
1333 RTC_DCHECK_RUN_ON(network_thread_);
1334 // Log at LS_INFO if we receive a ping response on an unwritable
1335 // connection.
1336 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1337
1338 int rtt = request->Elapsed();
1339
1340 if (RTC_LOG_CHECK_LEVEL_V(sev)) {
1341 std::string pings;
1342 PrintPingsSinceLastResponse(&pings, 5);
1343 RTC_LOG_V(sev) << ToString() << ": Received "
1344 << StunMethodToString(response->type())
1345 << ", id=" << rtc::hex_encode(request->id())
1346 << ", code=0" // Makes logging easier to parse.
1347 ", rtt="
1348 << rtt << ", pings_since_last_response=" << pings;
1349 }
1350 absl::optional<uint32_t> nomination;
1351 const std::string request_id = request->id();
1352 auto iter = absl::c_find_if(
1353 pings_since_last_response_,
1354 [&request_id](const SentPing& ping) { return ping.id == request_id; });
1355 if (iter != pings_since_last_response_.end()) {
1356 nomination.emplace(iter->nomination);
1357 }
1358 ReceivedPingResponse(rtt, request_id, nomination);
1359
1360 stats_.recv_ping_responses++;
1361 LogCandidatePairEvent(
1362 webrtc::IceCandidatePairEventType::kCheckResponseReceived,
1363 response->reduced_transaction_id());
1364
1365 if (request->msg()->type() == STUN_BINDING_REQUEST) {
1366 if (!remote_support_goog_ping_.has_value()) {
1367 auto goog_misc = response->GetUInt16List(STUN_ATTR_GOOG_MISC_INFO);
1368 if (goog_misc != nullptr &&
1369 goog_misc->Size() >= kSupportGoogPingVersionResponseIndex) {
1370 // The remote peer has indicated that it {does/does not} supports
1371 // GOOG_PING.
1372 remote_support_goog_ping_ =
1373 goog_misc->GetType(kSupportGoogPingVersionResponseIndex) >=
1374 kGoogPingVersion;
1375 } else {
1376 remote_support_goog_ping_ = false;
1377 }
1378 }
1379
1380 MaybeUpdateLocalCandidate(request, response);
1381
1382 if (field_trials_->enable_goog_ping && remote_support_goog_ping_) {
1383 cached_stun_binding_ = request->msg()->Clone();
1384 }
1385 }
1386 }
1387
OnConnectionRequestErrorResponse(ConnectionRequest * request,StunMessage * response)1388 void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1389 StunMessage* response) {
1390 if (!port_)
1391 return;
1392
1393 int error_code = response->GetErrorCodeValue();
1394 RTC_LOG(LS_WARNING) << ToString() << ": Received "
1395 << StunMethodToString(response->type())
1396 << " id=" << rtc::hex_encode(request->id())
1397 << " code=" << error_code
1398 << " rtt=" << request->Elapsed();
1399
1400 cached_stun_binding_.reset();
1401 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1402 error_code == STUN_ERROR_SERVER_ERROR ||
1403 error_code == STUN_ERROR_UNAUTHORIZED) {
1404 // Recoverable error, retry
1405 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1406 port_->SignalRoleConflict(port_.get());
1407 } else if (request->msg()->type() == GOOG_PING_REQUEST) {
1408 // Race, retry.
1409 } else {
1410 // This is not a valid connection.
1411 RTC_LOG(LS_ERROR) << ToString()
1412 << ": Received STUN error response, code=" << error_code
1413 << "; killing connection";
1414 set_state(IceCandidatePairState::FAILED);
1415 port_->DestroyConnectionAsync(this);
1416 }
1417 }
1418
OnConnectionRequestTimeout(ConnectionRequest * request)1419 void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1420 // Log at LS_INFO if we miss a ping on a writable connection.
1421 rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1422 RTC_LOG_V(sev) << ToString() << ": Timing-out STUN ping "
1423 << rtc::hex_encode(request->id()) << " after "
1424 << request->Elapsed() << " ms";
1425 }
1426
OnConnectionRequestSent(ConnectionRequest * request)1427 void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1428 RTC_DCHECK_RUN_ON(network_thread_);
1429 // Log at LS_INFO if we send a ping on an unwritable connection.
1430 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1431 RTC_LOG_V(sev) << ToString() << ": Sent "
1432 << StunMethodToString(request->msg()->type())
1433 << ", id=" << rtc::hex_encode(request->id())
1434 << ", use_candidate=" << use_candidate_attr()
1435 << ", nomination=" << nomination_;
1436 stats_.sent_ping_requests_total++;
1437 LogCandidatePairEvent(webrtc::IceCandidatePairEventType::kCheckSent,
1438 request->reduced_transaction_id());
1439 if (stats_.recv_ping_responses == 0) {
1440 stats_.sent_ping_requests_before_first_response++;
1441 }
1442 }
1443
state() const1444 IceCandidatePairState Connection::state() const {
1445 RTC_DCHECK_RUN_ON(network_thread_);
1446 return state_;
1447 }
1448
num_pings_sent() const1449 int Connection::num_pings_sent() const {
1450 RTC_DCHECK_RUN_ON(network_thread_);
1451 return num_pings_sent_;
1452 }
1453
MaybeSetRemoteIceParametersAndGeneration(const IceParameters & ice_params,int generation)1454 void Connection::MaybeSetRemoteIceParametersAndGeneration(
1455 const IceParameters& ice_params,
1456 int generation) {
1457 if (remote_candidate_.username() == ice_params.ufrag &&
1458 remote_candidate_.password().empty()) {
1459 remote_candidate_.set_password(ice_params.pwd);
1460 }
1461 // TODO(deadbeef): A value of '0' for the generation is used for both
1462 // generation 0 and "generation unknown". It should be changed to an
1463 // absl::optional to fix this.
1464 if (remote_candidate_.username() == ice_params.ufrag &&
1465 remote_candidate_.password() == ice_params.pwd &&
1466 remote_candidate_.generation() == 0) {
1467 remote_candidate_.set_generation(generation);
1468 }
1469 }
1470
MaybeUpdatePeerReflexiveCandidate(const Candidate & new_candidate)1471 void Connection::MaybeUpdatePeerReflexiveCandidate(
1472 const Candidate& new_candidate) {
1473 if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1474 new_candidate.type() != PRFLX_PORT_TYPE &&
1475 remote_candidate_.protocol() == new_candidate.protocol() &&
1476 remote_candidate_.address() == new_candidate.address() &&
1477 remote_candidate_.username() == new_candidate.username() &&
1478 remote_candidate_.password() == new_candidate.password() &&
1479 remote_candidate_.generation() == new_candidate.generation()) {
1480 remote_candidate_ = new_candidate;
1481 }
1482 }
1483
last_received() const1484 int64_t Connection::last_received() const {
1485 RTC_DCHECK_RUN_ON(network_thread_);
1486 return std::max(last_data_received_,
1487 std::max(last_ping_received_, last_ping_response_received_));
1488 }
1489
receiving_unchanged_since() const1490 int64_t Connection::receiving_unchanged_since() const {
1491 RTC_DCHECK_RUN_ON(network_thread_);
1492 return receiving_unchanged_since_;
1493 }
1494
prflx_priority() const1495 uint32_t Connection::prflx_priority() const {
1496 RTC_DCHECK_RUN_ON(network_thread_);
1497 // PRIORITY Attribute.
1498 // Changing the type preference to Peer Reflexive and local preference
1499 // and component id information is unchanged from the original priority.
1500 // priority = (2^24)*(type preference) +
1501 // (2^8)*(local preference) +
1502 // (2^0)*(256 - component ID)
1503 IcePriorityValue type_preference =
1504 (local_candidate_.protocol() == TCP_PROTOCOL_NAME)
1505 ? ICE_TYPE_PREFERENCE_PRFLX_TCP
1506 : ICE_TYPE_PREFERENCE_PRFLX;
1507 return type_preference << 24 | (local_candidate_.priority() & 0x00FFFFFF);
1508 }
1509
stats()1510 ConnectionInfo Connection::stats() {
1511 RTC_DCHECK_RUN_ON(network_thread_);
1512 stats_.recv_bytes_second = round(recv_rate_tracker_.ComputeRate());
1513 stats_.recv_total_bytes = recv_rate_tracker_.TotalSampleCount();
1514 stats_.sent_bytes_second = round(send_rate_tracker_.ComputeRate());
1515 stats_.sent_total_bytes = send_rate_tracker_.TotalSampleCount();
1516 stats_.receiving = receiving_;
1517 stats_.writable = write_state_ == STATE_WRITABLE;
1518 stats_.timeout = write_state_ == STATE_WRITE_TIMEOUT;
1519 stats_.rtt = rtt_;
1520 stats_.key = this;
1521 stats_.state = state_;
1522 if (port_) {
1523 stats_.priority = priority();
1524 stats_.local_candidate = local_candidate();
1525 }
1526 stats_.nominated = nominated();
1527 stats_.total_round_trip_time_ms = total_round_trip_time_ms_;
1528 stats_.current_round_trip_time_ms = current_round_trip_time_ms_;
1529 stats_.remote_candidate = remote_candidate();
1530 if (last_data_received_ > 0) {
1531 stats_.last_data_received = webrtc::Timestamp::Millis(
1532 last_data_received_ + delta_internal_unix_epoch_ms_);
1533 }
1534 if (last_send_data_ > 0) {
1535 stats_.last_data_sent = webrtc::Timestamp::Millis(
1536 last_send_data_ + delta_internal_unix_epoch_ms_);
1537 }
1538 return stats_;
1539 }
1540
MaybeUpdateLocalCandidate(StunRequest * request,StunMessage * response)1541 void Connection::MaybeUpdateLocalCandidate(StunRequest* request,
1542 StunMessage* response) {
1543 if (!port_)
1544 return;
1545
1546 // RFC 5245
1547 // The agent checks the mapped address from the STUN response. If the
1548 // transport address does not match any of the local candidates that the
1549 // agent knows about, the mapped address represents a new candidate -- a
1550 // peer reflexive candidate.
1551 const StunAddressAttribute* addr =
1552 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1553 if (!addr) {
1554 RTC_LOG(LS_WARNING)
1555 << "Connection::OnConnectionRequestResponse - "
1556 "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1557 "stun response message";
1558 return;
1559 }
1560
1561 for (const Candidate& candidate : port_->Candidates()) {
1562 if (candidate.address() == addr->GetAddress()) {
1563 if (local_candidate_ != candidate) {
1564 RTC_LOG(LS_INFO) << ToString()
1565 << ": Updating local candidate type to srflx.";
1566 local_candidate_ = candidate;
1567 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1568 // Connection's local candidate has changed.
1569 SignalStateChange(this);
1570 }
1571 return;
1572 }
1573 }
1574
1575 // RFC 5245
1576 // Its priority is set equal to the value of the PRIORITY attribute
1577 // in the Binding request.
1578 const StunUInt32Attribute* priority_attr =
1579 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1580 if (!priority_attr) {
1581 RTC_LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1582 "No STUN_ATTR_PRIORITY found in the "
1583 "stun response message";
1584 return;
1585 }
1586 const uint32_t priority = priority_attr->value();
1587 std::string id = rtc::CreateRandomString(8);
1588
1589 // Create a peer-reflexive candidate based on the local candidate.
1590 local_candidate_.set_id(id);
1591 local_candidate_.set_type(PRFLX_PORT_TYPE);
1592 // Set the related address and foundation attributes before changing the
1593 // address.
1594 local_candidate_.set_related_address(local_candidate_.address());
1595 local_candidate_.set_foundation(port()->ComputeFoundation(
1596 PRFLX_PORT_TYPE, local_candidate_.protocol(),
1597 local_candidate_.relay_protocol(), local_candidate_.address()));
1598 local_candidate_.set_priority(priority);
1599 local_candidate_.set_address(addr->GetAddress());
1600
1601 // Change the local candidate of this Connection to the new prflx candidate.
1602 RTC_LOG(LS_INFO) << ToString() << ": Updating local candidate type to prflx.";
1603 port_->AddPrflxCandidate(local_candidate_);
1604
1605 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1606 // Connection's local candidate has changed.
1607 SignalStateChange(this);
1608 }
1609
rtt_converged() const1610 bool Connection::rtt_converged() const {
1611 RTC_DCHECK_RUN_ON(network_thread_);
1612 return rtt_samples_ > (RTT_RATIO + 1);
1613 }
1614
missing_responses(int64_t now) const1615 bool Connection::missing_responses(int64_t now) const {
1616 RTC_DCHECK_RUN_ON(network_thread_);
1617 if (pings_since_last_response_.empty()) {
1618 return false;
1619 }
1620
1621 int64_t waiting = now - pings_since_last_response_[0].sent_time;
1622 return waiting > 2 * rtt();
1623 }
1624
TooManyOutstandingPings(const absl::optional<int> & max_outstanding_pings) const1625 bool Connection::TooManyOutstandingPings(
1626 const absl::optional<int>& max_outstanding_pings) const {
1627 RTC_DCHECK_RUN_ON(network_thread_);
1628 if (!max_outstanding_pings.has_value()) {
1629 return false;
1630 }
1631 if (static_cast<int>(pings_since_last_response_.size()) <
1632 *max_outstanding_pings) {
1633 return false;
1634 }
1635 return true;
1636 }
1637
SetLocalCandidateNetworkCost(uint16_t cost)1638 void Connection::SetLocalCandidateNetworkCost(uint16_t cost) {
1639 RTC_DCHECK_RUN_ON(network_thread_);
1640
1641 if (cost == local_candidate_.network_cost())
1642 return;
1643
1644 local_candidate_.set_network_cost(cost);
1645
1646 // Network cost change will affect the connection selection criteria.
1647 // Signal the connection state change to force a re-sort in
1648 // P2PTransportChannel.
1649 SignalStateChange(this);
1650 }
1651
ShouldSendGoogPing(const StunMessage * message)1652 bool Connection::ShouldSendGoogPing(const StunMessage* message) {
1653 RTC_DCHECK_RUN_ON(network_thread_);
1654 if (remote_support_goog_ping_ == true && cached_stun_binding_ &&
1655 cached_stun_binding_->EqualAttributes(message, [](int type) {
1656 // Ignore these attributes.
1657 // NOTE: Consider what to do if adding more content to
1658 // STUN_ATTR_GOOG_MISC_INFO
1659 return type != STUN_ATTR_FINGERPRINT &&
1660 type != STUN_ATTR_MESSAGE_INTEGRITY &&
1661 type != STUN_ATTR_RETRANSMIT_COUNT &&
1662 type != STUN_ATTR_GOOG_MISC_INFO;
1663 })) {
1664 return true;
1665 }
1666 return false;
1667 }
1668
ForgetLearnedState()1669 void Connection::ForgetLearnedState() {
1670 RTC_DCHECK_RUN_ON(network_thread_);
1671 RTC_LOG(LS_INFO) << ToString() << ": Connection forget learned state";
1672 requests_.Clear();
1673 receiving_ = false;
1674 write_state_ = STATE_WRITE_INIT;
1675 rtt_estimate_.Reset();
1676 pings_since_last_response_.clear();
1677 }
1678
ProxyConnection(rtc::WeakPtr<Port> port,size_t index,const Candidate & remote_candidate)1679 ProxyConnection::ProxyConnection(rtc::WeakPtr<Port> port,
1680 size_t index,
1681 const Candidate& remote_candidate)
1682 : Connection(std::move(port), index, remote_candidate) {}
1683
Send(const void * data,size_t size,const rtc::PacketOptions & options)1684 int ProxyConnection::Send(const void* data,
1685 size_t size,
1686 const rtc::PacketOptions& options) {
1687 if (!port_)
1688 return SOCKET_ERROR;
1689
1690 stats_.sent_total_packets++;
1691 int sent =
1692 port_->SendTo(data, size, remote_candidate_.address(), options, true);
1693 int64_t now = rtc::TimeMillis();
1694 if (sent <= 0) {
1695 RTC_DCHECK(sent < 0);
1696 error_ = port_->GetError();
1697 stats_.sent_discarded_packets++;
1698 stats_.sent_discarded_bytes += size;
1699 } else {
1700 send_rate_tracker_.AddSamplesAtTime(now, sent);
1701 }
1702 last_send_data_ = now;
1703 return sent;
1704 }
1705
GetError()1706 int ProxyConnection::GetError() {
1707 return error_;
1708 }
1709
1710 } // namespace cricket
1711