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/p2ptransportchannel.h"
29
30 #include <set>
31 #include "talk/p2p/base/common.h"
32 #include "talk/p2p/base/relayport.h" // For RELAY_PORT_TYPE.
33 #include "talk/p2p/base/stunport.h" // For STUN_PORT_TYPE.
34 #include "webrtc/base/common.h"
35 #include "webrtc/base/crc32.h"
36 #include "webrtc/base/logging.h"
37 #include "webrtc/base/stringencode.h"
38
39 namespace {
40
41 // messages for queuing up work for ourselves
42 enum {
43 MSG_SORT = 1,
44 MSG_PING,
45 };
46
47 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
48 // for pinging. When the socket is writable, we will use only 1 Kbps because
49 // we don't want to degrade the quality on a modem. These numbers should work
50 // well on a 28.8K modem, which is the slowest connection on which the voice
51 // quality is reasonable at all.
52 static const uint32 PING_PACKET_SIZE = 60 * 8;
53 static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000; // 480ms
54 static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000; // 50ms
55
56 // If there is a current writable connection, then we will also try hard to
57 // make sure it is pinged at this rate.
58 static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900; // 2*WRITABLE_DELAY - bit
59
60 // The minimum improvement in RTT that justifies a switch.
61 static const double kMinImprovement = 10;
62
GetOrigin(cricket::PortInterface * port,cricket::PortInterface * origin_port)63 cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
64 cricket::PortInterface* origin_port) {
65 if (!origin_port)
66 return cricket::PortInterface::ORIGIN_MESSAGE;
67 else if (port == origin_port)
68 return cricket::PortInterface::ORIGIN_THIS_PORT;
69 else
70 return cricket::PortInterface::ORIGIN_OTHER_PORT;
71 }
72
73 // Compares two connections based only on static information about them.
CompareConnectionCandidates(cricket::Connection * a,cricket::Connection * b)74 int CompareConnectionCandidates(cricket::Connection* a,
75 cricket::Connection* b) {
76 // Compare connection priority. Lower values get sorted last.
77 if (a->priority() > b->priority())
78 return 1;
79 if (a->priority() < b->priority())
80 return -1;
81
82 // If we're still tied at this point, prefer a younger generation.
83 return (a->remote_candidate().generation() + a->port()->generation()) -
84 (b->remote_candidate().generation() + b->port()->generation());
85 }
86
87 // Compare two connections based on their writability and static preferences.
CompareConnections(cricket::Connection * a,cricket::Connection * b)88 int CompareConnections(cricket::Connection *a, cricket::Connection *b) {
89 // Sort based on write-state. Better states have lower values.
90 if (a->write_state() < b->write_state())
91 return 1;
92 if (a->write_state() > b->write_state())
93 return -1;
94
95 // Compare the candidate information.
96 return CompareConnectionCandidates(a, b);
97 }
98
99 // Wraps the comparison connection into a less than operator that puts higher
100 // priority writable connections first.
101 class ConnectionCompare {
102 public:
operator ()(const cricket::Connection * ca,const cricket::Connection * cb)103 bool operator()(const cricket::Connection *ca,
104 const cricket::Connection *cb) {
105 cricket::Connection* a = const_cast<cricket::Connection*>(ca);
106 cricket::Connection* b = const_cast<cricket::Connection*>(cb);
107
108 ASSERT(a->port()->IceProtocol() == b->port()->IceProtocol());
109
110 // Compare first on writability and static preferences.
111 int cmp = CompareConnections(a, b);
112 if (cmp > 0)
113 return true;
114 if (cmp < 0)
115 return false;
116
117 // Otherwise, sort based on latency estimate.
118 return a->rtt() < b->rtt();
119
120 // Should we bother checking for the last connection that last received
121 // data? It would help rendezvous on the connection that is also receiving
122 // packets.
123 //
124 // TODO: Yes we should definitely do this. The TCP protocol gains
125 // efficiency by being used bidirectionally, as opposed to two separate
126 // unidirectional streams. This test should probably occur before
127 // comparison of local prefs (assuming combined prefs are the same). We
128 // need to be careful though, not to bounce back and forth with both sides
129 // trying to rendevous with the other.
130 }
131 };
132
133 // Determines whether we should switch between two connections, based first on
134 // static preferences and then (if those are equal) on latency estimates.
ShouldSwitch(cricket::Connection * a_conn,cricket::Connection * b_conn)135 bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
136 if (a_conn == b_conn)
137 return false;
138
139 if (!a_conn || !b_conn) // don't think the latter should happen
140 return true;
141
142 int prefs_cmp = CompareConnections(a_conn, b_conn);
143 if (prefs_cmp < 0)
144 return true;
145 if (prefs_cmp > 0)
146 return false;
147
148 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
149 }
150
151 } // unnamed namespace
152
153 namespace cricket {
154
P2PTransportChannel(const std::string & content_name,int component,P2PTransport * transport,PortAllocator * allocator)155 P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
156 int component,
157 P2PTransport* transport,
158 PortAllocator *allocator) :
159 TransportChannelImpl(content_name, component),
160 transport_(transport),
161 allocator_(allocator),
162 worker_thread_(rtc::Thread::Current()),
163 incoming_only_(false),
164 waiting_for_signaling_(false),
165 error_(0),
166 best_connection_(NULL),
167 pending_best_connection_(NULL),
168 sort_dirty_(false),
169 was_writable_(false),
170 protocol_type_(ICEPROTO_HYBRID),
171 remote_ice_mode_(ICEMODE_FULL),
172 ice_role_(ICEROLE_UNKNOWN),
173 tiebreaker_(0),
174 remote_candidate_generation_(0) {
175 }
176
~P2PTransportChannel()177 P2PTransportChannel::~P2PTransportChannel() {
178 ASSERT(worker_thread_ == rtc::Thread::Current());
179
180 for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
181 delete allocator_sessions_[i];
182 }
183
184 // Add the allocator session to our list so that we know which sessions
185 // are still active.
AddAllocatorSession(PortAllocatorSession * session)186 void P2PTransportChannel::AddAllocatorSession(PortAllocatorSession* session) {
187 session->set_generation(static_cast<uint32>(allocator_sessions_.size()));
188 allocator_sessions_.push_back(session);
189
190 // We now only want to apply new candidates that we receive to the ports
191 // created by this new session because these are replacing those of the
192 // previous sessions.
193 ports_.clear();
194
195 session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
196 session->SignalCandidatesReady.connect(
197 this, &P2PTransportChannel::OnCandidatesReady);
198 session->SignalCandidatesAllocationDone.connect(
199 this, &P2PTransportChannel::OnCandidatesAllocationDone);
200 session->StartGettingPorts();
201 }
202
AddConnection(Connection * connection)203 void P2PTransportChannel::AddConnection(Connection* connection) {
204 connections_.push_back(connection);
205 connection->set_remote_ice_mode(remote_ice_mode_);
206 connection->SignalReadPacket.connect(
207 this, &P2PTransportChannel::OnReadPacket);
208 connection->SignalReadyToSend.connect(
209 this, &P2PTransportChannel::OnReadyToSend);
210 connection->SignalStateChange.connect(
211 this, &P2PTransportChannel::OnConnectionStateChange);
212 connection->SignalDestroyed.connect(
213 this, &P2PTransportChannel::OnConnectionDestroyed);
214 connection->SignalUseCandidate.connect(
215 this, &P2PTransportChannel::OnUseCandidate);
216 }
217
SetIceRole(IceRole ice_role)218 void P2PTransportChannel::SetIceRole(IceRole ice_role) {
219 ASSERT(worker_thread_ == rtc::Thread::Current());
220 if (ice_role_ != ice_role) {
221 ice_role_ = ice_role;
222 for (std::vector<PortInterface *>::iterator it = ports_.begin();
223 it != ports_.end(); ++it) {
224 (*it)->SetIceRole(ice_role);
225 }
226 }
227 }
228
SetIceTiebreaker(uint64 tiebreaker)229 void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) {
230 ASSERT(worker_thread_ == rtc::Thread::Current());
231 if (!ports_.empty()) {
232 LOG(LS_ERROR)
233 << "Attempt to change tiebreaker after Port has been allocated.";
234 return;
235 }
236
237 tiebreaker_ = tiebreaker;
238 }
239
GetIceProtocolType(IceProtocolType * type) const240 bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const {
241 *type = protocol_type_;
242 return true;
243 }
244
SetIceProtocolType(IceProtocolType type)245 void P2PTransportChannel::SetIceProtocolType(IceProtocolType type) {
246 ASSERT(worker_thread_ == rtc::Thread::Current());
247
248 protocol_type_ = type;
249 for (std::vector<PortInterface *>::iterator it = ports_.begin();
250 it != ports_.end(); ++it) {
251 (*it)->SetIceProtocolType(protocol_type_);
252 }
253 }
254
SetIceCredentials(const std::string & ice_ufrag,const std::string & ice_pwd)255 void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
256 const std::string& ice_pwd) {
257 ASSERT(worker_thread_ == rtc::Thread::Current());
258 bool ice_restart = false;
259 if (!ice_ufrag_.empty() && !ice_pwd_.empty()) {
260 // Restart candidate allocation if there is any change in either
261 // ice ufrag or password.
262 ice_restart =
263 IceCredentialsChanged(ice_ufrag_, ice_pwd_, ice_ufrag, ice_pwd);
264 }
265
266 ice_ufrag_ = ice_ufrag;
267 ice_pwd_ = ice_pwd;
268
269 if (ice_restart) {
270 // Restart candidate gathering.
271 Allocate();
272 }
273 }
274
SetRemoteIceCredentials(const std::string & ice_ufrag,const std::string & ice_pwd)275 void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
276 const std::string& ice_pwd) {
277 ASSERT(worker_thread_ == rtc::Thread::Current());
278 bool ice_restart = false;
279 if (!remote_ice_ufrag_.empty() && !remote_ice_pwd_.empty()) {
280 ice_restart = (remote_ice_ufrag_ != ice_ufrag) ||
281 (remote_ice_pwd_!= ice_pwd);
282 }
283
284 remote_ice_ufrag_ = ice_ufrag;
285 remote_ice_pwd_ = ice_pwd;
286
287 if (ice_restart) {
288 // |candidate.generation()| is not signaled in ICEPROTO_RFC5245.
289 // Therefore we need to keep track of the remote ice restart so
290 // newer connections are prioritized over the older.
291 ++remote_candidate_generation_;
292 }
293 }
294
SetRemoteIceMode(IceMode mode)295 void P2PTransportChannel::SetRemoteIceMode(IceMode mode) {
296 remote_ice_mode_ = mode;
297 }
298
299 // Go into the state of processing candidates, and running in general
Connect()300 void P2PTransportChannel::Connect() {
301 ASSERT(worker_thread_ == rtc::Thread::Current());
302 if (ice_ufrag_.empty() || ice_pwd_.empty()) {
303 ASSERT(false);
304 LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the "
305 << "ice_pwd_ are not set.";
306 return;
307 }
308
309 // Kick off an allocator session
310 Allocate();
311
312 // Start pinging as the ports come in.
313 thread()->Post(this, MSG_PING);
314 }
315
316 // Reset the socket, clear up any previous allocations and start over
Reset()317 void P2PTransportChannel::Reset() {
318 ASSERT(worker_thread_ == rtc::Thread::Current());
319
320 // Get rid of all the old allocators. This should clean up everything.
321 for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
322 delete allocator_sessions_[i];
323
324 allocator_sessions_.clear();
325 ports_.clear();
326 connections_.clear();
327 best_connection_ = NULL;
328
329 // Forget about all of the candidates we got before.
330 remote_candidates_.clear();
331
332 // Revert to the initial state.
333 set_readable(false);
334 set_writable(false);
335
336 // Reinitialize the rest of our state.
337 waiting_for_signaling_ = false;
338 sort_dirty_ = false;
339
340 // If we allocated before, start a new one now.
341 if (transport_->connect_requested())
342 Allocate();
343
344 // Start pinging as the ports come in.
345 thread()->Clear(this);
346 thread()->Post(this, MSG_PING);
347 }
348
349 // A new port is available, attempt to make connections for it
OnPortReady(PortAllocatorSession * session,PortInterface * port)350 void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
351 PortInterface* port) {
352 ASSERT(worker_thread_ == rtc::Thread::Current());
353
354 // Set in-effect options on the new port
355 for (OptionMap::const_iterator it = options_.begin();
356 it != options_.end();
357 ++it) {
358 int val = port->SetOption(it->first, it->second);
359 if (val < 0) {
360 LOG_J(LS_WARNING, port) << "SetOption(" << it->first
361 << ", " << it->second
362 << ") failed: " << port->GetError();
363 }
364 }
365
366 // Remember the ports and candidates, and signal that candidates are ready.
367 // The session will handle this, and send an initiate/accept/modify message
368 // if one is pending.
369
370 port->SetIceProtocolType(protocol_type_);
371 port->SetIceRole(ice_role_);
372 port->SetIceTiebreaker(tiebreaker_);
373 ports_.push_back(port);
374 port->SignalUnknownAddress.connect(
375 this, &P2PTransportChannel::OnUnknownAddress);
376 port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
377 port->SignalRoleConflict.connect(
378 this, &P2PTransportChannel::OnRoleConflict);
379
380 // Attempt to create a connection from this new port to all of the remote
381 // candidates that we were given so far.
382
383 std::vector<RemoteCandidate>::iterator iter;
384 for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
385 ++iter) {
386 CreateConnection(port, *iter, iter->origin_port(), false);
387 }
388
389 SortConnections();
390 }
391
392 // A new candidate is available, let listeners know
OnCandidatesReady(PortAllocatorSession * session,const std::vector<Candidate> & candidates)393 void P2PTransportChannel::OnCandidatesReady(
394 PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
395 ASSERT(worker_thread_ == rtc::Thread::Current());
396 for (size_t i = 0; i < candidates.size(); ++i) {
397 SignalCandidateReady(this, candidates[i]);
398 }
399 }
400
OnCandidatesAllocationDone(PortAllocatorSession * session)401 void P2PTransportChannel::OnCandidatesAllocationDone(
402 PortAllocatorSession* session) {
403 ASSERT(worker_thread_ == rtc::Thread::Current());
404 SignalCandidatesAllocationDone(this);
405 }
406
407 // Handle stun packets
OnUnknownAddress(PortInterface * port,const rtc::SocketAddress & address,ProtocolType proto,IceMessage * stun_msg,const std::string & remote_username,bool port_muxed)408 void P2PTransportChannel::OnUnknownAddress(
409 PortInterface* port,
410 const rtc::SocketAddress& address, ProtocolType proto,
411 IceMessage* stun_msg, const std::string &remote_username,
412 bool port_muxed) {
413 ASSERT(worker_thread_ == rtc::Thread::Current());
414
415 // Port has received a valid stun packet from an address that no Connection
416 // is currently available for. See if we already have a candidate with the
417 // address. If it isn't we need to create new candidate for it.
418
419 // Determine if the remote candidates use shared ufrag.
420 bool ufrag_per_port = false;
421 std::vector<RemoteCandidate>::iterator it;
422 if (remote_candidates_.size() > 0) {
423 it = remote_candidates_.begin();
424 std::string username = it->username();
425 for (; it != remote_candidates_.end(); ++it) {
426 if (it->username() != username) {
427 ufrag_per_port = true;
428 break;
429 }
430 }
431 }
432
433 const Candidate* candidate = NULL;
434 bool known_username = false;
435 std::string remote_password;
436 for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
437 if (it->username() == remote_username) {
438 remote_password = it->password();
439 known_username = true;
440 if (ufrag_per_port ||
441 (it->address() == address &&
442 it->protocol() == ProtoToString(proto))) {
443 candidate = &(*it);
444 break;
445 }
446 // We don't want to break here because we may find a match of the address
447 // later.
448 }
449 }
450
451 if (!known_username) {
452 if (port_muxed) {
453 // When Ports are muxed, SignalUnknownAddress is delivered to all
454 // P2PTransportChannel belong to a session. Return from here will
455 // save us from sending stun binding error message from incorrect channel.
456 return;
457 }
458 // Don't know about this username, the request is bogus
459 // This sometimes happens if a binding response comes in before the ACCEPT
460 // message. It is totally valid; the retry state machine will try again.
461 port->SendBindingErrorResponse(stun_msg, address,
462 STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS);
463 return;
464 }
465
466 Candidate new_remote_candidate;
467 if (candidate != NULL) {
468 new_remote_candidate = *candidate;
469 if (ufrag_per_port) {
470 new_remote_candidate.set_address(address);
471 }
472 } else {
473 // Create a new candidate with this address.
474 std::string type;
475 if (port->IceProtocol() == ICEPROTO_RFC5245) {
476 type = PRFLX_PORT_TYPE;
477 } else {
478 // G-ICE doesn't support prflx candidate.
479 // We set candidate type to STUN_PORT_TYPE if the binding request comes
480 // from a relay port or the shared socket is used. Otherwise we use the
481 // port's type as the candidate type.
482 if (port->Type() == RELAY_PORT_TYPE || port->SharedSocket()) {
483 type = STUN_PORT_TYPE;
484 } else {
485 type = port->Type();
486 }
487 }
488
489 std::string id = rtc::CreateRandomString(8);
490 new_remote_candidate = Candidate(
491 id, component(), ProtoToString(proto), address,
492 0, remote_username, remote_password, type,
493 port->Network()->name(), 0U,
494 rtc::ToString<uint32>(rtc::ComputeCrc32(id)));
495 new_remote_candidate.set_priority(
496 new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX,
497 port->Network()->preference(), 0));
498 }
499
500 if (port->IceProtocol() == ICEPROTO_RFC5245) {
501 // RFC 5245
502 // If the source transport address of the request does not match any
503 // existing remote candidates, it represents a new peer reflexive remote
504 // candidate.
505
506 // The priority of the candidate is set to the PRIORITY attribute
507 // from the request.
508 const StunUInt32Attribute* priority_attr =
509 stun_msg->GetUInt32(STUN_ATTR_PRIORITY);
510 if (!priority_attr) {
511 LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
512 << "No STUN_ATTR_PRIORITY found in the "
513 << "stun request message";
514 port->SendBindingErrorResponse(stun_msg, address,
515 STUN_ERROR_BAD_REQUEST,
516 STUN_ERROR_REASON_BAD_REQUEST);
517 return;
518 }
519 new_remote_candidate.set_priority(priority_attr->value());
520
521 // RFC5245, the agent constructs a pair whose local candidate is equal to
522 // the transport address on which the STUN request was received, and a
523 // remote candidate equal to the source transport address where the
524 // request came from.
525
526 // There shouldn't be an existing connection with this remote address.
527 // When ports are muxed, this channel might get multiple unknown address
528 // signals. In that case if the connection is already exists, we should
529 // simply ignore the signal othewise send server error.
530 if (port->GetConnection(new_remote_candidate.address())) {
531 if (port_muxed) {
532 LOG(LS_INFO) << "Connection already exists for peer reflexive "
533 << "candidate: " << new_remote_candidate.ToString();
534 return;
535 } else {
536 ASSERT(false);
537 port->SendBindingErrorResponse(stun_msg, address,
538 STUN_ERROR_SERVER_ERROR,
539 STUN_ERROR_REASON_SERVER_ERROR);
540 return;
541 }
542 }
543
544 Connection* connection = port->CreateConnection(
545 new_remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT);
546 if (!connection) {
547 ASSERT(false);
548 port->SendBindingErrorResponse(stun_msg, address,
549 STUN_ERROR_SERVER_ERROR,
550 STUN_ERROR_REASON_SERVER_ERROR);
551 return;
552 }
553
554 AddConnection(connection);
555 connection->ReceivedPing();
556
557 // Send the pinger a successful stun response.
558 port->SendBindingResponse(stun_msg, address);
559
560 // Update the list of connections since we just added another. We do this
561 // after sending the response since it could (in principle) delete the
562 // connection in question.
563 SortConnections();
564 } else {
565 // Check for connectivity to this address. Create connections
566 // to this address across all local ports. First, add this as a new remote
567 // address
568 if (!CreateConnections(new_remote_candidate, port, true)) {
569 // Hopefully this won't occur, because changing a destination address
570 // shouldn't cause a new connection to fail
571 ASSERT(false);
572 port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
573 STUN_ERROR_REASON_SERVER_ERROR);
574 return;
575 }
576
577 // Send the pinger a successful stun response.
578 port->SendBindingResponse(stun_msg, address);
579
580 // Update the list of connections since we just added another. We do this
581 // after sending the response since it could (in principle) delete the
582 // connection in question.
583 SortConnections();
584 }
585 }
586
OnRoleConflict(PortInterface * port)587 void P2PTransportChannel::OnRoleConflict(PortInterface* port) {
588 SignalRoleConflict(this); // STUN ping will be sent when SetRole is called
589 // from Transport.
590 }
591
592 // When the signalling channel is ready, we can really kick off the allocator
OnSignalingReady()593 void P2PTransportChannel::OnSignalingReady() {
594 ASSERT(worker_thread_ == rtc::Thread::Current());
595 if (waiting_for_signaling_) {
596 waiting_for_signaling_ = false;
597 AddAllocatorSession(allocator_->CreateSession(
598 SessionId(), content_name(), component(), ice_ufrag_, ice_pwd_));
599 }
600 }
601
OnUseCandidate(Connection * conn)602 void P2PTransportChannel::OnUseCandidate(Connection* conn) {
603 ASSERT(worker_thread_ == rtc::Thread::Current());
604 ASSERT(ice_role_ == ICEROLE_CONTROLLED);
605 ASSERT(protocol_type_ == ICEPROTO_RFC5245);
606 if (conn->write_state() == Connection::STATE_WRITABLE) {
607 if (best_connection_ != conn) {
608 pending_best_connection_ = NULL;
609 SwitchBestConnectionTo(conn);
610 // Now we have selected the best connection, time to prune other existing
611 // connections and update the read/write state of the channel.
612 RequestSort();
613 }
614 } else {
615 pending_best_connection_ = conn;
616 }
617 }
618
OnCandidate(const Candidate & candidate)619 void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
620 ASSERT(worker_thread_ == rtc::Thread::Current());
621
622 // Create connections to this remote candidate.
623 CreateConnections(candidate, NULL, false);
624
625 // Resort the connections list, which may have new elements.
626 SortConnections();
627 }
628
629 // Creates connections from all of the ports that we care about to the given
630 // remote candidate. The return value is true if we created a connection from
631 // the origin port.
CreateConnections(const Candidate & remote_candidate,PortInterface * origin_port,bool readable)632 bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate,
633 PortInterface* origin_port,
634 bool readable) {
635 ASSERT(worker_thread_ == rtc::Thread::Current());
636
637 Candidate new_remote_candidate(remote_candidate);
638 new_remote_candidate.set_generation(
639 GetRemoteCandidateGeneration(remote_candidate));
640 // ICE candidates don't need to have username and password set, but
641 // the code below this (specifically, ConnectionRequest::Prepare in
642 // port.cc) uses the remote candidates's username. So, we set it
643 // here.
644 if (remote_candidate.username().empty()) {
645 new_remote_candidate.set_username(remote_ice_ufrag_);
646 }
647 if (remote_candidate.password().empty()) {
648 new_remote_candidate.set_password(remote_ice_pwd_);
649 }
650
651 // If we've already seen the new remote candidate (in the current candidate
652 // generation), then we shouldn't try creating connections for it.
653 // We either already have a connection for it, or we previously created one
654 // and then later pruned it. If we don't return, the channel will again
655 // re-create any connections that were previously pruned, which will then
656 // immediately be re-pruned, churning the network for no purpose.
657 // This only applies to candidates received over signaling (i.e. origin_port
658 // is NULL).
659 if (!origin_port && IsDuplicateRemoteCandidate(new_remote_candidate)) {
660 // return true to indicate success, without creating any new connections.
661 return true;
662 }
663
664 // Add a new connection for this candidate to every port that allows such a
665 // connection (i.e., if they have compatible protocols) and that does not
666 // already have a connection to an equivalent candidate. We must be careful
667 // to make sure that the origin port is included, even if it was pruned,
668 // since that may be the only port that can create this connection.
669 bool created = false;
670 std::vector<PortInterface *>::reverse_iterator it;
671 for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
672 if (CreateConnection(*it, new_remote_candidate, origin_port, readable)) {
673 if (*it == origin_port)
674 created = true;
675 }
676 }
677
678 if ((origin_port != NULL) &&
679 std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
680 if (CreateConnection(
681 origin_port, new_remote_candidate, origin_port, readable))
682 created = true;
683 }
684
685 // Remember this remote candidate so that we can add it to future ports.
686 RememberRemoteCandidate(new_remote_candidate, origin_port);
687
688 return created;
689 }
690
691 // Setup a connection object for the local and remote candidate combination.
692 // And then listen to connection object for changes.
CreateConnection(PortInterface * port,const Candidate & remote_candidate,PortInterface * origin_port,bool readable)693 bool P2PTransportChannel::CreateConnection(PortInterface* port,
694 const Candidate& remote_candidate,
695 PortInterface* origin_port,
696 bool readable) {
697 // Look for an existing connection with this remote address. If one is not
698 // found, then we can create a new connection for this address.
699 Connection* connection = port->GetConnection(remote_candidate.address());
700 if (connection != NULL) {
701 // It is not legal to try to change any of the parameters of an existing
702 // connection; however, the other side can send a duplicate candidate.
703 if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
704 LOG(INFO) << "Attempt to change a remote candidate."
705 << " Existing remote candidate: "
706 << connection->remote_candidate().ToString()
707 << "New remote candidate: "
708 << remote_candidate.ToString();
709 return false;
710 }
711 } else {
712 PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port);
713
714 // Don't create connection if this is a candidate we received in a
715 // message and we are not allowed to make outgoing connections.
716 if (origin == cricket::PortInterface::ORIGIN_MESSAGE && incoming_only_)
717 return false;
718
719 connection = port->CreateConnection(remote_candidate, origin);
720 if (!connection)
721 return false;
722
723 AddConnection(connection);
724
725 LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
726 << connections_.size() << " total)";
727 }
728
729 // If we are readable, it is because we are creating this in response to a
730 // ping from the other side. This will cause the state to become readable.
731 if (readable)
732 connection->ReceivedPing();
733
734 return true;
735 }
736
FindConnection(cricket::Connection * connection) const737 bool P2PTransportChannel::FindConnection(
738 cricket::Connection* connection) const {
739 std::vector<Connection*>::const_iterator citer =
740 std::find(connections_.begin(), connections_.end(), connection);
741 return citer != connections_.end();
742 }
743
GetRemoteCandidateGeneration(const Candidate & candidate)744 uint32 P2PTransportChannel::GetRemoteCandidateGeneration(
745 const Candidate& candidate) {
746 if (protocol_type_ == ICEPROTO_GOOGLE) {
747 // The Candidate.generation() can be trusted. Nothing needs to be done.
748 return candidate.generation();
749 }
750 // |candidate.generation()| is not signaled in ICEPROTO_RFC5245.
751 // Therefore we need to keep track of the remote ice restart so
752 // newer connections are prioritized over the older.
753 ASSERT(candidate.generation() == 0 ||
754 candidate.generation() == remote_candidate_generation_);
755 return remote_candidate_generation_;
756 }
757
758 // Check if remote candidate is already cached.
IsDuplicateRemoteCandidate(const Candidate & candidate)759 bool P2PTransportChannel::IsDuplicateRemoteCandidate(
760 const Candidate& candidate) {
761 for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
762 if (remote_candidates_[i].IsEquivalent(candidate)) {
763 return true;
764 }
765 }
766 return false;
767 }
768
769 // Maintain our remote candidate list, adding this new remote one.
RememberRemoteCandidate(const Candidate & remote_candidate,PortInterface * origin_port)770 void P2PTransportChannel::RememberRemoteCandidate(
771 const Candidate& remote_candidate, PortInterface* origin_port) {
772 // Remove any candidates whose generation is older than this one. The
773 // presence of a new generation indicates that the old ones are not useful.
774 uint32 i = 0;
775 while (i < remote_candidates_.size()) {
776 if (remote_candidates_[i].generation() < remote_candidate.generation()) {
777 LOG(INFO) << "Pruning candidate from old generation: "
778 << remote_candidates_[i].address().ToSensitiveString();
779 remote_candidates_.erase(remote_candidates_.begin() + i);
780 } else {
781 i += 1;
782 }
783 }
784
785 // Make sure this candidate is not a duplicate.
786 if (IsDuplicateRemoteCandidate(remote_candidate)) {
787 LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString();
788 return;
789 }
790
791 // Try this candidate for all future ports.
792 remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
793 }
794
795 // Set options on ourselves is simply setting options on all of our available
796 // port objects.
SetOption(rtc::Socket::Option opt,int value)797 int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) {
798 OptionMap::iterator it = options_.find(opt);
799 if (it == options_.end()) {
800 options_.insert(std::make_pair(opt, value));
801 } else if (it->second == value) {
802 return 0;
803 } else {
804 it->second = value;
805 }
806
807 for (uint32 i = 0; i < ports_.size(); ++i) {
808 int val = ports_[i]->SetOption(opt, value);
809 if (val < 0) {
810 // Because this also occurs deferred, probably no point in reporting an
811 // error
812 LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: "
813 << ports_[i]->GetError();
814 }
815 }
816 return 0;
817 }
818
819 // Send data to the other side, using our best connection.
SendPacket(const char * data,size_t len,const rtc::PacketOptions & options,int flags)820 int P2PTransportChannel::SendPacket(const char *data, size_t len,
821 const rtc::PacketOptions& options,
822 int flags) {
823 ASSERT(worker_thread_ == rtc::Thread::Current());
824 if (flags != 0) {
825 error_ = EINVAL;
826 return -1;
827 }
828 if (best_connection_ == NULL) {
829 error_ = EWOULDBLOCK;
830 return -1;
831 }
832
833 int sent = best_connection_->Send(data, len, options);
834 if (sent <= 0) {
835 ASSERT(sent < 0);
836 error_ = best_connection_->GetError();
837 }
838 return sent;
839 }
840
GetStats(ConnectionInfos * infos)841 bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
842 ASSERT(worker_thread_ == rtc::Thread::Current());
843 // Gather connection infos.
844 infos->clear();
845
846 std::vector<Connection *>::const_iterator it;
847 for (it = connections_.begin(); it != connections_.end(); ++it) {
848 Connection *connection = *it;
849 ConnectionInfo info;
850 info.best_connection = (best_connection_ == connection);
851 info.readable =
852 (connection->read_state() == Connection::STATE_READABLE);
853 info.writable =
854 (connection->write_state() == Connection::STATE_WRITABLE);
855 info.timeout =
856 (connection->write_state() == Connection::STATE_WRITE_TIMEOUT);
857 info.new_connection = !connection->reported();
858 connection->set_reported(true);
859 info.rtt = connection->rtt();
860 info.sent_total_bytes = connection->sent_total_bytes();
861 info.sent_bytes_second = connection->sent_bytes_second();
862 info.recv_total_bytes = connection->recv_total_bytes();
863 info.recv_bytes_second = connection->recv_bytes_second();
864 info.local_candidate = connection->local_candidate();
865 info.remote_candidate = connection->remote_candidate();
866 info.key = connection;
867 infos->push_back(info);
868 }
869
870 return true;
871 }
872
DefaultDscpValue() const873 rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const {
874 OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP);
875 if (it == options_.end()) {
876 return rtc::DSCP_NO_CHANGE;
877 }
878 return static_cast<rtc::DiffServCodePoint> (it->second);
879 }
880
881 // Begin allocate (or immediately re-allocate, if MSG_ALLOCATE pending)
Allocate()882 void P2PTransportChannel::Allocate() {
883 // Time for a new allocator, lets make sure we have a signalling channel
884 // to communicate candidates through first.
885 waiting_for_signaling_ = true;
886 SignalRequestSignaling(this);
887 }
888
889 // Monitor connection states.
UpdateConnectionStates()890 void P2PTransportChannel::UpdateConnectionStates() {
891 uint32 now = rtc::Time();
892
893 // We need to copy the list of connections since some may delete themselves
894 // when we call UpdateState.
895 for (uint32 i = 0; i < connections_.size(); ++i)
896 connections_[i]->UpdateState(now);
897 }
898
899 // Prepare for best candidate sorting.
RequestSort()900 void P2PTransportChannel::RequestSort() {
901 if (!sort_dirty_) {
902 worker_thread_->Post(this, MSG_SORT);
903 sort_dirty_ = true;
904 }
905 }
906
907 // Sort the available connections to find the best one. We also monitor
908 // the number of available connections and the current state.
SortConnections()909 void P2PTransportChannel::SortConnections() {
910 ASSERT(worker_thread_ == rtc::Thread::Current());
911
912 // Make sure the connection states are up-to-date since this affects how they
913 // will be sorted.
914 UpdateConnectionStates();
915
916 if (protocol_type_ == ICEPROTO_HYBRID) {
917 // If we are in hybrid mode, we are not sending any ping requests, so there
918 // is no point in sorting the connections. In hybrid state, ports can have
919 // different protocol than hybrid and protocol may differ from one another.
920 // Instead just update the state of this channel
921 UpdateChannelState();
922 return;
923 }
924
925 // Any changes after this point will require a re-sort.
926 sort_dirty_ = false;
927
928 // Get a list of the networks that we are using.
929 std::set<rtc::Network*> networks;
930 for (uint32 i = 0; i < connections_.size(); ++i)
931 networks.insert(connections_[i]->port()->Network());
932
933 // Find the best alternative connection by sorting. It is important to note
934 // that amongst equal preference, writable connections, this will choose the
935 // one whose estimated latency is lowest. So it is the only one that we
936 // need to consider switching to.
937
938 ConnectionCompare cmp;
939 std::stable_sort(connections_.begin(), connections_.end(), cmp);
940 LOG(LS_VERBOSE) << "Sorting available connections:";
941 for (uint32 i = 0; i < connections_.size(); ++i) {
942 LOG(LS_VERBOSE) << connections_[i]->ToString();
943 }
944
945 Connection* top_connection = NULL;
946 if (connections_.size() > 0)
947 top_connection = connections_[0];
948
949 // We don't want to pick the best connections if channel is using RFC5245
950 // and it's mode is CONTROLLED, as connections will be selected by the
951 // CONTROLLING agent.
952
953 // If necessary, switch to the new choice.
954 if (protocol_type_ != ICEPROTO_RFC5245 || ice_role_ == ICEROLE_CONTROLLING) {
955 if (ShouldSwitch(best_connection_, top_connection))
956 SwitchBestConnectionTo(top_connection);
957 }
958
959 // We can prune any connection for which there is a writable connection on
960 // the same network with better or equal priority. We leave those with
961 // better priority just in case they become writable later (at which point,
962 // we would prune out the current best connection). We leave connections on
963 // other networks because they may not be using the same resources and they
964 // may represent very distinct paths over which we can switch.
965 std::set<rtc::Network*>::iterator network;
966 for (network = networks.begin(); network != networks.end(); ++network) {
967 Connection* primier = GetBestConnectionOnNetwork(*network);
968 if (!primier || (primier->write_state() != Connection::STATE_WRITABLE))
969 continue;
970
971 for (uint32 i = 0; i < connections_.size(); ++i) {
972 if ((connections_[i] != primier) &&
973 (connections_[i]->port()->Network() == *network) &&
974 (CompareConnectionCandidates(primier, connections_[i]) >= 0)) {
975 connections_[i]->Prune();
976 }
977 }
978 }
979
980 // Check if all connections are timedout.
981 bool all_connections_timedout = true;
982 for (uint32 i = 0; i < connections_.size(); ++i) {
983 if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
984 all_connections_timedout = false;
985 break;
986 }
987 }
988
989 // Now update the writable state of the channel with the information we have
990 // so far.
991 if (best_connection_ && best_connection_->writable()) {
992 HandleWritable();
993 } else if (all_connections_timedout) {
994 HandleAllTimedOut();
995 } else {
996 HandleNotWritable();
997 }
998
999 // Update the state of this channel. This method is called whenever the
1000 // state of any connection changes, so this is a good place to do this.
1001 UpdateChannelState();
1002 }
1003
1004
1005 // Track the best connection, and let listeners know
SwitchBestConnectionTo(Connection * conn)1006 void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
1007 // Note: if conn is NULL, the previous best_connection_ has been destroyed,
1008 // so don't use it.
1009 Connection* old_best_connection = best_connection_;
1010 best_connection_ = conn;
1011 if (best_connection_) {
1012 if (old_best_connection) {
1013 LOG_J(LS_INFO, this) << "Previous best connection: "
1014 << old_best_connection->ToString();
1015 }
1016 LOG_J(LS_INFO, this) << "New best connection: "
1017 << best_connection_->ToString();
1018 SignalRouteChange(this, best_connection_->remote_candidate());
1019 } else {
1020 LOG_J(LS_INFO, this) << "No best connection";
1021 }
1022 }
1023
UpdateChannelState()1024 void P2PTransportChannel::UpdateChannelState() {
1025 // The Handle* functions already set the writable state. We'll just double-
1026 // check it here.
1027 bool writable = ((best_connection_ != NULL) &&
1028 (best_connection_->write_state() ==
1029 Connection::STATE_WRITABLE));
1030 ASSERT(writable == this->writable());
1031 if (writable != this->writable())
1032 LOG(LS_ERROR) << "UpdateChannelState: writable state mismatch";
1033
1034 bool readable = false;
1035 for (uint32 i = 0; i < connections_.size(); ++i) {
1036 if (connections_[i]->read_state() == Connection::STATE_READABLE) {
1037 readable = true;
1038 break;
1039 }
1040 }
1041 set_readable(readable);
1042 }
1043
1044 // We checked the status of our connections and we had at least one that
1045 // was writable, go into the writable state.
HandleWritable()1046 void P2PTransportChannel::HandleWritable() {
1047 ASSERT(worker_thread_ == rtc::Thread::Current());
1048 if (!writable()) {
1049 for (uint32 i = 0; i < allocator_sessions_.size(); ++i) {
1050 if (allocator_sessions_[i]->IsGettingPorts()) {
1051 allocator_sessions_[i]->StopGettingPorts();
1052 }
1053 }
1054 }
1055
1056 was_writable_ = true;
1057 set_writable(true);
1058 }
1059
1060 // Notify upper layer about channel not writable state, if it was before.
HandleNotWritable()1061 void P2PTransportChannel::HandleNotWritable() {
1062 ASSERT(worker_thread_ == rtc::Thread::Current());
1063 if (was_writable_) {
1064 was_writable_ = false;
1065 set_writable(false);
1066 }
1067 }
1068
HandleAllTimedOut()1069 void P2PTransportChannel::HandleAllTimedOut() {
1070 // Currently we are treating this as channel not writable.
1071 HandleNotWritable();
1072 }
1073
1074 // If we have a best connection, return it, otherwise return top one in the
1075 // list (later we will mark it best).
GetBestConnectionOnNetwork(rtc::Network * network)1076 Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
1077 rtc::Network* network) {
1078 // If the best connection is on this network, then it wins.
1079 if (best_connection_ && (best_connection_->port()->Network() == network))
1080 return best_connection_;
1081
1082 // Otherwise, we return the top-most in sorted order.
1083 for (uint32 i = 0; i < connections_.size(); ++i) {
1084 if (connections_[i]->port()->Network() == network)
1085 return connections_[i];
1086 }
1087
1088 return NULL;
1089 }
1090
1091 // Handle any queued up requests
OnMessage(rtc::Message * pmsg)1092 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) {
1093 switch (pmsg->message_id) {
1094 case MSG_SORT:
1095 OnSort();
1096 break;
1097 case MSG_PING:
1098 OnPing();
1099 break;
1100 default:
1101 ASSERT(false);
1102 break;
1103 }
1104 }
1105
1106 // Handle queued up sort request
OnSort()1107 void P2PTransportChannel::OnSort() {
1108 // Resort the connections based on the new statistics.
1109 SortConnections();
1110 }
1111
1112 // Handle queued up ping request
OnPing()1113 void P2PTransportChannel::OnPing() {
1114 // Make sure the states of the connections are up-to-date (since this affects
1115 // which ones are pingable).
1116 UpdateConnectionStates();
1117
1118 // Find the oldest pingable connection and have it do a ping.
1119 Connection* conn = FindNextPingableConnection();
1120 if (conn)
1121 PingConnection(conn);
1122
1123 // Post ourselves a message to perform the next ping.
1124 uint32 delay = writable() ? WRITABLE_DELAY : UNWRITABLE_DELAY;
1125 thread()->PostDelayed(delay, this, MSG_PING);
1126 }
1127
1128 // Is the connection in a state for us to even consider pinging the other side?
IsPingable(Connection * conn)1129 bool P2PTransportChannel::IsPingable(Connection* conn) {
1130 // An unconnected connection cannot be written to at all, so pinging is out
1131 // of the question.
1132 if (!conn->connected())
1133 return false;
1134
1135 if (writable()) {
1136 // If we are writable, then we only want to ping connections that could be
1137 // better than this one, i.e., the ones that were not pruned.
1138 return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT);
1139 } else {
1140 // If we are not writable, then we need to try everything that might work.
1141 // This includes both connections that do not have write timeout as well as
1142 // ones that do not have read timeout. A connection could be readable but
1143 // be in write-timeout if we pruned it before. Since the other side is
1144 // still pinging it, it very well might still work.
1145 return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) ||
1146 (conn->read_state() != Connection::STATE_READ_TIMEOUT);
1147 }
1148 }
1149
1150 // Returns the next pingable connection to ping. This will be the oldest
1151 // pingable connection unless we have a writable connection that is past the
1152 // maximum acceptable ping delay.
FindNextPingableConnection()1153 Connection* P2PTransportChannel::FindNextPingableConnection() {
1154 uint32 now = rtc::Time();
1155 if (best_connection_ &&
1156 (best_connection_->write_state() == Connection::STATE_WRITABLE) &&
1157 (best_connection_->last_ping_sent()
1158 + MAX_CURRENT_WRITABLE_DELAY <= now)) {
1159 return best_connection_;
1160 }
1161
1162 Connection* oldest_conn = NULL;
1163 uint32 oldest_time = 0xFFFFFFFF;
1164 for (uint32 i = 0; i < connections_.size(); ++i) {
1165 if (IsPingable(connections_[i])) {
1166 if (connections_[i]->last_ping_sent() < oldest_time) {
1167 oldest_time = connections_[i]->last_ping_sent();
1168 oldest_conn = connections_[i];
1169 }
1170 }
1171 }
1172 return oldest_conn;
1173 }
1174
1175 // Apart from sending ping from |conn| this method also updates
1176 // |use_candidate_attr| flag. The criteria to update this flag is
1177 // explained below.
1178 // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND
1179 // a) Channel is in FULL ICE AND
1180 // a.1) |conn| is the best connection OR
1181 // a.2) there is no best connection OR
1182 // a.3) the best connection is unwritable OR
1183 // a.4) |conn| has higher priority than best_connection.
1184 // b) we're doing LITE ICE AND
1185 // b.1) |conn| is the best_connection AND
1186 // b.2) |conn| is writable.
PingConnection(Connection * conn)1187 void P2PTransportChannel::PingConnection(Connection* conn) {
1188 bool use_candidate = false;
1189 if (protocol_type_ == ICEPROTO_RFC5245) {
1190 if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) {
1191 use_candidate = (conn == best_connection_) ||
1192 (best_connection_ == NULL) ||
1193 (!best_connection_->writable()) ||
1194 (conn->priority() > best_connection_->priority());
1195 } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) {
1196 use_candidate = best_connection_->writable();
1197 }
1198 }
1199 conn->set_use_candidate_attr(use_candidate);
1200 conn->Ping(rtc::Time());
1201 }
1202
1203 // When a connection's state changes, we need to figure out who to use as
1204 // the best connection again. It could have become usable, or become unusable.
OnConnectionStateChange(Connection * connection)1205 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
1206 ASSERT(worker_thread_ == rtc::Thread::Current());
1207
1208 // Update the best connection if the state change is from pending best
1209 // connection and role is controlled.
1210 if (protocol_type_ == ICEPROTO_RFC5245 && ice_role_ == ICEROLE_CONTROLLED) {
1211 if (connection == pending_best_connection_ && connection->writable()) {
1212 pending_best_connection_ = NULL;
1213 SwitchBestConnectionTo(connection);
1214 }
1215 }
1216
1217 // We have to unroll the stack before doing this because we may be changing
1218 // the state of connections while sorting.
1219 RequestSort();
1220 }
1221
1222 // When a connection is removed, edit it out, and then update our best
1223 // connection.
OnConnectionDestroyed(Connection * connection)1224 void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
1225 ASSERT(worker_thread_ == rtc::Thread::Current());
1226
1227 // Note: the previous best_connection_ may be destroyed by now, so don't
1228 // use it.
1229
1230 // Remove this connection from the list.
1231 std::vector<Connection*>::iterator iter =
1232 std::find(connections_.begin(), connections_.end(), connection);
1233 ASSERT(iter != connections_.end());
1234 connections_.erase(iter);
1235
1236 LOG_J(LS_INFO, this) << "Removed connection ("
1237 << static_cast<int>(connections_.size()) << " remaining)";
1238
1239 if (pending_best_connection_ == connection) {
1240 pending_best_connection_ = NULL;
1241 }
1242
1243 // If this is currently the best connection, then we need to pick a new one.
1244 // The call to SortConnections will pick a new one. It looks at the current
1245 // best connection in order to avoid switching between fairly similar ones.
1246 // Since this connection is no longer an option, we can just set best to NULL
1247 // and re-choose a best assuming that there was no best connection.
1248 if (best_connection_ == connection) {
1249 SwitchBestConnectionTo(NULL);
1250 RequestSort();
1251 }
1252
1253 SignalConnectionRemoved(this);
1254 }
1255
1256 // When a port is destroyed remove it from our list of ports to use for
1257 // connection attempts.
OnPortDestroyed(PortInterface * port)1258 void P2PTransportChannel::OnPortDestroyed(PortInterface* port) {
1259 ASSERT(worker_thread_ == rtc::Thread::Current());
1260
1261 // Remove this port from the list (if we didn't drop it already).
1262 std::vector<PortInterface*>::iterator iter =
1263 std::find(ports_.begin(), ports_.end(), port);
1264 if (iter != ports_.end())
1265 ports_.erase(iter);
1266
1267 LOG(INFO) << "Removed port from p2p socket: "
1268 << static_cast<int>(ports_.size()) << " remaining";
1269 }
1270
1271 // We data is available, let listeners know
OnReadPacket(Connection * connection,const char * data,size_t len,const rtc::PacketTime & packet_time)1272 void P2PTransportChannel::OnReadPacket(
1273 Connection *connection, const char *data, size_t len,
1274 const rtc::PacketTime& packet_time) {
1275 ASSERT(worker_thread_ == rtc::Thread::Current());
1276
1277 // Do not deliver, if packet doesn't belong to the correct transport channel.
1278 if (!FindConnection(connection))
1279 return;
1280
1281 // Let the client know of an incoming packet
1282 SignalReadPacket(this, data, len, packet_time, 0);
1283 }
1284
OnReadyToSend(Connection * connection)1285 void P2PTransportChannel::OnReadyToSend(Connection* connection) {
1286 if (connection == best_connection_ && writable()) {
1287 SignalReadyToSend(this);
1288 }
1289 }
1290
1291 } // namespace cricket
1292