diff options
-rw-r--r-- | remoting/protocol/fake_session.cc | 12 | ||||
-rw-r--r-- | remoting/protocol/fake_session.h | 5 | ||||
-rw-r--r-- | remoting/protocol/jingle_channel_connector.h | 44 | ||||
-rw-r--r-- | remoting/protocol/jingle_datagram_connector.cc | 49 | ||||
-rw-r--r-- | remoting/protocol/jingle_datagram_connector.h | 52 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.cc | 398 | ||||
-rw-r--r-- | remoting/protocol/jingle_session.h | 144 | ||||
-rw-r--r-- | remoting/protocol/jingle_stream_connector.cc | 188 | ||||
-rw-r--r-- | remoting/protocol/jingle_stream_connector.h | 85 | ||||
-rw-r--r-- | remoting/protocol/protocol_mock_objects.h | 4 | ||||
-rw-r--r-- | remoting/protocol/session.h | 30 | ||||
-rw-r--r-- | remoting/remoting.gyp | 5 |
12 files changed, 344 insertions, 672 deletions
diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc index 2403a20..c11fa34 100644 --- a/remoting/protocol/fake_session.cc +++ b/remoting/protocol/fake_session.cc @@ -140,18 +140,6 @@ void FakeSession::SetStateChangeCallback( callback_.reset(callback); } -void FakeSession::CreateStreamChannel( - const std::string& name, const StreamChannelCallback& callback) { - NOTIMPLEMENTED(); - callback.Run(name, NULL); -} - -void FakeSession::CreateDatagramChannel( - const std::string& name, const DatagramChannelCallback& callback) { - NOTIMPLEMENTED(); - callback.Run(name, NULL); -} - FakeSocket* FakeSession::control_channel() { return &control_channel_; } diff --git a/remoting/protocol/fake_session.h b/remoting/protocol/fake_session.h index d892ede..1427bf3 100644 --- a/remoting/protocol/fake_session.h +++ b/remoting/protocol/fake_session.h @@ -105,11 +105,6 @@ class FakeSession : public Session { virtual void SetStateChangeCallback(StateChangeCallback* callback); - virtual void CreateStreamChannel( - const std::string& name, const StreamChannelCallback& callback); - virtual void CreateDatagramChannel( - const std::string& name, const DatagramChannelCallback& callback); - virtual FakeSocket* control_channel(); virtual FakeSocket* event_channel(); virtual FakeSocket* video_channel(); diff --git a/remoting/protocol/jingle_channel_connector.h b/remoting/protocol/jingle_channel_connector.h deleted file mode 100644 index 6037ee4..0000000 --- a/remoting/protocol/jingle_channel_connector.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef REMOTING_PROTOCOL_JINGLE_CHANNEL_CONNECTOR_H_ -#define REMOTING_PROTOCOL_JINGLE_CHANNEL_CONNECTOR_H_ - -#include "base/basictypes.h" -#include "base/threading/non_thread_safe.h" - -namespace cricket { -class TransportChannel; -} // namespace cricket - -namespace crypto { -class RSAPrivateKey; -} // namespace crypto - -namespace net { -class X509Certificate; -} // namespace net - -namespace remoting { -namespace protocol { - -class JingleChannelConnector : public base::NonThreadSafe { - public: - JingleChannelConnector() { } - virtual ~JingleChannelConnector() { } - - virtual void Connect(bool initiator, - net::X509Certificate* local_cert, - net::X509Certificate* remote_cert, - crypto::RSAPrivateKey* local_private_key, - cricket::TransportChannel* raw_channel) = 0; - - protected: - DISALLOW_COPY_AND_ASSIGN(JingleChannelConnector); -}; - -} // namespace protocol -} // namespace remoting - -#endif // REMOTING_PROTOCOL_JINGLE_CHANNEL_CONNECTOR_H_ diff --git a/remoting/protocol/jingle_datagram_connector.cc b/remoting/protocol/jingle_datagram_connector.cc deleted file mode 100644 index ff717a0..0000000 --- a/remoting/protocol/jingle_datagram_connector.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2011 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/jingle_datagram_connector.h" - -#include "jingle/glue/channel_socket_adapter.h" -#include "remoting/protocol/jingle_session.h" -#include "third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h" - -namespace remoting { -namespace protocol { - -JingleDatagramConnector::JingleDatagramConnector( - JingleSession* session, - const std::string& name, - const Session::DatagramChannelCallback& callback) - : session_(session), - name_(name), - callback_(callback) { -} - -JingleDatagramConnector::~JingleDatagramConnector() { -} - -void JingleDatagramConnector::Connect( - bool initiator, - net::X509Certificate* local_cert, - net::X509Certificate* remote_cert, - crypto::RSAPrivateKey* local_private_key, - cricket::TransportChannel* raw_channel) { - DCHECK(CalledOnValidThread()); - - if (!initiator) { - // Don't make outgoing connections from the host to client. - raw_channel->GetP2PChannel()->set_incoming_only(true); - } - - net::Socket* socket = - new jingle_glue::TransportChannelSocketAdapter(raw_channel); - - // TODO(sergeyu): Implement encryption for datagram channels. - - callback_.Run(name_, socket); - session_->OnChannelConnectorFinished(name_, this); -} - -} // namespace protocol -} // namespace remoting diff --git a/remoting/protocol/jingle_datagram_connector.h b/remoting/protocol/jingle_datagram_connector.h deleted file mode 100644 index 25a7ab6..0000000 --- a/remoting/protocol/jingle_datagram_connector.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef REMOTING_PROTOCOL_JINGLE_DATAGRAM_CONNECTOR_H_ -#define REMOTING_PROTOCOL_JINGLE_DATAGRAM_CONNECTOR_H_ - -#include "net/base/completion_callback.h" -#include "remoting/protocol/jingle_channel_connector.h" -#include "remoting/protocol/session.h" - -namespace cricket { -class TransportChannel; -} // namespace cricket - -namespace jingle_glue { -class TransportChannelSocketAdapter; -} // namespace jingle_glue - -namespace remoting { -namespace protocol { - -class JingleSession; - -class JingleDatagramConnector : public JingleChannelConnector { - public: - JingleDatagramConnector(JingleSession* session, - const std::string& name, - const Session::DatagramChannelCallback& callback); - virtual ~JingleDatagramConnector(); - - // Starts connection process for the channel. |local_private_key| is - // owned by the caller, and must exist until this object is - // destroyed. - void Connect(bool initiator, - net::X509Certificate* local_cert, - net::X509Certificate* remote_cert, - crypto::RSAPrivateKey* local_private_key, - cricket::TransportChannel* raw_channel); - - private: - JingleSession* session_; - std::string name_; - Session::DatagramChannelCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(JingleDatagramConnector); -}; - -} // namespace protocol -} // namespace remoting - -#endif // REMOTING_PROTOCOL_JINGLE_DATAGRAM_CONNECTOR_H_ diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc index f7d61f1..ad417ef 100644 --- a/remoting/protocol/jingle_session.cc +++ b/remoting/protocol/jingle_session.cc @@ -4,21 +4,26 @@ #include "remoting/protocol/jingle_session.h" -#include "base/bind.h" #include "base/message_loop.h" #include "base/rand_util.h" -#include "base/stl_util-inl.h" #include "crypto/hmac.h" #include "crypto/rsa_private_key.h" +#include "jingle/glue/channel_socket_adapter.h" +#include "jingle/glue/pseudotcp_adapter.h" +#include "net/base/cert_status_flags.h" +#include "net/base/cert_verifier.h" +#include "net/base/host_port_pair.h" #include "net/base/net_errors.h" -#include "net/socket/stream_socket.h" +#include "net/base/ssl_config_service.h" +#include "net/base/x509_certificate.h" +#include "net/socket/client_socket_factory.h" +#include "net/socket/ssl_client_socket.h" +#include "net/socket/ssl_server_socket.h" #include "remoting/base/constants.h" -#include "remoting/protocol/jingle_datagram_connector.h" #include "remoting/protocol/jingle_session_manager.h" -#include "remoting/protocol/jingle_stream_connector.h" #include "third_party/libjingle/source/talk/base/thread.h" #include "third_party/libjingle/source/talk/p2p/base/session.h" -#include "third_party/libjingle/source/talk/p2p/base/transport.h" +#include "third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h" using cricket::BaseSession; @@ -39,6 +44,34 @@ const char kVideoRtcpChannelName[] = "videortcp"; const int kMasterKeyLength = 16; const int kChannelKeyLength = 16; +// Value is choosen to balance the extra latency against the reduced +// load due to ACK traffic. +const int kTcpAckDelayMilliseconds = 10; + +// Helper method to create a SSL client socket. +net::SSLClientSocket* CreateSSLClientSocket( + net::StreamSocket* socket, scoped_refptr<net::X509Certificate> cert, + net::CertVerifier* cert_verifier) { + net::SSLConfig ssl_config; + ssl_config.cached_info_enabled = false; + ssl_config.false_start_enabled = false; + ssl_config.ssl3_enabled = true; + ssl_config.tls1_enabled = true; + + // Certificate provided by the host doesn't need authority. + net::SSLConfig::CertAndStatus cert_and_status; + cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID; + cert_and_status.cert = cert; + ssl_config.allowed_bad_certs.push_back(cert_and_status); + + // SSLClientSocket takes ownership of the adapter. + net::HostPortPair host_and_pair(JingleSession::kChromotingContentName, 0); + net::SSLClientSocket* ssl_socket = + net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( + socket, host_and_pair, ssl_config, NULL, cert_verifier); + return ssl_socket; +} + std::string GenerateRandomMasterKey() { std::string result; result.resize(kMasterKeyLength); @@ -109,6 +142,10 @@ JingleSession::JingleSession( closed_(false), closing_(false), cricket_session_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(connect_callback_( + this, &JingleSession::OnConnect)), + ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_( + this, &JingleSession::OnSSLConnect)), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { // TODO(hclam): Need a better way to clone a key. if (local_private_key) { @@ -132,6 +169,7 @@ void JingleSession::Init(cricket::Session* cricket_session) { cricket_session_ = cricket_session; jid_ = cricket_session_->remote_name(); + cert_verifier_.reset(new net::CertVerifier()); cricket_session_->SignalState.connect( this, &JingleSession::OnSessionState); cricket_session_->SignalError.connect( @@ -156,13 +194,18 @@ void JingleSession::CloseInternal(int result, bool failed) { else SetState(CLOSED); - control_channel_socket_.reset(); - event_channel_socket_.reset(); - video_channel_socket_.reset(); - video_rtp_channel_socket_.reset(); - video_rtcp_channel_socket_.reset(); - STLDeleteContainerPairSecondPointers(channel_connectors_.begin(), - channel_connectors_.end()); + // Now tear down the remoting channel resources. + control_channel_.reset(); + control_socket_.reset(); + control_ssl_socket_.reset(); + event_channel_.reset(); + event_socket_.reset(); + event_ssl_socket_.reset(); + video_channel_.reset(); + video_socket_.reset(); + video_ssl_socket_.reset(); + video_rtp_channel_.reset(); + video_rtcp_channel_.reset(); // Tear down the cricket session, including the cricket transport channels. if (cricket_session_) { @@ -172,6 +215,7 @@ void JingleSession::CloseInternal(int result, bool failed) { closed_ = true; } + cert_verifier_.reset(); } bool JingleSession::HasSession(cricket::Session* cricket_session) { @@ -198,45 +242,30 @@ void JingleSession::SetStateChangeCallback(StateChangeCallback* callback) { state_change_callback_.reset(callback); } -void JingleSession::CreateStreamChannel( - const std::string& name, const StreamChannelCallback& callback) { - DCHECK(CalledOnValidThread()); - - AddChannelConnector( - name, new JingleStreamConnector(this, name, callback)); -} - -void JingleSession::CreateDatagramChannel( - const std::string& name, const DatagramChannelCallback& callback) { - DCHECK(CalledOnValidThread()); - - AddChannelConnector( - name, new JingleDatagramConnector(this, name, callback)); -} - net::Socket* JingleSession::control_channel() { DCHECK(CalledOnValidThread()); - return control_channel_socket_.get(); + return control_ssl_socket_.get(); } net::Socket* JingleSession::event_channel() { DCHECK(CalledOnValidThread()); - return event_channel_socket_.get(); + return event_ssl_socket_.get(); } +// TODO(sergeyu): Remove this method after we switch to RTP. net::Socket* JingleSession::video_channel() { DCHECK(CalledOnValidThread()); - return video_channel_socket_.get(); + return video_ssl_socket_.get(); } net::Socket* JingleSession::video_rtp_channel() { DCHECK(CalledOnValidThread()); - return video_rtp_channel_socket_.get(); + return video_rtp_channel_.get(); } net::Socket* JingleSession::video_rtcp_channel() { DCHECK(CalledOnValidThread()); - return video_rtcp_channel_socket_.get(); + return video_rtcp_channel_.get(); } const std::string& JingleSession::jid() { @@ -361,12 +390,22 @@ void JingleSession::OnInitiate() { DCHECK(CalledOnValidThread()); jid_ = cricket_session_->remote_name(); - if (!cricket_session_->initiator()) { - const protocol::ContentDescription* content_description = - static_cast<const protocol::ContentDescription*>( - GetContentInfo()->description); - CHECK(content_description); + const cricket::SessionDescription* session_description; + // If we initiate the session, we get to specify the content name. When + // accepting one, the remote end specifies it. + if (cricket_session_->initiator()) { + session_description = cricket_session_->local_description(); + } else { + session_description = cricket_session_->remote_description(); + } + const cricket::ContentInfo* content = + session_description->FirstContentByType(kChromotingXmlNamespace); + CHECK(content); + const ContentDescription* content_description = + static_cast<const ContentDescription*>(content->description); + std::string content_name = content->name; + if (!cricket_session_->initiator()) { if (!DecryptMasterKey(local_private_key_.get(), content_description->master_key(), &master_key_)) { LOG(ERROR) << "Failed to decrypt master-key"; @@ -375,23 +414,103 @@ void JingleSession::OnInitiate() { } } + // Create video RTP channels. + raw_video_rtp_channel_ = + cricket_session_->CreateChannel(content_name, kVideoRtpChannelName); + video_rtp_channel_.reset( + new jingle_glue::TransportChannelSocketAdapter(raw_video_rtp_channel_)); + raw_video_rtcp_channel_ = + cricket_session_->CreateChannel(content_name, kVideoRtcpChannelName); + video_rtcp_channel_.reset( + new jingle_glue::TransportChannelSocketAdapter(raw_video_rtcp_channel_)); + + // Create control channel. + raw_control_channel_ = + cricket_session_->CreateChannel(content_name, kControlChannelName); + control_channel_.reset( + new jingle_glue::TransportChannelSocketAdapter(raw_control_channel_)); + + // Create event channel. + raw_event_channel_ = + cricket_session_->CreateChannel(content_name, kEventChannelName); + event_channel_.reset( + new jingle_glue::TransportChannelSocketAdapter(raw_event_channel_)); + + // Create video channel. + // TODO(wez): When we have RTP video support, we'll need to negotiate the + // type of video channel to allocate, for legacy compatibility. + raw_video_channel_ = + cricket_session_->CreateChannel(content_name, kVideoChannelName); + video_channel_.reset( + new jingle_glue::TransportChannelSocketAdapter(raw_video_channel_)); + + if (!cricket_session_->initiator()) { + if (!jingle_session_manager_->AcceptConnection(this, cricket_session_)) { + Close(); + // Release session so that + // JingleSessionManager::SessionDestroyed() doesn't try to call + // cricket::SessionManager::DestroySession() for it. + ReleaseSession(); + delete this; + return; + } + } + + // Set state to CONNECTING if the session is being accepted. + SetState(CONNECTING); +} + +bool JingleSession::EstablishPseudoTcp( + net::Socket* channel, + scoped_ptr<net::StreamSocket>* stream) { + jingle_glue::PseudoTcpAdapter* adapter = + new jingle_glue::PseudoTcpAdapter(channel); + adapter->SetAckDelay(kTcpAckDelayMilliseconds); + adapter->SetNoDelay(true); + + stream->reset(adapter); + int result = (*stream)->Connect(&connect_callback_); + return (result == net::OK) || (result == net::ERR_IO_PENDING); +} + +bool JingleSession::EstablishSSLConnection( + net::StreamSocket* socket, + scoped_ptr<net::StreamSocket>* ssl_socket) { + DCHECK(socket); + DCHECK(socket->IsConnected()); if (cricket_session_->initiator()) { - // Set state to CONNECTING if this is an outgoing message. We need - // to post this task because channel creation works only after we - // return from this method. This is because - // JingleChannelConnector::Connect() needs to call - // set_incoming_only() on P2PTransportChannel, but - // P2PTransportChannel is created only after we return from this - // method. - // TODO(sergeyu): Add set_incoming_only() in TransportChannelProxy. - MessageLoop::current()->PostTask( - FROM_HERE, task_factory_.NewRunnableMethod( - &JingleSession::SetState, CONNECTING)); + // Create client SSL socket. + net::SSLClientSocket* ssl_client_socket = CreateSSLClientSocket( + socket, remote_cert_, cert_verifier_.get()); + ssl_socket->reset(ssl_client_socket); + + int ret = ssl_client_socket->Connect(&ssl_connect_callback_); + if (ret == net::ERR_IO_PENDING) { + return true; + } else if (ret != net::OK) { + LOG(ERROR) << "Failed to establish SSL connection"; + cricket_session_->Terminate(); + return false; + } } else { - MessageLoop::current()->PostTask( - FROM_HERE, task_factory_.NewRunnableMethod( - &JingleSession::AcceptConnection)); + // Create server SSL socket. + net::SSLConfig ssl_config; + net::SSLServerSocket* ssl_server_socket = net::CreateSSLServerSocket( + socket, local_cert_, local_private_key_.get(), ssl_config); + ssl_socket->reset(ssl_server_socket); + + int ret = ssl_server_socket->Handshake(&ssl_connect_callback_); + if (ret == net::ERR_IO_PENDING) { + return true; + } else if (ret != net::OK) { + LOG(ERROR) << "Failed to establish SSL connection"; + cricket_session_->Terminate(); + return false; + } } + // Reach here if net::OK is received. + ssl_connect_callback_.Run(net::OK); + return true; } bool JingleSession::InitializeConfigFromDescription( @@ -399,13 +518,14 @@ bool JingleSession::InitializeConfigFromDescription( // We should only be called after ParseContent has succeeded, in which // case there will always be a Chromoting session configuration. const cricket::ContentInfo* content = - description->FirstContentByType(kChromotingXmlNamespace); + description->FirstContentByType(kChromotingXmlNamespace); CHECK(content); const protocol::ContentDescription* content_description = - static_cast<const protocol::ContentDescription*>(content->description); + static_cast<const protocol::ContentDescription*>(content->description); CHECK(content_description); - remote_cert_ = content_description->certificate(); if (!remote_cert_) { + remote_cert_ = content_description->certificate(); + if (!remote_cert_) { LOG(ERROR) << "Connection response does not specify certificate"; return false; } @@ -425,6 +545,29 @@ bool JingleSession::InitializeConfigFromDescription( return true; } +void JingleSession::InitializeChannels() { + // Disable incoming connections on the host so that we don't traverse + // the firewall. + if (!cricket_session_->initiator()) { + raw_control_channel_->GetP2PChannel()->set_incoming_only(true); + raw_event_channel_->GetP2PChannel()->set_incoming_only(true); + raw_video_channel_->GetP2PChannel()->set_incoming_only(true); + raw_video_rtp_channel_->GetP2PChannel()->set_incoming_only(true); + raw_video_rtcp_channel_->GetP2PChannel()->set_incoming_only(true); + } + + // Create the Control, Event and Video connections on the channels. + if (!EstablishPseudoTcp(control_channel_.release(), + &control_socket_) || + !EstablishPseudoTcp(event_channel_.release(), + &event_socket_) || + !EstablishPseudoTcp(video_channel_.release(), + &video_socket_)) { + CloseInternal(net::ERR_CONNECTION_FAILED, true); + return; + } +} + void JingleSession::OnAccept() { DCHECK(CalledOnValidThread()); @@ -432,13 +575,21 @@ void JingleSession::OnAccept() { // host responded with, to refer to later. if (cricket_session_->initiator()) { if (!InitializeConfigFromDescription( - cricket_session_->remote_description())) { + cricket_session_->remote_description())) { CloseInternal(net::ERR_CONNECTION_FAILED, true); return; } } - CreateChannels(); + // TODO(sergeyu): This is a hack: Currently set_incoming_only() + // needs to be called on each channel before the channel starts + // creating candidates but after session is accepted (after + // TransportChannelProxy::GetP2PChannel() starts returning actual + // P2P channel). By posting a task here we can call it at the right + // moment. This problem will go away when we switch to Pepper P2P + // API. + MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod( + &JingleSession::InitializeChannels)); } void JingleSession::OnTerminate() { @@ -446,113 +597,58 @@ void JingleSession::OnTerminate() { CloseInternal(net::ERR_CONNECTION_ABORTED, false); } -void JingleSession::AcceptConnection() { - if (!jingle_session_manager_->AcceptConnection(this, cricket_session_)) { - Close(); - // Release session so that JingleSessionManager::SessionDestroyed() - // doesn't try to call cricket::SessionManager::DestroySession() for it. - ReleaseSession(); - delete this; +void JingleSession::OnConnect(int result) { + DCHECK(CalledOnValidThread()); + + if (result != net::OK) { + LOG(ERROR) << "PseudoTCP connection failed: " << result; + CloseInternal(result, true); return; } - // Set state to CONNECTING if the session is being accepted. - SetState(CONNECTING); -} - -void JingleSession::AddChannelConnector( - const std::string& name, JingleChannelConnector* connector) { - DCHECK(channel_connectors_.find(name) == channel_connectors_.end()); - - const std::string& content_name = GetContentInfo()->name; - cricket::TransportChannel* raw_channel = - cricket_session_->CreateChannel(content_name, name); - - channel_connectors_[name] = connector; - connector->Connect(cricket_session_->initiator(), local_cert_, - remote_cert_, local_private_key_.get(), raw_channel); - - // Workaround bug in libjingle - it doesn't connect channels if they - // are created after the session is accepted. See crbug.com/89384. - // TODO(sergeyu): Fix the bug and remove this line. - cricket_session_->GetTransport(content_name)->ConnectChannels(); + if (control_socket_.get() && control_socket_->IsConnected()) { + if (!EstablishSSLConnection(control_socket_.release(), + &control_ssl_socket_)) { + LOG(ERROR) << "Establish control channel failed"; + CloseInternal(net::ERR_CONNECTION_FAILED, true); + return; + } + } + if (event_socket_.get() && event_socket_->IsConnected()) { + if (!EstablishSSLConnection(event_socket_.release(), + &event_ssl_socket_)) { + LOG(ERROR) << "Establish control event failed"; + CloseInternal(net::ERR_CONNECTION_FAILED, true); + return; + } + } + if (video_socket_.get() && video_socket_->IsConnected()) { + if (!EstablishSSLConnection(video_socket_.release(), + &video_ssl_socket_)) { + LOG(ERROR) << "Establish control video failed"; + CloseInternal(net::ERR_CONNECTION_FAILED, true); + return; + } + } } -void JingleSession::OnChannelConnectorFinished( - const std::string& name, JingleChannelConnector* connector) { +void JingleSession::OnSSLConnect(int result) { DCHECK(CalledOnValidThread()); - DCHECK_EQ(channel_connectors_[name], connector); - channel_connectors_[name] = NULL; - delete connector; -} - -void JingleSession::CreateChannels() { - StreamChannelCallback stream_callback( - base::Bind(&JingleSession::OnStreamChannelConnected, - base::Unretained(this))); - CreateStreamChannel(kControlChannelName, stream_callback); - CreateStreamChannel(kEventChannelName, stream_callback); - CreateStreamChannel(kVideoChannelName, stream_callback); - - DatagramChannelCallback datagram_callback( - base::Bind(&JingleSession::OnChannelConnected, - base::Unretained(this))); - CreateDatagramChannel(kVideoRtpChannelName, datagram_callback); - CreateDatagramChannel(kVideoRtcpChannelName, datagram_callback); -} - -void JingleSession::OnStreamChannelConnected(const std::string& name, - net::StreamSocket* socket) { - OnChannelConnected(name, socket); -} -void JingleSession::OnChannelConnected(const std::string& name, - net::Socket* socket) { - if (!socket) { - LOG(ERROR) << "Failed to connect channel " << name - << ". Terminating connection"; - CloseInternal(net::ERR_CONNECTION_CLOSED, true); + DCHECK(!closed_); + if (result != net::OK) { + LOG(ERROR) << "Error during SSL connection: " << result; + CloseInternal(result, true); return; } - if (name == kControlChannelName) { - control_channel_socket_.reset(socket); - } else if (name == kEventChannelName) { - event_channel_socket_.reset(socket); - } else if (name == kVideoChannelName) { - video_channel_socket_.reset(socket); - } else if (name == kVideoRtpChannelName) { - video_rtp_channel_socket_.reset(socket); - } else if (name == kVideoRtcpChannelName) { - video_rtcp_channel_socket_.reset(socket); - } else { - NOTREACHED(); - } - - if (control_channel_socket_.get() && event_channel_socket_.get() && - video_channel_socket_.get() && video_rtp_channel_socket_.get() && - video_rtcp_channel_socket_.get()) { - // TODO(sergeyu): State should be set to CONNECTED in OnAccept - // independent of the channels state. + if (event_ssl_socket_.get() && event_ssl_socket_->IsConnected() && + control_ssl_socket_.get() && control_ssl_socket_->IsConnected() && + video_ssl_socket_.get() && video_ssl_socket_->IsConnected()) { SetState(CONNECTED); } } -const cricket::ContentInfo* JingleSession::GetContentInfo() const { - const cricket::SessionDescription* session_description; - // If we initiate the session, we get to specify the content name. When - // accepting one, the remote end specifies it. - if (cricket_session_->initiator()) { - session_description = cricket_session_->local_description(); - } else { - session_description = cricket_session_->remote_description(); - } - const cricket::ContentInfo* content = - session_description->FirstContentByType(kChromotingXmlNamespace); - CHECK(content); - return content; -} - void JingleSession::SetState(State new_state) { DCHECK(CalledOnValidThread()); diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h index 13a29bc..c011e88 100644 --- a/remoting/protocol/jingle_session.h +++ b/remoting/protocol/jingle_session.h @@ -13,7 +13,17 @@ #include "third_party/libjingle/source/talk/base/sigslot.h" #include "third_party/libjingle/source/talk/p2p/base/session.h" +namespace jingle_glue { +class PseudoTcpAdapter; +class StreamSocketAdapter; +class TransportChannelSocketAdapter; +} // namespace jingle_glue + namespace net { +class CertVerifier; +class ClientSocketFactory; +class Socket; +class StreamSocket; class X509Certificate; } // namespace net @@ -21,7 +31,6 @@ namespace remoting { namespace protocol { -class JingleChannelConnector; class JingleSessionManager; // Implements protocol::Session that work over libjingle session (the @@ -32,33 +41,32 @@ class JingleSession : public protocol::Session, public: static const char kChromotingContentName[]; - // Session interface. - virtual void SetStateChangeCallback(StateChangeCallback* callback) OVERRIDE; - virtual void CreateStreamChannel( - const std::string& name, - const StreamChannelCallback& callback) OVERRIDE; - virtual void CreateDatagramChannel( - const std::string& name, - const DatagramChannelCallback& callback) OVERRIDE; - virtual net::Socket* control_channel() OVERRIDE; - virtual net::Socket* event_channel() OVERRIDE; - virtual net::Socket* video_channel() OVERRIDE; - virtual net::Socket* video_rtp_channel() OVERRIDE; - virtual net::Socket* video_rtcp_channel() OVERRIDE; - virtual const std::string& jid() OVERRIDE; - virtual const CandidateSessionConfig* candidate_config() OVERRIDE; - virtual const SessionConfig* config() OVERRIDE; - virtual void set_config(const SessionConfig* config) OVERRIDE; - virtual const std::string& initiator_token() OVERRIDE; - virtual void set_initiator_token(const std::string& initiator_token) OVERRIDE; - virtual const std::string& receiver_token() OVERRIDE; - virtual void set_receiver_token(const std::string& receiver_token) OVERRIDE; - virtual void Close() OVERRIDE; + // Chromotocol Session interface. + virtual void SetStateChangeCallback(StateChangeCallback* callback); + + virtual net::Socket* control_channel(); + virtual net::Socket* event_channel(); + virtual net::Socket* video_channel(); + + virtual net::Socket* video_rtp_channel(); + virtual net::Socket* video_rtcp_channel(); + + virtual const std::string& jid(); + + virtual const CandidateSessionConfig* candidate_config(); + + virtual const SessionConfig* config(); + virtual void set_config(const SessionConfig* config); + + virtual const std::string& initiator_token(); + virtual void set_initiator_token(const std::string& initiator_token); + virtual const std::string& receiver_token(); + virtual void set_receiver_token(const std::string& receiver_token); + + virtual void Close(); private: - friend class JingleDatagramConnector; friend class JingleSessionManager; - friend class JingleStreamConnector; // Create a JingleSession used in client mode. A server certificate is // required. @@ -96,7 +104,20 @@ class JingleSession : public protocol::Session, // Initialize the session configuration from a received connection response // stanza. bool InitializeConfigFromDescription( - const cricket::SessionDescription* description); + const cricket::SessionDescription* description); + + // Configures channels and calls InitializeSSL(). + void InitializeChannels(); + + // Helper method to initialize PseudoTcp over the datagram-oriented |channel|. + // If things don't immediately fail then a new StreamSocket is placed in + // |pseudo_tcp|. + bool EstablishPseudoTcp(net::Socket* channel, + scoped_ptr<net::StreamSocket>* pseudo_tcp); + + // Helper method to initialize SSL over a StreamSocket. + bool EstablishSSLConnection(net::StreamSocket* socket, + scoped_ptr<net::StreamSocket>* ssl_socket); // Used for Session.SignalState sigslot. void OnSessionState(cricket::BaseSession* session, @@ -109,30 +130,10 @@ class JingleSession : public protocol::Session, void OnAccept(); void OnTerminate(); - // Notifies upper layer about incoming connection and - // accepts/rejects connection. - void AcceptConnection(); - - void AddChannelConnector(const std::string& name, - JingleChannelConnector* connector); + void OnConnect(int result); - // Called by JingleChannelConnector when it has finished connecting - // the channel and needs to be destroyed. - void OnChannelConnectorFinished(const std::string& name, - JingleChannelConnector* connector); - - // Creates channels after session has been accepted. - // TODO(sergeyu): Don't create channels in JingleSession. - void CreateChannels(); - - // Callbacks for the channels created in JingleSession. - // TODO(sergeyu): Remove this method once *_channel() methods are - // removed from Session interface. - void OnStreamChannelConnected( - const std::string& name, net::StreamSocket* socket); - void OnChannelConnected(const std::string& name, net::Socket* socket); - - const cricket::ContentInfo* GetContentInfo() const; + // Called by SSL socket to notify connect event. + void OnSSLConnect(int result); void SetState(State new_state); @@ -177,14 +178,43 @@ class JingleSession : public protocol::Session, // These data members are only set on the receiving side. scoped_ptr<const CandidateSessionConfig> candidate_config_; - // Channels that are currently being connected. - std::map<std::string, JingleChannelConnector*> channel_connectors_; - - scoped_ptr<net::Socket> control_channel_socket_; - scoped_ptr<net::Socket> event_channel_socket_; - scoped_ptr<net::Socket> video_channel_socket_; - scoped_ptr<net::Socket> video_rtp_channel_socket_; - scoped_ptr<net::Socket> video_rtcp_channel_socket_; + // |raw_foo_channel_| is a reference to the Cricket transport channel foo, + // which is owned by the Cricket session. + // |foo_channel_| owns the Socket adapter for that channel. + // |foo_socket_| takes ownership of the Socket from |foo_channel_| and wraps + // it with PseudoTcp. |foo_ssl_socket_| takes ownership from |foo_socket_| + // and runs the SSL protocol over it. Finally |foo_socket_wrapper_| takes + // ownership of |foo_ssl_socket_|, wrapping it with a SocketWrapper to work + // around issues with callers of the resulting Sockets continuing to access + // them after CloseInternal() has completed. + // TODO(wez): Fix the tear-down issue and remove SocketWrapper. + + cricket::TransportChannel* raw_control_channel_; + scoped_ptr<jingle_glue::TransportChannelSocketAdapter> control_channel_; + scoped_ptr<net::StreamSocket> control_socket_; + scoped_ptr<net::StreamSocket> control_ssl_socket_; + + cricket::TransportChannel* raw_event_channel_; + scoped_ptr<jingle_glue::TransportChannelSocketAdapter> event_channel_; + scoped_ptr<net::StreamSocket> event_socket_; + scoped_ptr<net::StreamSocket> event_ssl_socket_; + + cricket::TransportChannel* raw_video_channel_; + scoped_ptr<jingle_glue::TransportChannelSocketAdapter> video_channel_; + scoped_ptr<net::StreamSocket> video_socket_; + scoped_ptr<net::StreamSocket> video_ssl_socket_; + + // Used to verify the certificate received in SSLClientSocket. + scoped_ptr<net::CertVerifier> cert_verifier_; + + cricket::TransportChannel* raw_video_rtp_channel_; + scoped_ptr<jingle_glue::TransportChannelSocketAdapter> video_rtp_channel_; + cricket::TransportChannel* raw_video_rtcp_channel_; + scoped_ptr<jingle_glue::TransportChannelSocketAdapter> video_rtcp_channel_; + + // Callback called by the SSL layer. + net::CompletionCallbackImpl<JingleSession> connect_callback_; + net::CompletionCallbackImpl<JingleSession> ssl_connect_callback_; ScopedRunnableMethodFactory<JingleSession> task_factory_; diff --git a/remoting/protocol/jingle_stream_connector.cc b/remoting/protocol/jingle_stream_connector.cc deleted file mode 100644 index f150749..0000000 --- a/remoting/protocol/jingle_stream_connector.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 2011 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/jingle_stream_connector.h" - -#include "jingle/glue/channel_socket_adapter.h" -#include "jingle/glue/pseudotcp_adapter.h" -#include "net/base/cert_status_flags.h" -#include "net/base/cert_verifier.h" -#include "net/base/host_port_pair.h" -#include "net/base/ssl_config_service.h" -#include "net/base/x509_certificate.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/ssl_server_socket.h" -#include "net/socket/client_socket_factory.h" -#include "remoting/protocol/jingle_session.h" -#include "third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h" - -namespace remoting { -namespace protocol { - -namespace { - -// Value is choosen to balance the extra latency against the reduced -// load due to ACK traffic. -const int kTcpAckDelayMilliseconds = 10; - -// Helper method to create a SSL client socket. -net::SSLClientSocket* CreateSSLClientSocket( - net::StreamSocket* socket, scoped_refptr<net::X509Certificate> cert, - net::CertVerifier* cert_verifier) { - net::SSLConfig ssl_config; - - // Certificate provided by the host doesn't need authority. - net::SSLConfig::CertAndStatus cert_and_status; - cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID; - cert_and_status.cert = cert; - ssl_config.allowed_bad_certs.push_back(cert_and_status); - - // SSLClientSocket takes ownership of the adapter. - net::HostPortPair host_and_pair(JingleSession::kChromotingContentName, 0); - net::SSLClientSocket* ssl_socket = - net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket( - socket, host_and_pair, ssl_config, NULL, cert_verifier); - return ssl_socket; -} - -} // namespace - -JingleStreamConnector::JingleStreamConnector( - JingleSession* session, - const std::string& name, - const Session::StreamChannelCallback& callback) - : session_(session), - name_(name), - callback_(callback), - initiator_(false), - local_private_key_(NULL), - raw_channel_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(tcp_connect_callback_( - this, &JingleStreamConnector::OnTCPConnect)), - ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_( - this, &JingleStreamConnector::OnSSLConnect)) { -} - -JingleStreamConnector::~JingleStreamConnector() { -} - -void JingleStreamConnector::Connect(bool initiator, - net::X509Certificate* local_cert, - net::X509Certificate* remote_cert, - crypto::RSAPrivateKey* local_private_key, - cricket::TransportChannel* raw_channel) { - DCHECK(CalledOnValidThread()); - DCHECK(!raw_channel_); - - initiator_ = initiator; - local_cert_ = local_cert; - remote_cert_ = remote_cert; - local_private_key_ = local_private_key; - raw_channel_ = raw_channel; - - if (!initiator_) { - // Don't make outgoing connections from the host to client. - raw_channel_->GetP2PChannel()->set_incoming_only(true); - } - - net::Socket* socket = - new jingle_glue::TransportChannelSocketAdapter(raw_channel_); - - if (!EstablishTCPConnection(socket)) - NotifyError(); -} - -bool JingleStreamConnector::EstablishTCPConnection(net::Socket* socket) { - jingle_glue::PseudoTcpAdapter* adapter = - new jingle_glue::PseudoTcpAdapter(socket); - adapter->SetAckDelay(kTcpAckDelayMilliseconds); - adapter->SetNoDelay(true); - - socket_.reset(adapter); - int result = socket_->Connect(&tcp_connect_callback_); - if (result == net::ERR_IO_PENDING) { - return true; - } else if (result == net::OK) { - tcp_connect_callback_.Run(result); - return true; - } - - return false; -} - -bool JingleStreamConnector::EstablishSSLConnection() { - DCHECK(socket_->IsConnected()); - - int result; - if (initiator_) { - cert_verifier_.reset(new net::CertVerifier()); - - // Create client SSL socket. - net::SSLClientSocket* ssl_client_socket = CreateSSLClientSocket( - socket_.release(), remote_cert_, cert_verifier_.get()); - socket_.reset(ssl_client_socket); - - int result = ssl_client_socket->Connect(&ssl_connect_callback_); - } else { - // Create server SSL socket. - net::SSLConfig ssl_config; - net::SSLServerSocket* ssl_server_socket = - net::CreateSSLServerSocket(socket_.release(), local_cert_, - local_private_key_, ssl_config); - socket_.reset(ssl_server_socket); - - int result = ssl_server_socket->Handshake(&ssl_connect_callback_); - } - - if (result == net::ERR_IO_PENDING) { - return true; - } else if (result != net::OK) { - LOG(ERROR) << "Failed to establish SSL connection"; - return false; - } - - // Reach here if net::OK is received. - ssl_connect_callback_.Run(net::OK); - return true; -} - -void JingleStreamConnector::OnTCPConnect(int result) { - DCHECK(CalledOnValidThread()); - - if (result != net::OK) { - LOG(ERROR) << "PseudoTCP connection failed: " << result; - NotifyError(); - return; - } - - if (!EstablishSSLConnection()) - NotifyError(); -} - -void JingleStreamConnector::OnSSLConnect(int result) { - DCHECK(CalledOnValidThread()); - - if (result != net::OK) { - LOG(ERROR) << "Error during SSL connection: " << result; - NotifyError(); - return; - } - - DCHECK(socket_->IsConnected()); - NotifyDone(socket_.release()); -} - -void JingleStreamConnector::NotifyDone(net::StreamSocket* socket) { - callback_.Run(name_, socket); - session_->OnChannelConnectorFinished(name_, this); -} - -void JingleStreamConnector::NotifyError() { - socket_.reset(); - callback_.Run(name_, NULL); - session_->OnChannelConnectorFinished(name_, this); -} - -} // namespace protocol -} // namespace remoting diff --git a/remoting/protocol/jingle_stream_connector.h b/remoting/protocol/jingle_stream_connector.h deleted file mode 100644 index ab7968b..0000000 --- a/remoting/protocol/jingle_stream_connector.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef REMOTING_PROTOCOL_JINGLE_STREAM_CONNECTOR_H_ -#define REMOTING_PROTOCOL_JINGLE_STREAM_CONNECTOR_H_ - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "net/base/completion_callback.h" -#include "remoting/protocol/jingle_channel_connector.h" -#include "remoting/protocol/session.h" - -namespace cricket { -class TransportChannel; -} // namespace cricket - -namespace jingle_glue { -class TransportChannelSocketAdapter; -} // namespace jingle_glue - -namespace net { -class CertVerifier; -class StreamSocket; -} // namespace net - -namespace remoting { -namespace protocol { - -class JingleSession; - -class JingleStreamConnector : public JingleChannelConnector { - public: - JingleStreamConnector(JingleSession* session, - const std::string& name, - const Session::StreamChannelCallback& callback); - virtual ~JingleStreamConnector(); - - // Starts connection process for the channel. |local_private_key| is - // owned by the caller, and must exist until this object is - // destroyed. - virtual void Connect(bool initiator, - net::X509Certificate* local_cert, - net::X509Certificate* remote_cert, - crypto::RSAPrivateKey* local_private_key, - cricket::TransportChannel* raw_channel) OVERRIDE; - - private: - bool EstablishTCPConnection(net::Socket* socket); - void OnTCPConnect(int result); - - bool EstablishSSLConnection(); - void OnSSLConnect(int result); - - void NotifyDone(net::StreamSocket* socket); - void NotifyError(); - - JingleSession* session_; - - std::string name_; - - Session::StreamChannelCallback callback_; - - bool initiator_; - scoped_refptr<net::X509Certificate> local_cert_; - scoped_refptr<net::X509Certificate> remote_cert_; - crypto::RSAPrivateKey* local_private_key_; - - cricket::TransportChannel* raw_channel_; - scoped_ptr<net::StreamSocket> socket_; - - // Used to verify the certificate received in SSLClientSocket. - scoped_ptr<net::CertVerifier> cert_verifier_; - - // Callback called by the TCP and SSL layers. - net::CompletionCallbackImpl<JingleStreamConnector> tcp_connect_callback_; - net::CompletionCallbackImpl<JingleStreamConnector> ssl_connect_callback_; - - DISALLOW_COPY_AND_ASSIGN(JingleStreamConnector); -}; - -} // namespace protocol -} // namespace remoting - -#endif // REMOTING_PROTOCOL_JINGLE_STREAM_CONNECTOR_H_ diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h index 9b34b8e..274b304 100644 --- a/remoting/protocol/protocol_mock_objects.h +++ b/remoting/protocol/protocol_mock_objects.h @@ -112,10 +112,6 @@ class MockSession : public Session { virtual ~MockSession(); MOCK_METHOD1(SetStateChangeCallback, void(StateChangeCallback* callback)); - MOCK_METHOD2(CreateStreamChannel, void( - const std::string& name, const StreamChannelCallback& callback)); - MOCK_METHOD2(CreateDatagramChannel, void( - const std::string& name, const DatagramChannelCallback& callback)); MOCK_METHOD0(control_channel, net::Socket*()); MOCK_METHOD0(event_channel, net::Socket*()); MOCK_METHOD0(video_channel, net::Socket*()); diff --git a/remoting/protocol/session.h b/remoting/protocol/session.h index 059a21f..754b223 100644 --- a/remoting/protocol/session.h +++ b/remoting/protocol/session.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -16,7 +16,6 @@ class Task; namespace net { class Socket; -class StreamSocket; } // namespace net namespace remoting { @@ -25,6 +24,7 @@ namespace protocol { // Generic interface for Chromotocol connection used by both client and host. // Provides access to the connection channels, but doesn't depend on the // protocol used for each channel. +// TODO(sergeyu): Remove refcounting? class Session : public base::NonThreadSafe { public: enum State { @@ -36,10 +36,6 @@ class Session : public base::NonThreadSafe { }; typedef Callback1<State>::Type StateChangeCallback; - typedef base::Callback<void(const std::string&, net::StreamSocket*)> - StreamChannelCallback; - typedef base::Callback<void(const std::string&, net::Socket*)> - DatagramChannelCallback; Session() { } virtual ~Session() { } @@ -48,26 +44,20 @@ class Session : public base::NonThreadSafe { // Must be called on the jingle thread only. virtual void SetStateChangeCallback(StateChangeCallback* callback) = 0; - // Creates new channels for this connection. The specified callback - // is called when then new channel is created and connected. The - // callback is called with NULL if connection failed for any reason. - // Ownership of the channel socket is given to the caller when the - // callback is called. All channels must be destroyed before the - // session is destroyed. Can be called only when in CONNECTING or - // CONNECTED state. - virtual void CreateStreamChannel( - const std::string& name, const StreamChannelCallback& callback) = 0; - virtual void CreateDatagramChannel( - const std::string& name, const DatagramChannelCallback& callback) = 0; - - // TODO(sergeyu): Remove these methods, and use CreateChannel() - // instead. + // Reliable PseudoTCP channels for this connection. virtual net::Socket* control_channel() = 0; virtual net::Socket* event_channel() = 0; + + // TODO(sergeyu): Remove VideoChannel, and use RTP channels instead. virtual net::Socket* video_channel() = 0; + + // Unreliable channels for this connection. virtual net::Socket* video_rtp_channel() = 0; virtual net::Socket* video_rtcp_channel() = 0; + // TODO(sergeyu): Make it possible to create/destroy additional channels + // on-fly? + // JID of the other side. virtual const std::string& jid() = 0; diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 8ce526a..094a9d0 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -562,15 +562,10 @@ 'protocol/input_sender.cc', 'protocol/input_sender.h', 'protocol/input_stub.h', - 'protocol/jingle_channel_connector.h', - 'protocol/jingle_datagram_connector.cc', - 'protocol/jingle_datagram_connector.h', 'protocol/jingle_session.cc', 'protocol/jingle_session.h', 'protocol/jingle_session_manager.cc', 'protocol/jingle_session_manager.h', - 'protocol/jingle_stream_connector.cc', - 'protocol/jingle_stream_connector.h', 'protocol/message_decoder.cc', 'protocol/message_decoder.h', 'protocol/message_reader.cc', |