| Index: remoting/protocol/ice_transport_session.cc
|
| diff --git a/remoting/protocol/ice_transport_session.cc b/remoting/protocol/ice_transport_session.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f87e65534b5dd1671f34daeb981d606ed98c09ec
|
| --- /dev/null
|
| +++ b/remoting/protocol/ice_transport_session.cc
|
| @@ -0,0 +1,193 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "remoting/protocol/ice_transport_session.h"
|
| +
|
| +#include "remoting/protocol/channel_authenticator.h"
|
| +#include "remoting/protocol/channel_multiplexer.h"
|
| +#include "remoting/protocol/libjingle_transport_factory.h"
|
| +#include "remoting/protocol/pseudotcp_channel_factory.h"
|
| +#include "remoting/protocol/secure_channel_factory.h"
|
| +#include "remoting/protocol/stream_channel_factory.h"
|
| +
|
| +namespace remoting {
|
| +namespace protocol {
|
| +
|
| +// Delay after candidate creation before sending transport-info message to
|
| +// accumulate multiple candidates. This is an optimization to reduce number of
|
| +// transport-info messages.
|
| +const int kTransportInfoSendDelayMs = 20;
|
| +
|
| +// Name of the multiplexed channel.
|
| +static const char kMuxChannelName[] = "mux";
|
| +
|
| +IceTransportSession::IceTransportSession(
|
| + LibjingleTransportFactory* libjingle_transport_factory)
|
| + : libjingle_transport_factory_(libjingle_transport_factory) {}
|
| +
|
| +IceTransportSession::~IceTransportSession() {
|
| + channel_multiplexer_.reset();
|
| + DCHECK(channels_.empty());
|
| +}
|
| +
|
| +void IceTransportSession::Start(TransportSession::EventHandler* event_handler,
|
| + Authenticator* authenticator) {
|
| + event_handler_ = event_handler;
|
| + pseudotcp_channel_factory_.reset(new PseudoTcpChannelFactory(this));
|
| + secure_channel_factory_.reset(new SecureChannelFactory(
|
| + pseudotcp_channel_factory_.get(), authenticator));
|
| +}
|
| +
|
| +bool IceTransportSession::ProcessTransportInfo(
|
| + buzz::XmlElement* transport_info_xml) {
|
| + IceTransportInfo transport_info;
|
| + if (!transport_info.ParseXml(transport_info_xml))
|
| + return false;
|
| +
|
| + for (auto it = transport_info.ice_credentials.begin();
|
| + it != transport_info.ice_credentials.end(); ++it) {
|
| + ChannelsMap::iterator channel = channels_.find(it->channel);
|
| + if (channel != channels_.end()) {
|
| + channel->second->SetRemoteCredentials(it->ufrag, it->password);
|
| + } else {
|
| + // Transport info was received before the channel was created.
|
| + // This could happen due to messages being reordered on the wire.
|
| + pending_remote_ice_credentials_.push_back(*it);
|
| + }
|
| + }
|
| +
|
| + for (auto it = transport_info.candidates.begin();
|
| + it != transport_info.candidates.end(); ++it) {
|
| + ChannelsMap::iterator channel = channels_.find(it->name);
|
| + if (channel != channels_.end()) {
|
| + channel->second->AddRemoteCandidate(it->candidate);
|
| + } else {
|
| + // Transport info was received before the channel was created.
|
| + // This could happen due to messages being reordered on the wire.
|
| + pending_remote_candidates_.push_back(*it);
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +DatagramChannelFactory* IceTransportSession::GetDatagramChannelFactory() {
|
| + return this;
|
| +}
|
| +
|
| +StreamChannelFactory* IceTransportSession::GetStreamChannelFactory() {
|
| + return secure_channel_factory_.get();
|
| +}
|
| +
|
| +StreamChannelFactory* IceTransportSession::GetMultiplexedChannelFactory() {
|
| + if (!channel_multiplexer_.get()) {
|
| + channel_multiplexer_.reset(
|
| + new ChannelMultiplexer(GetStreamChannelFactory(), kMuxChannelName));
|
| + }
|
| + return channel_multiplexer_.get();
|
| +}
|
| +
|
| +void IceTransportSession::CreateChannel(
|
| + const std::string& name,
|
| + const ChannelCreatedCallback& callback) {
|
| + DCHECK(!channels_[name]);
|
| +
|
| + scoped_ptr<Transport> channel =
|
| + libjingle_transport_factory_->CreateTransport();
|
| + channel->Connect(name, this, callback);
|
| + AddPendingRemoteTransportInfo(channel.get());
|
| + channels_[name] = channel.release();
|
| +}
|
| +
|
| +void IceTransportSession::CancelChannelCreation(const std::string& name) {
|
| + ChannelsMap::iterator it = channels_.find(name);
|
| + if (it != channels_.end()) {
|
| + DCHECK(!it->second->is_connected());
|
| + delete it->second;
|
| + DCHECK(channels_.find(name) == channels_.end());
|
| + }
|
| +}
|
| +
|
| +void IceTransportSession::AddPendingRemoteTransportInfo(Transport* channel) {
|
| + std::list<IceTransportInfo::IceCredentials>::iterator credentials =
|
| + pending_remote_ice_credentials_.begin();
|
| + while (credentials != pending_remote_ice_credentials_.end()) {
|
| + if (credentials->channel == channel->name()) {
|
| + channel->SetRemoteCredentials(credentials->ufrag, credentials->password);
|
| + credentials = pending_remote_ice_credentials_.erase(credentials);
|
| + } else {
|
| + ++credentials;
|
| + }
|
| + }
|
| +
|
| + std::list<IceTransportInfo::NamedCandidate>::iterator candidate =
|
| + pending_remote_candidates_.begin();
|
| + while (candidate != pending_remote_candidates_.end()) {
|
| + if (candidate->name == channel->name()) {
|
| + channel->AddRemoteCandidate(candidate->candidate);
|
| + candidate = pending_remote_candidates_.erase(candidate);
|
| + } else {
|
| + ++candidate;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void IceTransportSession::OnTransportIceCredentials(
|
| + Transport* transport,
|
| + const std::string& ufrag,
|
| + const std::string& password) {
|
| + EnsurePendingTransportInfoMessage();
|
| + pending_transport_info_message_->ice_credentials.push_back(
|
| + IceTransportInfo::IceCredentials(transport->name(), ufrag, password));
|
| +}
|
| +
|
| +void IceTransportSession::OnTransportCandidate(
|
| + Transport* transport,
|
| + const cricket::Candidate& candidate) {
|
| + EnsurePendingTransportInfoMessage();
|
| + pending_transport_info_message_->candidates.push_back(
|
| + IceTransportInfo::NamedCandidate(transport->name(), candidate));
|
| +}
|
| +
|
| +void IceTransportSession::OnTransportRouteChange(Transport* transport,
|
| + const TransportRoute& route) {
|
| + if (event_handler_)
|
| + event_handler_->OnTransportRouteChange(transport->name(), route);
|
| +}
|
| +
|
| +void IceTransportSession::OnTransportFailed(Transport* transport) {
|
| + event_handler_->OnTransportError(CHANNEL_CONNECTION_ERROR);
|
| +}
|
| +
|
| +void IceTransportSession::OnTransportDeleted(Transport* transport) {
|
| + ChannelsMap::iterator it = channels_.find(transport->name());
|
| + DCHECK_EQ(it->second, transport);
|
| + channels_.erase(it);
|
| +}
|
| +
|
| +void IceTransportSession::EnsurePendingTransportInfoMessage() {
|
| + // |transport_info_timer_| must be running iff
|
| + // |pending_transport_info_message_| exists.
|
| + DCHECK_EQ(pending_transport_info_message_ != nullptr,
|
| + transport_info_timer_.IsRunning());
|
| +
|
| + if (!pending_transport_info_message_) {
|
| + pending_transport_info_message_.reset(new IceTransportInfo());
|
| + // Delay sending the new candidates in case we get more candidates
|
| + // that we can send in one message.
|
| + transport_info_timer_.Start(
|
| + FROM_HERE, base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs),
|
| + this, &IceTransportSession::SendTransportInfo);
|
| + }
|
| +}
|
| +
|
| +void IceTransportSession::SendTransportInfo() {
|
| + DCHECK(pending_transport_info_message_);
|
| + event_handler_->OnOutgoingTransportInfo(
|
| + pending_transport_info_message_->ToXml());
|
| + pending_transport_info_message_.reset();
|
| +}
|
| +
|
| +} // namespace protocol
|
| +} // namespace remoting
|
|
|