blob: bd7368bf3a4848f6235171791ac3a078dc0b8a07 [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/stringencode.h"
25#include "webrtc/base/stringutils.h"
26
27namespace {
28
29// Determines whether we have seen at least the given maximum number of
30// pings fail to have a response.
31inline bool TooManyFailures(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070032 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
Peter Boström0c4e06b2015-10-07 12:23:21 +020033 uint32_t maximum_failures,
honghaiz34b11eb2016-03-16 08:55:44 -070034 int rtt_estimate,
35 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000036 // If we haven't sent that many pings, then we can't have failed that many.
37 if (pings_since_last_response.size() < maximum_failures)
38 return false;
39
40 // Check if the window in which we would expect a response to the ping has
41 // already elapsed.
honghaiz34b11eb2016-03-16 08:55:44 -070042 int64_t expected_response_time =
Peter Thatcher1cf6f812015-05-15 10:40:45 -070043 pings_since_last_response[maximum_failures - 1].sent_time + rtt_estimate;
44 return now > expected_response_time;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000045}
46
47// Determines whether we have gone too long without seeing any response.
48inline bool TooLongWithoutResponse(
Peter Thatcher1cf6f812015-05-15 10:40:45 -070049 const std::vector<cricket::Connection::SentPing>& pings_since_last_response,
honghaiz34b11eb2016-03-16 08:55:44 -070050 int64_t maximum_time,
51 int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000052 if (pings_since_last_response.size() == 0)
53 return false;
54
Peter Thatcher1cf6f812015-05-15 10:40:45 -070055 auto first = pings_since_last_response[0];
56 return now > (first.sent_time + maximum_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000057}
58
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000059// We will restrict RTT estimates (when used for determining state) to be
60// within a reasonable range.
honghaiz34b11eb2016-03-16 08:55:44 -070061const int MINIMUM_RTT = 100; // 0.1 seconds
62const int MAXIMUM_RTT = 3000; // 3 seconds
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000063
64// When we don't have any RTT data, we have to pick something reasonable. We
65// use a large value just in case the connection is really slow.
honghaiz34b11eb2016-03-16 08:55:44 -070066const int DEFAULT_RTT = MAXIMUM_RTT;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000067
68// Computes our estimate of the RTT given the current estimate.
honghaiz34b11eb2016-03-16 08:55:44 -070069inline int ConservativeRTTEstimate(int rtt) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000070 return std::max(MINIMUM_RTT, std::min(MAXIMUM_RTT, 2 * rtt));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000071}
72
73// Weighting of the old rtt value to new data.
74const int RTT_RATIO = 3; // 3 : 1
75
76// The delay before we begin checking if this port is useless.
77const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
Honghai Zhang351d77b2016-05-20 15:08:29 -070078} // namespace
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000079
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 11:54:45 -0800123static 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:11 +0000127 std::ostringstream ost;
Honghai Zhang80f1db92016-01-27 11:54:45 -0800128 ost << type << base_address.ipaddr().ToString() << protocol << relay_protocol;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200129 return rtc::ToString<uint32_t>(rtc::ComputeCrc32(ost.str()));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000130}
131
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000132Port::Port(rtc::Thread* thread,
133 rtc::PacketSocketFactory* factory,
134 rtc::Network* network,
135 const rtc::IPAddress& ip,
136 const std::string& username_fragment,
137 const std::string& password)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000138 : thread_(thread),
139 factory_(factory),
140 send_retransmit_count_attribute_(false),
141 network_(network),
142 ip_(ip),
143 min_port_(0),
144 max_port_(0),
145 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
146 generation_(0),
147 ice_username_fragment_(username_fragment),
148 password_(password),
149 timeout_delay_(kPortTimeoutDelay),
150 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000151 ice_role_(ICEROLE_UNKNOWN),
152 tiebreaker_(0),
153 shared_socket_(true),
154 candidate_filter_(CF_ALL) {
155 Construct();
156}
157
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000158Port::Port(rtc::Thread* thread,
159 const std::string& type,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000160 rtc::PacketSocketFactory* factory,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000161 rtc::Network* network,
162 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200163 uint16_t min_port,
164 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000165 const std::string& username_fragment,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000166 const std::string& password)
167 : thread_(thread),
168 factory_(factory),
169 type_(type),
170 send_retransmit_count_attribute_(false),
171 network_(network),
172 ip_(ip),
173 min_port_(min_port),
174 max_port_(max_port),
175 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
176 generation_(0),
177 ice_username_fragment_(username_fragment),
178 password_(password),
179 timeout_delay_(kPortTimeoutDelay),
180 enable_port_packets_(false),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000181 ice_role_(ICEROLE_UNKNOWN),
182 tiebreaker_(0),
183 shared_socket_(false),
184 candidate_filter_(CF_ALL) {
185 ASSERT(factory_ != NULL);
186 Construct();
187}
188
189void Port::Construct() {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700190 // TODO(pthatcher): Remove this old behavior once we're sure no one
191 // relies on it. If the username_fragment and password are empty,
192 // we should just create one.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000193 if (ice_username_fragment_.empty()) {
194 ASSERT(password_.empty());
195 ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
196 password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
197 }
honghaize3c6c822016-02-17 13:00:28 -0800198 network_->SignalInactive.connect(this, &Port::OnNetworkInactive);
Honghai Zhang351d77b2016-05-20 15:08:29 -0700199 network_->SignalTypeChanged.connect(this, &Port::OnNetworkTypeChanged);
200 network_cost_ = network_->GetCost();
honghaize1a0c942016-02-16 14:54:56 -0800201
Honghai Zhang351d77b2016-05-20 15:08:29 -0700202 LOG_J(LS_INFO, this) << "Port created with network cost " << network_cost_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000203}
204
205Port::~Port() {
206 // Delete all of the remaining connections. We copy the list up front
207 // because each deletion will cause it to be modified.
208
209 std::vector<Connection*> list;
210
211 AddressMap::iterator iter = connections_.begin();
212 while (iter != connections_.end()) {
213 list.push_back(iter->second);
214 ++iter;
215 }
216
Peter Boström0c4e06b2015-10-07 12:23:21 +0200217 for (uint32_t i = 0; i < list.size(); i++)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000218 delete list[i];
219}
220
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700221void Port::SetIceParameters(int component,
222 const std::string& username_fragment,
223 const std::string& password) {
224 component_ = component;
225 ice_username_fragment_ = username_fragment;
226 password_ = password;
227 for (Candidate& c : candidates_) {
228 c.set_component(component);
229 c.set_username(username_fragment);
230 c.set_password(password);
231 }
232}
233
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000234Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
235 AddressMap::const_iterator iter = connections_.find(remote_addr);
236 if (iter != connections_.end())
237 return iter->second;
238 else
239 return NULL;
240}
241
242void Port::AddAddress(const rtc::SocketAddress& address,
243 const rtc::SocketAddress& base_address,
244 const rtc::SocketAddress& related_address,
245 const std::string& protocol,
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700246 const std::string& relay_protocol,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000247 const std::string& tcptype,
248 const std::string& type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200249 uint32_t type_preference,
250 uint32_t relay_preference,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000251 bool final) {
252 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
253 ASSERT(!tcptype.empty());
254 }
255
honghaiza0c44ea2016-03-23 16:07:48 -0700256 std::string foundation =
257 ComputeFoundation(type, protocol, relay_protocol, base_address);
258 Candidate c(component_, protocol, address, 0U, username_fragment(), password_,
259 type, generation_, foundation, network_->id(), network_cost_);
260 c.set_priority(
261 c.GetPriority(type_preference, network_->preference(), relay_preference));
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700262 c.set_relay_protocol(relay_protocol);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000263 c.set_tcptype(tcptype);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000264 c.set_network_name(network_->name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000265 c.set_network_type(network_->type());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000266 c.set_related_address(related_address);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000267 candidates_.push_back(c);
268 SignalCandidateReady(this, c);
269
270 if (final) {
271 SignalPortComplete(this);
272 }
273}
274
275void Port::AddConnection(Connection* conn) {
276 connections_[conn->remote_candidate().address()] = conn;
277 conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
278 SignalConnectionCreated(this, conn);
279}
280
281void Port::OnReadPacket(
282 const char* data, size_t size, const rtc::SocketAddress& addr,
283 ProtocolType proto) {
284 // If the user has enabled port packets, just hand this over.
285 if (enable_port_packets_) {
286 SignalReadPacket(this, data, size, addr);
287 return;
288 }
289
290 // If this is an authenticated STUN request, then signal unknown address and
291 // send back a proper binding response.
kwiberg3ec46792016-04-27 07:22:53 -0700292 std::unique_ptr<IceMessage> msg;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000293 std::string remote_username;
kwiberg6baec032016-03-15 11:09:39 -0700294 if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000295 LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
296 << addr.ToSensitiveString() << ")";
297 } else if (!msg) {
298 // STUN message handled already
299 } else if (msg->type() == STUN_BINDING_REQUEST) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700300 LOG(LS_INFO) << "Received STUN ping "
301 << " id=" << rtc::hex_encode(msg->transaction_id())
302 << " from unknown address " << addr.ToSensitiveString();
303
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000304 // Check for role conflicts.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700305 if (!MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 LOG(LS_INFO) << "Received conflicting role from the peer.";
307 return;
308 }
309
310 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
311 } else {
312 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
313 // pruned a connection for this port while it had STUN requests in flight,
314 // because we then get back responses for them, which this code correctly
315 // does not handle.
316 if (msg->type() != STUN_BINDING_RESPONSE) {
317 LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
318 << msg->type() << ") from unknown address ("
319 << addr.ToSensitiveString() << ")";
320 }
321 }
322}
323
324void Port::OnReadyToSend() {
325 AddressMap::iterator iter = connections_.begin();
326 for (; iter != connections_.end(); ++iter) {
327 iter->second->OnReadyToSend();
328 }
329}
330
331size_t Port::AddPrflxCandidate(const Candidate& local) {
332 candidates_.push_back(local);
333 return (candidates_.size() - 1);
334}
335
kwiberg6baec032016-03-15 11:09:39 -0700336bool Port::GetStunMessage(const char* data,
337 size_t size,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000338 const rtc::SocketAddress& addr,
kwiberg3ec46792016-04-27 07:22:53 -0700339 std::unique_ptr<IceMessage>* out_msg,
kwiberg6baec032016-03-15 11:09:39 -0700340 std::string* out_username) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000341 // NOTE: This could clearly be optimized to avoid allocating any memory.
342 // However, at the data rates we'll be looking at on the client side,
343 // this probably isn't worth worrying about.
344 ASSERT(out_msg != NULL);
345 ASSERT(out_username != NULL);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000346 out_username->clear();
347
348 // Don't bother parsing the packet if we can tell it's not STUN.
349 // In ICE mode, all STUN packets will have a valid fingerprint.
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700350 if (!StunMessage::ValidateFingerprint(data, size)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000351 return false;
352 }
353
354 // Parse the request message. If the packet is not a complete and correct
355 // STUN message, then ignore it.
kwiberg3ec46792016-04-27 07:22:53 -0700356 std::unique_ptr<IceMessage> stun_msg(new IceMessage());
jbauchf1f87202016-03-30 06:43:37 -0700357 rtc::ByteBufferReader buf(data, size);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000358 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
359 return false;
360 }
361
362 if (stun_msg->type() == STUN_BINDING_REQUEST) {
363 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
364 // If not present, fail with a 400 Bad Request.
365 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700366 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000367 LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
368 << "from " << addr.ToSensitiveString();
369 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
370 STUN_ERROR_REASON_BAD_REQUEST);
371 return true;
372 }
373
374 // If the username is bad or unknown, fail with a 401 Unauthorized.
375 std::string local_ufrag;
376 std::string remote_ufrag;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700377 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag) ||
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000378 local_ufrag != username_fragment()) {
379 LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
380 << local_ufrag << " from "
381 << addr.ToSensitiveString();
382 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
383 STUN_ERROR_REASON_UNAUTHORIZED);
384 return true;
385 }
386
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000387 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700388 if (!stun_msg->ValidateMessageIntegrity(data, size, password_)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000389 LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000390 << "from " << addr.ToSensitiveString()
391 << ", password_=" << password_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000392 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
393 STUN_ERROR_REASON_UNAUTHORIZED);
394 return true;
395 }
396 out_username->assign(remote_ufrag);
397 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
398 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
399 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
400 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
401 LOG_J(LS_ERROR, this) << "Received STUN binding error:"
402 << " class=" << error_code->eclass()
403 << " number=" << error_code->number()
404 << " reason='" << error_code->reason() << "'"
405 << " from " << addr.ToSensitiveString();
406 // Return message to allow error-specific processing
407 } else {
408 LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
409 << "code from " << addr.ToSensitiveString();
410 return true;
411 }
412 }
413 // NOTE: Username should not be used in verifying response messages.
414 out_username->clear();
415 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
416 LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
417 << " from " << addr.ToSensitiveString();
418 out_username->clear();
419 // No stun attributes will be verified, if it's stun indication message.
420 // Returning from end of the this method.
421 } else {
422 LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
423 << stun_msg->type() << ") from "
424 << addr.ToSensitiveString();
425 return true;
426 }
427
428 // Return the STUN message found.
kwiberg6baec032016-03-15 11:09:39 -0700429 *out_msg = std::move(stun_msg);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000430 return true;
431}
432
433bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
434 int family = ip().family();
435 // We use single-stack sockets, so families must match.
436 if (addr.family() != family) {
437 return false;
438 }
439 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
Peter Thatcherb8b01432015-07-07 16:45:53 -0700440 if (family == AF_INET6 &&
441 (IPIsLinkLocal(ip()) != IPIsLinkLocal(addr.ipaddr()))) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000442 return false;
443 }
444 return true;
445}
446
447bool Port::ParseStunUsername(const StunMessage* stun_msg,
448 std::string* local_ufrag,
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700449 std::string* remote_ufrag) const {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000450 // The packet must include a username that either begins or ends with our
451 // fragment. It should begin with our fragment if it is a request and it
452 // should end with our fragment if it is a response.
453 local_ufrag->clear();
454 remote_ufrag->clear();
455 const StunByteStringAttribute* username_attr =
456 stun_msg->GetByteString(STUN_ATTR_USERNAME);
457 if (username_attr == NULL)
458 return false;
459
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700460 // RFRAG:LFRAG
461 const std::string username = username_attr->GetString();
462 size_t colon_pos = username.find(":");
463 if (colon_pos == std::string::npos) {
464 return false;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000465 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000466
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700467 *local_ufrag = username.substr(0, colon_pos);
468 *remote_ufrag = username.substr(colon_pos + 1, username.size());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000469 return true;
470}
471
472bool Port::MaybeIceRoleConflict(
473 const rtc::SocketAddress& addr, IceMessage* stun_msg,
474 const std::string& remote_ufrag) {
475 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
476 bool ret = true;
477 IceRole remote_ice_role = ICEROLE_UNKNOWN;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200478 uint64_t remote_tiebreaker = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000479 const StunUInt64Attribute* stun_attr =
480 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
481 if (stun_attr) {
482 remote_ice_role = ICEROLE_CONTROLLING;
483 remote_tiebreaker = stun_attr->value();
484 }
485
486 // If |remote_ufrag| is same as port local username fragment and
487 // tie breaker value received in the ping message matches port
488 // tiebreaker value this must be a loopback call.
489 // We will treat this as valid scenario.
490 if (remote_ice_role == ICEROLE_CONTROLLING &&
491 username_fragment() == remote_ufrag &&
492 remote_tiebreaker == IceTiebreaker()) {
493 return true;
494 }
495
496 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
497 if (stun_attr) {
498 remote_ice_role = ICEROLE_CONTROLLED;
499 remote_tiebreaker = stun_attr->value();
500 }
501
502 switch (ice_role_) {
503 case ICEROLE_CONTROLLING:
504 if (ICEROLE_CONTROLLING == 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 case ICEROLE_CONTROLLED:
516 if (ICEROLE_CONTROLLED == remote_ice_role) {
517 if (remote_tiebreaker < tiebreaker_) {
518 SignalRoleConflict(this);
519 } else {
520 // Send Role Conflict (487) error response.
521 SendBindingErrorResponse(stun_msg, addr,
522 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
523 ret = false;
524 }
525 }
526 break;
527 default:
528 ASSERT(false);
529 }
530 return ret;
531}
532
533void Port::CreateStunUsername(const std::string& remote_username,
534 std::string* stun_username_attr_str) const {
535 stun_username_attr_str->clear();
536 *stun_username_attr_str = remote_username;
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700537 stun_username_attr_str->append(":");
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000538 stun_username_attr_str->append(username_fragment());
539}
540
541void Port::SendBindingResponse(StunMessage* request,
542 const rtc::SocketAddress& addr) {
543 ASSERT(request->type() == STUN_BINDING_REQUEST);
544
545 // Retrieve the username from the request.
546 const StunByteStringAttribute* username_attr =
547 request->GetByteString(STUN_ATTR_USERNAME);
548 ASSERT(username_attr != NULL);
549 if (username_attr == NULL) {
550 // No valid username, skip the response.
551 return;
552 }
553
554 // Fill in the response message.
555 StunMessage response;
556 response.SetType(STUN_BINDING_RESPONSE);
557 response.SetTransactionID(request->transaction_id());
558 const StunUInt32Attribute* retransmit_attr =
559 request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
560 if (retransmit_attr) {
561 // Inherit the incoming retransmit value in the response so the other side
562 // can see our view of lost pings.
563 response.AddAttribute(new StunUInt32Attribute(
564 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
565
566 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
567 LOG_J(LS_INFO, this)
568 << "Received a remote ping with high retransmit count: "
569 << retransmit_attr->value();
570 }
571 }
572
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700573 response.AddAttribute(
574 new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
575 response.AddMessageIntegrity(password_);
576 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000577
578 // Send the response message.
jbauchf1f87202016-03-30 06:43:37 -0700579 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000580 response.Write(&buf);
581 rtc::PacketOptions options(DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700582 auto err = SendTo(buf.Data(), buf.Length(), addr, options, false);
583 if (err < 0) {
584 LOG_J(LS_ERROR, this)
585 << "Failed to send STUN ping response"
586 << ", to=" << addr.ToSensitiveString()
587 << ", err=" << err
588 << ", id=" << rtc::hex_encode(response.transaction_id());
589 } else {
590 // Log at LS_INFO if we send a stun ping response on an unwritable
591 // connection.
honghaiz9b5ee9c2015-11-11 13:19:17 -0800592 Connection* conn = GetConnection(addr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700593 rtc::LoggingSeverity sev = (conn && !conn->writable()) ?
594 rtc::LS_INFO : rtc::LS_VERBOSE;
595 LOG_JV(sev, this)
596 << "Sent STUN ping response"
597 << ", to=" << addr.ToSensitiveString()
598 << ", id=" << rtc::hex_encode(response.transaction_id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000599 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000600}
601
602void Port::SendBindingErrorResponse(StunMessage* request,
603 const rtc::SocketAddress& addr,
604 int error_code, const std::string& reason) {
605 ASSERT(request->type() == STUN_BINDING_REQUEST);
606
607 // Fill in the response message.
608 StunMessage response;
609 response.SetType(STUN_BINDING_ERROR_RESPONSE);
610 response.SetTransactionID(request->transaction_id());
611
612 // When doing GICE, we need to write out the error code incorrectly to
613 // maintain backwards compatiblility.
614 StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700615 error_attr->SetCode(error_code);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000616 error_attr->SetReason(reason);
617 response.AddAttribute(error_attr);
618
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700619 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
620 // because we don't have enough information to determine the shared secret.
621 if (error_code != STUN_ERROR_BAD_REQUEST &&
622 error_code != STUN_ERROR_UNAUTHORIZED)
623 response.AddMessageIntegrity(password_);
624 response.AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000625
626 // Send the response message.
jbauchf1f87202016-03-30 06:43:37 -0700627 rtc::ByteBufferWriter buf;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000628 response.Write(&buf);
629 rtc::PacketOptions options(DefaultDscpValue());
630 SendTo(buf.Data(), buf.Length(), addr, options, false);
631 LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
632 << " to " << addr.ToSensitiveString();
633}
634
635void Port::OnMessage(rtc::Message *pmsg) {
honghaizd0b31432015-09-30 12:42:17 -0700636 ASSERT(pmsg->message_id == MSG_DEAD);
637 if (dead()) {
638 Destroy();
639 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000640}
641
honghaize3c6c822016-02-17 13:00:28 -0800642void Port::OnNetworkInactive(const rtc::Network* network) {
643 ASSERT(network == network_);
644 SignalNetworkInactive(this);
645}
646
Honghai Zhang351d77b2016-05-20 15:08:29 -0700647void Port::OnNetworkTypeChanged(const rtc::Network* network) {
648 ASSERT(network == network_);
649
650 UpdateNetworkCost();
651}
652
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000653std::string Port::ToString() const {
654 std::stringstream ss;
honghaize3c6c822016-02-17 13:00:28 -0800655 ss << "Port[" << std::hex << this << std::dec << ":" << content_name_ << ":"
656 << component_ << ":" << generation_ << ":" << type_ << ":"
657 << network_->ToString() << "]";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000658 return ss.str();
659}
660
Honghai Zhang351d77b2016-05-20 15:08:29 -0700661// TODO(honghaiz): Make the network cost configurable from user setting.
662void Port::UpdateNetworkCost() {
663 uint16_t new_cost = network_->GetCost();
664 if (network_cost_ == new_cost) {
665 return;
666 }
667 LOG(LS_INFO) << "Network cost changed from " << network_cost_
668 << " to " << new_cost
669 << ". Number of candidates created: " << candidates_.size()
670 << ". Number of connections created: " << connections_.size();
671 network_cost_ = new_cost;
672 for (cricket::Candidate& candidate : candidates_) {
673 candidate.set_network_cost(network_cost_);
674 }
675 // Network cost change will affect the connection selection criteria.
676 // Signal the connection state change on each connection to force a
677 // re-sort in P2PTransportChannel.
678 for (auto kv : connections_) {
679 Connection* conn = kv.second;
680 conn->SignalStateChange(conn);
681 }
682}
683
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000684void Port::EnablePortPackets() {
685 enable_port_packets_ = true;
686}
687
688void Port::OnConnectionDestroyed(Connection* conn) {
689 AddressMap::iterator iter =
690 connections_.find(conn->remote_candidate().address());
691 ASSERT(iter != connections_.end());
692 connections_.erase(iter);
693
honghaizd0b31432015-09-30 12:42:17 -0700694 // On the controlled side, ports time out after all connections fail.
695 // Note: If a new connection is added after this message is posted, but it
696 // fails and is removed before kPortTimeoutDelay, then this message will
697 // still cause the Port to be destroyed.
698 if (dead()) {
699 thread_->PostDelayed(timeout_delay_, this, MSG_DEAD);
700 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000701}
702
703void Port::Destroy() {
704 ASSERT(connections_.empty());
705 LOG_J(LS_INFO, this) << "Port deleted";
706 SignalDestroyed(this);
707 delete this;
708}
709
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000710const std::string Port::username_fragment() const {
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700711 return ice_username_fragment_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000712}
713
714// A ConnectionRequest is a simple STUN ping used to determine writability.
715class ConnectionRequest : public StunRequest {
716 public:
717 explicit ConnectionRequest(Connection* connection)
718 : StunRequest(new IceMessage()),
719 connection_(connection) {
720 }
721
722 virtual ~ConnectionRequest() {
723 }
724
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700725 void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000726 request->SetType(STUN_BINDING_REQUEST);
727 std::string username;
728 connection_->port()->CreateStunUsername(
729 connection_->remote_candidate().username(), &username);
730 request->AddAttribute(
731 new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
732
733 // connection_ already holds this ping, so subtract one from count.
734 if (connection_->port()->send_retransmit_count_attribute()) {
735 request->AddAttribute(new StunUInt32Attribute(
736 STUN_ATTR_RETRANSMIT_COUNT,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200737 static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
738 1)));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000739 }
honghaiza0c44ea2016-03-23 16:07:48 -0700740 uint32_t network_info = connection_->port()->Network()->id();
741 network_info = (network_info << 16) | connection_->port()->network_cost();
742 request->AddAttribute(
743 new StunUInt32Attribute(STUN_ATTR_NETWORK_INFO, network_info));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000744
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700745 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
746 if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
747 request->AddAttribute(new StunUInt64Attribute(
748 STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
749 // Since we are trying aggressive nomination, sending USE-CANDIDATE
750 // attribute in every ping.
751 // If we are dealing with a ice-lite end point, nomination flag
752 // in Connection will be set to false by default. Once the connection
753 // becomes "best connection", nomination flag will be turned on.
754 if (connection_->use_candidate_attr()) {
755 request->AddAttribute(new StunByteStringAttribute(
756 STUN_ATTR_USE_CANDIDATE));
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000757 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700758 } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
759 request->AddAttribute(new StunUInt64Attribute(
760 STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
761 } else {
762 ASSERT(false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000763 }
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700764
765 // Adding PRIORITY Attribute.
766 // Changing the type preference to Peer Reflexive and local preference
767 // and component id information is unchanged from the original priority.
768 // priority = (2^24)*(type preference) +
769 // (2^8)*(local preference) +
770 // (2^0)*(256 - component ID)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200771 uint32_t prflx_priority =
772 ICE_TYPE_PREFERENCE_PRFLX << 24 |
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700773 (connection_->local_candidate().priority() & 0x00FFFFFF);
774 request->AddAttribute(
775 new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
776
777 // Adding Message Integrity attribute.
778 request->AddMessageIntegrity(connection_->remote_candidate().password());
779 // Adding Fingerprint.
780 request->AddFingerprint();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000781 }
782
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700783 void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000784 connection_->OnConnectionRequestResponse(this, response);
785 }
786
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700787 void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000788 connection_->OnConnectionRequestErrorResponse(this, response);
789 }
790
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700791 void OnTimeout() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000792 connection_->OnConnectionRequestTimeout(this);
793 }
794
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700795 void OnSent() override {
796 connection_->OnConnectionRequestSent(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000797 // Each request is sent only once. After a single delay , the request will
798 // time out.
799 timeout_ = true;
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700800 }
801
802 int resend_delay() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000803 return CONNECTION_RESPONSE_TIMEOUT;
804 }
805
806 private:
807 Connection* connection_;
808};
809
810//
811// Connection
812//
813
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000814Connection::Connection(Port* port,
815 size_t index,
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000816 const Candidate& remote_candidate)
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000817 : port_(port),
818 local_candidate_index_(index),
819 remote_candidate_(remote_candidate),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000820 write_state_(STATE_WRITE_INIT),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700821 receiving_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000822 connected_(true),
823 pruned_(false),
824 use_candidate_attr_(false),
honghaiz5a3acd82015-08-20 15:53:17 -0700825 nominated_(false),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000826 remote_ice_mode_(ICEMODE_FULL),
827 requests_(port->thread()),
828 rtt_(DEFAULT_RTT),
829 last_ping_sent_(0),
830 last_ping_received_(0),
831 last_data_received_(0),
832 last_ping_response_received_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700833 recv_rate_tracker_(100, 10u),
834 send_rate_tracker_(100, 10u),
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000835 sent_packets_discarded_(0),
836 sent_packets_total_(0),
837 reported_(false),
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700838 state_(STATE_WAITING),
Honghai Zhang2b342bf2015-09-30 09:51:58 -0700839 receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT),
nisse1bffc1d2016-05-02 08:18:55 -0700840 time_created_ms_(rtc::TimeMillis()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000841 // All of our connections start in WAITING state.
842 // TODO(mallinath) - Start connections from STATE_FROZEN.
843 // Wire up to send stun packets
844 requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
845 LOG_J(LS_INFO, this) << "Connection created";
846}
847
848Connection::~Connection() {
849}
850
851const Candidate& Connection::local_candidate() const {
852 ASSERT(local_candidate_index_ < port_->Candidates().size());
853 return port_->Candidates()[local_candidate_index_];
854}
855
Honghai Zhangcc411c02016-03-29 17:27:21 -0700856const Candidate& Connection::remote_candidate() const {
857 return remote_candidate_;
858}
859
Peter Boström0c4e06b2015-10-07 12:23:21 +0200860uint64_t Connection::priority() const {
861 uint64_t priority = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000862 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
863 // Let G be the priority for the candidate provided by the controlling
864 // agent. Let D be the priority for the candidate provided by the
865 // controlled agent.
866 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
867 IceRole role = port_->GetIceRole();
868 if (role != ICEROLE_UNKNOWN) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200869 uint32_t g = 0;
870 uint32_t d = 0;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000871 if (role == ICEROLE_CONTROLLING) {
872 g = local_candidate().priority();
873 d = remote_candidate_.priority();
874 } else {
875 g = remote_candidate_.priority();
876 d = local_candidate().priority();
877 }
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000878 priority = std::min(g, d);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000879 priority = priority << 32;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000880 priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000881 }
882 return priority;
883}
884
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000885void Connection::set_write_state(WriteState value) {
886 WriteState old_value = write_state_;
887 write_state_ = value;
888 if (value != old_value) {
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +0000889 LOG_J(LS_VERBOSE, this) << "set_write_state from: " << old_value << " to "
890 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000891 SignalStateChange(this);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000892 }
893}
894
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700895void Connection::set_receiving(bool value) {
896 if (value != receiving_) {
897 LOG_J(LS_VERBOSE, this) << "set_receiving to " << value;
898 receiving_ = value;
899 SignalStateChange(this);
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700900 }
901}
902
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000903void Connection::set_state(State state) {
904 State old_state = state_;
905 state_ = state;
906 if (state != old_state) {
907 LOG_J(LS_VERBOSE, this) << "set_state";
908 }
909}
910
911void Connection::set_connected(bool value) {
912 bool old_value = connected_;
913 connected_ = value;
914 if (value != old_value) {
Guo-wei Shiehbe508a12015-04-06 12:48:47 -0700915 LOG_J(LS_VERBOSE, this) << "set_connected from: " << old_value << " to "
916 << value;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000917 }
918}
919
920void Connection::set_use_candidate_attr(bool enable) {
921 use_candidate_attr_ = enable;
922}
923
924void Connection::OnSendStunPacket(const void* data, size_t size,
925 StunRequest* req) {
926 rtc::PacketOptions options(port_->DefaultDscpValue());
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700927 auto err = port_->SendTo(
928 data, size, remote_candidate_.address(), options, false);
929 if (err < 0) {
930 LOG_J(LS_WARNING, this) << "Failed to send STUN ping "
931 << " err=" << err
932 << " id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000933 }
934}
935
936void Connection::OnReadPacket(
937 const char* data, size_t size, const rtc::PacketTime& packet_time) {
kwiberg3ec46792016-04-27 07:22:53 -0700938 std::unique_ptr<IceMessage> msg;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000939 std::string remote_ufrag;
940 const rtc::SocketAddress& addr(remote_candidate_.address());
kwiberg6baec032016-03-15 11:09:39 -0700941 if (!port_->GetStunMessage(data, size, addr, &msg, &remote_ufrag)) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000942 // The packet did not parse as a valid STUN message
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700943 // This is a data packet, pass it along.
944 set_receiving(true);
nisse1bffc1d2016-05-02 08:18:55 -0700945 last_data_received_ = rtc::TimeMillis();
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700946 recv_rate_tracker_.AddSamples(size);
947 SignalReadPacket(this, data, size, packet_time);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000948
Peter Thatcher04ac81f2015-09-21 11:48:28 -0700949 // If timed out sending writability checks, start up again
950 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
951 LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
952 << "Resetting state to STATE_WRITE_INIT.";
953 set_write_state(STATE_WRITE_INIT);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000954 }
955 } else if (!msg) {
956 // The packet was STUN, but failed a check and was handled internally.
957 } else {
958 // The packet is STUN and passed the Port checks.
959 // Perform our own checks to ensure this packet is valid.
honghaizd0b31432015-09-30 12:42:17 -0700960 // If this is a STUN request, then update the receiving bit and respond.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000961 // If this is a STUN response, then update the writable bit.
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700962 // Log at LS_INFO if we receive a ping on an unwritable connection.
963 rtc::LoggingSeverity sev = (!writable() ? rtc::LS_INFO : rtc::LS_VERBOSE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000964 switch (msg->type()) {
965 case STUN_BINDING_REQUEST:
Peter Thatcher1cf6f812015-05-15 10:40:45 -0700966 LOG_JV(sev, this) << "Received STUN ping"
967 << ", id=" << rtc::hex_encode(msg->transaction_id());
968
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000969 if (remote_ufrag == remote_candidate_.username()) {
honghaiz9b5ee9c2015-11-11 13:19:17 -0800970 HandleBindingRequest(msg.get());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000971 } else {
972 // The packet had the right local username, but the remote username
973 // was not the right one for the remote address.
974 LOG_J(LS_ERROR, this)
975 << "Received STUN request with bad remote username "
976 << remote_ufrag;
977 port_->SendBindingErrorResponse(msg.get(), addr,
978 STUN_ERROR_UNAUTHORIZED,
979 STUN_ERROR_REASON_UNAUTHORIZED);
980
981 }
982 break;
983
984 // Response from remote peer. Does it match request sent?
985 // This doesn't just check, it makes callbacks if transaction
986 // id's match.
987 case STUN_BINDING_RESPONSE:
988 case STUN_BINDING_ERROR_RESPONSE:
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700989 if (msg->ValidateMessageIntegrity(
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000990 data, size, remote_candidate().password())) {
991 requests_.CheckResponse(msg.get());
992 }
993 // Otherwise silently discard the response message.
994 break;
995
honghaizd0b31432015-09-30 12:42:17 -0700996 // Remote end point sent an STUN indication instead of regular binding
997 // request. In this case |last_ping_received_| will be updated but no
998 // response will be sent.
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000999 case STUN_BINDING_INDICATION:
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001000 ReceivedPing();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001001 break;
1002
1003 default:
1004 ASSERT(false);
1005 break;
1006 }
1007 }
1008}
1009
honghaiz9b5ee9c2015-11-11 13:19:17 -08001010void Connection::HandleBindingRequest(IceMessage* msg) {
1011 // This connection should now be receiving.
1012 ReceivedPing();
1013
1014 const rtc::SocketAddress& remote_addr = remote_candidate_.address();
1015 const std::string& remote_ufrag = remote_candidate_.username();
1016 // Check for role conflicts.
1017 if (!port_->MaybeIceRoleConflict(remote_addr, msg, remote_ufrag)) {
1018 // Received conflicting role from the peer.
1019 LOG(LS_INFO) << "Received conflicting role from the peer.";
1020 return;
1021 }
1022
1023 // This is a validated stun request from remote peer.
1024 port_->SendBindingResponse(msg, remote_addr);
1025
1026 // If it timed out on writing check, start up again
1027 if (!pruned_ && write_state_ == STATE_WRITE_TIMEOUT) {
1028 set_write_state(STATE_WRITE_INIT);
1029 }
1030
1031 if (port_->GetIceRole() == ICEROLE_CONTROLLED) {
1032 const StunByteStringAttribute* use_candidate_attr =
1033 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
1034 if (use_candidate_attr) {
1035 set_nominated(true);
1036 SignalNominated(this);
1037 }
1038 }
Honghai Zhang351d77b2016-05-20 15:08:29 -07001039 // Set the remote cost if the network_info attribute is available.
1040 // Note: If packets are re-ordered, we may get incorrect network cost
1041 // temporarily, but it should get the correct value shortly after that.
1042 const StunUInt32Attribute* network_attr =
1043 msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
1044 if (network_attr) {
1045 uint32_t network_info = network_attr->value();
1046 uint16_t network_cost = static_cast<uint16_t>(network_info);
1047 if (network_cost != remote_candidate_.network_cost()) {
1048 remote_candidate_.set_network_cost(network_cost);
1049 // Network cost change will affect the connection ranking, so signal
1050 // state change to force a re-sort in P2PTransportChannel.
1051 SignalStateChange(this);
1052 }
1053 }
honghaiz9b5ee9c2015-11-11 13:19:17 -08001054}
1055
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001056void Connection::OnReadyToSend() {
1057 if (write_state_ == STATE_WRITABLE) {
1058 SignalReadyToSend(this);
1059 }
1060}
1061
1062void Connection::Prune() {
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001063 if (!pruned_ || active()) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001064 LOG_J(LS_VERBOSE, this) << "Connection pruned";
1065 pruned_ = true;
1066 requests_.Clear();
1067 set_write_state(STATE_WRITE_TIMEOUT);
1068 }
1069}
1070
1071void Connection::Destroy() {
1072 LOG_J(LS_VERBOSE, this) << "Connection destroyed";
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001073 port_->thread()->Post(this, MSG_DELETE);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001074}
1075
deadbeef376e1232015-11-25 09:00:08 -08001076void Connection::FailAndDestroy() {
1077 set_state(Connection::STATE_FAILED);
1078 Destroy();
1079}
1080
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001081void Connection::PrintPingsSinceLastResponse(std::string* s, size_t max) {
1082 std::ostringstream oss;
1083 oss << std::boolalpha;
1084 if (pings_since_last_response_.size() > max) {
1085 for (size_t i = 0; i < max; i++) {
1086 const SentPing& ping = pings_since_last_response_[i];
1087 oss << rtc::hex_encode(ping.id) << " ";
1088 }
1089 oss << "... " << (pings_since_last_response_.size() - max) << " more";
1090 } else {
1091 for (const SentPing& ping : pings_since_last_response_) {
1092 oss << rtc::hex_encode(ping.id) << " ";
1093 }
1094 }
1095 *s = oss.str();
1096}
1097
honghaiz34b11eb2016-03-16 08:55:44 -07001098void Connection::UpdateState(int64_t now) {
1099 int rtt = ConservativeRTTEstimate(rtt_);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001100
Peter Thatcherb2d26232015-05-15 11:25:14 -07001101 if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001102 std::string pings;
1103 PrintPingsSinceLastResponse(&pings, 5);
1104 LOG_J(LS_VERBOSE, this) << "UpdateState()"
1105 << ", ms since last received response="
1106 << now - last_ping_response_received_
1107 << ", ms since last received data="
1108 << now - last_data_received_
1109 << ", rtt=" << rtt
1110 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001111 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001112
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001113 // Check the writable state. (The order of these checks is important.)
1114 //
1115 // Before becoming unwritable, we allow for a fixed number of pings to fail
1116 // (i.e., receive no response). We also have to give the response time to
1117 // get back, so we include a conservative estimate of this.
1118 //
1119 // Before timing out writability, we give a fixed amount of time. This is to
1120 // allow for changes in network conditions.
1121
1122 if ((write_state_ == STATE_WRITABLE) &&
1123 TooManyFailures(pings_since_last_response_,
1124 CONNECTION_WRITE_CONNECT_FAILURES,
1125 rtt,
1126 now) &&
1127 TooLongWithoutResponse(pings_since_last_response_,
1128 CONNECTION_WRITE_CONNECT_TIMEOUT,
1129 now)) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001130 uint32_t max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001131 LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
1132 << " ping failures and "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001133 << now - pings_since_last_response_[0].sent_time
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001134 << " ms without a response,"
1135 << " ms since last received ping="
1136 << now - last_ping_received_
1137 << " ms since last received data="
1138 << now - last_data_received_
1139 << " rtt=" << rtt;
1140 set_write_state(STATE_WRITE_UNRELIABLE);
1141 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001142 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
1143 write_state_ == STATE_WRITE_INIT) &&
1144 TooLongWithoutResponse(pings_since_last_response_,
1145 CONNECTION_WRITE_TIMEOUT,
1146 now)) {
1147 LOG_J(LS_INFO, this) << "Timed out after "
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001148 << now - pings_since_last_response_[0].sent_time
1149 << " ms without a response"
1150 << ", rtt=" << rtt;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001151 set_write_state(STATE_WRITE_TIMEOUT);
1152 }
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001153
1154 // Check the receiving state.
honghaiz34b11eb2016-03-16 08:55:44 -07001155 int64_t last_recv_time = last_received();
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001156 bool receiving = now <= last_recv_time + receiving_timeout_;
1157 set_receiving(receiving);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001158 if (dead(now)) {
1159 Destroy();
1160 }
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001161}
1162
honghaiz34b11eb2016-03-16 08:55:44 -07001163void Connection::Ping(int64_t now) {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001164 last_ping_sent_ = now;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001165 ConnectionRequest *req = new ConnectionRequest(this);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001166 pings_since_last_response_.push_back(SentPing(req->id(), now));
1167 LOG_J(LS_VERBOSE, this) << "Sending STUN ping "
1168 << ", id=" << rtc::hex_encode(req->id());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001169 requests_.Send(req);
1170 state_ = STATE_INPROGRESS;
1171}
1172
1173void Connection::ReceivedPing() {
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001174 set_receiving(true);
nisse1bffc1d2016-05-02 08:18:55 -07001175 last_ping_received_ = rtc::TimeMillis();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001176}
1177
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001178void Connection::ReceivedPingResponse() {
1179 // We've already validated that this is a STUN binding response with
1180 // the correct local and remote username for this connection.
1181 // So if we're not already, become writable. We may be bringing a pruned
1182 // connection back to life, but if we don't really want it, we can always
1183 // prune it again.
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001184 set_receiving(true);
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001185 set_write_state(STATE_WRITABLE);
1186 set_state(STATE_SUCCEEDED);
1187 pings_since_last_response_.clear();
nisse1bffc1d2016-05-02 08:18:55 -07001188 last_ping_response_received_ = rtc::TimeMillis();
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001189}
1190
honghaiz34b11eb2016-03-16 08:55:44 -07001191bool Connection::dead(int64_t now) const {
honghaiz37389b42016-01-04 21:57:33 -08001192 if (last_received() > 0) {
1193 // If it has ever received anything, we keep it alive until it hasn't
1194 // received anything for DEAD_CONNECTION_RECEIVE_TIMEOUT. This covers the
1195 // normal case of a successfully used connection that stops working. This
1196 // also allows a remote peer to continue pinging over a locally inactive
1197 // (pruned) connection.
1198 return (now > (last_received() + DEAD_CONNECTION_RECEIVE_TIMEOUT));
1199 }
1200
1201 if (active()) {
1202 // If it has never received anything, keep it alive as long as it is
1203 // actively pinging and not pruned. Otherwise, the connection might be
1204 // deleted before it has a chance to ping. This is the normal case for a
1205 // new connection that is pinging but hasn't received anything yet.
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001206 return false;
1207 }
1208
honghaiz37389b42016-01-04 21:57:33 -08001209 // If it has never received anything and is not actively pinging (pruned), we
1210 // keep it around for at least MIN_CONNECTION_LIFETIME to prevent connections
1211 // from being pruned too quickly during a network change event when two
1212 // networks would be up simultaneously but only for a brief period.
1213 return now > (time_created_ms_ + MIN_CONNECTION_LIFETIME);
Honghai Zhang2b342bf2015-09-30 09:51:58 -07001214}
1215
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001216std::string Connection::ToDebugId() const {
1217 std::stringstream ss;
1218 ss << std::hex << this;
1219 return ss.str();
1220}
1221
honghaize1a0c942016-02-16 14:54:56 -08001222uint32_t Connection::ComputeNetworkCost() const {
1223 // TODO(honghaiz): Will add rtt as part of the network cost.
Honghai Zhang351d77b2016-05-20 15:08:29 -07001224 return port()->network_cost() + remote_candidate_.network_cost();
honghaize1a0c942016-02-16 14:54:56 -08001225}
1226
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001227std::string Connection::ToString() const {
1228 const char CONNECT_STATE_ABBREV[2] = {
1229 '-', // not connected (false)
1230 'C', // connected (true)
1231 };
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001232 const char RECEIVE_STATE_ABBREV[2] = {
1233 '-', // not receiving (false)
1234 'R', // receiving (true)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001235 };
1236 const char WRITE_STATE_ABBREV[4] = {
1237 'W', // STATE_WRITABLE
1238 'w', // STATE_WRITE_UNRELIABLE
1239 '-', // STATE_WRITE_INIT
1240 'x', // STATE_WRITE_TIMEOUT
1241 };
1242 const std::string ICESTATE[4] = {
1243 "W", // STATE_WAITING
1244 "I", // STATE_INPROGRESS
1245 "S", // STATE_SUCCEEDED
1246 "F" // STATE_FAILED
1247 };
1248 const Candidate& local = local_candidate();
1249 const Candidate& remote = remote_candidate();
1250 std::stringstream ss;
guoweis@webrtc.org8c9ff202014-12-04 07:56:02 +00001251 ss << "Conn[" << ToDebugId()
1252 << ":" << port_->content_name()
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001253 << ":" << local.id() << ":" << local.component()
1254 << ":" << local.generation()
1255 << ":" << local.type() << ":" << local.protocol()
1256 << ":" << local.address().ToSensitiveString()
1257 << "->" << remote.id() << ":" << remote.component()
1258 << ":" << remote.priority()
1259 << ":" << remote.type() << ":"
1260 << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
1261 << CONNECT_STATE_ABBREV[connected()]
Peter Thatcher04ac81f2015-09-21 11:48:28 -07001262 << RECEIVE_STATE_ABBREV[receiving()]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001263 << WRITE_STATE_ABBREV[write_state()]
1264 << ICESTATE[state()] << "|"
1265 << priority() << "|";
1266 if (rtt_ < DEFAULT_RTT) {
1267 ss << rtt_ << "]";
1268 } else {
1269 ss << "-]";
1270 }
1271 return ss.str();
1272}
1273
1274std::string Connection::ToSensitiveString() const {
1275 return ToString();
1276}
1277
1278void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1279 StunMessage* response) {
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001280 // Log at LS_INFO if we receive a ping response on an unwritable
1281 // connection.
1282 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1283
honghaiz34b11eb2016-03-16 08:55:44 -07001284 int rtt = request->Elapsed();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001285
Peter Thatcher1fe120a2015-06-10 11:33:17 -07001286 ReceivedPingResponse();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001287
Peter Thatcherb2d26232015-05-15 11:25:14 -07001288 if (LOG_CHECK_LEVEL_V(sev)) {
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001289 bool use_candidate = (
1290 response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr);
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001291 std::string pings;
1292 PrintPingsSinceLastResponse(&pings, 5);
1293 LOG_JV(sev, this) << "Received STUN ping response"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001294 << ", id=" << rtc::hex_encode(request->id())
1295 << ", code=0" // Makes logging easier to parse.
1296 << ", rtt=" << rtt
1297 << ", use_candidate=" << use_candidate
1298 << ", pings_since_last_response=" << pings;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001299 }
1300
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001301 rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
1302
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001303 MaybeAddPrflxCandidate(request, response);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001304}
1305
1306void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1307 StunMessage* response) {
1308 const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
1309 int error_code = STUN_ERROR_GLOBAL_FAILURE;
1310 if (error_attr) {
Peter Thatcher7cbd1882015-09-17 18:54:52 -07001311 error_code = error_attr->code();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001312 }
1313
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001314 LOG_J(LS_INFO, this) << "Received STUN error response"
1315 << " id=" << rtc::hex_encode(request->id())
1316 << " code=" << error_code
1317 << " rtt=" << request->Elapsed();
1318
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001319 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1320 error_code == STUN_ERROR_SERVER_ERROR ||
1321 error_code == STUN_ERROR_UNAUTHORIZED) {
1322 // Recoverable error, retry
1323 } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1324 // Race failure, retry
1325 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1326 HandleRoleConflictFromPeer();
1327 } else {
1328 // This is not a valid connection.
1329 LOG_J(LS_ERROR, this) << "Received STUN error response, code="
1330 << error_code << "; killing connection";
deadbeef376e1232015-11-25 09:00:08 -08001331 FailAndDestroy();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001332 }
1333}
1334
1335void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1336 // Log at LS_INFO if we miss a ping on a writable connection.
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001337 rtc::LoggingSeverity sev = writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
1338 LOG_JV(sev, this) << "Timing-out STUN ping "
1339 << rtc::hex_encode(request->id())
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001340 << " after " << request->Elapsed() << " ms";
1341}
1342
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001343void Connection::OnConnectionRequestSent(ConnectionRequest* request) {
1344 // Log at LS_INFO if we send a ping on an unwritable connection.
1345 rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001346 bool use_candidate = use_candidate_attr();
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001347 LOG_JV(sev, this) << "Sent STUN ping"
Peter Thatcher42af6ca2015-05-15 12:23:27 -07001348 << ", id=" << rtc::hex_encode(request->id())
1349 << ", use_candidate=" << use_candidate;
Peter Thatcher1cf6f812015-05-15 10:40:45 -07001350}
1351
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001352void Connection::HandleRoleConflictFromPeer() {
1353 port_->SignalRoleConflict(port_);
1354}
1355
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -07001356void Connection::MaybeSetRemoteIceCredentialsAndGeneration(
1357 const std::string& ice_ufrag,
1358 const std::string& ice_pwd,
1359 int generation) {
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +00001360 if (remote_candidate_.username() == ice_ufrag &&
1361 remote_candidate_.password().empty()) {
1362 remote_candidate_.set_password(ice_pwd);
1363 }
Taylor Brandstetter0a1bc532016-04-19 18:03:26 -07001364 // TODO(deadbeef): A value of '0' for the generation is used for both
1365 // generation 0 and "generation unknown". It should be changed to an
1366 // rtc::Optional to fix this.
1367 if (remote_candidate_.username() == ice_ufrag &&
1368 remote_candidate_.password() == ice_pwd &&
1369 remote_candidate_.generation() == 0) {
1370 remote_candidate_.set_generation(generation);
1371 }
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +00001372}
1373
1374void Connection::MaybeUpdatePeerReflexiveCandidate(
1375 const Candidate& new_candidate) {
1376 if (remote_candidate_.type() == PRFLX_PORT_TYPE &&
1377 new_candidate.type() != PRFLX_PORT_TYPE &&
1378 remote_candidate_.protocol() == new_candidate.protocol() &&
1379 remote_candidate_.address() == new_candidate.address() &&
1380 remote_candidate_.username() == new_candidate.username() &&
1381 remote_candidate_.password() == new_candidate.password() &&
1382 remote_candidate_.generation() == new_candidate.generation()) {
1383 remote_candidate_ = new_candidate;
1384 }
1385}
1386
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001387void Connection::OnMessage(rtc::Message *pmsg) {
1388 ASSERT(pmsg->message_id == MSG_DELETE);
honghaizd0b31432015-09-30 12:42:17 -07001389 LOG_J(LS_INFO, this) << "Connection deleted";
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001390 SignalDestroyed(this);
1391 delete this;
1392}
1393
honghaiz34b11eb2016-03-16 08:55:44 -07001394int64_t Connection::last_received() const {
Peter Thatcher54360512015-07-08 11:08:35 -07001395 return std::max(last_data_received_,
1396 std::max(last_ping_received_, last_ping_response_received_));
1397}
1398
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001399size_t Connection::recv_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001400 return round(recv_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001401}
1402
1403size_t Connection::recv_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001404 return recv_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001405}
1406
1407size_t Connection::sent_bytes_second() {
Tim Psiakiad13d2f2015-11-10 16:34:50 -08001408 return round(send_rate_tracker_.ComputeRate());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001409}
1410
1411size_t Connection::sent_total_bytes() {
Tim Psiaki63046262015-09-14 10:38:08 -07001412 return send_rate_tracker_.TotalSampleCount();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001413}
1414
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001415size_t Connection::sent_discarded_packets() {
1416 return sent_packets_discarded_;
1417}
1418
1419size_t Connection::sent_total_packets() {
1420 return sent_packets_total_;
1421}
1422
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001423void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
1424 StunMessage* response) {
1425 // RFC 5245
1426 // The agent checks the mapped address from the STUN response. If the
1427 // transport address does not match any of the local candidates that the
1428 // agent knows about, the mapped address represents a new candidate -- a
1429 // peer reflexive candidate.
1430 const StunAddressAttribute* addr =
1431 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1432 if (!addr) {
1433 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1434 << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1435 << "stun response message";
1436 return;
1437 }
1438
1439 bool known_addr = false;
1440 for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1441 if (port_->Candidates()[i].address() == addr->GetAddress()) {
1442 known_addr = true;
1443 break;
1444 }
1445 }
1446 if (known_addr) {
1447 return;
1448 }
1449
1450 // RFC 5245
1451 // Its priority is set equal to the value of the PRIORITY attribute
1452 // in the Binding request.
1453 const StunUInt32Attribute* priority_attr =
1454 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1455 if (!priority_attr) {
1456 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1457 << "No STUN_ATTR_PRIORITY found in the "
1458 << "stun response message";
1459 return;
1460 }
Peter Boström0c4e06b2015-10-07 12:23:21 +02001461 const uint32_t priority = priority_attr->value();
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001462 std::string id = rtc::CreateRandomString(8);
1463
1464 Candidate new_local_candidate;
1465 new_local_candidate.set_id(id);
1466 new_local_candidate.set_component(local_candidate().component());
1467 new_local_candidate.set_type(PRFLX_PORT_TYPE);
1468 new_local_candidate.set_protocol(local_candidate().protocol());
1469 new_local_candidate.set_address(addr->GetAddress());
1470 new_local_candidate.set_priority(priority);
1471 new_local_candidate.set_username(local_candidate().username());
1472 new_local_candidate.set_password(local_candidate().password());
1473 new_local_candidate.set_network_name(local_candidate().network_name());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +00001474 new_local_candidate.set_network_type(local_candidate().network_type());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001475 new_local_candidate.set_related_address(local_candidate().address());
Honghai Zhang80f1db92016-01-27 11:54:45 -08001476 new_local_candidate.set_foundation(ComputeFoundation(
1477 PRFLX_PORT_TYPE, local_candidate().protocol(),
1478 local_candidate().relay_protocol(), local_candidate().address()));
honghaiza0c44ea2016-03-23 16:07:48 -07001479 new_local_candidate.set_network_id(local_candidate().network_id());
1480 new_local_candidate.set_network_cost(local_candidate().network_cost());
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001481
1482 // Change the local candidate of this Connection to the new prflx candidate.
1483 local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1484
1485 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1486 // Connection's local candidate has changed.
1487 SignalStateChange(this);
1488}
1489
deadbeef376e1232015-11-25 09:00:08 -08001490ProxyConnection::ProxyConnection(Port* port,
1491 size_t index,
1492 const Candidate& remote_candidate)
1493 : Connection(port, index, remote_candidate) {}
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001494
1495int ProxyConnection::Send(const void* data, size_t size,
1496 const rtc::PacketOptions& options) {
1497 if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
1498 error_ = EWOULDBLOCK;
1499 return SOCKET_ERROR;
1500 }
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001501 sent_packets_total_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001502 int sent = port_->SendTo(data, size, remote_candidate_.address(),
1503 options, true);
1504 if (sent <= 0) {
1505 ASSERT(sent < 0);
1506 error_ = port_->GetError();
guoweis@webrtc.org930e0042014-11-17 19:42:14 +00001507 sent_packets_discarded_++;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001508 } else {
Tim Psiaki63046262015-09-14 10:38:08 -07001509 send_rate_tracker_.AddSamples(sent);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001510 }
1511 return sent;
1512}
1513
1514} // namespace cricket