blob: 9207c9d04260433736e51b409f54ab6059c682ed [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"
honghaize3c6c822016-02-17 13:00:28 -080023#include "webrtc/base/network.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000024#include "webrtc/base/scoped_ptr.h"
25#include "webrtc/base/stringencode.h"
26#include "webrtc/base/stringutils.h"
27
28namespace {
29
30// Determines whether we have seen at least the given maximum number of
31// pings fail to have a response.
32inline bool TooManyFailures(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070033 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
Peter Boström0c4e06b2015-10-07 12:23:21 +020034 uint32_t maximum_failures,
honghaiz34b11eb2016-03-16 08:55:44 -070035 int rtt_estimate,
36 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000037 // If we haven't sent that many pings, then we can't have failed that many.
38 if (pings_since_last_response.size() < maximum_failures)
39 return false;
40
41 // Check if the window in which we would expect a response to the ping has
42 // already elapsed.
honghaiz34b11eb2016-03-16 08:55:44 -070043 int64_t expected_response_time =
Peter Thatcher1cf6f812015-05-15 10:40:45 -070044 pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
45 return now > expected_response_time;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000046}
47
48// Determines whether we have gone too long without seeing any response.
49inline bool TooLongWithoutResponse(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070050 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
honghaiz34b11eb2016-03-16 08:55:44 -070051 int64_t maximum_time,
52 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000053 if (pings_since_last_response.size() == 0)
54 return false;
55
Peter Thatcher1cf6f812015-05-15 10:40:45 -070056 auto first = pings_since_last_response[0];
57 return now > (first.sent_time + maximum_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000058}
59
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000060// We will restrict RTT estimates (when used for determining state) to be
61// within a reasonable range.
honghaiz34b11eb2016-03-16 08:55:44 -070062const int MINIMUM_RTT = 100; // 0.1 seconds
63const int MAXIMUM_RTT = 3000; // 3 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000064
65// When we don't have any RTT data, we have to pick something reasonable. We
66// use a large value just in case the connection is really slow.
honghaiz34b11eb2016-03-16 08:55:44 -070067const int DEFAULT_RTT = MAXIMUM_RTT;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000068
69// Computes our estimate of the RTT given the current estimate.
honghaiz34b11eb2016-03-16 08:55:44 -070070inline int ConservativeRTTEstimate(int rtt) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000071 return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000072}
73
74// Weighting of the old rtt value to new data.
75const int RTT_RATIO = 3; // 3 : 1
76
77// The delay before we begin checking if this port is useless.
78const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000079}
80
81namespace cricket {
82
83// TODO(ronghuawu): Use "host", "srflx", "prflx" and "relay". But this requires
84// the signaling part be updated correspondingly as well.
85const char LOCAL_PORT_TYPE[] = "local";
86const char STUN_PORT_TYPE[] = "stun";
87const char PRFLX_PORT_TYPE[] = "prflx";
88const char RELAY_PORT_TYPE[] = "relay";
89
90const char UDP_PROTOCOL_NAME[] = "udp";
91const char TCP_PROTOCOL_NAME[] = "tcp";
92const char SSLTCP_PROTOCOL_NAME[] = "ssltcp";
93
94static const char* const PROTO_NAMES[] = { UDP_PROTOCOL_NAME,
95 TCP_PROTOCOL_NAME,
96 SSLTCP_PROTOCOL_NAME };
97
98const char* ProtoToString(ProtocolType proto) {
99 return PROTO_NAMES[proto];
100}
101
102bool StringToProto(const char* value, ProtocolType* proto) {
103 for (size_t i = 0; i <= PROTO_LAST; ++i) {
104 if (_stricmp(PROTO_NAMES[i], value) == 0) {
105 *proto = static_cast<ProtocolType>(i);
106 return true;
107 }
108 }
109 return false;
110}
111
112// RFC 6544, TCP candidate encoding rules.
113const int DISCARD_PORT = 9;
114const char TCPTYPE_ACTIVE_STR[] = "active";
115const char TCPTYPE_PASSIVE_STR[] = "passive";
116const char TCPTYPE_SIMOPEN_STR[] = "so";
117
118// Foundation: An arbitrary string that is the same for two candidates
119// that have the same type, base IP address, protocol (UDP, TCP,
120// etc.), and STUN or TURN server. If any of these are different,
121// then the foundation will be different. Two candidate pairs with
122// the same foundation pairs are likely to have similar network
123// characteristics. Foundations are used in the frozen algorithm.
Honghai Zhang80f1db92016-01-27 11:54:45 -0800124static std::string ComputeFoundation(const std::string& type,
125 const std::string& protocol,
126 const std::string& relay_protocol,
127 const rtc::SocketAddress& base_address) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000128 std::ostringstream ost;
Honghai Zhang80f1db92016-01-27 11:54:45 -0800129 ost << type << base_address.ipaddr().ToString() << protocol << relay_protocol;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200130 return rtc::ToString<uint32_t>(rtc::ComputeCrc32(ost.str()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000131}
132
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000133Port::Port(rtc::Thread* thread,
134 rtc::PacketSocketFactory* factory,
135 rtc::Network* network,
136 const rtc::IPAddress& ip,
137 const std::string& username_fragment,
138 const std::string& password)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000139 : thread_(thread),
140 factory_(factory),
141 send_retransmit_count_attribute_(false),
142 network_(network),
143 ip_(ip),
144 min_port_(0),
145 max_port_(0),
146 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
147 generation_(0),
148 ice_username_fragment_(username_fragment),
149 password_(password),
150 timeout_delay_(kPortTimeoutDelay),
151 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000152 ice_role_(ICEROLE_UNKNOWN),
153 tiebreaker_(0),
154 shared_socket_(true),
155 candidate_filter_(CF_ALL) {
156 Construct();
157}
158
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000159Port::Port(rtc::Thread* thread,
160 const std::string& type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000161 rtc::PacketSocketFactory* factory,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000162 rtc::Network* network,
163 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200164 uint16_t min_port,
165 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000166 const std::string& username_fragment,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000167 const std::string& password)
168 : thread_(thread),
169 factory_(factory),
170 type_(type),
171 send_retransmit_count_attribute_(false),
172 network_(network),
173 ip_(ip),
174 min_port_(min_port),
175 max_port_(max_port),
176 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
177 generation_(0),
178 ice_username_fragment_(username_fragment),
179 password_(password),
180 timeout_delay_(kPortTimeoutDelay),
181 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000182 ice_role_(ICEROLE_UNKNOWN),
183 tiebreaker_(0),
184 shared_socket_(false),
185 candidate_filter_(CF_ALL) {
186 ASSERT(factory_ != NULL);
187 Construct();
188}
189
190void Port::Construct() {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700191 // TODO(pthatcher): Remove this old behavior once we're sure no one
192 // relies on it. If the username_fragment and password are empty,
193 // we should just create one.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000194 if (ice_username_fragment_.empty()) {
195 ASSERT(password_.empty());
196 ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
197 password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
198 }
honghaize3c6c822016-02-17 13:00:28 -0800199 network_->SignalInactive.connect(this, &Port::OnNetworkInactive);
honghaize1a0c942016-02-16 14:54:56 -0800200 // TODO(honghaiz): Make it configurable from user setting.
201 network_cost_ =
202 (network_->type() == rtc::ADAPTER_TYPE_CELLULAR) ? kMaxNetworkCost : 0;
203
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000204 LOG_J(LS_INFO, this) << "Port created";
205}
206
207Port::~Port() {
208 // Delete all of the remaining connections. We copy the list up front
209 // because each deletion will cause it to be modified.
210
211 std::vector<Connection*> list;
212
213 AddressMap::iterator iter = connections_.begin();
214 while (iter != connections_.end()) {
215 list.push_back(iter->second);
216 ++iter;
217 }
218
Peter Boström0c4e06b2015-10-07 12:23:21 +0200219 for (uint32_t i = 0; i < list.size(); i++)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000220 delete list[i];
221}
222
223Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
224 AddressMap::const_iterator iter = connections_.find(remote_addr);
225 if (iter != connections_.end())
226 return iter->second;
227 else
228 return NULL;
229}
230
231void Port::AddAddress(const rtc::SocketAddress& address,
232 const rtc::SocketAddress& base_address,
233 const rtc::SocketAddress& related_address,
234 const std::string& protocol,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700235 const std::string& relay_protocol,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000236 const std::string& tcptype,
237 const std::string& type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200238 uint32_t type_preference,
239 uint32_t relay_preference,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000240 bool final) {
241 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
242 ASSERT(!tcptype.empty());
243 }
244
245 Candidate c;
246 c.set_id(rtc::CreateRandomString(8));
247 c.set_component(component_);
248 c.set_type(type);
249 c.set_protocol(protocol);
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700250 c.set_relay_protocol(relay_protocol);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 c.set_tcptype(tcptype);
252 c.set_address(address);
253 c.set_priority(c.GetPriority(type_preference, network_->preference(),
254 relay_preference));
255 c.set_username(username_fragment());
256 c.set_password(password_);
257 c.set_network_name(network_->name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000258 c.set_network_type(network_->type());
honghaize1a0c942016-02-16 14:54:56 -0800259 c.set_network_cost(network_cost_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000260 c.set_generation(generation_);
261 c.set_related_address(related_address);
Honghai Zhang80f1db92016-01-27 11:54:45 -0800262 c.set_foundation(
263 ComputeFoundation(type, protocol, relay_protocol, base_address));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264 candidates_.push_back(c);
265 SignalCandidateReady(this, c);
266
267 if (final) {
268 SignalPortComplete(this);
269 }
270}
271
272void Port::AddConnection(Connection* conn) {
273 connections_[conn->remote_candidate().address()] = conn;
274 conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
275 SignalConnectionCreated(this, conn);
276}
277
278void Port::OnReadPacket(
279 const char* data, size_t size, const rtc::SocketAddress& addr,
280 ProtocolType proto) {
281 // If the user has enabled port packets, just hand this over.
282 if (enable_port_packets_) {
283 SignalReadPacket(this, data, size, addr);
284 return;
285 }
286
287 // If this is an authenticated STUN request, then signal unknown address and
288 // send back a proper binding response.
289 rtc::scoped_ptr<IceMessage> msg;
290 std::string remote_username;
kwiberg6baec032016-03-15 11:09:39 -0700291 if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000292 LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
293 << addr.ToSensitiveString() << ")";
294 } else if (!msg) {
295 // STUN message handled already
296 } else if (msg->type() == STUN_BINDING_REQUEST) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700297 LOG(LS_INFO) << "Received STUN ping "
298 << " id=" << rtc::hex_encode(msg->transaction_id())
299 << " from unknown address " << addr.ToSensitiveString();
300
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000301 // Check for role conflicts.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700302 if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000303 LOG(LS_INFO) << "Received conflicting role from the peer.";
304 return;
305 }
306
307 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
308 } else {
309 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
310 // pruned a connection for this port while it had STUN requests in flight,
311 // because we then get back responses for them, which this code correctly
312 // does not handle.
313 if (msg->type() != STUN_BINDING_RESPONSE) {
314 LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
315 << msg->type() << ") from unknown address ("
316 << addr.ToSensitiveString() << ")";
317 }
318 }
319}
320
321void Port::OnReadyToSend() {
322 AddressMap::iterator iter = connections_.begin();
323 for (; iter != connections_.end(); ++iter) {
324 iter->second->OnReadyToSend();
325 }
326}
327
328size_t Port::AddPrflxCandidate(const Candidate& local) {
329 candidates_.push_back(local);
330 return (candidates_.size() - 1);
331}
332
kwiberg6baec032016-03-15 11:09:39 -0700333bool Port::GetStunMessage(const char* data,
334 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000335 const rtc::SocketAddress& addr,
kwiberg6baec032016-03-15 11:09:39 -0700336 rtc::scoped_ptr<IceMessage>* out_msg,
337 std::string* out_username) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 // NOTE: This could clearly be optimized to avoid allocating any memory.
339 // However, at the data rates we'll be looking at on the client side,
340 // this probably isn't worth worrying about.
341 ASSERT(out_msg != NULL);
342 ASSERT(out_username != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000343 out_username->clear();
344
345 // Don't bother parsing the packet if we can tell it's not STUN.
346 // In ICE mode, all STUN packets will have a valid fingerprint.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700347 if (!StunMessage::ValidateFingerprint(data, size)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000348 return false;
349 }
350
351 // Parse the request message. If the packet is not a complete and correct
352 // STUN message, then ignore it.
353 rtc::scoped_ptr<IceMessage> stun_msg(new IceMessage());
354 rtc::ByteBuffer buf(data, size);
355 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
356 return false;
357 }
358
359 if (stun_msg->type() == STUN_BINDING_REQUEST) {
360 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
361 // If not present, fail with a 400 Bad Request.
362 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700363 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000364 LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
365 << "from " << addr.ToSensitiveString();
366 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
367 STUN_ERROR_REASON_BAD_REQUEST);
368 return true;
369 }
370
371 // If the username is bad or unknown, fail with a 401 Unauthorized.
372 std::string local_ufrag;
373 std::string remote_ufrag;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700374 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000375 local_ufrag != username_fragment()) {
376 LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
377 << local_ufrag << " from "
378 << addr.ToSensitiveString();
379 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
380 STUN_ERROR_REASON_UNAUTHORIZED);
381 return true;
382 }
383
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000384 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700385 if (!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000386 LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000387 << "from " << addr.ToSensitiveString()
388 << ", password_=" << password_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
390 STUN_ERROR_REASON_UNAUTHORIZED);
391 return true;
392 }
393 out_username->assign(remote_ufrag);
394 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
395 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
396 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
397 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
398 LOG_J(LS_ERROR, this) << "Received STUN binding error:"
399 << " class=" << error_code->eclass()
400 << " number=" << error_code->number()
401 << " reason='" << error_code->reason() << "'"
402 << " from " << addr.ToSensitiveString();
403 // Return message to allow error-specific processing
404 } else {
405 LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
406 << "code from " << addr.ToSensitiveString();
407 return true;
408 }
409 }
410 // NOTE: Username should not be used in verifying response messages.
411 out_username->clear();
412 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
413 LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
414 << " from " << addr.ToSensitiveString();
415 out_username->clear();
416 // No stun attributes will be verified, if it's stun indication message.
417 // Returning from end of the this method.
418 } else {
419 LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
420 << stun_msg->type() << ") from "
421 << addr.ToSensitiveString();
422 return true;
423 }
424
425 // Return the STUN message found.
kwiberg6baec032016-03-15 11:09:39 -0700426 *out_msg = std::move(stun_msg);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000427 return true;
428}
429
430bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
431 int family = ip().family();
432 // We use single-stack sockets, so families must match.
433 if (addr.family() != family) {
434 return false;
435 }
436 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
Peter Thatcherb8b01432015-07-07 16:45:53 -0700437 if (family == AF_INET6 &&
438 (IPIsLinkLocal(ip()) != IPIsLinkLocal(addr.ipaddr()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000439 return false;
440 }
441 return true;
442}
443
444bool Port::ParseStunUsername(const StunMessage* stun_msg,
445 std::string* local_ufrag,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700446 std::string* remote_ufrag) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000447 // The packet must include a username that either begins or ends with our
448 // fragment. It should begin with our fragment if it is a request and it
449 // should end with our fragment if it is a response.
450 local_ufrag->clear();
451 remote_ufrag->clear();
452 const StunByteStringAttribute* username_attr =
453 stun_msg->GetByteString(STUN_ATTR_USERNAME);
454 if (username_attr == NULL)
455 return false;
456
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700457 // RFRAG:LFRAG
458 const std::string username = username_attr->GetString();
459 size_t colon_pos = username.find(":");
460 if (colon_pos == std::string::npos) {
461 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000462 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000463
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700464 *local_ufrag = username.substr(0, colon_pos);
465 *remote_ufrag = username.substr(colon_pos + 1, username.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000466 return true;
467}
468
469bool Port::MaybeIceRoleConflict(
470 const rtc::SocketAddress& addr, IceMessage* stun_msg,
471 const std::string& remote_ufrag) {
472 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
473 bool ret = true;
474 IceRole remote_ice_role = ICEROLE_UNKNOWN;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200475 uint64_t remote_tiebreaker = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000476 const StunUInt64Attribute* stun_attr =
477 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
478 if (stun_attr) {
479 remote_ice_role = ICEROLE_CONTROLLING;
480 remote_tiebreaker = stun_attr->value();
481 }
482
483 // If |remote_ufrag| is same as port local username fragment and
484 // tie breaker value received in the ping message matches port
485 // tiebreaker value this must be a loopback call.
486 // We will treat this as valid scenario.
487 if (remote_ice_role == ICEROLE_CONTROLLING &&
488 username_fragment() == remote_ufrag &&
489 remote_tiebreaker == IceTiebreaker()) {
490 return true;
491 }
492
493 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
494 if (stun_attr) {
495 remote_ice_role = ICEROLE_CONTROLLED;
496 remote_tiebreaker = stun_attr->value();
497 }
498
499 switch (ice_role_) {
500 case ICEROLE_CONTROLLING:
501 if (ICEROLE_CONTROLLING == remote_ice_role) {
502 if (remote_tiebreaker >= tiebreaker_) {
503 SignalRoleConflict(this);
504 } else {
505 // Send Role Conflict (487) error response.
506 SendBindingErrorResponse(stun_msg, addr,
507 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
508 ret = false;
509 }
510 }
511 break;
512 case ICEROLE_CONTROLLED:
513 if (ICEROLE_CONTROLLED == remote_ice_role) {
514 if (remote_tiebreaker < tiebreaker_) {
515 SignalRoleConflict(this);
516 } else {
517 // Send Role Conflict (487) error response.
518 SendBindingErrorResponse(stun_msg, addr,
519 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
520 ret = false;
521 }
522 }
523 break;
524 default:
525 ASSERT(false);
526 }
527 return ret;
528}
529
530void Port::CreateStunUsername(const std::string& remote_username,
531 std::string* stun_username_attr_str) const {
532 stun_username_attr_str->clear();
533 *stun_username_attr_str = remote_username;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700534 stun_username_attr_str->append(":");
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000535 stun_username_attr_str->append(username_fragment());
536}
537
538void Port::SendBindingResponse(StunMessage* request,
539 const rtc::SocketAddress& addr) {
540 ASSERT(request->type() == STUN_BINDING_REQUEST);
541
542 // Retrieve the username from the request.
543 const StunByteStringAttribute* username_attr =
544 request->GetByteString(STUN_ATTR_USERNAME);
545 ASSERT(username_attr != NULL);
546 if (username_attr == NULL) {
547 // No valid username, skip the response.
548 return;
549 }
550
551 // Fill in the response message.
552 StunMessage response;
553 response.SetType(STUN_BINDING_RESPONSE);
554 response.SetTransactionID(request->transaction_id());
555 const StunUInt32Attribute* retransmit_attr =
556 request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
557 if (retransmit_attr) {
558 // Inherit the incoming retransmit value in the response so the other side
559 // can see our view of lost pings.
560 response.AddAttribute(new StunUInt32Attribute(
561 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
562
563 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
564 LOG_J(LS_INFO, this)
565 << "Received a remote ping with high retransmit count: "
566 << retransmit_attr->value();
567 }
568 }
569
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700570 response.AddAttribute(
571 new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
572 response.AddMessageIntegrity(password_);
573 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000574
575 // Send the response message.
576 rtc::ByteBuffer buf;
577 response.Write(&buf);
578 rtc::PacketOptions options(DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700579 auto err = SendTo(buf.Data(), buf.Length(), addr, options, false);
580 if (err < 0) {
581 LOG_J(LS_ERROR, this)
582 << "Failed to send STUN ping response"
583 << ", to=" << addr.ToSensitiveString()
584 << ", err=" << err
585 << ", id=" << rtc::hex_encode(response.transaction_id());
586 } else {
587 // Log at LS_INFO if we send a stun ping response on an unwritable
588 // connection.
honghaiz9b5ee9c2015-11-11 13:19:17 -0800589 Connection* conn = GetConnection(addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700590 rtc::LoggingSeverity sev = (conn && !conn->writable()) ?
591 rtc::LS_INFO : rtc::LS_VERBOSE;
592 LOG_JV(sev, this)
593 << "Sent STUN ping response"
594 << ", to=" << addr.ToSensitiveString()
595 << ", id=" << rtc::hex_encode(response.transaction_id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000596 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000597}
598
599void Port::SendBindingErrorResponse(StunMessage* request,
600 const rtc::SocketAddress& addr,
601 int error_code, const std::string& reason) {
602 ASSERT(request->type() == STUN_BINDING_REQUEST);
603
604 // Fill in the response message.
605 StunMessage response;
606 response.SetType(STUN_BINDING_ERROR_RESPONSE);
607 response.SetTransactionID(request->transaction_id());
608
609 // When doing GICE, we need to write out the error code incorrectly to
610 // maintain backwards compatiblility.
611 StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700612 error_attr->SetCode(error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000613 error_attr->SetReason(reason);
614 response.AddAttribute(error_attr);
615
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700616 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
617 // because we don't have enough information to determine the shared secret.
618 if (error_code != STUN_ERROR_BAD_REQUEST &&
619 error_code != STUN_ERROR_UNAUTHORIZED)
620 response.AddMessageIntegrity(password_);
621 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000622
623 // Send the response message.
624 rtc::ByteBuffer buf;
625 response.Write(&buf);
626 rtc::PacketOptions options(DefaultDscpValue());
627 SendTo(buf.Data(), buf.Length(), addr, options, false);
628 LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
629 << " to " << addr.ToSensitiveString();
630}
631
632void Port::OnMessage(rtc::Message *pmsg) {
honghaizd0b31432015-09-30 12:42:17 -0700633 ASSERT(pmsg->message_id == MSG_DEAD);
634 if (dead()) {
635 Destroy();
636 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000637}
638
honghaize3c6c822016-02-17 13:00:28 -0800639void Port::OnNetworkInactive(const rtc::Network* network) {
640 ASSERT(network == network_);
641 SignalNetworkInactive(this);
642}
643
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000644std::string Port::ToString() const {
645 std::stringstream ss;
honghaize3c6c822016-02-17 13:00:28 -0800646 ss << "Port[" << std::hex << this << std::dec << ":" << content_name_ << ":"
647 << component_ << ":" << generation_ << ":" << type_ << ":"
648 << network_->ToString() << "]";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000649 return ss.str();
650}
651
652void Port::EnablePortPackets() {
653 enable_port_packets_ = true;
654}
655
656void Port::OnConnectionDestroyed(Connection* conn) {
657 AddressMap::iterator iter =
658 connections_.find(conn->remote_candidate().address());
659 ASSERT(iter != connections_.end());
660 connections_.erase(iter);
661
honghaizd0b31432015-09-30 12:42:17 -0700662 // On the controlled side, ports time out after all connections fail.
663 // Note: If a new connection is added after this message is posted, but it
664 // fails and is removed before kPortTimeoutDelay, then this message will
665 // still cause the Port to be destroyed.
666 if (dead()) {
667 thread_->PostDelayed(timeout_delay_, this, MSG_DEAD);
668 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000669}
670
671void Port::Destroy() {
672 ASSERT(connections_.empty());
673 LOG_J(LS_INFO, this) << "Port deleted";
674 SignalDestroyed(this);
675 delete this;
676}
677
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000678const std::string Port::username_fragment() const {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700679 return ice_username_fragment_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000680}
681
682// A ConnectionRequest is a simple STUN ping used to determine writability.
683class ConnectionRequest : public StunRequest {
684 public:
685 explicit ConnectionRequest(Connection* connection)
686 : StunRequest(new IceMessage()),
687 connection_(connection) {
688 }
689
690 virtual ~ConnectionRequest() {
691 }
692
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700693 void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000694 request->SetType(STUN_BINDING_REQUEST);
695 std::string username;
696 connection_->port()->CreateStunUsername(
697 connection_->remote_candidate().username(), &username);
698 request->AddAttribute(
699 new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
700
701 // connection_ already holds this ping, so subtract one from count.
702 if (connection_->port()->send_retransmit_count_attribute()) {
703 request->AddAttribute(new StunUInt32Attribute(
704 STUN_ATTR_RETRANSMIT_COUNT,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200705 static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
706 1)));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000707 }
honghaize1a0c942016-02-16 14:54:56 -0800708 uint32_t network_cost = connection_->port()->network_cost();
709 if (network_cost > 0) {
710 request->AddAttribute(
711 new StunUInt32Attribute(STUN_ATTR_NETWORK_COST, network_cost));
712 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000713
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700714 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
715 if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
716 request->AddAttribute(new StunUInt64Attribute(
717 STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
718 // Since we are trying aggressive nomination, sending USE-CANDIDATE
719 // attribute in every ping.
720 // If we are dealing with a ice-lite end point, nomination flag
721 // in Connection will be set to false by default. Once the connection
722 // becomes "best connection", nomination flag will be turned on.
723 if (connection_->use_candidate_attr()) {
724 request->AddAttribute(new StunByteStringAttribute(
725 STUN_ATTR_USE_CANDIDATE));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700727 } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
728 request->AddAttribute(new StunUInt64Attribute(
729 STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
730 } else {
731 ASSERT(false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000732 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700733
734 // Adding PRIORITY Attribute.
735 // Changing the type preference to Peer Reflexive and local preference
736 // and component id information is unchanged from the original priority.
737 // priority = (2^24)*(type preference) +
738 // (2^8)*(local preference) +
739 // (2^0)*(256 - component ID)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200740 uint32_t prflx_priority =
741 ICE_TYPE_PREFERENCE_PRFLX << 24 |
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700742 (connection_->local_candidate().priority() & 0x00FFFFFF);
743 request->AddAttribute(
744 new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
745
746 // Adding Message Integrity attribute.
747 request->AddMessageIntegrity(connection_->remote_candidate().password());
748 // Adding Fingerprint.
749 request->AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000750 }
751
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700752 void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000753 connection_->OnConnectionRequestResponse(this, response);
754 }
755
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700756 void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757 connection_->OnConnectionRequestErrorResponse(this, response);
758 }
759
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700760 void OnTimeout() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000761 connection_->OnConnectionRequestTimeout(this);
762 }
763
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700764 void OnSent() override {
765 connection_->OnConnectionRequestSent(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000766 // Each request is sent only once. After a single delay , the request will
767 // time out.
768 timeout_ = true;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700769 }
770
771 int resend_delay() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000772 return CONNECTION_RESPONSE_TIMEOUT;
773 }
774
775 private:
776 Connection* connection_;
777};
778
779//
780// Connection
781//
782
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000783Connection::Connection(Port* port,
784 size_t index,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000785 const Candidate& remote_candidate)
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000786 : port_(port),
787 local_candidate_index_(index),
788 remote_candidate_(remote_candidate),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000789 write_state_(STATE_WRITE_INIT),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700790 receiving_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000791 connected_(true),
792 pruned_(false),
793 use_candidate_attr_(false),
honghaiz5a3acd82015-08-20 15:53:17 -0700794 nominated_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000795 remote_ice_mode_(ICEMODE_FULL),
796 requests_(port->thread()),
797 rtt_(DEFAULT_RTT),
798 last_ping_sent_(0),
799 last_ping_received_(0),
800 last_data_received_(0),
801 last_ping_response_received_(0),
Tim Psiaki63046262015-09-14 10:38:08 -0700802 recv_rate_tracker_(100u, 10u),
803 send_rate_tracker_(100u, 10u),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000804 sent_packets_discarded_(0),
805 sent_packets_total_(0),
806 reported_(false),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700807 state_(STATE_WAITING),
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700808 receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT),
honghaiz34b11eb2016-03-16 08:55:44 -0700809 time_created_ms_(rtc::Time64()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000810 // All of our connections start in WAITING state.
811 // TODO(mallinath) - Start connections from STATE_FROZEN.
812 // Wire up to send stun packets
813 requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
814 LOG_J(LS_INFO, this) << "Connection created";
815}
816
817Connection::~Connection() {
818}
819
820const Candidate& Connection::local_candidate() const {
821 ASSERT(local_candidate_index_ < port_->Candidates().size());
822 return port_->Candidates()[local_candidate_index_];
823}
824
Peter Boström0c4e06b2015-10-07 12:23:21 +0200825uint64_t Connection::priority() const {
826 uint64_t priority = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000827 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
828 // Let G be the priority for the candidate provided by the controlling
829 // agent. Let D be the priority for the candidate provided by the
830 // controlled agent.
831 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
832 IceRole role = port_->GetIceRole();
833 if (role != ICEROLE_UNKNOWN) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200834 uint32_t g = 0;
835 uint32_t d = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000836 if (role == ICEROLE_CONTROLLING) {
837 g = local_candidate().priority();
838 d = remote_candidate_.priority();
839 } else {
840 g = remote_candidate_.priority();
841 d = local_candidate().priority();
842 }
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000843 priority = std::min(g, d);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000844 priority = priority << 32;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000845 priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000846 }
847 return priority;
848}
849
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000850void Connection::set_write_state(WriteState value) {
851 WriteState old_value = write_state_;
852 write_state_ = value;
853 if (value != old_value) {
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000854 LOG_J(LS_VERBOSE, this) << "set_write_state from: " << old_value << " to "
855 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000856 SignalStateChange(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000857 }
858}
859
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700860void Connection::set_receiving(bool value) {
861 if (value != receiving_) {
862 LOG_J(LS_VERBOSE, this) << "set_receiving to " << value;
863 receiving_ = value;
864 SignalStateChange(this);
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700865 }
866}
867
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000868void Connection::set_state(State state) {
869 State old_state = state_;
870 state_ = state;
871 if (state != old_state) {
872 LOG_J(LS_VERBOSE, this) << "set_state";
873 }
874}
875
876void Connection::set_connected(bool value) {
877 bool old_value = connected_;
878 connected_ = value;
879 if (value != old_value) {
Guo-wei Shiehbe508a12015-04-06 12:48:47 -0700880 LOG_J(LS_VERBOSE, this) << "set_connected from: " << old_value << " to "
881 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000882 }
883}
884
885void Connection::set_use_candidate_attr(bool enable) {
886 use_candidate_attr_ = enable;
887}
888
889void Connection::OnSendStunPacket(const void* data, size_t size,
890 StunRequest* req) {
891 rtc::PacketOptions options(port_->DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700892 auto err = port_->SendTo(
893 data, size, remote_candidate_.address(), options, false);
894 if (err < 0) {
895 LOG_J(LS_WARNING, this) << "Failed to send STUN ping "
896 << " err=" << err
897 << " id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000898 }
899}
900
901void Connection::OnReadPacket(
902 const char* data, size_t size, const rtc::PacketTime& packet_time) {
903 rtc::scoped_ptr<IceMessage> msg;
904 std::string remote_ufrag;
905 const rtc::SocketAddress& addr(remote_candidate_.address());
kwiberg6baec032016-03-15 11:09:39 -0700906 if (!port_->GetStunMessage(data, size, addr, &msg, &remote_ufrag)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000907 // The packet did not parse as a valid STUN message
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700908 // This is a data packet, pass it along.
909 set_receiving(true);
honghaiz34b11eb2016-03-16 08:55:44 -0700910 last_data_received_ = rtc::Time64();
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700911 recv_rate_tracker_.AddSamples(size);
912 SignalReadPacket(this, data, size, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000913
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700914 // If timed out sending writability checks, start up again
915 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
916 LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
917 << "Resetting state to STATE_WRITE_INIT.";
918 set_write_state(STATE_WRITE_INIT);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000919 }
920 } else if (!msg) {
921 // The packet was STUN, but failed a check and was handled internally.
922 } else {
923 // The packet is STUN and passed the Port checks.
924 // Perform our own checks to ensure this packet is valid.
honghaizd0b31432015-09-30 12:42:17 -0700925 // If this is a STUN request, then update the receiving bit and respond.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000926 // If this is a STUN response, then update the writable bit.
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700927 // Log at LS_INFO if we receive a ping on an unwritable connection.
928 rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000929 switch (msg->type()) {
930 case STUN_BINDING_REQUEST:
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700931 LOG_JV(sev, this) << "Received STUN ping"
932 << ", id=" << rtc::hex_encode(msg->transaction_id());
933
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000934 if (remote_ufrag == remote_candidate_.username()) {
honghaiz9b5ee9c2015-11-11 13:19:17 -0800935 HandleBindingRequest(msg.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000936 } else {
937 // The packet had the right local username, but the remote username
938 // was not the right one for the remote address.
939 LOG_J(LS_ERROR, this)
940 << "Received STUN request with bad remote username "
941 << remote_ufrag;
942 port_->SendBindingErrorResponse(msg.get(), addr,
943 STUN_ERROR_UNAUTHORIZED,
944 STUN_ERROR_REASON_UNAUTHORIZED);
945
946 }
947 break;
948
949 // Response from remote peer. Does it match request sent?
950 // This doesn't just check, it makes callbacks if transaction
951 // id's match.
952 case STUN_BINDING_RESPONSE:
953 case STUN_BINDING_ERROR_RESPONSE:
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700954 if (msg->ValidateMessageIntegrity(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000955 data, size, remote_candidate().password())) {
956 requests_.CheckResponse(msg.get());
957 }
958 // Otherwise silently discard the response message.
959 break;
960
honghaizd0b31432015-09-30 12:42:17 -0700961 // Remote end point sent an STUN indication instead of regular binding
962 // request. In this case |last_ping_received_| will be updated but no
963 // response will be sent.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964 case STUN_BINDING_INDICATION:
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700965 ReceivedPing();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000966 break;
967
968 default:
969 ASSERT(false);
970 break;
971 }
972 }
973}
974
honghaiz9b5ee9c2015-11-11 13:19:17 -0800975void Connection::HandleBindingRequest(IceMessage* msg) {
976 // This connection should now be receiving.
977 ReceivedPing();
978
979 const rtc::SocketAddress& remote_addr = remote_candidate_.address();
980 const std::string& remote_ufrag = remote_candidate_.username();
981 // Check for role conflicts.
982 if (!port_->MaybeIceRoleConflict(remote_addr, msg, remote_ufrag)) {
983 // Received conflicting role from the peer.
984 LOG(LS_INFO) << "Received conflicting role from the peer.";
985 return;
986 }
987
988 // This is a validated stun request from remote peer.
989 port_->SendBindingResponse(msg, remote_addr);
990
991 // If it timed out on writing check, start up again
992 if (!pruned_ && write_state_ == STATE_WRITE_TIMEOUT) {
993 set_write_state(STATE_WRITE_INIT);
994 }
995
996 if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
997 const StunByteStringAttribute* use_candidate_attr =
998 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
999 if (use_candidate_attr) {
1000 set_nominated(true);
1001 SignalNominated(this);
1002 }
1003 }
1004}
1005
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001006void Connection::OnReadyToSend() {
1007 if (write_state_ == STATE_WRITABLE) {
1008 SignalReadyToSend(this);
1009 }
1010}
1011
1012void Connection::Prune() {
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001013 if (!pruned_ || active()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001014 LOG_J(LS_VERBOSE, this) << "Connection pruned";
1015 pruned_ = true;
1016 requests_.Clear();
1017 set_write_state(STATE_WRITE_TIMEOUT);
1018 }
1019}
1020
1021void Connection::Destroy() {
1022 LOG_J(LS_VERBOSE, this) << "Connection destroyed";
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001023 port_->thread()->Post(this, MSG_DELETE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001024}
1025
deadbeef376e1232015-11-25 09:00:08 -08001026void Connection::FailAndDestroy() {
1027 set_state(Connection::STATE_FAILED);
1028 Destroy();
1029}
1030
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001031void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
1032 std::ostringstream oss;
1033 oss << std::boolalpha;
1034 if (pings_since_last_response_.size() > max) {
1035 for (size_t i = 0; i < max; i++) {
1036 const SentPing& ping = pings_since_last_response_[i];
1037 oss << rtc::hex_encode(ping.id) << " ";
1038 }
1039 oss << "... " << (pings_since_last_response_.size() - max) << " more";
1040 } else {
1041 for (const SentPing& ping : pings_since_last_response_) {
1042 oss << rtc::hex_encode(ping.id) << " ";
1043 }
1044 }
1045 *s = oss.str();
1046}
1047
honghaiz34b11eb2016-03-16 08:55:44 -07001048void Connection::UpdateState(int64_t now) {
1049 int rtt = ConservativeRTTEstimate(rtt_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001050
Peter Thatcherb2d26232015-05-15 11:25:14 -07001051 if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001052 std::string pings;
1053 PrintPingsSinceLastResponse(&pings, 5);
1054 LOG_J(LS_VERBOSE, this) << "UpdateState()"
1055 << ", ms since last received response="
1056 << now - last_ping_response_received_
1057 << ", ms since last received data="
1058 << now - last_data_received_
1059 << ", rtt=" << rtt
1060 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001061 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001062
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001063 // Check the writable state. (The order of these checks is important.)
1064 //
1065 // Before becoming unwritable, we allow for a fixed number of pings to fail
1066 // (i.e., receive no response). We also have to give the response time to
1067 // get back, so we include a conservative estimate of this.
1068 //
1069 // Before timing out writability, we give a fixed amount of time. This is to
1070 // allow for changes in network conditions.
1071
1072 if ((write_state_ == STATE_WRITABLE) &&
1073 TooManyFailures(pings_since_last_response_,
1074 CONNECTION_WRITE_CONNECT_FAILURES,
1075 rtt,
1076 now) &&
1077 TooLongWithoutResponse(pings_since_last_response_,
1078 CONNECTION_WRITE_CONNECT_TIMEOUT,
1079 now)) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001080 uint32_t max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001081 LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
1082 << " ping failures and "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001083 << now - pings_since_last_response_[0].sent_time
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001084 << " ms without a response,"
1085 << " ms since last received ping="
1086 << now - last_ping_received_
1087 << " ms since last received data="
1088 << now - last_data_received_
1089 << " rtt=" << rtt;
1090 set_write_state(STATE_WRITE_UNRELIABLE);
1091 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001092 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
1093 write_state_ == STATE_WRITE_INIT) &&
1094 TooLongWithoutResponse(pings_since_last_response_,
1095 CONNECTION_WRITE_TIMEOUT,
1096 now)) {
1097 LOG_J(LS_INFO, this) << "Timed out after "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001098 << now - pings_since_last_response_[0].sent_time
1099 << " ms without a response"
1100 << ", rtt=" << rtt;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001101 set_write_state(STATE_WRITE_TIMEOUT);
1102 }
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001103
1104 // Check the receiving state.
honghaiz34b11eb2016-03-16 08:55:44 -07001105 int64_t last_recv_time = last_received();
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001106 bool receiving = now <= last_recv_time + receiving_timeout_;
1107 set_receiving(receiving);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001108 if (dead(now)) {
1109 Destroy();
1110 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111}
1112
honghaiz34b11eb2016-03-16 08:55:44 -07001113void Connection::Ping(int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001114 last_ping_sent_ = now;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001115 ConnectionRequest *req = new ConnectionRequest(this);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001116 pings_since_last_response_.push_back(SentPing(req->id(), now));
1117 LOG_J(LS_VERBOSE, this) << "Sending STUN ping "
1118 << ", id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001119 requests_.Send(req);
1120 state_ = STATE_INPROGRESS;
1121}
1122
1123void Connection::ReceivedPing() {
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001124 set_receiving(true);
honghaiz34b11eb2016-03-16 08:55:44 -07001125 last_ping_received_ = rtc::Time64();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001126}
1127
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001128void Connection::ReceivedPingResponse() {
1129 // We've already validated that this is a STUN binding response with
1130 // the correct local and remote username for this connection.
1131 // So if we're not already, become writable. We may be bringing a pruned
1132 // connection back to life, but if we don't really want it, we can always
1133 // prune it again.
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001134 set_receiving(true);
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001135 set_write_state(STATE_WRITABLE);
1136 set_state(STATE_SUCCEEDED);
1137 pings_since_last_response_.clear();
honghaiz34b11eb2016-03-16 08:55:44 -07001138 last_ping_response_received_ = rtc::Time64();
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001139}
1140
honghaiz34b11eb2016-03-16 08:55:44 -07001141bool Connection::dead(int64_t now) const {
honghaiz37389b42016-01-04 21:57:33 -08001142 if (last_received() > 0) {
1143 // If it has ever received anything, we keep it alive until it hasn't
1144 // received anything for DEAD_CONNECTION_RECEIVE_TIMEOUT. This covers the
1145 // normal case of a successfully used connection that stops working. This
1146 // also allows a remote peer to continue pinging over a locally inactive
1147 // (pruned) connection.
1148 return (now > (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT));
1149 }
1150
1151 if (active()) {
1152 // If it has never received anything, keep it alive as long as it is
1153 // actively pinging and not pruned. Otherwise, the connection might be
1154 // deleted before it has a chance to ping. This is the normal case for a
1155 // new connection that is pinging but hasn't received anything yet.
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001156 return false;
1157 }
1158
honghaiz37389b42016-01-04 21:57:33 -08001159 // If it has never received anything and is not actively pinging (pruned), we
1160 // keep it around for at least MIN_CONNECTION_LIFETIME to prevent connections
1161 // from being pruned too quickly during a network change event when two
1162 // networks would be up simultaneously but only for a brief period.
1163 return now > (time_created_ms_ + MIN_CONNECTION_LIFETIME);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001164}
1165
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001166std::string Connection::ToDebugId() const {
1167 std::stringstream ss;
1168 ss << std::hex << this;
1169 return ss.str();
1170}
1171
honghaize1a0c942016-02-16 14:54:56 -08001172uint32_t Connection::ComputeNetworkCost() const {
1173 // TODO(honghaiz): Will add rtt as part of the network cost.
1174 return local_candidate().network_cost() + remote_candidate_.network_cost();
1175}
1176
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001177std::string Connection::ToString() const {
1178 const char CONNECT_STATE_ABBREV[2] = {
1179 '-', // not connected (false)
1180 'C', // connected (true)
1181 };
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001182 const char RECEIVE_STATE_ABBREV[2] = {
1183 '-', // not receiving (false)
1184 'R', // receiving (true)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001185 };
1186 const char WRITE_STATE_ABBREV[4] = {
1187 'W', // STATE_WRITABLE
1188 'w', // STATE_WRITE_UNRELIABLE
1189 '-', // STATE_WRITE_INIT
1190 'x', // STATE_WRITE_TIMEOUT
1191 };
1192 const std::string ICESTATE[4] = {
1193 "W", // STATE_WAITING
1194 "I", // STATE_INPROGRESS
1195 "S", // STATE_SUCCEEDED
1196 "F" // STATE_FAILED
1197 };
1198 const Candidate& local = local_candidate();
1199 const Candidate& remote = remote_candidate();
1200 std::stringstream ss;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001201 ss << "Conn[" << ToDebugId()
1202 << ":" << port_->content_name()
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001203 << ":" << local.id() << ":" << local.component()
1204 << ":" << local.generation()
1205 << ":" << local.type() << ":" << local.protocol()
1206 << ":" << local.address().ToSensitiveString()
1207 << "->" << remote.id() << ":" << remote.component()
1208 << ":" << remote.priority()
1209 << ":" << remote.type() << ":"
1210 << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
1211 << CONNECT_STATE_ABBREV[connected()]
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001212 << RECEIVE_STATE_ABBREV[receiving()]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001213 << WRITE_STATE_ABBREV[write_state()]
1214 << ICESTATE[state()] << "|"
1215 << priority() << "|";
1216 if (rtt_ < DEFAULT_RTT) {
1217 ss << rtt_ << "]";
1218 } else {
1219 ss << "-]";
1220 }
1221 return ss.str();
1222}
1223
1224std::string Connection::ToSensitiveString() const {
1225 return ToString();
1226}
1227
1228void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1229 StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001230 // Log at LS_INFO if we receive a ping response on an unwritable
1231 // connection.
1232 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1233
honghaiz34b11eb2016-03-16 08:55:44 -07001234 int rtt = request->Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001235
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001236 ReceivedPingResponse();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001237
Peter Thatcherb2d26232015-05-15 11:25:14 -07001238 if (LOG_CHECK_LEVEL_V(sev)) {
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001239 bool use_candidate = (
1240 response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001241 std::string pings;
1242 PrintPingsSinceLastResponse(&pings, 5);
1243 LOG_JV(sev, this) << "Received STUN ping response"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001244 << ", id=" << rtc::hex_encode(request->id())
1245 << ", code=0" // Makes logging easier to parse.
1246 << ", rtt=" << rtt
1247 << ", use_candidate=" << use_candidate
1248 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001249 }
1250
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001251 rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
1252
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001253 MaybeAddPrflxCandidate(request, response);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001254}
1255
1256void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1257 StunMessage* response) {
1258 const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
1259 int error_code = STUN_ERROR_GLOBAL_FAILURE;
1260 if (error_attr) {
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001261 error_code = error_attr->code();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001262 }
1263
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001264 LOG_J(LS_INFO, this) << "Received STUN error response"
1265 << " id=" << rtc::hex_encode(request->id())
1266 << " code=" << error_code
1267 << " rtt=" << request->Elapsed();
1268
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001269 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1270 error_code == STUN_ERROR_SERVER_ERROR ||
1271 error_code == STUN_ERROR_UNAUTHORIZED) {
1272 // Recoverable error, retry
1273 } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1274 // Race failure, retry
1275 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1276 HandleRoleConflictFromPeer();
1277 } else {
1278 // This is not a valid connection.
1279 LOG_J(LS_ERROR, this) << "Received STUN error response, code="
1280 << error_code << "; killing connection";
deadbeef376e1232015-11-25 09:00:08 -08001281 FailAndDestroy();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001282 }
1283}
1284
1285void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1286 // Log at LS_INFO if we miss a ping on a writable connection.
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001287 rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1288 LOG_JV(sev, this) << "Timing-out STUN ping "
1289 << rtc::hex_encode(request->id())
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001290 << " after " << request->Elapsed() << " ms";
1291}
1292
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001293void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1294 // Log at LS_INFO if we send a ping on an unwritable connection.
1295 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001296 bool use_candidate = use_candidate_attr();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001297 LOG_JV(sev, this) << "Sent STUN ping"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001298 << ", id=" << rtc::hex_encode(request->id())
1299 << ", use_candidate=" << use_candidate;
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001300}
1301
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001302void Connection::HandleRoleConflictFromPeer() {
1303 port_->SignalRoleConflict(port_);
1304}
1305
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +00001306void Connection::MaybeSetRemoteIceCredentials(const std::string& ice_ufrag,
1307 const std::string& ice_pwd) {
1308 if (remote_candidate_.username() == ice_ufrag &&
1309 remote_candidate_.password().empty()) {
1310 remote_candidate_.set_password(ice_pwd);
1311 }
1312}
1313
1314void Connection::MaybeUpdatePeerReflexiveCandidate(
1315 const Candidate& new_candidate) {
1316 if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1317 new_candidate.type() != PRFLX_PORT_TYPE &&
1318 remote_candidate_.protocol() == new_candidate.protocol() &&
1319 remote_candidate_.address() == new_candidate.address() &&
1320 remote_candidate_.username() == new_candidate.username() &&
1321 remote_candidate_.password() == new_candidate.password() &&
1322 remote_candidate_.generation() == new_candidate.generation()) {
1323 remote_candidate_ = new_candidate;
1324 }
1325}
1326
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001327void Connection::OnMessage(rtc::Message *pmsg) {
1328 ASSERT(pmsg->message_id == MSG_DELETE);
honghaizd0b31432015-09-30 12:42:17 -07001329 LOG_J(LS_INFO, this) << "Connection deleted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001330 SignalDestroyed(this);
1331 delete this;
1332}
1333
honghaiz34b11eb2016-03-16 08:55:44 -07001334int64_t Connection::last_received() const {
Peter Thatcher54360512015-07-08 11:08:35 -07001335 return std::max(last_data_received_,
1336 std::max(last_ping_received_, last_ping_response_received_));
1337}
1338
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001339size_t Connection::recv_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001340 return round(recv_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001341}
1342
1343size_t Connection::recv_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001344 return recv_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001345}
1346
1347size_t Connection::sent_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001348 return round(send_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001349}
1350
1351size_t Connection::sent_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001352 return send_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001353}
1354
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001355size_t Connection::sent_discarded_packets() {
1356 return sent_packets_discarded_;
1357}
1358
1359size_t Connection::sent_total_packets() {
1360 return sent_packets_total_;
1361}
1362
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001363void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
1364 StunMessage* response) {
1365 // RFC 5245
1366 // The agent checks the mapped address from the STUN response. If the
1367 // transport address does not match any of the local candidates that the
1368 // agent knows about, the mapped address represents a new candidate -- a
1369 // peer reflexive candidate.
1370 const StunAddressAttribute* addr =
1371 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1372 if (!addr) {
1373 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1374 << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1375 << "stun response message";
1376 return;
1377 }
1378
1379 bool known_addr = false;
1380 for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1381 if (port_->Candidates()[i].address() == addr->GetAddress()) {
1382 known_addr = true;
1383 break;
1384 }
1385 }
1386 if (known_addr) {
1387 return;
1388 }
1389
1390 // RFC 5245
1391 // Its priority is set equal to the value of the PRIORITY attribute
1392 // in the Binding request.
1393 const StunUInt32Attribute* priority_attr =
1394 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1395 if (!priority_attr) {
1396 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1397 << "No STUN_ATTR_PRIORITY found in the "
1398 << "stun response message";
1399 return;
1400 }
Peter Boström0c4e06b2015-10-07 12:23:21 +02001401 const uint32_t priority = priority_attr->value();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001402 std::string id = rtc::CreateRandomString(8);
1403
1404 Candidate new_local_candidate;
1405 new_local_candidate.set_id(id);
1406 new_local_candidate.set_component(local_candidate().component());
1407 new_local_candidate.set_type(PRFLX_PORT_TYPE);
1408 new_local_candidate.set_protocol(local_candidate().protocol());
1409 new_local_candidate.set_address(addr->GetAddress());
1410 new_local_candidate.set_priority(priority);
1411 new_local_candidate.set_username(local_candidate().username());
1412 new_local_candidate.set_password(local_candidate().password());
1413 new_local_candidate.set_network_name(local_candidate().network_name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001414 new_local_candidate.set_network_type(local_candidate().network_type());
honghaize1a0c942016-02-16 14:54:56 -08001415 new_local_candidate.set_network_cost(local_candidate().network_cost());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001416 new_local_candidate.set_related_address(local_candidate().address());
Honghai Zhang80f1db92016-01-27 11:54:45 -08001417 new_local_candidate.set_foundation(ComputeFoundation(
1418 PRFLX_PORT_TYPE, local_candidate().protocol(),
1419 local_candidate().relay_protocol(), local_candidate().address()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001420
1421 // Change the local candidate of this Connection to the new prflx candidate.
1422 local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1423
1424 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1425 // Connection's local candidate has changed.
1426 SignalStateChange(this);
1427}
1428
deadbeef376e1232015-11-25 09:00:08 -08001429ProxyConnection::ProxyConnection(Port* port,
1430 size_t index,
1431 const Candidate& remote_candidate)
1432 : Connection(port, index, remote_candidate) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001433
1434int ProxyConnection::Send(const void* data, size_t size,
1435 const rtc::PacketOptions& options) {
1436 if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
1437 error_ = EWOULDBLOCK;
1438 return SOCKET_ERROR;
1439 }
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001440 sent_packets_total_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001441 int sent = port_->SendTo(data, size, remote_candidate_.address(),
1442 options, true);
1443 if (sent <= 0) {
1444 ASSERT(sent < 0);
1445 error_ = port_->GetError();
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001446 sent_packets_discarded_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001447 } else {
Tim Psiaki63046262015-09-14 10:38:08 -07001448 send_rate_tracker_.AddSamples(sent);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001449 }
1450 return sent;
1451}
1452
1453} // namespace cricket