Index: remoting/protocol/libjingle_transport_factory.cc |
diff --git a/remoting/protocol/libjingle_transport_factory.cc b/remoting/protocol/libjingle_transport_factory.cc |
index 76c3507aaa6d55b6e107ce364e0618a9ec33ebd2..ef22f2a95f380a950171448b590edd010894b21e 100644 |
--- a/remoting/protocol/libjingle_transport_factory.cc |
+++ b/remoting/protocol/libjingle_transport_factory.cc |
@@ -4,6 +4,7 @@ |
#include "remoting/protocol/libjingle_transport_factory.h" |
+#include "base/callback.h" |
#include "base/single_thread_task_runner.h" |
#include "base/thread_task_runner_handle.h" |
#include "base/timer/timer.h" |
@@ -13,9 +14,9 @@ |
#include "jingle/glue/utils.h" |
#include "net/base/net_errors.h" |
#include "remoting/base/constants.h" |
+#include "remoting/jingle_glue/jingle_info_request.h" |
#include "remoting/jingle_glue/network_settings.h" |
#include "remoting/protocol/channel_authenticator.h" |
-#include "remoting/protocol/transport_config.h" |
#include "third_party/libjingle/source/talk/base/network.h" |
#include "third_party/libjingle/source/talk/p2p/base/constants.h" |
#include "third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h" |
@@ -40,13 +41,21 @@ const int kTcpSendBufferSize = kTcpReceiveBufferSize + 30 * 1024; |
const int kMaxReconnectAttempts = 2; |
const int kReconnectDelaySeconds = 15; |
-class LibjingleStreamTransport : public StreamTransport, |
- public sigslot::has_slots<> { |
+// Get fresh STUN/Relay configuration every hour. |
+const int kJingleInfoUpdatePeriodSeconds = 3600; |
+ |
+class LibjingleStreamTransport |
+ : public StreamTransport, |
+ public base::SupportsWeakPtr<LibjingleStreamTransport>, |
+ public sigslot::has_slots<> { |
public: |
LibjingleStreamTransport(cricket::PortAllocator* port_allocator, |
- bool incoming_only); |
+ const NetworkSettings& network_settings); |
virtual ~LibjingleStreamTransport(); |
+ // Called by JingleTransportFactory when it has fresh Jingle info. |
+ void OnCanStart(); |
+ |
// StreamTransport interface. |
virtual void Initialize( |
const std::string& name, |
@@ -59,6 +68,8 @@ class LibjingleStreamTransport : public StreamTransport, |
virtual bool is_connected() const OVERRIDE; |
private: |
+ void DoStart(); |
+ |
// Signal handlers for cricket::TransportChannel. |
void OnRequestSignaling(cricket::TransportChannelImpl* channel); |
void OnCandidateReady(cricket::TransportChannelImpl* channel, |
@@ -86,7 +97,7 @@ class LibjingleStreamTransport : public StreamTransport, |
void NotifyConnectFailed(); |
cricket::PortAllocator* port_allocator_; |
- bool incoming_only_; |
+ NetworkSettings network_settings_; |
std::string name_; |
EventHandler* event_handler_; |
@@ -95,6 +106,9 @@ class LibjingleStreamTransport : public StreamTransport, |
std::string ice_username_fragment_; |
std::string ice_password_; |
+ bool can_start_; |
+ |
+ std::list<cricket::Candidate> pending_candidates_; |
scoped_ptr<cricket::P2PTransportChannel> channel_; |
bool channel_was_writable_; |
int connect_attempts_left_; |
@@ -108,13 +122,14 @@ class LibjingleStreamTransport : public StreamTransport, |
LibjingleStreamTransport::LibjingleStreamTransport( |
cricket::PortAllocator* port_allocator, |
- bool incoming_only) |
+ const NetworkSettings& network_settings) |
: port_allocator_(port_allocator), |
- incoming_only_(incoming_only), |
+ network_settings_(network_settings), |
event_handler_(NULL), |
ice_username_fragment_( |
talk_base::CreateRandomString(cricket::ICE_UFRAG_LENGTH)), |
ice_password_(talk_base::CreateRandomString(cricket::ICE_PWD_LENGTH)), |
+ can_start_(false), |
channel_was_writable_(false), |
connect_attempts_left_(kMaxReconnectAttempts) { |
} |
@@ -131,6 +146,22 @@ LibjingleStreamTransport::~LibjingleStreamTransport() { |
} |
} |
+void LibjingleStreamTransport::OnCanStart() { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ DCHECK(!can_start_); |
+ can_start_ = true; |
+ |
+ // If Connect() has been called then start connection. |
+ if (!callback_.is_null()) |
+ DoStart(); |
+ |
+ while (!pending_candidates_.empty()) { |
+ channel_->OnCandidate(pending_candidates_.front()); |
+ pending_candidates_.pop_front(); |
+ } |
+} |
+ |
void LibjingleStreamTransport::Initialize( |
const std::string& name, |
Transport::EventHandler* event_handler, |
@@ -151,9 +182,13 @@ void LibjingleStreamTransport::Initialize( |
void LibjingleStreamTransport::Connect( |
const StreamTransport::ConnectedCallback& callback) { |
DCHECK(CalledOnValidThread()); |
- |
callback_ = callback; |
+ if (can_start_) |
+ DoStart(); |
+} |
+ |
+void LibjingleStreamTransport::DoStart() { |
DCHECK(!channel_.get()); |
// Create P2PTransportChannel, attach signal handlers and connect it. |
@@ -169,7 +204,10 @@ void LibjingleStreamTransport::Connect( |
this, &LibjingleStreamTransport::OnRouteChange); |
channel_->SignalWritableState.connect( |
this, &LibjingleStreamTransport::OnWritableState); |
- channel_->set_incoming_only(incoming_only_); |
+ if (network_settings_.nat_traversal_mode == |
+ NetworkSettings::NAT_TRAVERSAL_DISABLED) { |
+ channel_->set_incoming_only(true); |
+ } |
channel_->Connect(); |
@@ -211,7 +249,11 @@ void LibjingleStreamTransport::Connect( |
void LibjingleStreamTransport::AddRemoteCandidate( |
const cricket::Candidate& candidate) { |
DCHECK(CalledOnValidThread()); |
- channel_->OnCandidate(candidate); |
+ if (channel_) { |
+ channel_->OnCandidate(candidate); |
+ } else { |
+ pending_candidates_.push_back(candidate); |
+ } |
} |
const std::string& LibjingleStreamTransport::name() const { |
@@ -362,10 +404,12 @@ void LibjingleStreamTransport::NotifyConnectFailed() { |
} // namespace |
LibjingleTransportFactory::LibjingleTransportFactory( |
+ SignalStrategy* signal_strategy, |
scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator, |
- bool incoming_only) |
- : port_allocator_(port_allocator.Pass()), |
- incoming_only_(incoming_only) { |
+ const NetworkSettings& network_settings) |
+ : signal_strategy_(signal_strategy), |
+ port_allocator_(port_allocator.Pass()), |
+ network_settings_(network_settings) { |
jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
} |
@@ -377,27 +421,27 @@ LibjingleTransportFactory::~LibjingleTransportFactory() { |
task_runner->DeleteSoon(FROM_HERE, port_allocator_.release()); |
} |
-void LibjingleTransportFactory::SetTransportConfig( |
- const TransportConfig& config) { |
- std::vector<talk_base::SocketAddress> stun_hosts; |
- talk_base::SocketAddress stun_address; |
- if (stun_address.FromString(config.stun_server)) { |
- stun_hosts.push_back(stun_address); |
- port_allocator_->SetStunHosts(stun_hosts); |
- } else { |
- LOG(ERROR) << "Failed to parse stun server address: " |
- << config.stun_server; |
- } |
- |
- std::vector<std::string> relay_hosts; |
- relay_hosts.push_back(config.relay_server); |
- port_allocator_->SetRelayHosts(relay_hosts); |
- port_allocator_->SetRelayToken(config.relay_token); |
+void LibjingleTransportFactory::PrepareTokens() { |
+ EnsureFreshJingleInfo(); |
} |
scoped_ptr<StreamTransport> LibjingleTransportFactory::CreateStreamTransport() { |
- return scoped_ptr<StreamTransport>( |
- new LibjingleStreamTransport(port_allocator_.get(), incoming_only_)); |
+ scoped_ptr<LibjingleStreamTransport> result( |
+ new LibjingleStreamTransport(port_allocator_.get(), network_settings_)); |
+ |
+ EnsureFreshJingleInfo(); |
+ |
+ // If there is a pending |jingle_info_request_| delay starting the new |
+ // transport until the request is finished. |
+ if (jingle_info_request_) { |
+ on_jingle_info_callbacks_.push_back( |
+ base::Bind(&LibjingleStreamTransport::OnCanStart, |
+ result->AsWeakPtr())); |
+ } else { |
+ result->OnCanStart(); |
+ } |
+ |
+ return result.PassAs<StreamTransport>(); |
} |
scoped_ptr<DatagramTransport> |
@@ -406,5 +450,42 @@ LibjingleTransportFactory::CreateDatagramTransport() { |
return scoped_ptr<DatagramTransport>(); |
} |
+void LibjingleTransportFactory::EnsureFreshJingleInfo() { |
+ if (network_settings_.nat_traversal_mode != |
+ NetworkSettings::NAT_TRAVERSAL_ENABLED || |
+ jingle_info_request_) { |
+ return; |
+ } |
+ |
+ if (base::TimeTicks::Now() - last_jingle_info_update_time_ > |
+ base::TimeDelta::FromSeconds(kJingleInfoUpdatePeriodSeconds)) { |
+ jingle_info_request_.reset(new JingleInfoRequest(signal_strategy_)); |
+ jingle_info_request_->Send(base::Bind( |
+ &LibjingleTransportFactory::OnJingleInfo, base::Unretained(this))); |
+ } |
+} |
+ |
+void LibjingleTransportFactory::OnJingleInfo( |
+ const std::string& relay_token, |
+ const std::vector<std::string>& relay_hosts, |
+ const std::vector<talk_base::SocketAddress>& stun_hosts) { |
+ if (!relay_token.empty() && !relay_hosts.empty()) { |
+ port_allocator_->SetRelayHosts(relay_hosts); |
+ port_allocator_->SetRelayToken(relay_token); |
+ } |
+ if (!stun_hosts.empty()) { |
+ port_allocator_->SetStunHosts(stun_hosts); |
+ } |
+ |
+ jingle_info_request_.reset(); |
+ if ((!relay_token.empty() && !relay_hosts.empty()) || !stun_hosts.empty()) |
+ last_jingle_info_update_time_ = base::TimeTicks::Now(); |
+ |
+ while (!on_jingle_info_callbacks_.empty()) { |
+ on_jingle_info_callbacks_.begin()->Run(); |
+ on_jingle_info_callbacks_.pop_front(); |
+ } |
+} |
+ |
} // namespace protocol |
} // namespace remoting |