blob: a353dc2a2f0a75975af37fd2b1d5a2d3ae6cd93f [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:111/*
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"
honghaize3c6c822016-02-17 21:00:2823#include "webrtc/base/network.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:1124#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 17:40:4532 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
Peter Boström0c4e06b2015-10-07 10:23:2133 uint32_t maximum_failures,
honghaiz34b11eb2016-03-16 15:55:4434 int rtt_estimate,
35 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:1136 // 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.
honghaiz34b11eb2016-03-16 15:55:4442 int64_t expected_response_time =
Peter Thatcher1cf6f812015-05-15 17:40:4543 pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
44 return now > expected_response_time;
henrike@webrtc.org269fb4b2014-10-28 22:20:1145}
46
47// Determines whether we have gone too long without seeing any response.
48inline bool TooLongWithoutResponse(
Peter Thatcher1cf6f812015-05-15 17:40:4549 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
honghaiz34b11eb2016-03-16 15:55:4450 int64_t maximum_time,
51 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:1152 if (pings_since_last_response.size() == 0)
53 return false;
54
Peter Thatcher1cf6f812015-05-15 17:40:4555 auto first = pings_since_last_response[0];
56 return now > (first.sent_time + maximum_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:1157}
58
henrike@webrtc.org269fb4b2014-10-28 22:20:1159// We will restrict RTT estimates (when used for determining state) to be
60// within a reasonable range.
honghaiz34b11eb2016-03-16 15:55:4461const int MINIMUM_RTT = 100; // 0.1 seconds
62const int MAXIMUM_RTT = 3000; // 3 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:1163
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.
honghaiz34b11eb2016-03-16 15:55:4466const int DEFAULT_RTT = MAXIMUM_RTT;
henrike@webrtc.org269fb4b2014-10-28 22:20:1167
68// Computes our estimate of the RTT given the current estimate.
honghaiz34b11eb2016-03-16 15:55:4469inline int ConservativeRTTEstimate(int rtt) {
andresp@webrtc.orgff689be2015-02-12 11:54:2670 return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
henrike@webrtc.org269fb4b2014-10-28 22:20:1171}
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:1178}
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.
Honghai Zhang80f1db92016-01-27 19:54:45123static std::string ComputeFoundation(const std::string& type,
124 const std::string& protocol,
125 const std::string& relay_protocol,
126 const rtc::SocketAddress& base_address) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11127 std::ostringstream ost;
Honghai Zhang80f1db92016-01-27 19:54:45128 ost << type << base_address.ipaddr().ToString() << protocol << relay_protocol;
Peter Boström0c4e06b2015-10-07 10:23:21129 return rtc::ToString<uint32_t>(rtc::ComputeCrc32(ost.str()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11130}
131
pkasting@chromium.org332331f2014-11-06 20:19:22132Port::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:11138 : 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:11151 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:22158Port::Port(rtc::Thread* thread,
159 const std::string& type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11160 rtc::PacketSocketFactory* factory,
pkasting@chromium.org332331f2014-11-06 20:19:22161 rtc::Network* network,
162 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 10:23:21163 uint16_t min_port,
164 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22165 const std::string& username_fragment,
henrike@webrtc.org269fb4b2014-10-28 22:20:11166 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:11181 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-18 01:54:52190 // 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:11193 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 }
honghaize3c6c822016-02-17 21:00:28198 network_->SignalInactive.connect(this, &Port::OnNetworkInactive);
honghaize1a0c942016-02-16 22:54:56199 // TODO(honghaiz): Make it configurable from user setting.
200 network_cost_ =
201 (network_->type() == rtc::ADAPTER_TYPE_CELLULAR) ? kMaxNetworkCost : 0;
202
henrike@webrtc.org269fb4b2014-10-28 22:20:11203 LOG_J(LS_INFO, this) << "Port created";
204}
205
206Port::~Port() {
207 // Delete all of the remaining connections. We copy the list up front
208 // because each deletion will cause it to be modified.
209
210 std::vector<Connection*> list;
211
212 AddressMap::iterator iter = connections_.begin();
213 while (iter != connections_.end()) {
214 list.push_back(iter->second);
215 ++iter;
216 }
217
Peter Boström0c4e06b2015-10-07 10:23:21218 for (uint32_t i = 0; i < list.size(); i++)
henrike@webrtc.org269fb4b2014-10-28 22:20:11219 delete list[i];
220}
221
222Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
223 AddressMap::const_iterator iter = connections_.find(remote_addr);
224 if (iter != connections_.end())
225 return iter->second;
226 else
227 return NULL;
228}
229
230void Port::AddAddress(const rtc::SocketAddress& address,
231 const rtc::SocketAddress& base_address,
232 const rtc::SocketAddress& related_address,
233 const std::string& protocol,
Guo-wei Shieh3d564c12015-08-19 23:51:15234 const std::string& relay_protocol,
henrike@webrtc.org269fb4b2014-10-28 22:20:11235 const std::string& tcptype,
236 const std::string& type,
Peter Boström0c4e06b2015-10-07 10:23:21237 uint32_t type_preference,
238 uint32_t relay_preference,
henrike@webrtc.org269fb4b2014-10-28 22:20:11239 bool final) {
240 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
241 ASSERT(!tcptype.empty());
242 }
243
honghaiza0c44ea2016-03-23 23:07:48244 std::string foundation =
245 ComputeFoundation(type, protocol, relay_protocol, base_address);
246 Candidate c(component_, protocol, address, 0U, username_fragment(), password_,
247 type, generation_, foundation, network_->id(), network_cost_);
248 c.set_priority(
249 c.GetPriority(type_preference, network_->preference(), relay_preference));
Guo-wei Shieh3d564c12015-08-19 23:51:15250 c.set_relay_protocol(relay_protocol);
henrike@webrtc.org269fb4b2014-10-28 22:20:11251 c.set_tcptype(tcptype);
henrike@webrtc.org269fb4b2014-10-28 22:20:11252 c.set_network_name(network_->name());
guoweis@webrtc.org950c5182014-12-16 23:01:31253 c.set_network_type(network_->type());
henrike@webrtc.org269fb4b2014-10-28 22:20:11254 c.set_related_address(related_address);
henrike@webrtc.org269fb4b2014-10-28 22:20:11255 candidates_.push_back(c);
256 SignalCandidateReady(this, c);
257
258 if (final) {
259 SignalPortComplete(this);
260 }
261}
262
263void Port::AddConnection(Connection* conn) {
264 connections_[conn->remote_candidate().address()] = conn;
265 conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
266 SignalConnectionCreated(this, conn);
267}
268
269void Port::OnReadPacket(
270 const char* data, size_t size, const rtc::SocketAddress& addr,
271 ProtocolType proto) {
272 // If the user has enabled port packets, just hand this over.
273 if (enable_port_packets_) {
274 SignalReadPacket(this, data, size, addr);
275 return;
276 }
277
278 // If this is an authenticated STUN request, then signal unknown address and
279 // send back a proper binding response.
kwiberg3ec46792016-04-27 14:22:53280 std::unique_ptr<IceMessage> msg;
henrike@webrtc.org269fb4b2014-10-28 22:20:11281 std::string remote_username;
kwiberg6baec032016-03-15 18:09:39282 if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11283 LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
284 << addr.ToSensitiveString() << ")";
285 } else if (!msg) {
286 // STUN message handled already
287 } else if (msg->type() == STUN_BINDING_REQUEST) {
Peter Thatcher1cf6f812015-05-15 17:40:45288 LOG(LS_INFO) << "Received STUN ping "
289 << " id=" << rtc::hex_encode(msg->transaction_id())
290 << " from unknown address " << addr.ToSensitiveString();
291
henrike@webrtc.org269fb4b2014-10-28 22:20:11292 // Check for role conflicts.
Peter Thatcher7cbd1882015-09-18 01:54:52293 if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11294 LOG(LS_INFO) << "Received conflicting role from the peer.";
295 return;
296 }
297
298 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
299 } else {
300 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
301 // pruned a connection for this port while it had STUN requests in flight,
302 // because we then get back responses for them, which this code correctly
303 // does not handle.
304 if (msg->type() != STUN_BINDING_RESPONSE) {
305 LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
306 << msg->type() << ") from unknown address ("
307 << addr.ToSensitiveString() << ")";
308 }
309 }
310}
311
312void Port::OnReadyToSend() {
313 AddressMap::iterator iter = connections_.begin();
314 for (; iter != connections_.end(); ++iter) {
315 iter->second->OnReadyToSend();
316 }
317}
318
319size_t Port::AddPrflxCandidate(const Candidate& local) {
320 candidates_.push_back(local);
321 return (candidates_.size() - 1);
322}
323
kwiberg6baec032016-03-15 18:09:39324bool Port::GetStunMessage(const char* data,
325 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11326 const rtc::SocketAddress& addr,
kwiberg3ec46792016-04-27 14:22:53327 std::unique_ptr<IceMessage>* out_msg,
kwiberg6baec032016-03-15 18:09:39328 std::string* out_username) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11329 // NOTE: This could clearly be optimized to avoid allocating any memory.
330 // However, at the data rates we'll be looking at on the client side,
331 // this probably isn't worth worrying about.
332 ASSERT(out_msg != NULL);
333 ASSERT(out_username != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11334 out_username->clear();
335
336 // Don't bother parsing the packet if we can tell it's not STUN.
337 // In ICE mode, all STUN packets will have a valid fingerprint.
Peter Thatcher7cbd1882015-09-18 01:54:52338 if (!StunMessage::ValidateFingerprint(data, size)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11339 return false;
340 }
341
342 // Parse the request message. If the packet is not a complete and correct
343 // STUN message, then ignore it.
kwiberg3ec46792016-04-27 14:22:53344 std::unique_ptr<IceMessage> stun_msg(new IceMessage());
jbauchf1f87202016-03-30 13:43:37345 rtc::ByteBufferReader buf(data, size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11346 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
347 return false;
348 }
349
350 if (stun_msg->type() == STUN_BINDING_REQUEST) {
351 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
352 // If not present, fail with a 400 Bad Request.
353 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
Peter Thatcher7cbd1882015-09-18 01:54:52354 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11355 LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
356 << "from " << addr.ToSensitiveString();
357 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
358 STUN_ERROR_REASON_BAD_REQUEST);
359 return true;
360 }
361
362 // If the username is bad or unknown, fail with a 401 Unauthorized.
363 std::string local_ufrag;
364 std::string remote_ufrag;
Peter Thatcher7cbd1882015-09-18 01:54:52365 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
henrike@webrtc.org269fb4b2014-10-28 22:20:11366 local_ufrag != username_fragment()) {
367 LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
368 << local_ufrag << " from "
369 << addr.ToSensitiveString();
370 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
371 STUN_ERROR_REASON_UNAUTHORIZED);
372 return true;
373 }
374
henrike@webrtc.org269fb4b2014-10-28 22:20:11375 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
Peter Thatcher7cbd1882015-09-18 01:54:52376 if (!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11377 LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
jiayl@webrtc.orgdacdd942015-01-23 17:33:34378 << "from " << addr.ToSensitiveString()
379 << ", password_=" << password_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11380 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
381 STUN_ERROR_REASON_UNAUTHORIZED);
382 return true;
383 }
384 out_username->assign(remote_ufrag);
385 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
386 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
387 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
388 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
389 LOG_J(LS_ERROR, this) << "Received STUN binding error:"
390 << " class=" << error_code->eclass()
391 << " number=" << error_code->number()
392 << " reason='" << error_code->reason() << "'"
393 << " from " << addr.ToSensitiveString();
394 // Return message to allow error-specific processing
395 } else {
396 LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
397 << "code from " << addr.ToSensitiveString();
398 return true;
399 }
400 }
401 // NOTE: Username should not be used in verifying response messages.
402 out_username->clear();
403 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
404 LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
405 << " from " << addr.ToSensitiveString();
406 out_username->clear();
407 // No stun attributes will be verified, if it's stun indication message.
408 // Returning from end of the this method.
409 } else {
410 LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
411 << stun_msg->type() << ") from "
412 << addr.ToSensitiveString();
413 return true;
414 }
415
416 // Return the STUN message found.
kwiberg6baec032016-03-15 18:09:39417 *out_msg = std::move(stun_msg);
henrike@webrtc.org269fb4b2014-10-28 22:20:11418 return true;
419}
420
421bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
422 int family = ip().family();
423 // We use single-stack sockets, so families must match.
424 if (addr.family() != family) {
425 return false;
426 }
427 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
Peter Thatcherb8b01432015-07-07 23:45:53428 if (family == AF_INET6 &&
429 (IPIsLinkLocal(ip()) != IPIsLinkLocal(addr.ipaddr()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11430 return false;
431 }
432 return true;
433}
434
435bool Port::ParseStunUsername(const StunMessage* stun_msg,
436 std::string* local_ufrag,
Peter Thatcher7cbd1882015-09-18 01:54:52437 std::string* remote_ufrag) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11438 // The packet must include a username that either begins or ends with our
439 // fragment. It should begin with our fragment if it is a request and it
440 // should end with our fragment if it is a response.
441 local_ufrag->clear();
442 remote_ufrag->clear();
443 const StunByteStringAttribute* username_attr =
444 stun_msg->GetByteString(STUN_ATTR_USERNAME);
445 if (username_attr == NULL)
446 return false;
447
Peter Thatcher7cbd1882015-09-18 01:54:52448 // RFRAG:LFRAG
449 const std::string username = username_attr->GetString();
450 size_t colon_pos = username.find(":");
451 if (colon_pos == std::string::npos) {
452 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11453 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11454
Peter Thatcher7cbd1882015-09-18 01:54:52455 *local_ufrag = username.substr(0, colon_pos);
456 *remote_ufrag = username.substr(colon_pos + 1, username.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11457 return true;
458}
459
460bool Port::MaybeIceRoleConflict(
461 const rtc::SocketAddress& addr, IceMessage* stun_msg,
462 const std::string& remote_ufrag) {
463 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
464 bool ret = true;
465 IceRole remote_ice_role = ICEROLE_UNKNOWN;
Peter Boström0c4e06b2015-10-07 10:23:21466 uint64_t remote_tiebreaker = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11467 const StunUInt64Attribute* stun_attr =
468 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
469 if (stun_attr) {
470 remote_ice_role = ICEROLE_CONTROLLING;
471 remote_tiebreaker = stun_attr->value();
472 }
473
474 // If |remote_ufrag| is same as port local username fragment and
475 // tie breaker value received in the ping message matches port
476 // tiebreaker value this must be a loopback call.
477 // We will treat this as valid scenario.
478 if (remote_ice_role == ICEROLE_CONTROLLING &&
479 username_fragment() == remote_ufrag &&
480 remote_tiebreaker == IceTiebreaker()) {
481 return true;
482 }
483
484 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
485 if (stun_attr) {
486 remote_ice_role = ICEROLE_CONTROLLED;
487 remote_tiebreaker = stun_attr->value();
488 }
489
490 switch (ice_role_) {
491 case ICEROLE_CONTROLLING:
492 if (ICEROLE_CONTROLLING == remote_ice_role) {
493 if (remote_tiebreaker >= tiebreaker_) {
494 SignalRoleConflict(this);
495 } else {
496 // Send Role Conflict (487) error response.
497 SendBindingErrorResponse(stun_msg, addr,
498 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
499 ret = false;
500 }
501 }
502 break;
503 case ICEROLE_CONTROLLED:
504 if (ICEROLE_CONTROLLED == remote_ice_role) {
505 if (remote_tiebreaker < tiebreaker_) {
506 SignalRoleConflict(this);
507 } else {
508 // Send Role Conflict (487) error response.
509 SendBindingErrorResponse(stun_msg, addr,
510 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
511 ret = false;
512 }
513 }
514 break;
515 default:
516 ASSERT(false);
517 }
518 return ret;
519}
520
521void Port::CreateStunUsername(const std::string& remote_username,
522 std::string* stun_username_attr_str) const {
523 stun_username_attr_str->clear();
524 *stun_username_attr_str = remote_username;
Peter Thatcher7cbd1882015-09-18 01:54:52525 stun_username_attr_str->append(":");
henrike@webrtc.org269fb4b2014-10-28 22:20:11526 stun_username_attr_str->append(username_fragment());
527}
528
529void Port::SendBindingResponse(StunMessage* request,
530 const rtc::SocketAddress& addr) {
531 ASSERT(request->type() == STUN_BINDING_REQUEST);
532
533 // Retrieve the username from the request.
534 const StunByteStringAttribute* username_attr =
535 request->GetByteString(STUN_ATTR_USERNAME);
536 ASSERT(username_attr != NULL);
537 if (username_attr == NULL) {
538 // No valid username, skip the response.
539 return;
540 }
541
542 // Fill in the response message.
543 StunMessage response;
544 response.SetType(STUN_BINDING_RESPONSE);
545 response.SetTransactionID(request->transaction_id());
546 const StunUInt32Attribute* retransmit_attr =
547 request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
548 if (retransmit_attr) {
549 // Inherit the incoming retransmit value in the response so the other side
550 // can see our view of lost pings.
551 response.AddAttribute(new StunUInt32Attribute(
552 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
553
554 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
555 LOG_J(LS_INFO, this)
556 << "Received a remote ping with high retransmit count: "
557 << retransmit_attr->value();
558 }
559 }
560
Peter Thatcher7cbd1882015-09-18 01:54:52561 response.AddAttribute(
562 new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
563 response.AddMessageIntegrity(password_);
564 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11565
566 // Send the response message.
jbauchf1f87202016-03-30 13:43:37567 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11568 response.Write(&buf);
569 rtc::PacketOptions options(DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 17:40:45570 auto err = SendTo(buf.Data(), buf.Length(), addr, options, false);
571 if (err < 0) {
572 LOG_J(LS_ERROR, this)
573 << "Failed to send STUN ping response"
574 << ", to=" << addr.ToSensitiveString()
575 << ", err=" << err
576 << ", id=" << rtc::hex_encode(response.transaction_id());
577 } else {
578 // Log at LS_INFO if we send a stun ping response on an unwritable
579 // connection.
honghaiz9b5ee9c2015-11-11 21:19:17580 Connection* conn = GetConnection(addr);
Peter Thatcher1cf6f812015-05-15 17:40:45581 rtc::LoggingSeverity sev = (conn && !conn->writable()) ?
582 rtc::LS_INFO : rtc::LS_VERBOSE;
583 LOG_JV(sev, this)
584 << "Sent STUN ping response"
585 << ", to=" << addr.ToSensitiveString()
586 << ", id=" << rtc::hex_encode(response.transaction_id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11587 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11588}
589
590void Port::SendBindingErrorResponse(StunMessage* request,
591 const rtc::SocketAddress& addr,
592 int error_code, const std::string& reason) {
593 ASSERT(request->type() == STUN_BINDING_REQUEST);
594
595 // Fill in the response message.
596 StunMessage response;
597 response.SetType(STUN_BINDING_ERROR_RESPONSE);
598 response.SetTransactionID(request->transaction_id());
599
600 // When doing GICE, we need to write out the error code incorrectly to
601 // maintain backwards compatiblility.
602 StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
Peter Thatcher7cbd1882015-09-18 01:54:52603 error_attr->SetCode(error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11604 error_attr->SetReason(reason);
605 response.AddAttribute(error_attr);
606
Peter Thatcher7cbd1882015-09-18 01:54:52607 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
608 // because we don't have enough information to determine the shared secret.
609 if (error_code != STUN_ERROR_BAD_REQUEST &&
610 error_code != STUN_ERROR_UNAUTHORIZED)
611 response.AddMessageIntegrity(password_);
612 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11613
614 // Send the response message.
jbauchf1f87202016-03-30 13:43:37615 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11616 response.Write(&buf);
617 rtc::PacketOptions options(DefaultDscpValue());
618 SendTo(buf.Data(), buf.Length(), addr, options, false);
619 LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
620 << " to " << addr.ToSensitiveString();
621}
622
623void Port::OnMessage(rtc::Message *pmsg) {
honghaizd0b31432015-09-30 19:42:17624 ASSERT(pmsg->message_id == MSG_DEAD);
625 if (dead()) {
626 Destroy();
627 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11628}
629
honghaize3c6c822016-02-17 21:00:28630void Port::OnNetworkInactive(const rtc::Network* network) {
631 ASSERT(network == network_);
632 SignalNetworkInactive(this);
633}
634
henrike@webrtc.org269fb4b2014-10-28 22:20:11635std::string Port::ToString() const {
636 std::stringstream ss;
honghaize3c6c822016-02-17 21:00:28637 ss << "Port[" << std::hex << this << std::dec << ":" << content_name_ << ":"
638 << component_ << ":" << generation_ << ":" << type_ << ":"
639 << network_->ToString() << "]";
henrike@webrtc.org269fb4b2014-10-28 22:20:11640 return ss.str();
641}
642
643void Port::EnablePortPackets() {
644 enable_port_packets_ = true;
645}
646
647void Port::OnConnectionDestroyed(Connection* conn) {
648 AddressMap::iterator iter =
649 connections_.find(conn->remote_candidate().address());
650 ASSERT(iter != connections_.end());
651 connections_.erase(iter);
652
honghaizd0b31432015-09-30 19:42:17653 // On the controlled side, ports time out after all connections fail.
654 // Note: If a new connection is added after this message is posted, but it
655 // fails and is removed before kPortTimeoutDelay, then this message will
656 // still cause the Port to be destroyed.
657 if (dead()) {
658 thread_->PostDelayed(timeout_delay_, this, MSG_DEAD);
659 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11660}
661
662void Port::Destroy() {
663 ASSERT(connections_.empty());
664 LOG_J(LS_INFO, this) << "Port deleted";
665 SignalDestroyed(this);
666 delete this;
667}
668
henrike@webrtc.org269fb4b2014-10-28 22:20:11669const std::string Port::username_fragment() const {
Peter Thatcher7cbd1882015-09-18 01:54:52670 return ice_username_fragment_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11671}
672
673// A ConnectionRequest is a simple STUN ping used to determine writability.
674class ConnectionRequest : public StunRequest {
675 public:
676 explicit ConnectionRequest(Connection* connection)
677 : StunRequest(new IceMessage()),
678 connection_(connection) {
679 }
680
681 virtual ~ConnectionRequest() {
682 }
683
Peter Thatcher1cf6f812015-05-15 17:40:45684 void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11685 request->SetType(STUN_BINDING_REQUEST);
686 std::string username;
687 connection_->port()->CreateStunUsername(
688 connection_->remote_candidate().username(), &username);
689 request->AddAttribute(
690 new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
691
692 // connection_ already holds this ping, so subtract one from count.
693 if (connection_->port()->send_retransmit_count_attribute()) {
694 request->AddAttribute(new StunUInt32Attribute(
695 STUN_ATTR_RETRANSMIT_COUNT,
Peter Boström0c4e06b2015-10-07 10:23:21696 static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
697 1)));
henrike@webrtc.org269fb4b2014-10-28 22:20:11698 }
honghaiza0c44ea2016-03-23 23:07:48699 uint32_t network_info = connection_->port()->Network()->id();
700 network_info = (network_info << 16) | connection_->port()->network_cost();
701 request->AddAttribute(
702 new StunUInt32Attribute(STUN_ATTR_NETWORK_INFO, network_info));
henrike@webrtc.org269fb4b2014-10-28 22:20:11703
Peter Thatcher7cbd1882015-09-18 01:54:52704 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
705 if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
706 request->AddAttribute(new StunUInt64Attribute(
707 STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
708 // Since we are trying aggressive nomination, sending USE-CANDIDATE
709 // attribute in every ping.
710 // If we are dealing with a ice-lite end point, nomination flag
711 // in Connection will be set to false by default. Once the connection
712 // becomes "best connection", nomination flag will be turned on.
713 if (connection_->use_candidate_attr()) {
714 request->AddAttribute(new StunByteStringAttribute(
715 STUN_ATTR_USE_CANDIDATE));
henrike@webrtc.org269fb4b2014-10-28 22:20:11716 }
Peter Thatcher7cbd1882015-09-18 01:54:52717 } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
718 request->AddAttribute(new StunUInt64Attribute(
719 STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
720 } else {
721 ASSERT(false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11722 }
Peter Thatcher7cbd1882015-09-18 01:54:52723
724 // Adding PRIORITY Attribute.
725 // Changing the type preference to Peer Reflexive and local preference
726 // and component id information is unchanged from the original priority.
727 // priority = (2^24)*(type preference) +
728 // (2^8)*(local preference) +
729 // (2^0)*(256 - component ID)
Peter Boström0c4e06b2015-10-07 10:23:21730 uint32_t prflx_priority =
731 ICE_TYPE_PREFERENCE_PRFLX << 24 |
Peter Thatcher7cbd1882015-09-18 01:54:52732 (connection_->local_candidate().priority() & 0x00FFFFFF);
733 request->AddAttribute(
734 new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
735
736 // Adding Message Integrity attribute.
737 request->AddMessageIntegrity(connection_->remote_candidate().password());
738 // Adding Fingerprint.
739 request->AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11740 }
741
Peter Thatcher1cf6f812015-05-15 17:40:45742 void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11743 connection_->OnConnectionRequestResponse(this, response);
744 }
745
Peter Thatcher1cf6f812015-05-15 17:40:45746 void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11747 connection_->OnConnectionRequestErrorResponse(this, response);
748 }
749
Peter Thatcher1cf6f812015-05-15 17:40:45750 void OnTimeout() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11751 connection_->OnConnectionRequestTimeout(this);
752 }
753
Peter Thatcher1cf6f812015-05-15 17:40:45754 void OnSent() override {
755 connection_->OnConnectionRequestSent(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11756 // Each request is sent only once. After a single delay , the request will
757 // time out.
758 timeout_ = true;
Peter Thatcher1cf6f812015-05-15 17:40:45759 }
760
761 int resend_delay() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11762 return CONNECTION_RESPONSE_TIMEOUT;
763 }
764
765 private:
766 Connection* connection_;
767};
768
769//
770// Connection
771//
772
guoweis@webrtc.org930e0042014-11-17 19:42:14773Connection::Connection(Port* port,
774 size_t index,
henrike@webrtc.org269fb4b2014-10-28 22:20:11775 const Candidate& remote_candidate)
guoweis@webrtc.org930e0042014-11-17 19:42:14776 : port_(port),
777 local_candidate_index_(index),
778 remote_candidate_(remote_candidate),
guoweis@webrtc.org930e0042014-11-17 19:42:14779 write_state_(STATE_WRITE_INIT),
Peter Thatcher04ac81f2015-09-21 18:48:28780 receiving_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14781 connected_(true),
782 pruned_(false),
783 use_candidate_attr_(false),
honghaiz5a3acd82015-08-20 22:53:17784 nominated_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14785 remote_ice_mode_(ICEMODE_FULL),
786 requests_(port->thread()),
787 rtt_(DEFAULT_RTT),
788 last_ping_sent_(0),
789 last_ping_received_(0),
790 last_data_received_(0),
791 last_ping_response_received_(0),
Honghai Zhang82d78622016-05-06 18:29:15792 recv_rate_tracker_(100, 10u),
793 send_rate_tracker_(100, 10u),
guoweis@webrtc.org930e0042014-11-17 19:42:14794 sent_packets_discarded_(0),
795 sent_packets_total_(0),
796 reported_(false),
Peter Thatcher04ac81f2015-09-21 18:48:28797 state_(STATE_WAITING),
Honghai Zhang2b342bf2015-09-30 16:51:58798 receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT),
nisse1bffc1d2016-05-02 15:18:55799 time_created_ms_(rtc::TimeMillis()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11800 // All of our connections start in WAITING state.
801 // TODO(mallinath) - Start connections from STATE_FROZEN.
802 // Wire up to send stun packets
803 requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
804 LOG_J(LS_INFO, this) << "Connection created";
805}
806
807Connection::~Connection() {
808}
809
810const Candidate& Connection::local_candidate() const {
811 ASSERT(local_candidate_index_ < port_->Candidates().size());
812 return port_->Candidates()[local_candidate_index_];
813}
814
Honghai Zhangcc411c02016-03-30 00:27:21815const Candidate& Connection::remote_candidate() const {
816 return remote_candidate_;
817}
818
Peter Boström0c4e06b2015-10-07 10:23:21819uint64_t Connection::priority() const {
820 uint64_t priority = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11821 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
822 // Let G be the priority for the candidate provided by the controlling
823 // agent. Let D be the priority for the candidate provided by the
824 // controlled agent.
825 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
826 IceRole role = port_->GetIceRole();
827 if (role != ICEROLE_UNKNOWN) {
Peter Boström0c4e06b2015-10-07 10:23:21828 uint32_t g = 0;
829 uint32_t d = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11830 if (role == ICEROLE_CONTROLLING) {
831 g = local_candidate().priority();
832 d = remote_candidate_.priority();
833 } else {
834 g = remote_candidate_.priority();
835 d = local_candidate().priority();
836 }
andresp@webrtc.orgff689be2015-02-12 11:54:26837 priority = std::min(g, d);
henrike@webrtc.org269fb4b2014-10-28 22:20:11838 priority = priority << 32;
andresp@webrtc.orgff689be2015-02-12 11:54:26839 priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11840 }
841 return priority;
842}
843
henrike@webrtc.org269fb4b2014-10-28 22:20:11844void Connection::set_write_state(WriteState value) {
845 WriteState old_value = write_state_;
846 write_state_ = value;
847 if (value != old_value) {
guoweis@webrtc.org8c9ff202014-12-04 07:56:02848 LOG_J(LS_VERBOSE, this) << "set_write_state from: " << old_value << " to "
849 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11850 SignalStateChange(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11851 }
852}
853
Peter Thatcher04ac81f2015-09-21 18:48:28854void Connection::set_receiving(bool value) {
855 if (value != receiving_) {
856 LOG_J(LS_VERBOSE, this) << "set_receiving to " << value;
857 receiving_ = value;
858 SignalStateChange(this);
Peter Thatcher04ac81f2015-09-21 18:48:28859 }
860}
861
henrike@webrtc.org269fb4b2014-10-28 22:20:11862void Connection::set_state(State state) {
863 State old_state = state_;
864 state_ = state;
865 if (state != old_state) {
866 LOG_J(LS_VERBOSE, this) << "set_state";
867 }
868}
869
870void Connection::set_connected(bool value) {
871 bool old_value = connected_;
872 connected_ = value;
873 if (value != old_value) {
Guo-wei Shiehbe508a12015-04-06 19:48:47874 LOG_J(LS_VERBOSE, this) << "set_connected from: " << old_value << " to "
875 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11876 }
877}
878
879void Connection::set_use_candidate_attr(bool enable) {
880 use_candidate_attr_ = enable;
881}
882
883void Connection::OnSendStunPacket(const void* data, size_t size,
884 StunRequest* req) {
885 rtc::PacketOptions options(port_->DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 17:40:45886 auto err = port_->SendTo(
887 data, size, remote_candidate_.address(), options, false);
888 if (err < 0) {
889 LOG_J(LS_WARNING, this) << "Failed to send STUN ping "
890 << " err=" << err
891 << " id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11892 }
893}
894
895void Connection::OnReadPacket(
896 const char* data, size_t size, const rtc::PacketTime& packet_time) {
kwiberg3ec46792016-04-27 14:22:53897 std::unique_ptr<IceMessage> msg;
henrike@webrtc.org269fb4b2014-10-28 22:20:11898 std::string remote_ufrag;
899 const rtc::SocketAddress& addr(remote_candidate_.address());
kwiberg6baec032016-03-15 18:09:39900 if (!port_->GetStunMessage(data, size, addr, &msg, &remote_ufrag)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11901 // The packet did not parse as a valid STUN message
Peter Thatcher04ac81f2015-09-21 18:48:28902 // This is a data packet, pass it along.
903 set_receiving(true);
nisse1bffc1d2016-05-02 15:18:55904 last_data_received_ = rtc::TimeMillis();
Peter Thatcher04ac81f2015-09-21 18:48:28905 recv_rate_tracker_.AddSamples(size);
906 SignalReadPacket(this, data, size, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11907
Peter Thatcher04ac81f2015-09-21 18:48:28908 // If timed out sending writability checks, start up again
909 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
910 LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
911 << "Resetting state to STATE_WRITE_INIT.";
912 set_write_state(STATE_WRITE_INIT);
henrike@webrtc.org269fb4b2014-10-28 22:20:11913 }
914 } else if (!msg) {
915 // The packet was STUN, but failed a check and was handled internally.
916 } else {
917 // The packet is STUN and passed the Port checks.
918 // Perform our own checks to ensure this packet is valid.
honghaizd0b31432015-09-30 19:42:17919 // If this is a STUN request, then update the receiving bit and respond.
henrike@webrtc.org269fb4b2014-10-28 22:20:11920 // If this is a STUN response, then update the writable bit.
Peter Thatcher1cf6f812015-05-15 17:40:45921 // Log at LS_INFO if we receive a ping on an unwritable connection.
922 rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11923 switch (msg->type()) {
924 case STUN_BINDING_REQUEST:
Peter Thatcher1cf6f812015-05-15 17:40:45925 LOG_JV(sev, this) << "Received STUN ping"
926 << ", id=" << rtc::hex_encode(msg->transaction_id());
927
henrike@webrtc.org269fb4b2014-10-28 22:20:11928 if (remote_ufrag == remote_candidate_.username()) {
honghaiz9b5ee9c2015-11-11 21:19:17929 HandleBindingRequest(msg.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11930 } else {
931 // The packet had the right local username, but the remote username
932 // was not the right one for the remote address.
933 LOG_J(LS_ERROR, this)
934 << "Received STUN request with bad remote username "
935 << remote_ufrag;
936 port_->SendBindingErrorResponse(msg.get(), addr,
937 STUN_ERROR_UNAUTHORIZED,
938 STUN_ERROR_REASON_UNAUTHORIZED);
939
940 }
941 break;
942
943 // Response from remote peer. Does it match request sent?
944 // This doesn't just check, it makes callbacks if transaction
945 // id's match.
946 case STUN_BINDING_RESPONSE:
947 case STUN_BINDING_ERROR_RESPONSE:
Peter Thatcher7cbd1882015-09-18 01:54:52948 if (msg->ValidateMessageIntegrity(
henrike@webrtc.org269fb4b2014-10-28 22:20:11949 data, size, remote_candidate().password())) {
950 requests_.CheckResponse(msg.get());
951 }
952 // Otherwise silently discard the response message.
953 break;
954
honghaizd0b31432015-09-30 19:42:17955 // Remote end point sent an STUN indication instead of regular binding
956 // request. In this case |last_ping_received_| will be updated but no
957 // response will be sent.
henrike@webrtc.org269fb4b2014-10-28 22:20:11958 case STUN_BINDING_INDICATION:
Peter Thatcher04ac81f2015-09-21 18:48:28959 ReceivedPing();
henrike@webrtc.org269fb4b2014-10-28 22:20:11960 break;
961
962 default:
963 ASSERT(false);
964 break;
965 }
966 }
967}
968
honghaiz9b5ee9c2015-11-11 21:19:17969void Connection::HandleBindingRequest(IceMessage* msg) {
970 // This connection should now be receiving.
971 ReceivedPing();
972
973 const rtc::SocketAddress& remote_addr = remote_candidate_.address();
974 const std::string& remote_ufrag = remote_candidate_.username();
975 // Check for role conflicts.
976 if (!port_->MaybeIceRoleConflict(remote_addr, msg, remote_ufrag)) {
977 // Received conflicting role from the peer.
978 LOG(LS_INFO) << "Received conflicting role from the peer.";
979 return;
980 }
981
982 // This is a validated stun request from remote peer.
983 port_->SendBindingResponse(msg, remote_addr);
984
985 // If it timed out on writing check, start up again
986 if (!pruned_ && write_state_ == STATE_WRITE_TIMEOUT) {
987 set_write_state(STATE_WRITE_INIT);
988 }
989
990 if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
991 const StunByteStringAttribute* use_candidate_attr =
992 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
993 if (use_candidate_attr) {
994 set_nominated(true);
995 SignalNominated(this);
996 }
997 }
998}
999
henrike@webrtc.org269fb4b2014-10-28 22:20:111000void Connection::OnReadyToSend() {
1001 if (write_state_ == STATE_WRITABLE) {
1002 SignalReadyToSend(this);
1003 }
1004}
1005
1006void Connection::Prune() {
Honghai Zhang2b342bf2015-09-30 16:51:581007 if (!pruned_ || active()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:111008 LOG_J(LS_VERBOSE, this) << "Connection pruned";
1009 pruned_ = true;
1010 requests_.Clear();
1011 set_write_state(STATE_WRITE_TIMEOUT);
1012 }
1013}
1014
1015void Connection::Destroy() {
1016 LOG_J(LS_VERBOSE, this) << "Connection destroyed";
Peter Thatcher04ac81f2015-09-21 18:48:281017 port_->thread()->Post(this, MSG_DELETE);
henrike@webrtc.org269fb4b2014-10-28 22:20:111018}
1019
deadbeef376e1232015-11-25 17:00:081020void Connection::FailAndDestroy() {
1021 set_state(Connection::STATE_FAILED);
1022 Destroy();
1023}
1024
Peter Thatcher1cf6f812015-05-15 17:40:451025void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
1026 std::ostringstream oss;
1027 oss << std::boolalpha;
1028 if (pings_since_last_response_.size() > max) {
1029 for (size_t i = 0; i < max; i++) {
1030 const SentPing& ping = pings_since_last_response_[i];
1031 oss << rtc::hex_encode(ping.id) << " ";
1032 }
1033 oss << "... " << (pings_since_last_response_.size() - max) << " more";
1034 } else {
1035 for (const SentPing& ping : pings_since_last_response_) {
1036 oss << rtc::hex_encode(ping.id) << " ";
1037 }
1038 }
1039 *s = oss.str();
1040}
1041
honghaiz34b11eb2016-03-16 15:55:441042void Connection::UpdateState(int64_t now) {
1043 int rtt = ConservativeRTTEstimate(rtt_);
henrike@webrtc.org269fb4b2014-10-28 22:20:111044
Peter Thatcherb2d26232015-05-15 18:25:141045 if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
Peter Thatcher1cf6f812015-05-15 17:40:451046 std::string pings;
1047 PrintPingsSinceLastResponse(&pings, 5);
1048 LOG_J(LS_VERBOSE, this) << "UpdateState()"
1049 << ", ms since last received response="
1050 << now - last_ping_response_received_
1051 << ", ms since last received data="
1052 << now - last_data_received_
1053 << ", rtt=" << rtt
1054 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:111055 }
henrike@webrtc.org269fb4b2014-10-28 22:20:111056
henrike@webrtc.org269fb4b2014-10-28 22:20:111057 // Check the writable state. (The order of these checks is important.)
1058 //
1059 // Before becoming unwritable, we allow for a fixed number of pings to fail
1060 // (i.e., receive no response). We also have to give the response time to
1061 // get back, so we include a conservative estimate of this.
1062 //
1063 // Before timing out writability, we give a fixed amount of time. This is to
1064 // allow for changes in network conditions.
1065
1066 if ((write_state_ == STATE_WRITABLE) &&
1067 TooManyFailures(pings_since_last_response_,
1068 CONNECTION_WRITE_CONNECT_FAILURES,
1069 rtt,
1070 now) &&
1071 TooLongWithoutResponse(pings_since_last_response_,
1072 CONNECTION_WRITE_CONNECT_TIMEOUT,
1073 now)) {
Peter Boström0c4e06b2015-10-07 10:23:211074 uint32_t max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
henrike@webrtc.org269fb4b2014-10-28 22:20:111075 LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
1076 << " ping failures and "
Peter Thatcher1cf6f812015-05-15 17:40:451077 << now - pings_since_last_response_[0].sent_time
henrike@webrtc.org269fb4b2014-10-28 22:20:111078 << " ms without a response,"
1079 << " ms since last received ping="
1080 << now - last_ping_received_
1081 << " ms since last received data="
1082 << now - last_data_received_
1083 << " rtt=" << rtt;
1084 set_write_state(STATE_WRITE_UNRELIABLE);
1085 }
henrike@webrtc.org269fb4b2014-10-28 22:20:111086 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
1087 write_state_ == STATE_WRITE_INIT) &&
1088 TooLongWithoutResponse(pings_since_last_response_,
1089 CONNECTION_WRITE_TIMEOUT,
1090 now)) {
1091 LOG_J(LS_INFO, this) << "Timed out after "
Peter Thatcher1cf6f812015-05-15 17:40:451092 << now - pings_since_last_response_[0].sent_time
1093 << " ms without a response"
1094 << ", rtt=" << rtt;
henrike@webrtc.org269fb4b2014-10-28 22:20:111095 set_write_state(STATE_WRITE_TIMEOUT);
1096 }
Peter Thatcher04ac81f2015-09-21 18:48:281097
1098 // Check the receiving state.
honghaiz34b11eb2016-03-16 15:55:441099 int64_t last_recv_time = last_received();
Peter Thatcher04ac81f2015-09-21 18:48:281100 bool receiving = now <= last_recv_time + receiving_timeout_;
1101 set_receiving(receiving);
Honghai Zhang2b342bf2015-09-30 16:51:581102 if (dead(now)) {
1103 Destroy();
1104 }
henrike@webrtc.org269fb4b2014-10-28 22:20:111105}
1106
honghaiz34b11eb2016-03-16 15:55:441107void Connection::Ping(int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:111108 last_ping_sent_ = now;
henrike@webrtc.org269fb4b2014-10-28 22:20:111109 ConnectionRequest *req = new ConnectionRequest(this);
Peter Thatcher1cf6f812015-05-15 17:40:451110 pings_since_last_response_.push_back(SentPing(req->id(), now));
1111 LOG_J(LS_VERBOSE, this) << "Sending STUN ping "
1112 << ", id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:111113 requests_.Send(req);
1114 state_ = STATE_INPROGRESS;
1115}
1116
1117void Connection::ReceivedPing() {
Peter Thatcher04ac81f2015-09-21 18:48:281118 set_receiving(true);
nisse1bffc1d2016-05-02 15:18:551119 last_ping_received_ = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:111120}
1121
Peter Thatcher1fe120a2015-06-10 18:33:171122void Connection::ReceivedPingResponse() {
1123 // We've already validated that this is a STUN binding response with
1124 // the correct local and remote username for this connection.
1125 // So if we're not already, become writable. We may be bringing a pruned
1126 // connection back to life, but if we don't really want it, we can always
1127 // prune it again.
Peter Thatcher04ac81f2015-09-21 18:48:281128 set_receiving(true);
Peter Thatcher1fe120a2015-06-10 18:33:171129 set_write_state(STATE_WRITABLE);
1130 set_state(STATE_SUCCEEDED);
1131 pings_since_last_response_.clear();
nisse1bffc1d2016-05-02 15:18:551132 last_ping_response_received_ = rtc::TimeMillis();
Peter Thatcher1fe120a2015-06-10 18:33:171133}
1134
honghaiz34b11eb2016-03-16 15:55:441135bool Connection::dead(int64_t now) const {
honghaiz37389b42016-01-05 05:57:331136 if (last_received() > 0) {
1137 // If it has ever received anything, we keep it alive until it hasn't
1138 // received anything for DEAD_CONNECTION_RECEIVE_TIMEOUT. This covers the
1139 // normal case of a successfully used connection that stops working. This
1140 // also allows a remote peer to continue pinging over a locally inactive
1141 // (pruned) connection.
1142 return (now > (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT));
1143 }
1144
1145 if (active()) {
1146 // If it has never received anything, keep it alive as long as it is
1147 // actively pinging and not pruned. Otherwise, the connection might be
1148 // deleted before it has a chance to ping. This is the normal case for a
1149 // new connection that is pinging but hasn't received anything yet.
Honghai Zhang2b342bf2015-09-30 16:51:581150 return false;
1151 }
1152
honghaiz37389b42016-01-05 05:57:331153 // If it has never received anything and is not actively pinging (pruned), we
1154 // keep it around for at least MIN_CONNECTION_LIFETIME to prevent connections
1155 // from being pruned too quickly during a network change event when two
1156 // networks would be up simultaneously but only for a brief period.
1157 return now > (time_created_ms_ + MIN_CONNECTION_LIFETIME);
Honghai Zhang2b342bf2015-09-30 16:51:581158}
1159
guoweis@webrtc.org8c9ff202014-12-04 07:56:021160std::string Connection::ToDebugId() const {
1161 std::stringstream ss;
1162 ss << std::hex << this;
1163 return ss.str();
1164}
1165
honghaize1a0c942016-02-16 22:54:561166uint32_t Connection::ComputeNetworkCost() const {
1167 // TODO(honghaiz): Will add rtt as part of the network cost.
1168 return local_candidate().network_cost() + remote_candidate_.network_cost();
1169}
1170
henrike@webrtc.org269fb4b2014-10-28 22:20:111171std::string Connection::ToString() const {
1172 const char CONNECT_STATE_ABBREV[2] = {
1173 '-', // not connected (false)
1174 'C', // connected (true)
1175 };
Peter Thatcher04ac81f2015-09-21 18:48:281176 const char RECEIVE_STATE_ABBREV[2] = {
1177 '-', // not receiving (false)
1178 'R', // receiving (true)
henrike@webrtc.org269fb4b2014-10-28 22:20:111179 };
1180 const char WRITE_STATE_ABBREV[4] = {
1181 'W', // STATE_WRITABLE
1182 'w', // STATE_WRITE_UNRELIABLE
1183 '-', // STATE_WRITE_INIT
1184 'x', // STATE_WRITE_TIMEOUT
1185 };
1186 const std::string ICESTATE[4] = {
1187 "W", // STATE_WAITING
1188 "I", // STATE_INPROGRESS
1189 "S", // STATE_SUCCEEDED
1190 "F" // STATE_FAILED
1191 };
1192 const Candidate& local = local_candidate();
1193 const Candidate& remote = remote_candidate();
1194 std::stringstream ss;
guoweis@webrtc.org8c9ff202014-12-04 07:56:021195 ss << "Conn[" << ToDebugId()
1196 << ":" << port_->content_name()
henrike@webrtc.org269fb4b2014-10-28 22:20:111197 << ":" << local.id() << ":" << local.component()
1198 << ":" << local.generation()
1199 << ":" << local.type() << ":" << local.protocol()
1200 << ":" << local.address().ToSensitiveString()
1201 << "->" << remote.id() << ":" << remote.component()
1202 << ":" << remote.priority()
1203 << ":" << remote.type() << ":"
1204 << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
1205 << CONNECT_STATE_ABBREV[connected()]
Peter Thatcher04ac81f2015-09-21 18:48:281206 << RECEIVE_STATE_ABBREV[receiving()]
henrike@webrtc.org269fb4b2014-10-28 22:20:111207 << WRITE_STATE_ABBREV[write_state()]
1208 << ICESTATE[state()] << "|"
1209 << priority() << "|";
1210 if (rtt_ < DEFAULT_RTT) {
1211 ss << rtt_ << "]";
1212 } else {
1213 ss << "-]";
1214 }
1215 return ss.str();
1216}
1217
1218std::string Connection::ToSensitiveString() const {
1219 return ToString();
1220}
1221
1222void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1223 StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 17:40:451224 // Log at LS_INFO if we receive a ping response on an unwritable
1225 // connection.
1226 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1227
honghaiz34b11eb2016-03-16 15:55:441228 int rtt = request->Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:111229
Peter Thatcher1fe120a2015-06-10 18:33:171230 ReceivedPingResponse();
henrike@webrtc.org269fb4b2014-10-28 22:20:111231
Peter Thatcherb2d26232015-05-15 18:25:141232 if (LOG_CHECK_LEVEL_V(sev)) {
Peter Thatcher42af6ca2015-05-15 19:23:271233 bool use_candidate = (
1234 response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr);
Peter Thatcher1cf6f812015-05-15 17:40:451235 std::string pings;
1236 PrintPingsSinceLastResponse(&pings, 5);
1237 LOG_JV(sev, this) << "Received STUN ping response"
Peter Thatcher42af6ca2015-05-15 19:23:271238 << ", id=" << rtc::hex_encode(request->id())
1239 << ", code=0" // Makes logging easier to parse.
1240 << ", rtt=" << rtt
1241 << ", use_candidate=" << use_candidate
1242 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:111243 }
1244
henrike@webrtc.org269fb4b2014-10-28 22:20:111245 rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
1246
Peter Thatcher7cbd1882015-09-18 01:54:521247 MaybeAddPrflxCandidate(request, response);
henrike@webrtc.org269fb4b2014-10-28 22:20:111248}
1249
1250void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1251 StunMessage* response) {
1252 const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
1253 int error_code = STUN_ERROR_GLOBAL_FAILURE;
1254 if (error_attr) {
Peter Thatcher7cbd1882015-09-18 01:54:521255 error_code = error_attr->code();
henrike@webrtc.org269fb4b2014-10-28 22:20:111256 }
1257
Peter Thatcher1cf6f812015-05-15 17:40:451258 LOG_J(LS_INFO, this) << "Received STUN error response"
1259 << " id=" << rtc::hex_encode(request->id())
1260 << " code=" << error_code
1261 << " rtt=" << request->Elapsed();
1262
henrike@webrtc.org269fb4b2014-10-28 22:20:111263 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1264 error_code == STUN_ERROR_SERVER_ERROR ||
1265 error_code == STUN_ERROR_UNAUTHORIZED) {
1266 // Recoverable error, retry
1267 } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1268 // Race failure, retry
1269 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1270 HandleRoleConflictFromPeer();
1271 } else {
1272 // This is not a valid connection.
1273 LOG_J(LS_ERROR, this) << "Received STUN error response, code="
1274 << error_code << "; killing connection";
deadbeef376e1232015-11-25 17:00:081275 FailAndDestroy();
henrike@webrtc.org269fb4b2014-10-28 22:20:111276 }
1277}
1278
1279void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1280 // Log at LS_INFO if we miss a ping on a writable connection.
Peter Thatcher1cf6f812015-05-15 17:40:451281 rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1282 LOG_JV(sev, this) << "Timing-out STUN ping "
1283 << rtc::hex_encode(request->id())
henrike@webrtc.org269fb4b2014-10-28 22:20:111284 << " after " << request->Elapsed() << " ms";
1285}
1286
Peter Thatcher1cf6f812015-05-15 17:40:451287void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1288 // Log at LS_INFO if we send a ping on an unwritable connection.
1289 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
Peter Thatcher42af6ca2015-05-15 19:23:271290 bool use_candidate = use_candidate_attr();
Peter Thatcher1cf6f812015-05-15 17:40:451291 LOG_JV(sev, this) << "Sent STUN ping"
Peter Thatcher42af6ca2015-05-15 19:23:271292 << ", id=" << rtc::hex_encode(request->id())
1293 << ", use_candidate=" << use_candidate;
Peter Thatcher1cf6f812015-05-15 17:40:451294}
1295
henrike@webrtc.org269fb4b2014-10-28 22:20:111296void Connection::HandleRoleConflictFromPeer() {
1297 port_->SignalRoleConflict(port_);
1298}
1299
Taylor Brandstetter0a1bc532016-04-20 01:03:261300void Connection::MaybeSetRemoteIceCredentialsAndGeneration(
1301 const std::string& ice_ufrag,
1302 const std::string& ice_pwd,
1303 int generation) {
jiayl@webrtc.orgdacdd942015-01-23 17:33:341304 if (remote_candidate_.username() == ice_ufrag &&
1305 remote_candidate_.password().empty()) {
1306 remote_candidate_.set_password(ice_pwd);
1307 }
Taylor Brandstetter0a1bc532016-04-20 01:03:261308 // TODO(deadbeef): A value of '0' for the generation is used for both
1309 // generation 0 and "generation unknown". It should be changed to an
1310 // rtc::Optional to fix this.
1311 if (remote_candidate_.username() == ice_ufrag &&
1312 remote_candidate_.password() == ice_pwd &&
1313 remote_candidate_.generation() == 0) {
1314 remote_candidate_.set_generation(generation);
1315 }
jiayl@webrtc.orgdacdd942015-01-23 17:33:341316}
1317
1318void Connection::MaybeUpdatePeerReflexiveCandidate(
1319 const Candidate& new_candidate) {
1320 if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1321 new_candidate.type() != PRFLX_PORT_TYPE &&
1322 remote_candidate_.protocol() == new_candidate.protocol() &&
1323 remote_candidate_.address() == new_candidate.address() &&
1324 remote_candidate_.username() == new_candidate.username() &&
1325 remote_candidate_.password() == new_candidate.password() &&
1326 remote_candidate_.generation() == new_candidate.generation()) {
1327 remote_candidate_ = new_candidate;
1328 }
1329}
1330
henrike@webrtc.org269fb4b2014-10-28 22:20:111331void Connection::OnMessage(rtc::Message *pmsg) {
1332 ASSERT(pmsg->message_id == MSG_DELETE);
honghaizd0b31432015-09-30 19:42:171333 LOG_J(LS_INFO, this) << "Connection deleted";
henrike@webrtc.org269fb4b2014-10-28 22:20:111334 SignalDestroyed(this);
1335 delete this;
1336}
1337
honghaiz34b11eb2016-03-16 15:55:441338int64_t Connection::last_received() const {
Peter Thatcher54360512015-07-08 18:08:351339 return std::max(last_data_received_,
1340 std::max(last_ping_received_, last_ping_response_received_));
1341}
1342
henrike@webrtc.org269fb4b2014-10-28 22:20:111343size_t Connection::recv_bytes_second() {
Tim Psiakiad13d2f2015-11-11 00:34:501344 return round(recv_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:111345}
1346
1347size_t Connection::recv_total_bytes() {
Tim Psiaki63046262015-09-14 17:38:081348 return recv_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:111349}
1350
1351size_t Connection::sent_bytes_second() {
Tim Psiakiad13d2f2015-11-11 00:34:501352 return round(send_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:111353}
1354
1355size_t Connection::sent_total_bytes() {
Tim Psiaki63046262015-09-14 17:38:081356 return send_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:111357}
1358
guoweis@webrtc.org930e0042014-11-17 19:42:141359size_t Connection::sent_discarded_packets() {
1360 return sent_packets_discarded_;
1361}
1362
1363size_t Connection::sent_total_packets() {
1364 return sent_packets_total_;
1365}
1366
henrike@webrtc.org269fb4b2014-10-28 22:20:111367void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
1368 StunMessage* response) {
1369 // RFC 5245
1370 // The agent checks the mapped address from the STUN response. If the
1371 // transport address does not match any of the local candidates that the
1372 // agent knows about, the mapped address represents a new candidate -- a
1373 // peer reflexive candidate.
1374 const StunAddressAttribute* addr =
1375 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1376 if (!addr) {
1377 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1378 << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1379 << "stun response message";
1380 return;
1381 }
1382
1383 bool known_addr = false;
1384 for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1385 if (port_->Candidates()[i].address() == addr->GetAddress()) {
1386 known_addr = true;
1387 break;
1388 }
1389 }
1390 if (known_addr) {
1391 return;
1392 }
1393
1394 // RFC 5245
1395 // Its priority is set equal to the value of the PRIORITY attribute
1396 // in the Binding request.
1397 const StunUInt32Attribute* priority_attr =
1398 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1399 if (!priority_attr) {
1400 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1401 << "No STUN_ATTR_PRIORITY found in the "
1402 << "stun response message";
1403 return;
1404 }
Peter Boström0c4e06b2015-10-07 10:23:211405 const uint32_t priority = priority_attr->value();
henrike@webrtc.org269fb4b2014-10-28 22:20:111406 std::string id = rtc::CreateRandomString(8);
1407
1408 Candidate new_local_candidate;
1409 new_local_candidate.set_id(id);
1410 new_local_candidate.set_component(local_candidate().component());
1411 new_local_candidate.set_type(PRFLX_PORT_TYPE);
1412 new_local_candidate.set_protocol(local_candidate().protocol());
1413 new_local_candidate.set_address(addr->GetAddress());
1414 new_local_candidate.set_priority(priority);
1415 new_local_candidate.set_username(local_candidate().username());
1416 new_local_candidate.set_password(local_candidate().password());
1417 new_local_candidate.set_network_name(local_candidate().network_name());
guoweis@webrtc.org950c5182014-12-16 23:01:311418 new_local_candidate.set_network_type(local_candidate().network_type());
henrike@webrtc.org269fb4b2014-10-28 22:20:111419 new_local_candidate.set_related_address(local_candidate().address());
Honghai Zhang80f1db92016-01-27 19:54:451420 new_local_candidate.set_foundation(ComputeFoundation(
1421 PRFLX_PORT_TYPE, local_candidate().protocol(),
1422 local_candidate().relay_protocol(), local_candidate().address()));
honghaiza0c44ea2016-03-23 23:07:481423 new_local_candidate.set_network_id(local_candidate().network_id());
1424 new_local_candidate.set_network_cost(local_candidate().network_cost());
henrike@webrtc.org269fb4b2014-10-28 22:20:111425
1426 // Change the local candidate of this Connection to the new prflx candidate.
1427 local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1428
1429 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1430 // Connection's local candidate has changed.
1431 SignalStateChange(this);
1432}
1433
deadbeef376e1232015-11-25 17:00:081434ProxyConnection::ProxyConnection(Port* port,
1435 size_t index,
1436 const Candidate& remote_candidate)
1437 : Connection(port, index, remote_candidate) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:111438
1439int ProxyConnection::Send(const void* data, size_t size,
1440 const rtc::PacketOptions& options) {
1441 if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
1442 error_ = EWOULDBLOCK;
1443 return SOCKET_ERROR;
1444 }
guoweis@webrtc.org930e0042014-11-17 19:42:141445 sent_packets_total_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:111446 int sent = port_->SendTo(data, size, remote_candidate_.address(),
1447 options, true);
1448 if (sent <= 0) {
1449 ASSERT(sent < 0);
1450 error_ = port_->GetError();
guoweis@webrtc.org930e0042014-11-17 19:42:141451 sent_packets_discarded_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:111452 } else {
Tim Psiaki63046262015-09-14 17:38:081453 send_rate_tracker_.AddSamples(sent);
henrike@webrtc.org269fb4b2014-10-28 22:20:111454 }
1455 return sent;
1456}
1457
1458} // namespace cricket