1 /*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/p2p/base/port.h"
29
30 #include <algorithm>
31 #include <vector>
32
33 #include "talk/p2p/base/common.h"
34 #include "webrtc/base/base64.h"
35 #include "webrtc/base/crc32.h"
36 #include "webrtc/base/helpers.h"
37 #include "webrtc/base/logging.h"
38 #include "webrtc/base/messagedigest.h"
39 #include "webrtc/base/scoped_ptr.h"
40 #include "webrtc/base/stringencode.h"
41 #include "webrtc/base/stringutils.h"
42
43 namespace {
44
45 // Determines whether we have seen at least the given maximum number of
46 // pings fail to have a response.
TooManyFailures(const std::vector<uint32> & pings_since_last_response,uint32 maximum_failures,uint32 rtt_estimate,uint32 now)47 inline bool TooManyFailures(
48 const std::vector<uint32>& pings_since_last_response,
49 uint32 maximum_failures,
50 uint32 rtt_estimate,
51 uint32 now) {
52
53 // If we haven't sent that many pings, then we can't have failed that many.
54 if (pings_since_last_response.size() < maximum_failures)
55 return false;
56
57 // Check if the window in which we would expect a response to the ping has
58 // already elapsed.
59 return pings_since_last_response[maximum_failures - 1] + rtt_estimate < now;
60 }
61
62 // Determines whether we have gone too long without seeing any response.
TooLongWithoutResponse(const std::vector<uint32> & pings_since_last_response,uint32 maximum_time,uint32 now)63 inline bool TooLongWithoutResponse(
64 const std::vector<uint32>& pings_since_last_response,
65 uint32 maximum_time,
66 uint32 now) {
67
68 if (pings_since_last_response.size() == 0)
69 return false;
70
71 return pings_since_last_response[0] + maximum_time < now;
72 }
73
74 // GICE(ICEPROTO_GOOGLE) requires different username for RTP and RTCP.
75 // This function generates a different username by +1 on the last character of
76 // the given username (|rtp_ufrag|).
GetRtcpUfragFromRtpUfrag(const std::string & rtp_ufrag)77 std::string GetRtcpUfragFromRtpUfrag(const std::string& rtp_ufrag) {
78 ASSERT(!rtp_ufrag.empty());
79 if (rtp_ufrag.empty()) {
80 return rtp_ufrag;
81 }
82 // Change the last character to the one next to it in the base64 table.
83 char new_last_char;
84 if (!rtc::Base64::GetNextBase64Char(rtp_ufrag[rtp_ufrag.size() - 1],
85 &new_last_char)) {
86 // Should not be here.
87 ASSERT(false);
88 }
89 std::string rtcp_ufrag = rtp_ufrag;
90 rtcp_ufrag[rtcp_ufrag.size() - 1] = new_last_char;
91 ASSERT(rtcp_ufrag != rtp_ufrag);
92 return rtcp_ufrag;
93 }
94
95 // We will restrict RTT estimates (when used for determining state) to be
96 // within a reasonable range.
97 const uint32 MINIMUM_RTT = 100; // 0.1 seconds
98 const uint32 MAXIMUM_RTT = 3000; // 3 seconds
99
100 // When we don't have any RTT data, we have to pick something reasonable. We
101 // use a large value just in case the connection is really slow.
102 const uint32 DEFAULT_RTT = MAXIMUM_RTT;
103
104 // Computes our estimate of the RTT given the current estimate.
ConservativeRTTEstimate(uint32 rtt)105 inline uint32 ConservativeRTTEstimate(uint32 rtt) {
106 return rtc::_max(MINIMUM_RTT, rtc::_min(MAXIMUM_RTT, 2 * rtt));
107 }
108
109 // Weighting of the old rtt value to new data.
110 const int RTT_RATIO = 3; // 3 : 1
111
112 // The delay before we begin checking if this port is useless.
113 const int kPortTimeoutDelay = 30 * 1000; // 30 seconds
114
115 // Used by the Connection.
116 const uint32 MSG_DELETE = 1;
117 }
118
119 namespace cricket {
120
121 // TODO(ronghuawu): Use "host", "srflx", "prflx" and "relay". But this requires
122 // the signaling part be updated correspondingly as well.
123 const char LOCAL_PORT_TYPE[] = "local";
124 const char STUN_PORT_TYPE[] = "stun";
125 const char PRFLX_PORT_TYPE[] = "prflx";
126 const char RELAY_PORT_TYPE[] = "relay";
127
128 const char UDP_PROTOCOL_NAME[] = "udp";
129 const char TCP_PROTOCOL_NAME[] = "tcp";
130 const char SSLTCP_PROTOCOL_NAME[] = "ssltcp";
131
132 static const char* const PROTO_NAMES[] = { UDP_PROTOCOL_NAME,
133 TCP_PROTOCOL_NAME,
134 SSLTCP_PROTOCOL_NAME };
135
ProtoToString(ProtocolType proto)136 const char* ProtoToString(ProtocolType proto) {
137 return PROTO_NAMES[proto];
138 }
139
StringToProto(const char * value,ProtocolType * proto)140 bool StringToProto(const char* value, ProtocolType* proto) {
141 for (size_t i = 0; i <= PROTO_LAST; ++i) {
142 if (_stricmp(PROTO_NAMES[i], value) == 0) {
143 *proto = static_cast<ProtocolType>(i);
144 return true;
145 }
146 }
147 return false;
148 }
149
150 // RFC 6544, TCP candidate encoding rules.
151 const int DISCARD_PORT = 9;
152 const char TCPTYPE_ACTIVE_STR[] = "active";
153 const char TCPTYPE_PASSIVE_STR[] = "passive";
154 const char TCPTYPE_SIMOPEN_STR[] = "so";
155
156 // Foundation: An arbitrary string that is the same for two candidates
157 // that have the same type, base IP address, protocol (UDP, TCP,
158 // etc.), and STUN or TURN server. If any of these are different,
159 // then the foundation will be different. Two candidate pairs with
160 // the same foundation pairs are likely to have similar network
161 // characteristics. Foundations are used in the frozen algorithm.
ComputeFoundation(const std::string & type,const std::string & protocol,const rtc::SocketAddress & base_address)162 static std::string ComputeFoundation(
163 const std::string& type,
164 const std::string& protocol,
165 const rtc::SocketAddress& base_address) {
166 std::ostringstream ost;
167 ost << type << base_address.ipaddr().ToString() << protocol;
168 return rtc::ToString<uint32>(rtc::ComputeCrc32(ost.str()));
169 }
170
Port(rtc::Thread * thread,rtc::PacketSocketFactory * factory,rtc::Network * network,const rtc::IPAddress & ip,const std::string & username_fragment,const std::string & password)171 Port::Port(rtc::Thread* thread, rtc::PacketSocketFactory* factory,
172 rtc::Network* network, const rtc::IPAddress& ip,
173 const std::string& username_fragment, const std::string& password)
174 : thread_(thread),
175 factory_(factory),
176 send_retransmit_count_attribute_(false),
177 network_(network),
178 ip_(ip),
179 min_port_(0),
180 max_port_(0),
181 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
182 generation_(0),
183 ice_username_fragment_(username_fragment),
184 password_(password),
185 timeout_delay_(kPortTimeoutDelay),
186 enable_port_packets_(false),
187 ice_protocol_(ICEPROTO_HYBRID),
188 ice_role_(ICEROLE_UNKNOWN),
189 tiebreaker_(0),
190 shared_socket_(true) {
191 Construct();
192 }
193
Port(rtc::Thread * thread,const std::string & type,rtc::PacketSocketFactory * factory,rtc::Network * network,const rtc::IPAddress & ip,int min_port,int max_port,const std::string & username_fragment,const std::string & password)194 Port::Port(rtc::Thread* thread, const std::string& type,
195 rtc::PacketSocketFactory* factory,
196 rtc::Network* network, const rtc::IPAddress& ip,
197 int min_port, int max_port, const std::string& username_fragment,
198 const std::string& password)
199 : thread_(thread),
200 factory_(factory),
201 type_(type),
202 send_retransmit_count_attribute_(false),
203 network_(network),
204 ip_(ip),
205 min_port_(min_port),
206 max_port_(max_port),
207 component_(ICE_CANDIDATE_COMPONENT_DEFAULT),
208 generation_(0),
209 ice_username_fragment_(username_fragment),
210 password_(password),
211 timeout_delay_(kPortTimeoutDelay),
212 enable_port_packets_(false),
213 ice_protocol_(ICEPROTO_HYBRID),
214 ice_role_(ICEROLE_UNKNOWN),
215 tiebreaker_(0),
216 shared_socket_(false) {
217 ASSERT(factory_ != NULL);
218 Construct();
219 }
220
Construct()221 void Port::Construct() {
222 // If the username_fragment and password are empty, we should just create one.
223 if (ice_username_fragment_.empty()) {
224 ASSERT(password_.empty());
225 ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
226 password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
227 }
228 LOG_J(LS_INFO, this) << "Port created";
229 }
230
~Port()231 Port::~Port() {
232 // Delete all of the remaining connections. We copy the list up front
233 // because each deletion will cause it to be modified.
234
235 std::vector<Connection*> list;
236
237 AddressMap::iterator iter = connections_.begin();
238 while (iter != connections_.end()) {
239 list.push_back(iter->second);
240 ++iter;
241 }
242
243 for (uint32 i = 0; i < list.size(); i++)
244 delete list[i];
245 }
246
GetConnection(const rtc::SocketAddress & remote_addr)247 Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) {
248 AddressMap::const_iterator iter = connections_.find(remote_addr);
249 if (iter != connections_.end())
250 return iter->second;
251 else
252 return NULL;
253 }
254
AddAddress(const rtc::SocketAddress & address,const rtc::SocketAddress & base_address,const rtc::SocketAddress & related_address,const std::string & protocol,const std::string & tcptype,const std::string & type,uint32 type_preference,uint32 relay_preference,bool final)255 void Port::AddAddress(const rtc::SocketAddress& address,
256 const rtc::SocketAddress& base_address,
257 const rtc::SocketAddress& related_address,
258 const std::string& protocol,
259 const std::string& tcptype,
260 const std::string& type,
261 uint32 type_preference,
262 uint32 relay_preference,
263 bool final) {
264 if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) {
265 ASSERT(!tcptype.empty());
266 }
267
268 Candidate c;
269 c.set_id(rtc::CreateRandomString(8));
270 c.set_component(component_);
271 c.set_type(type);
272 c.set_protocol(protocol);
273 c.set_tcptype(tcptype);
274 c.set_address(address);
275 c.set_priority(c.GetPriority(type_preference, network_->preference(),
276 relay_preference));
277 c.set_username(username_fragment());
278 c.set_password(password_);
279 c.set_network_name(network_->name());
280 c.set_generation(generation_);
281 c.set_related_address(related_address);
282 c.set_foundation(ComputeFoundation(type, protocol, base_address));
283 candidates_.push_back(c);
284 SignalCandidateReady(this, c);
285
286 if (final) {
287 SignalPortComplete(this);
288 }
289 }
290
AddConnection(Connection * conn)291 void Port::AddConnection(Connection* conn) {
292 connections_[conn->remote_candidate().address()] = conn;
293 conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed);
294 SignalConnectionCreated(this, conn);
295 }
296
OnReadPacket(const char * data,size_t size,const rtc::SocketAddress & addr,ProtocolType proto)297 void Port::OnReadPacket(
298 const char* data, size_t size, const rtc::SocketAddress& addr,
299 ProtocolType proto) {
300 // If the user has enabled port packets, just hand this over.
301 if (enable_port_packets_) {
302 SignalReadPacket(this, data, size, addr);
303 return;
304 }
305
306 // If this is an authenticated STUN request, then signal unknown address and
307 // send back a proper binding response.
308 rtc::scoped_ptr<IceMessage> msg;
309 std::string remote_username;
310 if (!GetStunMessage(data, size, addr, msg.accept(), &remote_username)) {
311 LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
312 << addr.ToSensitiveString() << ")";
313 } else if (!msg) {
314 // STUN message handled already
315 } else if (msg->type() == STUN_BINDING_REQUEST) {
316 // Check for role conflicts.
317 if (IsStandardIce() &&
318 !MaybeIceRoleConflict(addr, msg.get(), remote_username)) {
319 LOG(LS_INFO) << "Received conflicting role from the peer.";
320 return;
321 }
322
323 SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false);
324 } else {
325 // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we
326 // pruned a connection for this port while it had STUN requests in flight,
327 // because we then get back responses for them, which this code correctly
328 // does not handle.
329 if (msg->type() != STUN_BINDING_RESPONSE) {
330 LOG_J(LS_ERROR, this) << "Received unexpected STUN message type ("
331 << msg->type() << ") from unknown address ("
332 << addr.ToSensitiveString() << ")";
333 }
334 }
335 }
336
OnReadyToSend()337 void Port::OnReadyToSend() {
338 AddressMap::iterator iter = connections_.begin();
339 for (; iter != connections_.end(); ++iter) {
340 iter->second->OnReadyToSend();
341 }
342 }
343
AddPrflxCandidate(const Candidate & local)344 size_t Port::AddPrflxCandidate(const Candidate& local) {
345 candidates_.push_back(local);
346 return (candidates_.size() - 1);
347 }
348
IsStandardIce() const349 bool Port::IsStandardIce() const {
350 return (ice_protocol_ == ICEPROTO_RFC5245);
351 }
352
IsGoogleIce() const353 bool Port::IsGoogleIce() const {
354 return (ice_protocol_ == ICEPROTO_GOOGLE);
355 }
356
IsHybridIce() const357 bool Port::IsHybridIce() const {
358 return (ice_protocol_ == ICEPROTO_HYBRID);
359 }
360
GetStunMessage(const char * data,size_t size,const rtc::SocketAddress & addr,IceMessage ** out_msg,std::string * out_username)361 bool Port::GetStunMessage(const char* data, size_t size,
362 const rtc::SocketAddress& addr,
363 IceMessage** out_msg, std::string* out_username) {
364 // NOTE: This could clearly be optimized to avoid allocating any memory.
365 // However, at the data rates we'll be looking at on the client side,
366 // this probably isn't worth worrying about.
367 ASSERT(out_msg != NULL);
368 ASSERT(out_username != NULL);
369 *out_msg = NULL;
370 out_username->clear();
371
372 // Don't bother parsing the packet if we can tell it's not STUN.
373 // In ICE mode, all STUN packets will have a valid fingerprint.
374 if (IsStandardIce() && !StunMessage::ValidateFingerprint(data, size)) {
375 return false;
376 }
377
378 // Parse the request message. If the packet is not a complete and correct
379 // STUN message, then ignore it.
380 rtc::scoped_ptr<IceMessage> stun_msg(new IceMessage());
381 rtc::ByteBuffer buf(data, size);
382 if (!stun_msg->Read(&buf) || (buf.Length() > 0)) {
383 return false;
384 }
385
386 if (stun_msg->type() == STUN_BINDING_REQUEST) {
387 // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first.
388 // If not present, fail with a 400 Bad Request.
389 if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) ||
390 (IsStandardIce() &&
391 !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY))) {
392 LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I "
393 << "from " << addr.ToSensitiveString();
394 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
395 STUN_ERROR_REASON_BAD_REQUEST);
396 return true;
397 }
398
399 // If the username is bad or unknown, fail with a 401 Unauthorized.
400 std::string local_ufrag;
401 std::string remote_ufrag;
402 IceProtocolType remote_protocol_type;
403 if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag,
404 &remote_protocol_type) ||
405 local_ufrag != username_fragment()) {
406 LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
407 << local_ufrag << " from "
408 << addr.ToSensitiveString();
409 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
410 STUN_ERROR_REASON_UNAUTHORIZED);
411 return true;
412 }
413
414 // Port is initialized to GOOGLE-ICE protocol type. If pings from remote
415 // are received before the signal message, protocol type may be different.
416 // Based on the STUN username, we can determine what's the remote protocol.
417 // This also enables us to send the response back using the same protocol
418 // as the request.
419 if (IsHybridIce()) {
420 SetIceProtocolType(remote_protocol_type);
421 }
422
423 // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized
424 if (IsStandardIce() &&
425 !stun_msg->ValidateMessageIntegrity(data, size, password_)) {
426 LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I "
427 << "from " << addr.ToSensitiveString();
428 SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED,
429 STUN_ERROR_REASON_UNAUTHORIZED);
430 return true;
431 }
432 out_username->assign(remote_ufrag);
433 } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) ||
434 (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
435 if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
436 if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
437 LOG_J(LS_ERROR, this) << "Received STUN binding error:"
438 << " class=" << error_code->eclass()
439 << " number=" << error_code->number()
440 << " reason='" << error_code->reason() << "'"
441 << " from " << addr.ToSensitiveString();
442 // Return message to allow error-specific processing
443 } else {
444 LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
445 << "code from " << addr.ToSensitiveString();
446 return true;
447 }
448 }
449 // NOTE: Username should not be used in verifying response messages.
450 out_username->clear();
451 } else if (stun_msg->type() == STUN_BINDING_INDICATION) {
452 LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:"
453 << " from " << addr.ToSensitiveString();
454 out_username->clear();
455 // No stun attributes will be verified, if it's stun indication message.
456 // Returning from end of the this method.
457 } else {
458 LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
459 << stun_msg->type() << ") from "
460 << addr.ToSensitiveString();
461 return true;
462 }
463
464 // Return the STUN message found.
465 *out_msg = stun_msg.release();
466 return true;
467 }
468
IsCompatibleAddress(const rtc::SocketAddress & addr)469 bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) {
470 int family = ip().family();
471 // We use single-stack sockets, so families must match.
472 if (addr.family() != family) {
473 return false;
474 }
475 // Link-local IPv6 ports can only connect to other link-local IPv6 ports.
476 if (family == AF_INET6 && (IPIsPrivate(ip()) != IPIsPrivate(addr.ipaddr()))) {
477 return false;
478 }
479 return true;
480 }
481
ParseStunUsername(const StunMessage * stun_msg,std::string * local_ufrag,std::string * remote_ufrag,IceProtocolType * remote_protocol_type) const482 bool Port::ParseStunUsername(const StunMessage* stun_msg,
483 std::string* local_ufrag,
484 std::string* remote_ufrag,
485 IceProtocolType* remote_protocol_type) const {
486 // The packet must include a username that either begins or ends with our
487 // fragment. It should begin with our fragment if it is a request and it
488 // should end with our fragment if it is a response.
489 local_ufrag->clear();
490 remote_ufrag->clear();
491 const StunByteStringAttribute* username_attr =
492 stun_msg->GetByteString(STUN_ATTR_USERNAME);
493 if (username_attr == NULL)
494 return false;
495
496 const std::string username_attr_str = username_attr->GetString();
497 size_t colon_pos = username_attr_str.find(":");
498 // If we are in hybrid mode set the appropriate ice protocol type based on
499 // the username argument style.
500 if (IsHybridIce()) {
501 *remote_protocol_type = (colon_pos != std::string::npos) ?
502 ICEPROTO_RFC5245 : ICEPROTO_GOOGLE;
503 } else {
504 *remote_protocol_type = ice_protocol_;
505 }
506 if (*remote_protocol_type == ICEPROTO_RFC5245) {
507 if (colon_pos != std::string::npos) { // RFRAG:LFRAG
508 *local_ufrag = username_attr_str.substr(0, colon_pos);
509 *remote_ufrag = username_attr_str.substr(
510 colon_pos + 1, username_attr_str.size());
511 } else {
512 return false;
513 }
514 } else if (*remote_protocol_type == ICEPROTO_GOOGLE) {
515 int remote_frag_len = static_cast<int>(username_attr_str.size());
516 remote_frag_len -= static_cast<int>(username_fragment().size());
517 if (remote_frag_len < 0)
518 return false;
519
520 *local_ufrag = username_attr_str.substr(0, username_fragment().size());
521 *remote_ufrag = username_attr_str.substr(
522 username_fragment().size(), username_attr_str.size());
523 }
524 return true;
525 }
526
MaybeIceRoleConflict(const rtc::SocketAddress & addr,IceMessage * stun_msg,const std::string & remote_ufrag)527 bool Port::MaybeIceRoleConflict(
528 const rtc::SocketAddress& addr, IceMessage* stun_msg,
529 const std::string& remote_ufrag) {
530 // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes.
531 bool ret = true;
532 IceRole remote_ice_role = ICEROLE_UNKNOWN;
533 uint64 remote_tiebreaker = 0;
534 const StunUInt64Attribute* stun_attr =
535 stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING);
536 if (stun_attr) {
537 remote_ice_role = ICEROLE_CONTROLLING;
538 remote_tiebreaker = stun_attr->value();
539 }
540
541 // If |remote_ufrag| is same as port local username fragment and
542 // tie breaker value received in the ping message matches port
543 // tiebreaker value this must be a loopback call.
544 // We will treat this as valid scenario.
545 if (remote_ice_role == ICEROLE_CONTROLLING &&
546 username_fragment() == remote_ufrag &&
547 remote_tiebreaker == IceTiebreaker()) {
548 return true;
549 }
550
551 stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED);
552 if (stun_attr) {
553 remote_ice_role = ICEROLE_CONTROLLED;
554 remote_tiebreaker = stun_attr->value();
555 }
556
557 switch (ice_role_) {
558 case ICEROLE_CONTROLLING:
559 if (ICEROLE_CONTROLLING == remote_ice_role) {
560 if (remote_tiebreaker >= tiebreaker_) {
561 SignalRoleConflict(this);
562 } else {
563 // Send Role Conflict (487) error response.
564 SendBindingErrorResponse(stun_msg, addr,
565 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
566 ret = false;
567 }
568 }
569 break;
570 case ICEROLE_CONTROLLED:
571 if (ICEROLE_CONTROLLED == remote_ice_role) {
572 if (remote_tiebreaker < tiebreaker_) {
573 SignalRoleConflict(this);
574 } else {
575 // Send Role Conflict (487) error response.
576 SendBindingErrorResponse(stun_msg, addr,
577 STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT);
578 ret = false;
579 }
580 }
581 break;
582 default:
583 ASSERT(false);
584 }
585 return ret;
586 }
587
CreateStunUsername(const std::string & remote_username,std::string * stun_username_attr_str) const588 void Port::CreateStunUsername(const std::string& remote_username,
589 std::string* stun_username_attr_str) const {
590 stun_username_attr_str->clear();
591 *stun_username_attr_str = remote_username;
592 if (IsStandardIce()) {
593 // Connectivity checks from L->R will have username RFRAG:LFRAG.
594 stun_username_attr_str->append(":");
595 }
596 stun_username_attr_str->append(username_fragment());
597 }
598
SendBindingResponse(StunMessage * request,const rtc::SocketAddress & addr)599 void Port::SendBindingResponse(StunMessage* request,
600 const rtc::SocketAddress& addr) {
601 ASSERT(request->type() == STUN_BINDING_REQUEST);
602
603 // Retrieve the username from the request.
604 const StunByteStringAttribute* username_attr =
605 request->GetByteString(STUN_ATTR_USERNAME);
606 ASSERT(username_attr != NULL);
607 if (username_attr == NULL) {
608 // No valid username, skip the response.
609 return;
610 }
611
612 // Fill in the response message.
613 StunMessage response;
614 response.SetType(STUN_BINDING_RESPONSE);
615 response.SetTransactionID(request->transaction_id());
616 const StunUInt32Attribute* retransmit_attr =
617 request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT);
618 if (retransmit_attr) {
619 // Inherit the incoming retransmit value in the response so the other side
620 // can see our view of lost pings.
621 response.AddAttribute(new StunUInt32Attribute(
622 STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value()));
623
624 if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) {
625 LOG_J(LS_INFO, this)
626 << "Received a remote ping with high retransmit count: "
627 << retransmit_attr->value();
628 }
629 }
630
631 // Only GICE messages have USERNAME and MAPPED-ADDRESS in the response.
632 // ICE messages use XOR-MAPPED-ADDRESS, and add MESSAGE-INTEGRITY.
633 if (IsStandardIce()) {
634 response.AddAttribute(
635 new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr));
636 response.AddMessageIntegrity(password_);
637 response.AddFingerprint();
638 } else if (IsGoogleIce()) {
639 response.AddAttribute(
640 new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, addr));
641 response.AddAttribute(new StunByteStringAttribute(
642 STUN_ATTR_USERNAME, username_attr->GetString()));
643 }
644
645 // Send the response message.
646 rtc::ByteBuffer buf;
647 response.Write(&buf);
648 rtc::PacketOptions options(DefaultDscpValue());
649 if (SendTo(buf.Data(), buf.Length(), addr, options, false) < 0) {
650 LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to "
651 << addr.ToSensitiveString();
652 }
653
654 // The fact that we received a successful request means that this connection
655 // (if one exists) should now be readable.
656 Connection* conn = GetConnection(addr);
657 ASSERT(conn != NULL);
658 if (conn)
659 conn->ReceivedPing();
660 }
661
SendBindingErrorResponse(StunMessage * request,const rtc::SocketAddress & addr,int error_code,const std::string & reason)662 void Port::SendBindingErrorResponse(StunMessage* request,
663 const rtc::SocketAddress& addr,
664 int error_code, const std::string& reason) {
665 ASSERT(request->type() == STUN_BINDING_REQUEST);
666
667 // Fill in the response message.
668 StunMessage response;
669 response.SetType(STUN_BINDING_ERROR_RESPONSE);
670 response.SetTransactionID(request->transaction_id());
671
672 // When doing GICE, we need to write out the error code incorrectly to
673 // maintain backwards compatiblility.
674 StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode();
675 if (IsStandardIce()) {
676 error_attr->SetCode(error_code);
677 } else if (IsGoogleIce()) {
678 error_attr->SetClass(error_code / 256);
679 error_attr->SetNumber(error_code % 256);
680 }
681 error_attr->SetReason(reason);
682 response.AddAttribute(error_attr);
683
684 if (IsStandardIce()) {
685 // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY,
686 // because we don't have enough information to determine the shared secret.
687 if (error_code != STUN_ERROR_BAD_REQUEST &&
688 error_code != STUN_ERROR_UNAUTHORIZED)
689 response.AddMessageIntegrity(password_);
690 response.AddFingerprint();
691 } else if (IsGoogleIce()) {
692 // GICE responses include a username, if one exists.
693 const StunByteStringAttribute* username_attr =
694 request->GetByteString(STUN_ATTR_USERNAME);
695 if (username_attr)
696 response.AddAttribute(new StunByteStringAttribute(
697 STUN_ATTR_USERNAME, username_attr->GetString()));
698 }
699
700 // Send the response message.
701 rtc::ByteBuffer buf;
702 response.Write(&buf);
703 rtc::PacketOptions options(DefaultDscpValue());
704 SendTo(buf.Data(), buf.Length(), addr, options, false);
705 LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
706 << " to " << addr.ToSensitiveString();
707 }
708
OnMessage(rtc::Message * pmsg)709 void Port::OnMessage(rtc::Message *pmsg) {
710 ASSERT(pmsg->message_id == MSG_CHECKTIMEOUT);
711 CheckTimeout();
712 }
713
ToString() const714 std::string Port::ToString() const {
715 std::stringstream ss;
716 ss << "Port[" << content_name_ << ":" << component_
717 << ":" << generation_ << ":" << type_
718 << ":" << network_->ToString() << "]";
719 return ss.str();
720 }
721
EnablePortPackets()722 void Port::EnablePortPackets() {
723 enable_port_packets_ = true;
724 }
725
OnConnectionDestroyed(Connection * conn)726 void Port::OnConnectionDestroyed(Connection* conn) {
727 AddressMap::iterator iter =
728 connections_.find(conn->remote_candidate().address());
729 ASSERT(iter != connections_.end());
730 connections_.erase(iter);
731
732 // On the controlled side, ports time out, but only after all connections
733 // fail. Note: If a new connection is added after this message is posted,
734 // but it fails and is removed before kPortTimeoutDelay, then this message
735 // will still cause the Port to be destroyed.
736 if (ice_role_ == ICEROLE_CONTROLLED)
737 thread_->PostDelayed(timeout_delay_, this, MSG_CHECKTIMEOUT);
738 }
739
Destroy()740 void Port::Destroy() {
741 ASSERT(connections_.empty());
742 LOG_J(LS_INFO, this) << "Port deleted";
743 SignalDestroyed(this);
744 delete this;
745 }
746
CheckTimeout()747 void Port::CheckTimeout() {
748 ASSERT(ice_role_ == ICEROLE_CONTROLLED);
749 // If this port has no connections, then there's no reason to keep it around.
750 // When the connections time out (both read and write), they will delete
751 // themselves, so if we have any connections, they are either readable or
752 // writable (or still connecting).
753 if (connections_.empty())
754 Destroy();
755 }
756
username_fragment() const757 const std::string Port::username_fragment() const {
758 if (!IsStandardIce() &&
759 component_ == ICE_CANDIDATE_COMPONENT_RTCP) {
760 // In GICE mode, we should adjust username fragment for rtcp component.
761 return GetRtcpUfragFromRtpUfrag(ice_username_fragment_);
762 } else {
763 return ice_username_fragment_;
764 }
765 }
766
767 // A ConnectionRequest is a simple STUN ping used to determine writability.
768 class ConnectionRequest : public StunRequest {
769 public:
ConnectionRequest(Connection * connection)770 explicit ConnectionRequest(Connection* connection)
771 : StunRequest(new IceMessage()),
772 connection_(connection) {
773 }
774
~ConnectionRequest()775 virtual ~ConnectionRequest() {
776 }
777
Prepare(StunMessage * request)778 virtual void Prepare(StunMessage* request) {
779 request->SetType(STUN_BINDING_REQUEST);
780 std::string username;
781 connection_->port()->CreateStunUsername(
782 connection_->remote_candidate().username(), &username);
783 request->AddAttribute(
784 new StunByteStringAttribute(STUN_ATTR_USERNAME, username));
785
786 // connection_ already holds this ping, so subtract one from count.
787 if (connection_->port()->send_retransmit_count_attribute()) {
788 request->AddAttribute(new StunUInt32Attribute(
789 STUN_ATTR_RETRANSMIT_COUNT,
790 static_cast<uint32>(
791 connection_->pings_since_last_response_.size() - 1)));
792 }
793
794 // Adding ICE-specific attributes to the STUN request message.
795 if (connection_->port()->IsStandardIce()) {
796 // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
797 if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
798 request->AddAttribute(new StunUInt64Attribute(
799 STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker()));
800 // Since we are trying aggressive nomination, sending USE-CANDIDATE
801 // attribute in every ping.
802 // If we are dealing with a ice-lite end point, nomination flag
803 // in Connection will be set to false by default. Once the connection
804 // becomes "best connection", nomination flag will be turned on.
805 if (connection_->use_candidate_attr()) {
806 request->AddAttribute(new StunByteStringAttribute(
807 STUN_ATTR_USE_CANDIDATE));
808 }
809 } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) {
810 request->AddAttribute(new StunUInt64Attribute(
811 STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker()));
812 } else {
813 ASSERT(false);
814 }
815
816 // Adding PRIORITY Attribute.
817 // Changing the type preference to Peer Reflexive and local preference
818 // and component id information is unchanged from the original priority.
819 // priority = (2^24)*(type preference) +
820 // (2^8)*(local preference) +
821 // (2^0)*(256 - component ID)
822 uint32 prflx_priority = ICE_TYPE_PREFERENCE_PRFLX << 24 |
823 (connection_->local_candidate().priority() & 0x00FFFFFF);
824 request->AddAttribute(
825 new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority));
826
827 // Adding Message Integrity attribute.
828 request->AddMessageIntegrity(connection_->remote_candidate().password());
829 // Adding Fingerprint.
830 request->AddFingerprint();
831 }
832 }
833
OnResponse(StunMessage * response)834 virtual void OnResponse(StunMessage* response) {
835 connection_->OnConnectionRequestResponse(this, response);
836 }
837
OnErrorResponse(StunMessage * response)838 virtual void OnErrorResponse(StunMessage* response) {
839 connection_->OnConnectionRequestErrorResponse(this, response);
840 }
841
OnTimeout()842 virtual void OnTimeout() {
843 connection_->OnConnectionRequestTimeout(this);
844 }
845
GetNextDelay()846 virtual int GetNextDelay() {
847 // Each request is sent only once. After a single delay , the request will
848 // time out.
849 timeout_ = true;
850 return CONNECTION_RESPONSE_TIMEOUT;
851 }
852
853 private:
854 Connection* connection_;
855 };
856
857 //
858 // Connection
859 //
860
Connection(Port * port,size_t index,const Candidate & remote_candidate)861 Connection::Connection(Port* port, size_t index,
862 const Candidate& remote_candidate)
863 : port_(port), local_candidate_index_(index),
864 remote_candidate_(remote_candidate), read_state_(STATE_READ_INIT),
865 write_state_(STATE_WRITE_INIT), connected_(true), pruned_(false),
866 use_candidate_attr_(false), remote_ice_mode_(ICEMODE_FULL),
867 requests_(port->thread()), rtt_(DEFAULT_RTT), last_ping_sent_(0),
868 last_ping_received_(0), last_data_received_(0),
869 last_ping_response_received_(0), reported_(false), state_(STATE_WAITING) {
870 // All of our connections start in WAITING state.
871 // TODO(mallinath) - Start connections from STATE_FROZEN.
872 // Wire up to send stun packets
873 requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
874 LOG_J(LS_INFO, this) << "Connection created";
875 }
876
~Connection()877 Connection::~Connection() {
878 }
879
local_candidate() const880 const Candidate& Connection::local_candidate() const {
881 ASSERT(local_candidate_index_ < port_->Candidates().size());
882 return port_->Candidates()[local_candidate_index_];
883 }
884
priority() const885 uint64 Connection::priority() const {
886 uint64 priority = 0;
887 // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
888 // Let G be the priority for the candidate provided by the controlling
889 // agent. Let D be the priority for the candidate provided by the
890 // controlled agent.
891 // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
892 IceRole role = port_->GetIceRole();
893 if (role != ICEROLE_UNKNOWN) {
894 uint32 g = 0;
895 uint32 d = 0;
896 if (role == ICEROLE_CONTROLLING) {
897 g = local_candidate().priority();
898 d = remote_candidate_.priority();
899 } else {
900 g = remote_candidate_.priority();
901 d = local_candidate().priority();
902 }
903 priority = rtc::_min(g, d);
904 priority = priority << 32;
905 priority += 2 * rtc::_max(g, d) + (g > d ? 1 : 0);
906 }
907 return priority;
908 }
909
set_read_state(ReadState value)910 void Connection::set_read_state(ReadState value) {
911 ReadState old_value = read_state_;
912 read_state_ = value;
913 if (value != old_value) {
914 LOG_J(LS_VERBOSE, this) << "set_read_state";
915 SignalStateChange(this);
916 CheckTimeout();
917 }
918 }
919
set_write_state(WriteState value)920 void Connection::set_write_state(WriteState value) {
921 WriteState old_value = write_state_;
922 write_state_ = value;
923 if (value != old_value) {
924 LOG_J(LS_VERBOSE, this) << "set_write_state";
925 SignalStateChange(this);
926 CheckTimeout();
927 }
928 }
929
set_state(State state)930 void Connection::set_state(State state) {
931 State old_state = state_;
932 state_ = state;
933 if (state != old_state) {
934 LOG_J(LS_VERBOSE, this) << "set_state";
935 }
936 }
937
set_connected(bool value)938 void Connection::set_connected(bool value) {
939 bool old_value = connected_;
940 connected_ = value;
941 if (value != old_value) {
942 LOG_J(LS_VERBOSE, this) << "set_connected";
943 }
944 }
945
set_use_candidate_attr(bool enable)946 void Connection::set_use_candidate_attr(bool enable) {
947 use_candidate_attr_ = enable;
948 }
949
OnSendStunPacket(const void * data,size_t size,StunRequest * req)950 void Connection::OnSendStunPacket(const void* data, size_t size,
951 StunRequest* req) {
952 rtc::PacketOptions options(port_->DefaultDscpValue());
953 if (port_->SendTo(data, size, remote_candidate_.address(),
954 options, false) < 0) {
955 LOG_J(LS_WARNING, this) << "Failed to send STUN ping " << req->id();
956 }
957 }
958
OnReadPacket(const char * data,size_t size,const rtc::PacketTime & packet_time)959 void Connection::OnReadPacket(
960 const char* data, size_t size, const rtc::PacketTime& packet_time) {
961 rtc::scoped_ptr<IceMessage> msg;
962 std::string remote_ufrag;
963 const rtc::SocketAddress& addr(remote_candidate_.address());
964 if (!port_->GetStunMessage(data, size, addr, msg.accept(), &remote_ufrag)) {
965 // The packet did not parse as a valid STUN message
966
967 // If this connection is readable, then pass along the packet.
968 if (read_state_ == STATE_READABLE) {
969 // readable means data from this address is acceptable
970 // Send it on!
971
972 last_data_received_ = rtc::Time();
973 recv_rate_tracker_.Update(size);
974 SignalReadPacket(this, data, size, packet_time);
975
976 // If timed out sending writability checks, start up again
977 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) {
978 LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. "
979 << "Resetting state to STATE_WRITE_INIT.";
980 set_write_state(STATE_WRITE_INIT);
981 }
982 } else {
983 // Not readable means the remote address hasn't sent a valid
984 // binding request yet.
985
986 LOG_J(LS_WARNING, this)
987 << "Received non-STUN packet from an unreadable connection.";
988 }
989 } else if (!msg) {
990 // The packet was STUN, but failed a check and was handled internally.
991 } else {
992 // The packet is STUN and passed the Port checks.
993 // Perform our own checks to ensure this packet is valid.
994 // If this is a STUN request, then update the readable bit and respond.
995 // If this is a STUN response, then update the writable bit.
996 switch (msg->type()) {
997 case STUN_BINDING_REQUEST:
998 if (remote_ufrag == remote_candidate_.username()) {
999 // Check for role conflicts.
1000 if (port_->IsStandardIce() &&
1001 !port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) {
1002 // Received conflicting role from the peer.
1003 LOG(LS_INFO) << "Received conflicting role from the peer.";
1004 return;
1005 }
1006
1007 // Incoming, validated stun request from remote peer.
1008 // This call will also set the connection readable.
1009 port_->SendBindingResponse(msg.get(), addr);
1010
1011 // If timed out sending writability checks, start up again
1012 if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
1013 set_write_state(STATE_WRITE_INIT);
1014
1015 if ((port_->IsStandardIce()) &&
1016 (port_->GetIceRole() == ICEROLE_CONTROLLED)) {
1017 const StunByteStringAttribute* use_candidate_attr =
1018 msg->GetByteString(STUN_ATTR_USE_CANDIDATE);
1019 if (use_candidate_attr)
1020 SignalUseCandidate(this);
1021 }
1022 } else {
1023 // The packet had the right local username, but the remote username
1024 // was not the right one for the remote address.
1025 LOG_J(LS_ERROR, this)
1026 << "Received STUN request with bad remote username "
1027 << remote_ufrag;
1028 port_->SendBindingErrorResponse(msg.get(), addr,
1029 STUN_ERROR_UNAUTHORIZED,
1030 STUN_ERROR_REASON_UNAUTHORIZED);
1031
1032 }
1033 break;
1034
1035 // Response from remote peer. Does it match request sent?
1036 // This doesn't just check, it makes callbacks if transaction
1037 // id's match.
1038 case STUN_BINDING_RESPONSE:
1039 case STUN_BINDING_ERROR_RESPONSE:
1040 if (port_->IsGoogleIce() ||
1041 msg->ValidateMessageIntegrity(
1042 data, size, remote_candidate().password())) {
1043 requests_.CheckResponse(msg.get());
1044 }
1045 // Otherwise silently discard the response message.
1046 break;
1047
1048 // Remote end point sent an STUN indication instead of regular
1049 // binding request. In this case |last_ping_received_| will be updated.
1050 // Otherwise we can mark connection to read timeout. No response will be
1051 // sent in this scenario.
1052 case STUN_BINDING_INDICATION:
1053 if (port_->IsStandardIce() && read_state_ == STATE_READABLE) {
1054 ReceivedPing();
1055 } else {
1056 LOG_J(LS_WARNING, this) << "Received STUN binding indication "
1057 << "from an unreadable connection.";
1058 }
1059 break;
1060
1061 default:
1062 ASSERT(false);
1063 break;
1064 }
1065 }
1066 }
1067
OnReadyToSend()1068 void Connection::OnReadyToSend() {
1069 if (write_state_ == STATE_WRITABLE) {
1070 SignalReadyToSend(this);
1071 }
1072 }
1073
Prune()1074 void Connection::Prune() {
1075 if (!pruned_) {
1076 LOG_J(LS_VERBOSE, this) << "Connection pruned";
1077 pruned_ = true;
1078 requests_.Clear();
1079 set_write_state(STATE_WRITE_TIMEOUT);
1080 }
1081 }
1082
Destroy()1083 void Connection::Destroy() {
1084 LOG_J(LS_VERBOSE, this) << "Connection destroyed";
1085 set_read_state(STATE_READ_TIMEOUT);
1086 set_write_state(STATE_WRITE_TIMEOUT);
1087 }
1088
UpdateState(uint32 now)1089 void Connection::UpdateState(uint32 now) {
1090 uint32 rtt = ConservativeRTTEstimate(rtt_);
1091
1092 std::string pings;
1093 for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
1094 char buf[32];
1095 rtc::sprintfn(buf, sizeof(buf), "%u",
1096 pings_since_last_response_[i]);
1097 pings.append(buf).append(" ");
1098 }
1099 LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_=" <<
1100 pings << ", rtt=" << rtt << ", now=" << now;
1101
1102 // Check the readable state.
1103 //
1104 // Since we don't know how many pings the other side has attempted, the best
1105 // test we can do is a simple window.
1106 // If other side has not sent ping after connection has become readable, use
1107 // |last_data_received_| as the indication.
1108 // If remote endpoint is doing RFC 5245, it's not required to send ping
1109 // after connection is established. If this connection is serving a data
1110 // channel, it may not be in a position to send media continuously. Do not
1111 // mark connection timeout if it's in RFC5245 mode.
1112 // Below check will be performed with end point if it's doing google-ice.
1113 if (port_->IsGoogleIce() && (read_state_ == STATE_READABLE) &&
1114 (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now) &&
1115 (last_data_received_ + CONNECTION_READ_TIMEOUT <= now)) {
1116 LOG_J(LS_INFO, this) << "Unreadable after "
1117 << now - last_ping_received_
1118 << " ms without a ping,"
1119 << " ms since last received response="
1120 << now - last_ping_response_received_
1121 << " ms since last received data="
1122 << now - last_data_received_
1123 << " rtt=" << rtt;
1124 set_read_state(STATE_READ_TIMEOUT);
1125 }
1126
1127 // Check the writable state. (The order of these checks is important.)
1128 //
1129 // Before becoming unwritable, we allow for a fixed number of pings to fail
1130 // (i.e., receive no response). We also have to give the response time to
1131 // get back, so we include a conservative estimate of this.
1132 //
1133 // Before timing out writability, we give a fixed amount of time. This is to
1134 // allow for changes in network conditions.
1135
1136 if ((write_state_ == STATE_WRITABLE) &&
1137 TooManyFailures(pings_since_last_response_,
1138 CONNECTION_WRITE_CONNECT_FAILURES,
1139 rtt,
1140 now) &&
1141 TooLongWithoutResponse(pings_since_last_response_,
1142 CONNECTION_WRITE_CONNECT_TIMEOUT,
1143 now)) {
1144 uint32 max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
1145 LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
1146 << " ping failures and "
1147 << now - pings_since_last_response_[0]
1148 << " ms without a response,"
1149 << " ms since last received ping="
1150 << now - last_ping_received_
1151 << " ms since last received data="
1152 << now - last_data_received_
1153 << " rtt=" << rtt;
1154 set_write_state(STATE_WRITE_UNRELIABLE);
1155 }
1156
1157 if ((write_state_ == STATE_WRITE_UNRELIABLE ||
1158 write_state_ == STATE_WRITE_INIT) &&
1159 TooLongWithoutResponse(pings_since_last_response_,
1160 CONNECTION_WRITE_TIMEOUT,
1161 now)) {
1162 LOG_J(LS_INFO, this) << "Timed out after "
1163 << now - pings_since_last_response_[0]
1164 << " ms without a response, rtt=" << rtt;
1165 set_write_state(STATE_WRITE_TIMEOUT);
1166 }
1167 }
1168
Ping(uint32 now)1169 void Connection::Ping(uint32 now) {
1170 ASSERT(connected_);
1171 last_ping_sent_ = now;
1172 pings_since_last_response_.push_back(now);
1173 ConnectionRequest *req = new ConnectionRequest(this);
1174 LOG_J(LS_VERBOSE, this) << "Sending STUN ping " << req->id() << " at " << now;
1175 requests_.Send(req);
1176 state_ = STATE_INPROGRESS;
1177 }
1178
ReceivedPing()1179 void Connection::ReceivedPing() {
1180 last_ping_received_ = rtc::Time();
1181 set_read_state(STATE_READABLE);
1182 }
1183
ToString() const1184 std::string Connection::ToString() const {
1185 const char CONNECT_STATE_ABBREV[2] = {
1186 '-', // not connected (false)
1187 'C', // connected (true)
1188 };
1189 const char READ_STATE_ABBREV[3] = {
1190 '-', // STATE_READ_INIT
1191 'R', // STATE_READABLE
1192 'x', // STATE_READ_TIMEOUT
1193 };
1194 const char WRITE_STATE_ABBREV[4] = {
1195 'W', // STATE_WRITABLE
1196 'w', // STATE_WRITE_UNRELIABLE
1197 '-', // STATE_WRITE_INIT
1198 'x', // STATE_WRITE_TIMEOUT
1199 };
1200 const std::string ICESTATE[4] = {
1201 "W", // STATE_WAITING
1202 "I", // STATE_INPROGRESS
1203 "S", // STATE_SUCCEEDED
1204 "F" // STATE_FAILED
1205 };
1206 const Candidate& local = local_candidate();
1207 const Candidate& remote = remote_candidate();
1208 std::stringstream ss;
1209 ss << "Conn[" << port_->content_name()
1210 << ":" << local.id() << ":" << local.component()
1211 << ":" << local.generation()
1212 << ":" << local.type() << ":" << local.protocol()
1213 << ":" << local.address().ToSensitiveString()
1214 << "->" << remote.id() << ":" << remote.component()
1215 << ":" << remote.priority()
1216 << ":" << remote.type() << ":"
1217 << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|"
1218 << CONNECT_STATE_ABBREV[connected()]
1219 << READ_STATE_ABBREV[read_state()]
1220 << WRITE_STATE_ABBREV[write_state()]
1221 << ICESTATE[state()] << "|"
1222 << priority() << "|";
1223 if (rtt_ < DEFAULT_RTT) {
1224 ss << rtt_ << "]";
1225 } else {
1226 ss << "-]";
1227 }
1228 return ss.str();
1229 }
1230
ToSensitiveString() const1231 std::string Connection::ToSensitiveString() const {
1232 return ToString();
1233 }
1234
OnConnectionRequestResponse(ConnectionRequest * request,StunMessage * response)1235 void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
1236 StunMessage* response) {
1237 // We've already validated that this is a STUN binding response with
1238 // the correct local and remote username for this connection.
1239 // So if we're not already, become writable. We may be bringing a pruned
1240 // connection back to life, but if we don't really want it, we can always
1241 // prune it again.
1242 uint32 rtt = request->Elapsed();
1243 set_write_state(STATE_WRITABLE);
1244 set_state(STATE_SUCCEEDED);
1245
1246 if (remote_ice_mode_ == ICEMODE_LITE) {
1247 // A ice-lite end point never initiates ping requests. This will allow
1248 // us to move to STATE_READABLE.
1249 ReceivedPing();
1250 }
1251
1252 std::string pings;
1253 for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
1254 char buf[32];
1255 rtc::sprintfn(buf, sizeof(buf), "%u",
1256 pings_since_last_response_[i]);
1257 pings.append(buf).append(" ");
1258 }
1259
1260 rtc::LoggingSeverity level =
1261 (pings_since_last_response_.size() > CONNECTION_WRITE_CONNECT_FAILURES) ?
1262 rtc::LS_INFO : rtc::LS_VERBOSE;
1263
1264 LOG_JV(level, this) << "Received STUN ping response " << request->id()
1265 << ", pings_since_last_response_=" << pings
1266 << ", rtt=" << rtt;
1267
1268 pings_since_last_response_.clear();
1269 last_ping_response_received_ = rtc::Time();
1270 rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
1271
1272 // Peer reflexive candidate is only for RFC 5245 ICE.
1273 if (port_->IsStandardIce()) {
1274 MaybeAddPrflxCandidate(request, response);
1275 }
1276 }
1277
OnConnectionRequestErrorResponse(ConnectionRequest * request,StunMessage * response)1278 void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
1279 StunMessage* response) {
1280 const StunErrorCodeAttribute* error_attr = response->GetErrorCode();
1281 int error_code = STUN_ERROR_GLOBAL_FAILURE;
1282 if (error_attr) {
1283 if (port_->IsGoogleIce()) {
1284 // When doing GICE, the error code is written out incorrectly, so we need
1285 // to unmunge it here.
1286 error_code = error_attr->eclass() * 256 + error_attr->number();
1287 } else {
1288 error_code = error_attr->code();
1289 }
1290 }
1291
1292 if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE ||
1293 error_code == STUN_ERROR_SERVER_ERROR ||
1294 error_code == STUN_ERROR_UNAUTHORIZED) {
1295 // Recoverable error, retry
1296 } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) {
1297 // Race failure, retry
1298 } else if (error_code == STUN_ERROR_ROLE_CONFLICT) {
1299 HandleRoleConflictFromPeer();
1300 } else {
1301 // This is not a valid connection.
1302 LOG_J(LS_ERROR, this) << "Received STUN error response, code="
1303 << error_code << "; killing connection";
1304 set_state(STATE_FAILED);
1305 set_write_state(STATE_WRITE_TIMEOUT);
1306 }
1307 }
1308
OnConnectionRequestTimeout(ConnectionRequest * request)1309 void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
1310 // Log at LS_INFO if we miss a ping on a writable connection.
1311 rtc::LoggingSeverity sev = (write_state_ == STATE_WRITABLE) ?
1312 rtc::LS_INFO : rtc::LS_VERBOSE;
1313 LOG_JV(sev, this) << "Timing-out STUN ping " << request->id()
1314 << " after " << request->Elapsed() << " ms";
1315 }
1316
CheckTimeout()1317 void Connection::CheckTimeout() {
1318 // If both read and write have timed out or read has never initialized, then
1319 // this connection can contribute no more to p2p socket unless at some later
1320 // date readability were to come back. However, we gave readability a long
1321 // time to timeout, so at this point, it seems fair to get rid of this
1322 // connection.
1323 if ((read_state_ == STATE_READ_TIMEOUT ||
1324 read_state_ == STATE_READ_INIT) &&
1325 write_state_ == STATE_WRITE_TIMEOUT) {
1326 port_->thread()->Post(this, MSG_DELETE);
1327 }
1328 }
1329
HandleRoleConflictFromPeer()1330 void Connection::HandleRoleConflictFromPeer() {
1331 port_->SignalRoleConflict(port_);
1332 }
1333
OnMessage(rtc::Message * pmsg)1334 void Connection::OnMessage(rtc::Message *pmsg) {
1335 ASSERT(pmsg->message_id == MSG_DELETE);
1336
1337 LOG_J(LS_INFO, this) << "Connection deleted";
1338 SignalDestroyed(this);
1339 delete this;
1340 }
1341
recv_bytes_second()1342 size_t Connection::recv_bytes_second() {
1343 return recv_rate_tracker_.units_second();
1344 }
1345
recv_total_bytes()1346 size_t Connection::recv_total_bytes() {
1347 return recv_rate_tracker_.total_units();
1348 }
1349
sent_bytes_second()1350 size_t Connection::sent_bytes_second() {
1351 return send_rate_tracker_.units_second();
1352 }
1353
sent_total_bytes()1354 size_t Connection::sent_total_bytes() {
1355 return send_rate_tracker_.total_units();
1356 }
1357
MaybeAddPrflxCandidate(ConnectionRequest * request,StunMessage * response)1358 void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
1359 StunMessage* response) {
1360 // RFC 5245
1361 // The agent checks the mapped address from the STUN response. If the
1362 // transport address does not match any of the local candidates that the
1363 // agent knows about, the mapped address represents a new candidate -- a
1364 // peer reflexive candidate.
1365 const StunAddressAttribute* addr =
1366 response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
1367 if (!addr) {
1368 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1369 << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the "
1370 << "stun response message";
1371 return;
1372 }
1373
1374 bool known_addr = false;
1375 for (size_t i = 0; i < port_->Candidates().size(); ++i) {
1376 if (port_->Candidates()[i].address() == addr->GetAddress()) {
1377 known_addr = true;
1378 break;
1379 }
1380 }
1381 if (known_addr) {
1382 return;
1383 }
1384
1385 // RFC 5245
1386 // Its priority is set equal to the value of the PRIORITY attribute
1387 // in the Binding request.
1388 const StunUInt32Attribute* priority_attr =
1389 request->msg()->GetUInt32(STUN_ATTR_PRIORITY);
1390 if (!priority_attr) {
1391 LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - "
1392 << "No STUN_ATTR_PRIORITY found in the "
1393 << "stun response message";
1394 return;
1395 }
1396 const uint32 priority = priority_attr->value();
1397 std::string id = rtc::CreateRandomString(8);
1398
1399 Candidate new_local_candidate;
1400 new_local_candidate.set_id(id);
1401 new_local_candidate.set_component(local_candidate().component());
1402 new_local_candidate.set_type(PRFLX_PORT_TYPE);
1403 new_local_candidate.set_protocol(local_candidate().protocol());
1404 new_local_candidate.set_address(addr->GetAddress());
1405 new_local_candidate.set_priority(priority);
1406 new_local_candidate.set_username(local_candidate().username());
1407 new_local_candidate.set_password(local_candidate().password());
1408 new_local_candidate.set_network_name(local_candidate().network_name());
1409 new_local_candidate.set_related_address(local_candidate().address());
1410 new_local_candidate.set_foundation(
1411 ComputeFoundation(PRFLX_PORT_TYPE, local_candidate().protocol(),
1412 local_candidate().address()));
1413
1414 // Change the local candidate of this Connection to the new prflx candidate.
1415 local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
1416
1417 // SignalStateChange to force a re-sort in P2PTransportChannel as this
1418 // Connection's local candidate has changed.
1419 SignalStateChange(this);
1420 }
1421
ProxyConnection(Port * port,size_t index,const Candidate & candidate)1422 ProxyConnection::ProxyConnection(Port* port, size_t index,
1423 const Candidate& candidate)
1424 : Connection(port, index, candidate), error_(0) {
1425 }
1426
Send(const void * data,size_t size,const rtc::PacketOptions & options)1427 int ProxyConnection::Send(const void* data, size_t size,
1428 const rtc::PacketOptions& options) {
1429 if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) {
1430 error_ = EWOULDBLOCK;
1431 return SOCKET_ERROR;
1432 }
1433 int sent = port_->SendTo(data, size, remote_candidate_.address(),
1434 options, true);
1435 if (sent <= 0) {
1436 ASSERT(sent < 0);
1437 error_ = port_->GetError();
1438 } else {
1439 send_rate_tracker_.Update(sent);
1440 }
1441 return sent;
1442 }
1443
1444 } // namespace cricket
1445