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