| Index: remoting/protocol/quic_channel_factory.cc
|
| diff --git a/remoting/protocol/quic_channel_factory.cc b/remoting/protocol/quic_channel_factory.cc
|
| deleted file mode 100644
|
| index 9c2240dc309f9d0a9d2fc4d45814139cc0447afe..0000000000000000000000000000000000000000
|
| --- a/remoting/protocol/quic_channel_factory.cc
|
| +++ /dev/null
|
| @@ -1,541 +0,0 @@
|
| -// 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/quic_channel_factory.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/location.h"
|
| -#include "base/single_thread_task_runner.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/quic/crypto/crypto_framer.h"
|
| -#include "net/quic/crypto/crypto_handshake_message.h"
|
| -#include "net/quic/crypto/crypto_protocol.h"
|
| -#include "net/quic/crypto/quic_random.h"
|
| -#include "net/quic/p2p/quic_p2p_crypto_config.h"
|
| -#include "net/quic/p2p/quic_p2p_session.h"
|
| -#include "net/quic/p2p/quic_p2p_stream.h"
|
| -#include "net/quic/quic_clock.h"
|
| -#include "net/quic/quic_connection_helper.h"
|
| -#include "net/quic/quic_default_packet_writer.h"
|
| -#include "net/quic/quic_protocol.h"
|
| -#include "net/socket/stream_socket.h"
|
| -#include "remoting/base/constants.h"
|
| -#include "remoting/protocol/datagram_channel_factory.h"
|
| -#include "remoting/protocol/p2p_datagram_socket.h"
|
| -#include "remoting/protocol/quic_channel.h"
|
| -
|
| -namespace remoting {
|
| -namespace protocol {
|
| -
|
| -namespace {
|
| -
|
| -// The maximum receive window sizes for QUIC sessions and streams. These are
|
| -// the same values that are used in chrome.
|
| -const int kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
|
| -const int kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
|
| -
|
| -class P2PQuicPacketWriter : public net::QuicPacketWriter {
|
| - public:
|
| - P2PQuicPacketWriter(net::QuicConnection* connection,
|
| - P2PDatagramSocket* socket)
|
| - : connection_(connection), socket_(socket), weak_factory_(this) {}
|
| - ~P2PQuicPacketWriter() override {}
|
| -
|
| - // QuicPacketWriter interface.
|
| - net::WriteResult WritePacket(const char* buffer,
|
| - size_t buf_len,
|
| - const net::IPAddressNumber& self_address,
|
| - const net::IPEndPoint& peer_address) override {
|
| - DCHECK(!write_blocked_);
|
| -
|
| - scoped_refptr<net::StringIOBuffer> buf(
|
| - new net::StringIOBuffer(std::string(buffer, buf_len)));
|
| - int result = socket_->Send(buf, buf_len,
|
| - base::Bind(&P2PQuicPacketWriter::OnSendComplete,
|
| - weak_factory_.GetWeakPtr()));
|
| - net::WriteStatus status = net::WRITE_STATUS_OK;
|
| - if (result < 0) {
|
| - if (result == net::ERR_IO_PENDING) {
|
| - status = net::WRITE_STATUS_BLOCKED;
|
| - write_blocked_ = true;
|
| - } else {
|
| - status = net::WRITE_STATUS_ERROR;
|
| - }
|
| - }
|
| -
|
| - return net::WriteResult(status, result);
|
| - }
|
| - bool IsWriteBlockedDataBuffered() const override {
|
| - // P2PDatagramSocket::Send() method buffer the data until the Send is
|
| - // unblocked.
|
| - return true;
|
| - }
|
| - bool IsWriteBlocked() const override { return write_blocked_; }
|
| - void SetWritable() override { write_blocked_ = false; }
|
| - net::QuicByteCount GetMaxPacketSize(const net::IPEndPoint& peer_address) const
|
| - override {
|
| - return net::kMaxPacketSize;
|
| - }
|
| -
|
| - private:
|
| - void OnSendComplete(int result){
|
| - DCHECK_NE(result, net::ERR_IO_PENDING);
|
| - write_blocked_ = false;
|
| - if (result < 0) {
|
| - connection_->OnWriteError(result);
|
| - }
|
| - connection_->OnCanWrite();
|
| - }
|
| -
|
| - net::QuicConnection* connection_;
|
| - P2PDatagramSocket* socket_;
|
| -
|
| - // Whether a write is currently in flight.
|
| - bool write_blocked_ = false;
|
| -
|
| - base::WeakPtrFactory<P2PQuicPacketWriter> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(P2PQuicPacketWriter);
|
| -};
|
| -
|
| -class QuicPacketWriterFactory
|
| - : public net::QuicConnection::PacketWriterFactory {
|
| - public:
|
| - explicit QuicPacketWriterFactory(P2PDatagramSocket* socket)
|
| - : socket_(socket) {}
|
| - ~QuicPacketWriterFactory() override {}
|
| -
|
| - net::QuicPacketWriter* Create(
|
| - net::QuicConnection* connection) const override {
|
| - return new P2PQuicPacketWriter(connection, socket_);
|
| - }
|
| -
|
| - private:
|
| - P2PDatagramSocket* socket_;
|
| -};
|
| -
|
| -class P2PDatagramSocketAdapter : public net::Socket {
|
| - public:
|
| - explicit P2PDatagramSocketAdapter(scoped_ptr<P2PDatagramSocket> socket)
|
| - : socket_(socket.Pass()) {}
|
| - ~P2PDatagramSocketAdapter() override {}
|
| -
|
| - int Read(net::IOBuffer* buf, int buf_len,
|
| - const net::CompletionCallback& callback) override {
|
| - return socket_->Recv(buf, buf_len, callback);
|
| - }
|
| - int Write(net::IOBuffer* buf, int buf_len,
|
| - const net::CompletionCallback& callback) override {
|
| - return socket_->Send(buf, buf_len, callback);
|
| - }
|
| -
|
| - int SetReceiveBufferSize(int32_t size) override {
|
| - NOTREACHED();
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - int SetSendBufferSize(int32_t size) override {
|
| - NOTREACHED();
|
| - return net::ERR_FAILED;
|
| - }
|
| -
|
| - private:
|
| - scoped_ptr<P2PDatagramSocket> socket_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -class QuicChannelFactory::Core : public net::QuicP2PSession::Delegate {
|
| - public:
|
| - Core(const std::string& session_id, bool is_server);
|
| - virtual ~Core();
|
| -
|
| - // Called from ~QuicChannelFactory() to synchronously release underlying
|
| - // socket. Core is destroyed later asynchronously.
|
| - void Close();
|
| -
|
| - // Implementation of all all methods for QuicChannelFactory.
|
| - const std::string& CreateSessionInitiateConfigMessage();
|
| - bool ProcessSessionAcceptConfigMessage(const std::string& message);
|
| -
|
| - bool ProcessSessionInitiateConfigMessage(const std::string& message);
|
| - const std::string& CreateSessionAcceptConfigMessage();
|
| -
|
| - void Start(DatagramChannelFactory* factory, const std::string& shared_secret);
|
| -
|
| - void CreateChannel(const std::string& name,
|
| - const ChannelCreatedCallback& callback);
|
| - void CancelChannelCreation(const std::string& name);
|
| -
|
| - private:
|
| - friend class QuicChannelFactory;
|
| -
|
| - struct PendingChannel {
|
| - PendingChannel(const std::string& name,
|
| - const ChannelCreatedCallback& callback)
|
| - : name(name), callback(callback) {}
|
| -
|
| - std::string name;
|
| - ChannelCreatedCallback callback;
|
| - };
|
| -
|
| - // QuicP2PSession::Delegate interface.
|
| - void OnIncomingStream(net::QuicP2PStream* stream) override;
|
| - void OnConnectionClosed(net::QuicErrorCode error) override;
|
| -
|
| - void OnBaseChannelReady(scoped_ptr<P2PDatagramSocket> socket);
|
| -
|
| - void OnNameReceived(QuicChannel* channel);
|
| -
|
| - void OnChannelDestroyed(int stream_id);
|
| -
|
| - std::string session_id_;
|
| - bool is_server_;
|
| - DatagramChannelFactory* base_channel_factory_ = nullptr;
|
| -
|
| - net::QuicConfig quic_config_;
|
| - std::string shared_secret_;
|
| - std::string session_initiate_quic_config_message_;
|
| - std::string session_accept_quic_config_message_;
|
| -
|
| - net::QuicClock quic_clock_;
|
| - net::QuicConnectionHelper quic_helper_;
|
| - scoped_ptr<net::QuicP2PSession> quic_session_;
|
| - bool connected_ = false;
|
| -
|
| - std::vector<PendingChannel*> pending_channels_;
|
| - std::vector<QuicChannel*> unnamed_incoming_channels_;
|
| -
|
| - base::WeakPtrFactory<Core> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Core);
|
| -};
|
| -
|
| -QuicChannelFactory::Core::Core(const std::string& session_id, bool is_server)
|
| - : session_id_(session_id),
|
| - is_server_(is_server),
|
| - quic_helper_(base::ThreadTaskRunnerHandle::Get().get(),
|
| - &quic_clock_,
|
| - net::QuicRandom::GetInstance()),
|
| - weak_factory_(this) {
|
| - quic_config_.SetInitialSessionFlowControlWindowToSend(
|
| - kQuicSessionMaxRecvWindowSize);
|
| - quic_config_.SetInitialStreamFlowControlWindowToSend(
|
| - kQuicStreamMaxRecvWindowSize);
|
| -}
|
| -
|
| -QuicChannelFactory::Core::~Core() {}
|
| -
|
| -void QuicChannelFactory::Core::Close() {
|
| - DCHECK(pending_channels_.empty());
|
| -
|
| - // Cancel creation of the base channel if it hasn't finished.
|
| - if (base_channel_factory_)
|
| - base_channel_factory_->CancelChannelCreation(kQuicChannelName);
|
| -
|
| - if (quic_session_ && quic_session_->connection()->connected())
|
| - quic_session_->connection()->CloseConnection(net::QUIC_NO_ERROR, false);
|
| -
|
| - DCHECK(unnamed_incoming_channels_.empty());
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::Start(DatagramChannelFactory* factory,
|
| - const std::string& shared_secret) {
|
| - base_channel_factory_ = factory;
|
| - shared_secret_ = shared_secret;
|
| -
|
| - base_channel_factory_->CreateChannel(
|
| - kQuicChannelName,
|
| - base::Bind(&Core::OnBaseChannelReady, weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -const std::string&
|
| -QuicChannelFactory::Core::CreateSessionInitiateConfigMessage() {
|
| - DCHECK(!is_server_);
|
| -
|
| - net::CryptoHandshakeMessage handshake_message;
|
| - handshake_message.set_tag(net::kCHLO);
|
| - quic_config_.ToHandshakeMessage(&handshake_message);
|
| -
|
| - session_initiate_quic_config_message_ =
|
| - handshake_message.GetSerialized().AsStringPiece().as_string();
|
| - return session_initiate_quic_config_message_;
|
| -}
|
| -
|
| -bool QuicChannelFactory::Core::ProcessSessionAcceptConfigMessage(
|
| - const std::string& message) {
|
| - DCHECK(!is_server_);
|
| -
|
| - session_accept_quic_config_message_ = message;
|
| -
|
| - scoped_ptr<net::CryptoHandshakeMessage> parsed_message(
|
| - net::CryptoFramer::ParseMessage(message));
|
| - if (!parsed_message) {
|
| - LOG(ERROR) << "Received invalid QUIC config.";
|
| - return false;
|
| - }
|
| -
|
| - if (parsed_message->tag() != net::kSHLO) {
|
| - LOG(ERROR) << "Received QUIC handshake message with unexpected tag "
|
| - << parsed_message->tag();
|
| - return false;
|
| - }
|
| -
|
| - std::string error_message;
|
| - net::QuicErrorCode error = quic_config_.ProcessPeerHello(
|
| - *parsed_message, net::SERVER, &error_message);
|
| - if (error != net::QUIC_NO_ERROR) {
|
| - LOG(ERROR) << "Failed to process QUIC handshake message: "
|
| - << error_message;
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool QuicChannelFactory::Core::ProcessSessionInitiateConfigMessage(
|
| - const std::string& message) {
|
| - DCHECK(is_server_);
|
| -
|
| - session_initiate_quic_config_message_ = message;
|
| -
|
| - scoped_ptr<net::CryptoHandshakeMessage> parsed_message(
|
| - net::CryptoFramer::ParseMessage(message));
|
| - if (!parsed_message) {
|
| - LOG(ERROR) << "Received invalid QUIC config.";
|
| - return false;
|
| - }
|
| -
|
| - if (parsed_message->tag() != net::kCHLO) {
|
| - LOG(ERROR) << "Received QUIC handshake message with unexpected tag "
|
| - << parsed_message->tag();
|
| - return false;
|
| - }
|
| -
|
| - std::string error_message;
|
| - net::QuicErrorCode error = quic_config_.ProcessPeerHello(
|
| - *parsed_message, net::CLIENT, &error_message);
|
| - if (error != net::QUIC_NO_ERROR) {
|
| - LOG(ERROR) << "Failed to process QUIC handshake message: "
|
| - << error_message;
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -const std::string&
|
| -QuicChannelFactory::Core::CreateSessionAcceptConfigMessage() {
|
| - DCHECK(is_server_);
|
| -
|
| - if (session_initiate_quic_config_message_.empty()) {
|
| - // Don't send quic-config to the client if the client didn't include the
|
| - // config in the session-initiate message.
|
| - DCHECK(session_accept_quic_config_message_.empty());
|
| - return session_accept_quic_config_message_;
|
| - }
|
| -
|
| - net::CryptoHandshakeMessage handshake_message;
|
| - handshake_message.set_tag(net::kSHLO);
|
| - quic_config_.ToHandshakeMessage(&handshake_message);
|
| -
|
| - session_accept_quic_config_message_ =
|
| - handshake_message.GetSerialized().AsStringPiece().as_string();
|
| - return session_accept_quic_config_message_;
|
| -}
|
| -
|
| -// StreamChannelFactory interface.
|
| -void QuicChannelFactory::Core::CreateChannel(
|
| - const std::string& name,
|
| - const ChannelCreatedCallback& callback) {
|
| - if (quic_session_ && quic_session_->connection()->connected()) {
|
| - if (!is_server_) {
|
| - net::QuicP2PStream* stream = quic_session_->CreateOutgoingDynamicStream();
|
| - scoped_ptr<QuicChannel> channel(new QuicClientChannel(
|
| - stream, base::Bind(&Core::OnChannelDestroyed, base::Unretained(this),
|
| - stream->id()),
|
| - name));
|
| - callback.Run(channel.Pass());
|
| - } else {
|
| - // On the server side wait for the client to create a QUIC stream and
|
| - // send the name. The channel will be connected in OnNameReceived().
|
| - pending_channels_.push_back(new PendingChannel(name, callback));
|
| - }
|
| - } else if (!base_channel_factory_) {
|
| - // Fail synchronously if we failed to connect transport.
|
| - callback.Run(nullptr);
|
| - } else {
|
| - // Still waiting for the transport.
|
| - pending_channels_.push_back(new PendingChannel(name, callback));
|
| - }
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::CancelChannelCreation(const std::string& name) {
|
| - for (auto it = pending_channels_.begin(); it != pending_channels_.end();
|
| - ++it) {
|
| - if ((*it)->name == name) {
|
| - delete *it;
|
| - pending_channels_.erase(it);
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::OnBaseChannelReady(
|
| - scoped_ptr<P2PDatagramSocket> socket) {
|
| - base_channel_factory_ = nullptr;
|
| -
|
| - // Failed to connect underlying transport connection. Fail all pending
|
| - // channel.
|
| - if (!socket) {
|
| - while (!pending_channels_.empty()) {
|
| - scoped_ptr<PendingChannel> pending_channel(pending_channels_.front());
|
| - pending_channels_.erase(pending_channels_.begin());
|
| - pending_channel->callback.Run(nullptr);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - QuicPacketWriterFactory writer_factory(socket.get());
|
| - net::IPAddressNumber ip(net::kIPv4AddressSize, 0);
|
| - scoped_ptr<net::QuicConnection> quic_connection(new net::QuicConnection(
|
| - 0, net::IPEndPoint(ip, 0), &quic_helper_, writer_factory,
|
| - true /* owns_writer */,
|
| - is_server_ ? net::Perspective::IS_SERVER : net::Perspective::IS_CLIENT,
|
| - net::QuicSupportedVersions()));
|
| -
|
| - net::QuicP2PCryptoConfig quic_crypto_config(shared_secret_);
|
| - quic_crypto_config.set_hkdf_input_suffix(
|
| - session_id_ + '\0' + kQuicChannelName + '\0' +
|
| - session_initiate_quic_config_message_ +
|
| - session_accept_quic_config_message_);
|
| -
|
| - quic_session_.reset(new net::QuicP2PSession(
|
| - quic_config_, quic_crypto_config, quic_connection.Pass(),
|
| - make_scoped_ptr(new P2PDatagramSocketAdapter(socket.Pass()))));
|
| - quic_session_->SetDelegate(this);
|
| - quic_session_->Initialize();
|
| -
|
| - if (!is_server_) {
|
| - // On the client create streams for all pending channels and send a name for
|
| - // each channel.
|
| - while (!pending_channels_.empty()) {
|
| - scoped_ptr<PendingChannel> pending_channel(pending_channels_.front());
|
| - pending_channels_.erase(pending_channels_.begin());
|
| -
|
| - net::QuicP2PStream* stream = quic_session_->CreateOutgoingDynamicStream();
|
| - scoped_ptr<QuicChannel> channel(new QuicClientChannel(
|
| - stream, base::Bind(&Core::OnChannelDestroyed, base::Unretained(this),
|
| - stream->id()),
|
| - pending_channel->name));
|
| - pending_channel->callback.Run(channel.Pass());
|
| - }
|
| - }
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::OnIncomingStream(net::QuicP2PStream* stream) {
|
| - QuicServerChannel* channel = new QuicServerChannel(
|
| - stream, base::Bind(&Core::OnChannelDestroyed, base::Unretained(this),
|
| - stream->id()));
|
| - unnamed_incoming_channels_.push_back(channel);
|
| - channel->ReceiveName(
|
| - base::Bind(&Core::OnNameReceived, base::Unretained(this), channel));
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::OnConnectionClosed(net::QuicErrorCode error) {
|
| - if (error != net::QUIC_NO_ERROR)
|
| - LOG(ERROR) << "QUIC connection was closed, error_code=" << error;
|
| -
|
| - while (!pending_channels_.empty()) {
|
| - scoped_ptr<PendingChannel> pending_channel(pending_channels_.front());
|
| - pending_channels_.erase(pending_channels_.begin());
|
| - pending_channel->callback.Run(nullptr);
|
| - }
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::OnNameReceived(QuicChannel* channel) {
|
| - DCHECK(is_server_);
|
| -
|
| - scoped_ptr<QuicChannel> owned_channel(channel);
|
| -
|
| - auto it = std::find(unnamed_incoming_channels_.begin(),
|
| - unnamed_incoming_channels_.end(), channel);
|
| - DCHECK(it != unnamed_incoming_channels_.end());
|
| - unnamed_incoming_channels_.erase(it);
|
| -
|
| - if (channel->name().empty()) {
|
| - // Failed to read a name for incoming channel.
|
| - return;
|
| - }
|
| -
|
| - for (auto it = pending_channels_.begin();
|
| - it != pending_channels_.end(); ++it) {
|
| - if ((*it)->name == channel->name()) {
|
| - scoped_ptr<PendingChannel> pending_channel(*it);
|
| - pending_channels_.erase(it);
|
| - pending_channel->callback.Run(owned_channel.Pass());
|
| - return;
|
| - }
|
| - }
|
| -
|
| - LOG(ERROR) << "Unexpected incoming channel: " << channel->name();
|
| -}
|
| -
|
| -void QuicChannelFactory::Core::OnChannelDestroyed(int stream_id) {
|
| - if (quic_session_)
|
| - quic_session_->CloseStream(stream_id);
|
| -}
|
| -
|
| -QuicChannelFactory::QuicChannelFactory(const std::string& session_id,
|
| - bool is_server)
|
| - : core_(new Core(session_id, is_server)) {}
|
| -
|
| -QuicChannelFactory::~QuicChannelFactory() {
|
| - core_->Close();
|
| - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, core_.release());
|
| -}
|
| -
|
| -const std::string& QuicChannelFactory::CreateSessionInitiateConfigMessage() {
|
| - return core_->CreateSessionInitiateConfigMessage();
|
| -}
|
| -
|
| -bool QuicChannelFactory::ProcessSessionAcceptConfigMessage(
|
| - const std::string& message) {
|
| - return core_->ProcessSessionAcceptConfigMessage(message);
|
| -}
|
| -
|
| -bool QuicChannelFactory::ProcessSessionInitiateConfigMessage(
|
| - const std::string& message) {
|
| - return core_->ProcessSessionInitiateConfigMessage(message);
|
| -}
|
| -
|
| -const std::string& QuicChannelFactory::CreateSessionAcceptConfigMessage() {
|
| - return core_->CreateSessionAcceptConfigMessage();
|
| -}
|
| -
|
| -void QuicChannelFactory::Start(DatagramChannelFactory* factory,
|
| - const std::string& shared_secret) {
|
| - core_->Start(factory, shared_secret);
|
| -}
|
| -
|
| -void QuicChannelFactory::CreateChannel(const std::string& name,
|
| - const ChannelCreatedCallback& callback) {
|
| - core_->CreateChannel(name, callback);
|
| -}
|
| -
|
| -void QuicChannelFactory::CancelChannelCreation(const std::string& name) {
|
| - core_->CancelChannelCreation(name);
|
| -}
|
| -
|
| -net::QuicP2PSession* QuicChannelFactory::GetP2PSessionForTests() {
|
| - return core_->quic_session_.get();
|
| -}
|
| -
|
| -} // namespace protocol
|
| -} // namespace remoting
|
|
|