blob: 69dff9483bd08bb9b79a95e15d426201094410ef [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 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 "webrtc/p2p/base/port.h"
12
13#include <algorithm>
14#include <vector>
15
16#include "webrtc/p2p/base/common.h"
17#include "webrtc/p2p/base/portallocator.h"
18#include "webrtc/base/base64.h"
19#include "webrtc/base/crc32.h"
20#include "webrtc/base/helpers.h"
21#include "webrtc/base/logging.h"
22#include "webrtc/base/messagedigest.h"
23#include "webrtc/base/scoped_ptr.h"
24#include "webrtc/base/stringencode.h"
25#include "webrtc/base/stringutils.h"
26
27namespace {
28
29// Determines whether we have seen at least the given maximum number of
30// pings fail to have a response.
31inline bool TooManyFailures(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070032 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
Peter Boström0c4e06b2015-10-07 12:23:21 +020033 uint32_t maximum_failures,
34 uint32_t rtt_estimate,
35 uint32_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000036 // If we haven't sent that many pings, then we can't have failed that many.
37 if (pings_since_last_response.size() < maximum_failures)
38 return false;
39
40 // Check if the window in which we would expect a response to the ping has
41 // already elapsed.
Peter Boström0c4e06b2015-10-07 12:23:21 +020042 uint32_t expected_response_time =
Peter Thatcher1cf6f812015-05-15 10:40:45 -070043 pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
44 return now > expected_response_time;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045}
46
47// Determines whether we have gone too long without seeing any response.
48inline bool TooLongWithoutResponse(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070049 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
Peter Boström0c4e06b2015-10-07 12:23:21 +020050 uint32_t maximum_time,
51 uint32_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052 if (pings_since_last_response.size() == 0)
53 return false;
54
Peter Thatcher1cf6f812015-05-15 10:40:45 -070055 auto first = pings_since_last_response[0];
56 return now > (first.sent_time + maximum_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000057}
58
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059// We will restrict RTT estimates (when used for determining state) to be
60// within a reasonable range.
Peter Boström0c4e06b2015-10-07 12:23:21 +020061const uint32_t MINIMUM_RTT = 100; // 0.1 seconds
62const uint32_t MAXIMUM_RTT = 3000; // 3 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063
64// When we don't have any RTT data, we have to pick something reasonable. We
65// use a large value just in case the connection is really slow.
Peter Boström0c4e06b2015-10-07 12:23:21 +020066const uint32_t DEFAULT_RTT = MAXIMUM_RTT;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067
68// Computes our estimate of the RTT given the current estimate.
Peter Boström0c4e06b2015-10-07 12:23:21 +020069inline uint32_t ConservativeRTTEstimate(uint32_t rtt) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000070 return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000071}
72
73// Weighting of the old rtt value to new data.
74const int RTT_RATIO = 3; // 3 : 1
75
76// The delay before we begin checking if this port is useless.
77const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000078}
79
80namespace cricket {
81
82// TODO(ronghuawu): Use "host", "srflx", "prflx" and "relay". But this requires
83// the signaling part be updated correspondingly as well.
84const char LOCAL_PORT_TYPE[] = "local";
85const char STUN_PORT_TYPE[] = "stun";
86const char PRFLX_PORT_TYPE[] = "prflx";
87const char RELAY_PORT_TYPE[] = "relay";
88
89const char UDP_PROTOCOL_NAME[] = "udp";
90const char TCP_PROTOCOL_NAME[] = "tcp";
91const char SSLTCP_PROTOCOL_NAME[] = "ssltcp";
92
93static const char* const PROTO_NAMES[] = { UDP_PROTOCOL_NAME,
94 TCP_PROTOCOL_NAME,
95 SSLTCP_PROTOCOL_NAME };
96
97const char* ProtoToString(ProtocolType proto) {
98 return PROTO_NAMES[proto];
99}
100
101bool StringToProto(const char* value, ProtocolType* proto) {
102 for (size_t i = 0; i <= PROTO_LAST; ++i) {
103 if (_stricmp(PROTO_NAMES[i], value) == 0) {
104 *proto = static_cast<ProtocolType>(i);
105 return true;
106 }
107 }
108 return false;
109}
110
111// RFC 6544, TCP candidate encoding rules.
112const int DISCARD_PORT = 9;
113const char TCPTYPE_ACTIVE_STR[] = "active";
114const char TCPTYPE_PASSIVE_STR[] = "passive";
115const char TCPTYPE_SIMOPEN_STR[] = "so";
116
117// Foundation: An arbitrary string that is the same for two candidates
118// that have the same type, base IP address, protocol (UDP, TCP,
119// etc.), and STUN or TURN server. If any of these are different,
120// then the foundation will be different. Two candidate pairs with
121// the same foundation pairs are likely to have similar network
122// characteristics. Foundations are used in the frozen algorithm.
123static std::string ComputeFoundation(
124 const std::string& type,
125 const std::string& protocol,
126 const rtc::SocketAddress& base_address) {
127 std::ostringstream ost;
128 ost << type << base_address.ipaddr().ToString() << protocol;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200129 return rtc::ToString<uint32_t>(rtc::ComputeCrc32(ost.str()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130}
131
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000132Port::Port(rtc::Thread* thread,
133 rtc::PacketSocketFactory* factory,
134 rtc::Network* network,
135 const rtc::IPAddress& ip,
136 const std::string& username_fragment,
137 const std::string& password)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000138 : thread_(thread),
139 factory_(factory),
140 send_retransmit_count_attribute_(false),
141 network_(network),
142 ip_(ip),
143 min_port_(0),
144 max_port_(0),
145 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
146 generation_(0),
147 ice_username_fragment_(username_fragment),
148 password_(password),
149 timeout_delay_(kPortTimeoutDelay),
150 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000151 ice_role_(ICEROLE_UNKNOWN),
152 tiebreaker_(0),
153 shared_socket_(true),
154 candidate_filter_(CF_ALL) {
155 Construct();
156}
157
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000158Port::Port(rtc::Thread* thread,
159 const std::string& type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 rtc::PacketSocketFactory* factory,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000161 rtc::Network* network,
162 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200163 uint16_t min_port,
164 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000165 const std::string& username_fragment,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 const std::string& password)
167 : thread_(thread),
168 factory_(factory),
169 type_(type),
170 send_retransmit_count_attribute_(false),
171 network_(network),
172 ip_(ip),
173 min_port_(min_port),
174 max_port_(max_port),
175 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
176 generation_(0),
177 ice_username_fragment_(username_fragment),
178 password_(password),
179 timeout_delay_(kPortTimeoutDelay),
180 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000181 ice_role_(ICEROLE_UNKNOWN),
182 tiebreaker_(0),
183 shared_socket_(false),
184 candidate_filter_(CF_ALL) {
185 ASSERT(factory_ != NULL);
186 Construct();
187}
188
189void Port::Construct() {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700190 // TODO(pthatcher): Remove this old behavior once we're sure no one
191 // relies on it. If the username_fragment and password are empty,
192 // we should just create one.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 if (ice_username_fragment_.empty()) {
194 ASSERT(password_.empty());
195 ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
196 password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
197 }
198 LOG_J(LS_INFO, this) << "Port created";
199}
200
201Port::~Port() {
202 // Delete all of the remaining connections. We copy the list up front
203 // because each deletion will cause it to be modified.
204
205 std::vector<Connection*> list;
206
207 AddressMap::iterator iter = connections_.begin();
208 while (iter != connections_.end()) {
209 list.push_back(iter->second);
210 ++iter;
211 }
212
Peter Boström0c4e06b2015-10-07 12:23:21 +0200213 for (uint32_t i = 0; i < list.size(); i++)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000214 delete list[i];
215}
216
217Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
218 AddressMap::const_iterator iter = connections_.find(remote_addr);
219 if (iter != connections_.end())
220 return iter->second;
221 else
222 return NULL;
223}
224
225void Port::AddAddress(const rtc::SocketAddress& address,
226 const rtc::SocketAddress& base_address,
227 const rtc::SocketAddress& related_address,
228 const std::string& protocol,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700229 const std::string& relay_protocol,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000230 const std::string& tcptype,
231 const std::string& type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200232 uint32_t type_preference,
233 uint32_t relay_preference,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234 bool final) {
235 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
236 ASSERT(!tcptype.empty());
237 }
238
239 Candidate c;
240 c.set_id(rtc::CreateRandomString(8));
241 c.set_component(component_);
242 c.set_type(type);
243 c.set_protocol(protocol);
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700244 c.set_relay_protocol(relay_protocol);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000245 c.set_tcptype(tcptype);
246 c.set_address(address);
247 c.set_priority(c.GetPriority(type_preference, network_->preference(),
248 relay_preference));
249 c.set_username(username_fragment());
250 c.set_password(password_);
251 c.set_network_name(network_->name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000252 c.set_network_type(network_->type());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000253 c.set_generation(generation_);
254 c.set_related_address(related_address);
255 c.set_foundation(ComputeFoundation(type, protocol, base_address));
256 candidates_.push_back(c);
257 SignalCandidateReady(this, c);
258
259 if (final) {
260 SignalPortComplete(this);
261 }
262}
263
264void Port::AddConnection(Connection* conn) {
265 connections_[conn->remote_candidate().address()] = conn;
266 conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
267 SignalConnectionCreated(this, conn);
268}
269
270void Port::OnReadPacket(
271 const char* data, size_t size, const rtc::SocketAddress& addr,
272 ProtocolType proto) {
273 // If the user has enabled port packets, just hand this over.
274 if (enable_port_packets_) {
275 SignalReadPacket(this, data, size, addr);
276 return;
277 }
278
279 // If this is an authenticated STUN request, then signal unknown address and
280 // send back a proper binding response.
281 rtc::scoped_ptr<IceMessage> msg;
282 std::string remote_username;
283 if (!GetStunMessage(data, size, addr, msg.accept(), &remote_username)) {
284 LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
285 << addr.ToSensitiveString() << ")";
286 } else if (!msg) {
287 // STUN message handled already
288 } else if (msg->type() == STUN_BINDING_REQUEST) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700289 LOG(LS_INFO) << "Received STUN ping "
290 << " id=" << rtc::hex_encode(msg->transaction_id())
291 << " from unknown address " << addr.ToSensitiveString();
292
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000293 // Check for role conflicts.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700294 if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 LOG(LS_INFO) << "Received conflicting role from the peer.";
296 return;
297 }
298
299 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
300 } else {
301 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
302 // pruned a connection for this port while it had STUN requests in flight,
303 // because we then get back responses for them, which this code correctly
304 // does not handle.
305 if (msg->type() != STUN_BINDING_RESPONSE) {
306 LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
307 << msg->type() << ") from unknown address ("
308 << addr.ToSensitiveString() << ")";
309 }
310 }
311}
312
stefanc1aeaf02015-10-15 07:26:07 -0700313void Port::OnSentPacket(const rtc::SentPacket& sent_packet) {
314 PortInterface::SignalSentPacket(this, sent_packet);
315}
316
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000317void Port::OnReadyToSend() {
318 AddressMap::iterator iter = connections_.begin();
319 for (; iter != connections_.end(); ++iter) {
320 iter->second->OnReadyToSend();
321 }
322}
323
324size_t Port::AddPrflxCandidate(const Candidate& local) {
325 candidates_.push_back(local);
326 return (candidates_.size() - 1);
327}
328
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000329bool Port::GetStunMessage(const char* data, size_t size,
330 const rtc::SocketAddress& addr,
331 IceMessage** out_msg, std::string* out_username) {
332 // NOTE: This could clearly be optimized to avoid allocating any memory.
333 // However, at the data rates we'll be looking at on the client side,
334 // this probably isn't worth worrying about.
335 ASSERT(out_msg != NULL);
336 ASSERT(out_username != NULL);
337 *out_msg = NULL;
338 out_username->clear();
339
340 // Don't bother parsing the packet if we can tell it's not STUN.
341 // In ICE mode, all STUN packets will have a valid fingerprint.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700342 if (!StunMessage::ValidateFingerprint(data, size)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343 return false;
344 }
345
346 // Parse the request message. If the packet is not a complete and correct
347 // STUN message, then ignore it.
348 rtc::scoped_ptr<IceMessage> stun_msg(new IceMessage());
349 rtc::ByteBuffer buf(data, size);
350 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
351 return false;
352 }
353
354 if (stun_msg->type() == STUN_BINDING_REQUEST) {
355 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
356 // If not present, fail with a 400 Bad Request.
357 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700358 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000359 LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
360 << "from " << addr.ToSensitiveString();
361 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
362 STUN_ERROR_REASON_BAD_REQUEST);
363 return true;
364 }
365
366 // If the username is bad or unknown, fail with a 401 Unauthorized.
367 std::string local_ufrag;
368 std::string remote_ufrag;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700369 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000370 local_ufrag != username_fragment()) {
371 LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
372 << local_ufrag << " from "
373 << addr.ToSensitiveString();
374 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
375 STUN_ERROR_REASON_UNAUTHORIZED);
376 return true;
377 }
378
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000379 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700380 if (!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000381 LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000382 << "from " << addr.ToSensitiveString()
383 << ", password_=" << password_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
385 STUN_ERROR_REASON_UNAUTHORIZED);
386 return true;
387 }
388 out_username->assign(remote_ufrag);
389 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
390 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
391 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
392 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
393 LOG_J(LS_ERROR, this) << "Received STUN binding error:"
394 << " class=" << error_code->eclass()
395 << " number=" << error_code->number()
396 << " reason='" << error_code->reason() << "'"
397 << " from " << addr.ToSensitiveString();
398 // Return message to allow error-specific processing
399 } else {
400 LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
401 << "code from " << addr.ToSensitiveString();
402 return true;
403 }
404 }
405 // NOTE: Username should not be used in verifying response messages.
406 out_username->clear();
407 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
408 LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
409 << " from " << addr.ToSensitiveString();
410 out_username->clear();
411 // No stun attributes will be verified, if it's stun indication message.
412 // Returning from end of the this method.
413 } else {
414 LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
415 << stun_msg->type() << ") from "
416 << addr.ToSensitiveString();
417 return true;
418 }
419
420 // Return the STUN message found.
421 *out_msg = stun_msg.release();
422 return true;
423}
424
425bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
426 int family = ip().family();
427 // We use single-stack sockets, so families must match.
428 if (addr.family() != family) {
429 return false;
430 }
431 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
Peter Thatcherb8b01432015-07-07 16:45:53 -0700432 if (family == AF_INET6 &&
433 (IPIsLinkLocal(ip()) != IPIsLinkLocal(addr.ipaddr()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000434 return false;
435 }
436 return true;
437}
438
439bool Port::ParseStunUsername(const StunMessage* stun_msg,
440 std::string* local_ufrag,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700441 std::string* remote_ufrag) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000442 // The packet must include a username that either begins or ends with our
443 // fragment. It should begin with our fragment if it is a request and it
444 // should end with our fragment if it is a response.
445 local_ufrag->clear();
446 remote_ufrag->clear();
447 const StunByteStringAttribute* username_attr =
448 stun_msg->GetByteString(STUN_ATTR_USERNAME);
449 if (username_attr == NULL)
450 return false;
451
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700452 // RFRAG:LFRAG
453 const std::string username = username_attr->GetString();
454 size_t colon_pos = username.find(":");
455 if (colon_pos == std::string::npos) {
456 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000457 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000458
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700459 *local_ufrag = username.substr(0, colon_pos);
460 *remote_ufrag = username.substr(colon_pos + 1, username.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000461 return true;
462}
463
464bool Port::MaybeIceRoleConflict(
465 const rtc::SocketAddress& addr, IceMessage* stun_msg,
466 const std::string& remote_ufrag) {
467 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
468 bool ret = true;
469 IceRole remote_ice_role = ICEROLE_UNKNOWN;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200470 uint64_t remote_tiebreaker = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000471 const StunUInt64Attribute* stun_attr =
472 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
473 if (stun_attr) {
474 remote_ice_role = ICEROLE_CONTROLLING;
475 remote_tiebreaker = stun_attr->value();
476 }
477
478 // If |remote_ufrag| is same as port local username fragment and
479 // tie breaker value received in the ping message matches port
480 // tiebreaker value this must be a loopback call.
481 // We will treat this as valid scenario.
482 if (remote_ice_role == ICEROLE_CONTROLLING &&
483 username_fragment() == remote_ufrag &&
484 remote_tiebreaker == IceTiebreaker()) {
485 return true;
486 }
487
488 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
489 if (stun_attr) {
490 remote_ice_role = ICEROLE_CONTROLLED;
491 remote_tiebreaker = stun_attr->value();
492 }
493
494 switch (ice_role_) {
495 case ICEROLE_CONTROLLING:
496 if (ICEROLE_CONTROLLING == remote_ice_role) {
497 if (remote_tiebreaker >= tiebreaker_) {
498 SignalRoleConflict(this);
499 } else {
500 // Send Role Conflict (487) error response.
501 SendBindingErrorResponse(stun_msg, addr,
502 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
503 ret = false;
504 }
505 }
506 break;
507 case ICEROLE_CONTROLLED:
508 if (ICEROLE_CONTROLLED == remote_ice_role) {
509 if (remote_tiebreaker < tiebreaker_) {
510 SignalRoleConflict(this);
511 } else {
512 // Send Role Conflict (487) error response.
513 SendBindingErrorResponse(stun_msg, addr,
514 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
515 ret = false;
516 }
517 }
518 break;
519 default:
520 ASSERT(false);
521 }
522 return ret;
523}
524
525void Port::CreateStunUsername(const std::string& remote_username,
526 std::string* stun_username_attr_str) const {
527 stun_username_attr_str->clear();
528 *stun_username_attr_str = remote_username;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700529 stun_username_attr_str->append(":");
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000530 stun_username_attr_str->append(username_fragment());
531}
532
533void Port::SendBindingResponse(StunMessage* request,
534 const rtc::SocketAddress& addr) {
535 ASSERT(request->type() == STUN_BINDING_REQUEST);
536
537 // Retrieve the username from the request.
538 const StunByteStringAttribute* username_attr =
539 request->GetByteString(STUN_ATTR_USERNAME);
540 ASSERT(username_attr != NULL);
541 if (username_attr == NULL) {
542 // No valid username, skip the response.
543 return;
544 }
545
546 // Fill in the response message.
547 StunMessage response;
548 response.SetType(STUN_BINDING_RESPONSE);
549 response.SetTransactionID(request->transaction_id());
550 const StunUInt32Attribute* retransmit_attr =
551 request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
552 if (retransmit_attr) {
553 // Inherit the incoming retransmit value in the response so the other side
554 // can see our view of lost pings.
555 response.AddAttribute(new StunUInt32Attribute(
556 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
557
558 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
559 LOG_J(LS_INFO, this)
560 << "Received a remote ping with high retransmit count: "
561 << retransmit_attr->value();
562 }
563 }
564
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700565 response.AddAttribute(
566 new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
567 response.AddMessageIntegrity(password_);
568 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000569
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700570 // The fact that we received a successful request means that this connection
honghaizd0b31432015-09-30 12:42:17 -0700571 // (if one exists) should now be receiving.
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700572 Connection* conn = GetConnection(addr);
573
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574 // Send the response message.
575 rtc::ByteBuffer buf;
576 response.Write(&buf);
577 rtc::PacketOptions options(DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700578 auto err = SendTo(buf.Data(), buf.Length(), addr, options, false);
579 if (err < 0) {
580 LOG_J(LS_ERROR, this)
581 << "Failed to send STUN ping response"
582 << ", to=" << addr.ToSensitiveString()
583 << ", err=" << err
584 << ", id=" << rtc::hex_encode(response.transaction_id());
585 } else {
586 // Log at LS_INFO if we send a stun ping response on an unwritable
587 // connection.
588 rtc::LoggingSeverity sev = (conn && !conn->writable()) ?
589 rtc::LS_INFO : rtc::LS_VERBOSE;
590 LOG_JV(sev, this)
591 << "Sent STUN ping response"
592 << ", to=" << addr.ToSensitiveString()
593 << ", id=" << rtc::hex_encode(response.transaction_id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000594 }
595
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 ASSERT(conn != NULL);
597 if (conn)
598 conn->ReceivedPing();
599}
600
601void Port::SendBindingErrorResponse(StunMessage* request,
602 const rtc::SocketAddress& addr,
603 int error_code, const std::string& reason) {
604 ASSERT(request->type() == STUN_BINDING_REQUEST);
605
606 // Fill in the response message.
607 StunMessage response;
608 response.SetType(STUN_BINDING_ERROR_RESPONSE);
609 response.SetTransactionID(request->transaction_id());
610
611 // When doing GICE, we need to write out the error code incorrectly to
612 // maintain backwards compatiblility.
613 StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700614 error_attr->SetCode(error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000615 error_attr->SetReason(reason);
616 response.AddAttribute(error_attr);
617
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700618 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
619 // because we don't have enough information to determine the shared secret.
620 if (error_code != STUN_ERROR_BAD_REQUEST &&
621 error_code != STUN_ERROR_UNAUTHORIZED)
622 response.AddMessageIntegrity(password_);
623 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000624
625 // Send the response message.
626 rtc::ByteBuffer buf;
627 response.Write(&buf);
628 rtc::PacketOptions options(DefaultDscpValue());
629 SendTo(buf.Data(), buf.Length(), addr, options, false);
630 LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
631 << " to " << addr.ToSensitiveString();
632}
633
634void Port::OnMessage(rtc::Message *pmsg) {
honghaizd0b31432015-09-30 12:42:17 -0700635 ASSERT(pmsg->message_id == MSG_DEAD);
636 if (dead()) {
637 Destroy();
638 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000639}
640
641std::string Port::ToString() const {
642 std::stringstream ss;
643 ss << "Port[" << content_name_ << ":" << component_
644 << ":" << generation_ << ":" << type_
645 << ":" << network_->ToString() << "]";
646 return ss.str();
647}
648
649void Port::EnablePortPackets() {
650 enable_port_packets_ = true;
651}
652
653void Port::OnConnectionDestroyed(Connection* conn) {
654 AddressMap::iterator iter =
655 connections_.find(conn->remote_candidate().address());
656 ASSERT(iter != connections_.end());
657 connections_.erase(iter);
658
honghaizd0b31432015-09-30 12:42:17 -0700659 // On the controlled side, ports time out after all connections fail.
660 // Note: If a new connection is added after this message is posted, but it
661 // fails and is removed before kPortTimeoutDelay, then this message will
662 // still cause the Port to be destroyed.
663 if (dead()) {
664 thread_->PostDelayed(timeout_delay_, this, MSG_DEAD);
665 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000666}
667
668void Port::Destroy() {
669 ASSERT(connections_.empty());
670 LOG_J(LS_INFO, this) << "Port deleted";
671 SignalDestroyed(this);
672 delete this;
673}
674
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000675const std::string Port::username_fragment() const {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700676 return ice_username_fragment_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000677}
678
679// A ConnectionRequest is a simple STUN ping used to determine writability.
680class ConnectionRequest : public StunRequest {
681 public:
682 explicit ConnectionRequest(Connection* connection)
683 : StunRequest(new IceMessage()),
684 connection_(connection) {
685 }
686
687 virtual ~ConnectionRequest() {
688 }
689
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700690 void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000691 request->SetType(STUN_BINDING_REQUEST);
692 std::string username;
693 connection_->port()->CreateStunUsername(
694 connection_->remote_candidate().username(), &username);
695 request->AddAttribute(
696 new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
697
698 // connection_ already holds this ping, so subtract one from count.
699 if (connection_->port()->send_retransmit_count_attribute()) {
700 request->AddAttribute(new StunUInt32Attribute(
701 STUN_ATTR_RETRANSMIT_COUNT,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200702 static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
703 1)));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000704 }
705
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700706 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
707 if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
708 request->AddAttribute(new StunUInt64Attribute(
709 STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
710 // Since we are trying aggressive nomination, sending USE-CANDIDATE
711 // attribute in every ping.
712 // If we are dealing with a ice-lite end point, nomination flag
713 // in Connection will be set to false by default. Once the connection
714 // becomes "best connection", nomination flag will be turned on.
715 if (connection_->use_candidate_attr()) {
716 request->AddAttribute(new StunByteStringAttribute(
717 STUN_ATTR_USE_CANDIDATE));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000718 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700719 } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
720 request->AddAttribute(new StunUInt64Attribute(
721 STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
722 } else {
723 ASSERT(false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000724 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700725
726 // Adding PRIORITY Attribute.
727 // Changing the type preference to Peer Reflexive and local preference
728 // and component id information is unchanged from the original priority.
729 // priority = (2^24)*(type preference) +
730 // (2^8)*(local preference) +
731 // (2^0)*(256 - component ID)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200732 uint32_t prflx_priority =
733 ICE_TYPE_PREFERENCE_PRFLX << 24 |
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700734 (connection_->local_candidate().priority() & 0x00FFFFFF);
735 request->AddAttribute(
736 new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
737
738 // Adding Message Integrity attribute.
739 request->AddMessageIntegrity(connection_->remote_candidate().password());
740 // Adding Fingerprint.
741 request->AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000742 }
743
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700744 void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000745 connection_->OnConnectionRequestResponse(this, response);
746 }
747
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700748 void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000749 connection_->OnConnectionRequestErrorResponse(this, response);
750 }
751
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700752 void OnTimeout() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 connection_->OnConnectionRequestTimeout(this);
754 }
755
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700756 void OnSent() override {
757 connection_->OnConnectionRequestSent(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000758 // Each request is sent only once. After a single delay , the request will
759 // time out.
760 timeout_ = true;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700761 }
762
763 int resend_delay() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000764 return CONNECTION_RESPONSE_TIMEOUT;
765 }
766
767 private:
768 Connection* connection_;
769};
770
771//
772// Connection
773//
774
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000775Connection::Connection(Port* port,
776 size_t index,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000777 const Candidate& remote_candidate)
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000778 : port_(port),
779 local_candidate_index_(index),
780 remote_candidate_(remote_candidate),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000781 write_state_(STATE_WRITE_INIT),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700782 receiving_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000783 connected_(true),
784 pruned_(false),
785 use_candidate_attr_(false),
honghaiz5a3acd82015-08-20 15:53:17 -0700786 nominated_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000787 remote_ice_mode_(ICEMODE_FULL),
788 requests_(port->thread()),
789 rtt_(DEFAULT_RTT),
790 last_ping_sent_(0),
791 last_ping_received_(0),
792 last_data_received_(0),
793 last_ping_response_received_(0),
Tim Psiaki63046262015-09-14 10:38:08 -0700794 recv_rate_tracker_(100u, 10u),
795 send_rate_tracker_(100u, 10u),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000796 sent_packets_discarded_(0),
797 sent_packets_total_(0),
798 reported_(false),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700799 state_(STATE_WAITING),
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700800 receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT),
801 time_created_ms_(rtc::Time()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000802 // All of our connections start in WAITING state.
803 // TODO(mallinath) - Start connections from STATE_FROZEN.
804 // Wire up to send stun packets
805 requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
806 LOG_J(LS_INFO, this) << "Connection created";
807}
808
809Connection::~Connection() {
810}
811
812const Candidate& Connection::local_candidate() const {
813 ASSERT(local_candidate_index_ < port_->Candidates().size());
814 return port_->Candidates()[local_candidate_index_];
815}
816
Peter Boström0c4e06b2015-10-07 12:23:21 +0200817uint64_t Connection::priority() const {
818 uint64_t priority = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000819 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
820 // Let G be the priority for the candidate provided by the controlling
821 // agent. Let D be the priority for the candidate provided by the
822 // controlled agent.
823 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
824 IceRole role = port_->GetIceRole();
825 if (role != ICEROLE_UNKNOWN) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200826 uint32_t g = 0;
827 uint32_t d = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000828 if (role == ICEROLE_CONTROLLING) {
829 g = local_candidate().priority();
830 d = remote_candidate_.priority();
831 } else {
832 g = remote_candidate_.priority();
833 d = local_candidate().priority();
834 }
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000835 priority = std::min(g, d);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000836 priority = priority << 32;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000837 priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000838 }
839 return priority;
840}
841
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000842void Connection::set_write_state(WriteState value) {
843 WriteState old_value = write_state_;
844 write_state_ = value;
845 if (value != old_value) {
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000846 LOG_J(LS_VERBOSE, this) << "set_write_state from: " << old_value << " to "
847 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000848 SignalStateChange(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000849 }
850}
851
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700852void Connection::set_receiving(bool value) {
853 if (value != receiving_) {
854 LOG_J(LS_VERBOSE, this) << "set_receiving to " << value;
855 receiving_ = value;
856 SignalStateChange(this);
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700857 }
858}
859
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000860void Connection::set_state(State state) {
861 State old_state = state_;
862 state_ = state;
863 if (state != old_state) {
864 LOG_J(LS_VERBOSE, this) << "set_state";
865 }
866}
867
868void Connection::set_connected(bool value) {
869 bool old_value = connected_;
870 connected_ = value;
871 if (value != old_value) {
Guo-wei Shiehbe508a12015-04-06 12:48:47 -0700872 LOG_J(LS_VERBOSE, this) << "set_connected from: " << old_value << " to "
873 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000874 }
875}
876
877void Connection::set_use_candidate_attr(bool enable) {
878 use_candidate_attr_ = enable;
879}
880
881void Connection::OnSendStunPacket(const void* data, size_t size,
882 StunRequest* req) {
883 rtc::PacketOptions options(port_->DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700884 auto err = port_->SendTo(
885 data, size, remote_candidate_.address(), options, false);
886 if (err < 0) {
887 LOG_J(LS_WARNING, this) << "Failed to send STUN ping "
888 << " err=" << err
889 << " id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000890 }
891}
892
893void Connection::OnReadPacket(
894 const char* data, size_t size, const rtc::PacketTime& packet_time) {
895 rtc::scoped_ptr<IceMessage> msg;
896 std::string remote_ufrag;
897 const rtc::SocketAddress& addr(remote_candidate_.address());
898 if (!port_->GetStunMessage(data, size, addr, msg.accept(), &remote_ufrag)) {
899 // The packet did not parse as a valid STUN message
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700900 // This is a data packet, pass it along.
901 set_receiving(true);
902 last_data_received_ = rtc::Time();
903 recv_rate_tracker_.AddSamples(size);
904 SignalReadPacket(this, data, size, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000905
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700906 // If timed out sending writability checks, start up again
907 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
908 LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
909 << "Resetting state to STATE_WRITE_INIT.";
910 set_write_state(STATE_WRITE_INIT);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000911 }
912 } else if (!msg) {
913 // The packet was STUN, but failed a check and was handled internally.
914 } else {
915 // The packet is STUN and passed the Port checks.
916 // Perform our own checks to ensure this packet is valid.
honghaizd0b31432015-09-30 12:42:17 -0700917 // If this is a STUN request, then update the receiving bit and respond.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000918 // If this is a STUN response, then update the writable bit.
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700919 // Log at LS_INFO if we receive a ping on an unwritable connection.
920 rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000921 switch (msg->type()) {
922 case STUN_BINDING_REQUEST:
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700923 LOG_JV(sev, this) << "Received STUN ping"
924 << ", id=" << rtc::hex_encode(msg->transaction_id());
925
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 if (remote_ufrag == remote_candidate_.username()) {
927 // Check for role conflicts.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700928 if (!port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000929 // Received conflicting role from the peer.
930 LOG(LS_INFO) << "Received conflicting role from the peer.";
931 return;
932 }
933
934 // Incoming, validated stun request from remote peer.
honghaizd0b31432015-09-30 12:42:17 -0700935 // This call will also set the connection receiving.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000936 port_->SendBindingResponse(msg.get(), addr);
937
938 // If timed out sending writability checks, start up again
939 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
940 set_write_state(STATE_WRITE_INIT);
941
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700942 if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000943 const StunByteStringAttribute* use_candidate_attr =
944 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
honghaiz5a3acd82015-08-20 15:53:17 -0700945 if (use_candidate_attr) {
946 set_nominated(true);
947 SignalNominated(this);
948 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000949 }
950 } else {
951 // The packet had the right local username, but the remote username
952 // was not the right one for the remote address.
953 LOG_J(LS_ERROR, this)
954 << "Received STUN request with bad remote username "
955 << remote_ufrag;
956 port_->SendBindingErrorResponse(msg.get(), addr,
957 STUN_ERROR_UNAUTHORIZED,
958 STUN_ERROR_REASON_UNAUTHORIZED);
959
960 }
961 break;
962
963 // Response from remote peer. Does it match request sent?
964 // This doesn't just check, it makes callbacks if transaction
965 // id's match.
966 case STUN_BINDING_RESPONSE:
967 case STUN_BINDING_ERROR_RESPONSE:
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700968 if (msg->ValidateMessageIntegrity(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000969 data, size, remote_candidate().password())) {
970 requests_.CheckResponse(msg.get());
971 }
972 // Otherwise silently discard the response message.
973 break;
974
honghaizd0b31432015-09-30 12:42:17 -0700975 // Remote end point sent an STUN indication instead of regular binding
976 // request. In this case |last_ping_received_| will be updated but no
977 // response will be sent.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000978 case STUN_BINDING_INDICATION:
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700979 ReceivedPing();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000980 break;
981
982 default:
983 ASSERT(false);
984 break;
985 }
986 }
987}
988
989void Connection::OnReadyToSend() {
990 if (write_state_ == STATE_WRITABLE) {
991 SignalReadyToSend(this);
992 }
993}
994
995void Connection::Prune() {
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700996 if (!pruned_ || active()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000997 LOG_J(LS_VERBOSE, this) << "Connection pruned";
998 pruned_ = true;
999 requests_.Clear();
1000 set_write_state(STATE_WRITE_TIMEOUT);
1001 }
1002}
1003
1004void Connection::Destroy() {
1005 LOG_J(LS_VERBOSE, this) << "Connection destroyed";
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001006 port_->thread()->Post(this, MSG_DELETE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001007}
1008
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001009void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
1010 std::ostringstream oss;
1011 oss << std::boolalpha;
1012 if (pings_since_last_response_.size() > max) {
1013 for (size_t i = 0; i < max; i++) {
1014 const SentPing& ping = pings_since_last_response_[i];
1015 oss << rtc::hex_encode(ping.id) << " ";
1016 }
1017 oss << "... " << (pings_since_last_response_.size() - max) << " more";
1018 } else {
1019 for (const SentPing& ping : pings_since_last_response_) {
1020 oss << rtc::hex_encode(ping.id) << " ";
1021 }
1022 }
1023 *s = oss.str();
1024}
1025
Peter Boström0c4e06b2015-10-07 12:23:21 +02001026void Connection::UpdateState(uint32_t now) {
1027 uint32_t rtt = ConservativeRTTEstimate(rtt_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001028
Peter Thatcherb2d26232015-05-15 11:25:14 -07001029 if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001030 std::string pings;
1031 PrintPingsSinceLastResponse(&pings, 5);
1032 LOG_J(LS_VERBOSE, this) << "UpdateState()"
1033 << ", ms since last received response="
1034 << now - last_ping_response_received_
1035 << ", ms since last received data="
1036 << now - last_data_received_
1037 << ", rtt=" << rtt
1038 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001039 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001040
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001041 // Check the writable state. (The order of these checks is important.)
1042 //
1043 // Before becoming unwritable, we allow for a fixed number of pings to fail
1044 // (i.e., receive no response). We also have to give the response time to
1045 // get back, so we include a conservative estimate of this.
1046 //
1047 // Before timing out writability, we give a fixed amount of time. This is to
1048 // allow for changes in network conditions.
1049
1050 if ((write_state_ == STATE_WRITABLE) &&
1051 TooManyFailures(pings_since_last_response_,
1052 CONNECTION_WRITE_CONNECT_FAILURES,
1053 rtt,
1054 now) &&
1055 TooLongWithoutResponse(pings_since_last_response_,
1056 CONNECTION_WRITE_CONNECT_TIMEOUT,
1057 now)) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001058 uint32_t max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001059 LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
1060 << " ping failures and "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001061 << now - pings_since_last_response_[0].sent_time
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001062 << " ms without a response,"
1063 << " ms since last received ping="
1064 << now - last_ping_received_
1065 << " ms since last received data="
1066 << now - last_data_received_
1067 << " rtt=" << rtt;
1068 set_write_state(STATE_WRITE_UNRELIABLE);
1069 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001070 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
1071 write_state_ == STATE_WRITE_INIT) &&
1072 TooLongWithoutResponse(pings_since_last_response_,
1073 CONNECTION_WRITE_TIMEOUT,
1074 now)) {
1075 LOG_J(LS_INFO, this) << "Timed out after "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001076 << now - pings_since_last_response_[0].sent_time
1077 << " ms without a response"
1078 << ", rtt=" << rtt;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001079 set_write_state(STATE_WRITE_TIMEOUT);
1080 }
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001081
1082 // Check the receiving state.
Peter Boström0c4e06b2015-10-07 12:23:21 +02001083 uint32_t last_recv_time = last_received();
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001084 bool receiving = now <= last_recv_time + receiving_timeout_;
1085 set_receiving(receiving);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001086 if (dead(now)) {
1087 Destroy();
1088 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001089}
1090
Peter Boström0c4e06b2015-10-07 12:23:21 +02001091void Connection::Ping(uint32_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001092 last_ping_sent_ = now;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001093 ConnectionRequest *req = new ConnectionRequest(this);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001094 pings_since_last_response_.push_back(SentPing(req->id(), now));
1095 LOG_J(LS_VERBOSE, this) << "Sending STUN ping "
1096 << ", id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001097 requests_.Send(req);
1098 state_ = STATE_INPROGRESS;
1099}
1100
1101void Connection::ReceivedPing() {
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001102 set_receiving(true);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001103 last_ping_received_ = rtc::Time();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001104}
1105
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001106void Connection::ReceivedPingResponse() {
1107 // We've already validated that this is a STUN binding response with
1108 // the correct local and remote username for this connection.
1109 // So if we're not already, become writable. We may be bringing a pruned
1110 // connection back to life, but if we don't really want it, we can always
1111 // prune it again.
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001112 set_receiving(true);
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001113 set_write_state(STATE_WRITABLE);
1114 set_state(STATE_SUCCEEDED);
1115 pings_since_last_response_.clear();
1116 last_ping_response_received_ = rtc::Time();
1117}
1118
Peter Boström0c4e06b2015-10-07 12:23:21 +02001119bool Connection::dead(uint32_t now) const {
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001120 if (now < (time_created_ms_ + MIN_CONNECTION_LIFETIME)) {
1121 // A connection that hasn't passed its minimum lifetime is still alive.
1122 // We do this to prevent connections from being pruned too quickly
1123 // during a network change event when two networks would be up
1124 // simultaneously but only for a brief period.
1125 return false;
1126 }
1127
1128 if (receiving_) {
1129 // A connection that is receiving is alive.
1130 return false;
1131 }
1132
1133 // A connection is alive until it is inactive.
1134 return !active();
1135
1136 // TODO(honghaiz): Move from using the write state to using the receiving
1137 // state with something like the following:
1138 // return (now > (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT));
1139}
1140
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001141std::string Connection::ToDebugId() const {
1142 std::stringstream ss;
1143 ss << std::hex << this;
1144 return ss.str();
1145}
1146
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001147std::string Connection::ToString() const {
1148 const char CONNECT_STATE_ABBREV[2] = {
1149 '-', // not connected (false)
1150 'C', // connected (true)
1151 };
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001152 const char RECEIVE_STATE_ABBREV[2] = {
1153 '-', // not receiving (false)
1154 'R', // receiving (true)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001155 };
1156 const char WRITE_STATE_ABBREV[4] = {
1157 'W', // STATE_WRITABLE
1158 'w', // STATE_WRITE_UNRELIABLE
1159 '-', // STATE_WRITE_INIT
1160 'x', // STATE_WRITE_TIMEOUT
1161 };
1162 const std::string ICESTATE[4] = {
1163 "W", // STATE_WAITING
1164 "I", // STATE_INPROGRESS
1165 "S", // STATE_SUCCEEDED
1166 "F" // STATE_FAILED
1167 };
1168 const Candidate& local = local_candidate();
1169 const Candidate& remote = remote_candidate();
1170 std::stringstream ss;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001171 ss << "Conn[" << ToDebugId()
1172 << ":" << port_->content_name()
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001173 << ":" << local.id() << ":" << local.component()
1174 << ":" << local.generation()
1175 << ":" << local.type() << ":" << local.protocol()
1176 << ":" << local.address().ToSensitiveString()
1177 << "->" << remote.id() << ":" << remote.component()
1178 << ":" << remote.priority()
1179 << ":" << remote.type() << ":"
1180 << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
1181 << CONNECT_STATE_ABBREV[connected()]
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001182 << RECEIVE_STATE_ABBREV[receiving()]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001183 << WRITE_STATE_ABBREV[write_state()]
1184 << ICESTATE[state()] << "|"
1185 << priority() << "|";
1186 if (rtt_ < DEFAULT_RTT) {
1187 ss << rtt_ << "]";
1188 } else {
1189 ss << "-]";
1190 }
1191 return ss.str();
1192}
1193
1194std::string Connection::ToSensitiveString() const {
1195 return ToString();
1196}
1197
1198void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1199 StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001200 // Log at LS_INFO if we receive a ping response on an unwritable
1201 // connection.
1202 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1203
Peter Boström0c4e06b2015-10-07 12:23:21 +02001204 uint32_t rtt = request->Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001205
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001206 ReceivedPingResponse();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001207
Peter Thatcherb2d26232015-05-15 11:25:14 -07001208 if (LOG_CHECK_LEVEL_V(sev)) {
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001209 bool use_candidate = (
1210 response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001211 std::string pings;
1212 PrintPingsSinceLastResponse(&pings, 5);
1213 LOG_JV(sev, this) << "Received STUN ping response"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001214 << ", id=" << rtc::hex_encode(request->id())
1215 << ", code=0" // Makes logging easier to parse.
1216 << ", rtt=" << rtt
1217 << ", use_candidate=" << use_candidate
1218 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001219 }
1220
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001221 rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
1222
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001223 MaybeAddPrflxCandidate(request, response);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001224}
1225
1226void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1227 StunMessage* response) {
1228 const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
1229 int error_code = STUN_ERROR_GLOBAL_FAILURE;
1230 if (error_attr) {
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001231 error_code = error_attr->code();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001232 }
1233
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001234 LOG_J(LS_INFO, this) << "Received STUN error response"
1235 << " id=" << rtc::hex_encode(request->id())
1236 << " code=" << error_code
1237 << " rtt=" << request->Elapsed();
1238
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001239 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1240 error_code == STUN_ERROR_SERVER_ERROR ||
1241 error_code == STUN_ERROR_UNAUTHORIZED) {
1242 // Recoverable error, retry
1243 } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1244 // Race failure, retry
1245 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1246 HandleRoleConflictFromPeer();
1247 } else {
1248 // This is not a valid connection.
1249 LOG_J(LS_ERROR, this) << "Received STUN error response, code="
1250 << error_code << "; killing connection";
1251 set_state(STATE_FAILED);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001252 Destroy();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001253 }
1254}
1255
1256void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1257 // Log at LS_INFO if we miss a ping on a writable connection.
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001258 rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1259 LOG_JV(sev, this) << "Timing-out STUN ping "
1260 << rtc::hex_encode(request->id())
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001261 << " after " << request->Elapsed() << " ms";
1262}
1263
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001264void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1265 // Log at LS_INFO if we send a ping on an unwritable connection.
1266 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001267 bool use_candidate = use_candidate_attr();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001268 LOG_JV(sev, this) << "Sent STUN ping"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001269 << ", id=" << rtc::hex_encode(request->id())
1270 << ", use_candidate=" << use_candidate;
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001271}
1272
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001273void Connection::HandleRoleConflictFromPeer() {
1274 port_->SignalRoleConflict(port_);
1275}
1276
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +00001277void Connection::MaybeSetRemoteIceCredentials(const std::string& ice_ufrag,
1278 const std::string& ice_pwd) {
1279 if (remote_candidate_.username() == ice_ufrag &&
1280 remote_candidate_.password().empty()) {
1281 remote_candidate_.set_password(ice_pwd);
1282 }
1283}
1284
1285void Connection::MaybeUpdatePeerReflexiveCandidate(
1286 const Candidate& new_candidate) {
1287 if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1288 new_candidate.type() != PRFLX_PORT_TYPE &&
1289 remote_candidate_.protocol() == new_candidate.protocol() &&
1290 remote_candidate_.address() == new_candidate.address() &&
1291 remote_candidate_.username() == new_candidate.username() &&
1292 remote_candidate_.password() == new_candidate.password() &&
1293 remote_candidate_.generation() == new_candidate.generation()) {
1294 remote_candidate_ = new_candidate;
1295 }
1296}
1297
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001298void Connection::OnMessage(rtc::Message *pmsg) {
1299 ASSERT(pmsg->message_id == MSG_DELETE);
honghaizd0b31432015-09-30 12:42:17 -07001300 LOG_J(LS_INFO, this) << "Connection deleted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001301 SignalDestroyed(this);
1302 delete this;
1303}
1304
Peter Boström0c4e06b2015-10-07 12:23:21 +02001305uint32_t Connection::last_received() {
Peter Thatcher54360512015-07-08 11:08:35 -07001306 return std::max(last_data_received_,
1307 std::max(last_ping_received_, last_ping_response_received_));
1308}
1309
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001310size_t Connection::recv_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001311 return round(recv_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001312}
1313
1314size_t Connection::recv_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001315 return recv_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001316}
1317
1318size_t Connection::sent_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001319 return round(send_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001320}
1321
1322size_t Connection::sent_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001323 return send_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001324}
1325
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001326size_t Connection::sent_discarded_packets() {
1327 return sent_packets_discarded_;
1328}
1329
1330size_t Connection::sent_total_packets() {
1331 return sent_packets_total_;
1332}
1333
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001334void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
1335 StunMessage* response) {
1336 // RFC 5245
1337 // The agent checks the mapped address from the STUN response. If the
1338 // transport address does not match any of the local candidates that the
1339 // agent knows about, the mapped address represents a new candidate -- a
1340 // peer reflexive candidate.
1341 const StunAddressAttribute* addr =
1342 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1343 if (!addr) {
1344 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1345 << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1346 << "stun response message";
1347 return;
1348 }
1349
1350 bool known_addr = false;
1351 for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1352 if (port_->Candidates()[i].address() == addr->GetAddress()) {
1353 known_addr = true;
1354 break;
1355 }
1356 }
1357 if (known_addr) {
1358 return;
1359 }
1360
1361 // RFC 5245
1362 // Its priority is set equal to the value of the PRIORITY attribute
1363 // in the Binding request.
1364 const StunUInt32Attribute* priority_attr =
1365 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1366 if (!priority_attr) {
1367 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1368 << "No STUN_ATTR_PRIORITY found in the "
1369 << "stun response message";
1370 return;
1371 }
Peter Boström0c4e06b2015-10-07 12:23:21 +02001372 const uint32_t priority = priority_attr->value();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001373 std::string id = rtc::CreateRandomString(8);
1374
1375 Candidate new_local_candidate;
1376 new_local_candidate.set_id(id);
1377 new_local_candidate.set_component(local_candidate().component());
1378 new_local_candidate.set_type(PRFLX_PORT_TYPE);
1379 new_local_candidate.set_protocol(local_candidate().protocol());
1380 new_local_candidate.set_address(addr->GetAddress());
1381 new_local_candidate.set_priority(priority);
1382 new_local_candidate.set_username(local_candidate().username());
1383 new_local_candidate.set_password(local_candidate().password());
1384 new_local_candidate.set_network_name(local_candidate().network_name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001385 new_local_candidate.set_network_type(local_candidate().network_type());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001386 new_local_candidate.set_related_address(local_candidate().address());
1387 new_local_candidate.set_foundation(
1388 ComputeFoundation(PRFLX_PORT_TYPE, local_candidate().protocol(),
1389 local_candidate().address()));
1390
1391 // Change the local candidate of this Connection to the new prflx candidate.
1392 local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1393
1394 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1395 // Connection's local candidate has changed.
1396 SignalStateChange(this);
1397}
1398
1399ProxyConnection::ProxyConnection(Port* port, size_t index,
1400 const Candidate& candidate)
1401 : Connection(port, index, candidate), error_(0) {
1402}
1403
1404int ProxyConnection::Send(const void* data, size_t size,
1405 const rtc::PacketOptions& options) {
1406 if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
1407 error_ = EWOULDBLOCK;
1408 return SOCKET_ERROR;
1409 }
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001410 sent_packets_total_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001411 int sent = port_->SendTo(data, size, remote_candidate_.address(),
1412 options, true);
1413 if (sent <= 0) {
1414 ASSERT(sent < 0);
1415 error_ = port_->GetError();
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001416 sent_packets_discarded_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001417 } else {
Tim Psiaki63046262015-09-14 10:38:08 -07001418 send_rate_tracker_.AddSamples(sent);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001419 }
1420 return sent;
1421}
1422
1423} // namespace cricket