Commit f31a5ce1 authored by kmarshall's avatar kmarshall Committed by Commit bot

Create new class "CastTransport", which encapsulates the message read and write event loops.

They currently target a revised stub interface for CastSocket, but not a full implementation.
That change is witheld in a separate Git client so this CL can remain at a manageable size.

Thanks!
BUG=396345
R=mfoltz@chromium.org
CC=wez@chromium.org

Review URL: https://codereview.chromium.org/555283002

Cr-Commit-Position: refs/heads/master@{#296993}
parent b6fc7567
......@@ -91,6 +91,8 @@ source_set("browser") {
"api/cast_channel/cast_message_util.h",
"api/cast_channel/cast_socket.cc",
"api/cast_channel/cast_socket.h",
"api/cast_channel/cast_transport.cc",
"api/cast_channel/cast_transport.h",
"api/cast_channel/logger.cc",
"api/cast_channel/logger.h",
"api/cast_channel/logger_util.cc",
......
......@@ -131,27 +131,14 @@ CastChannelAPI::GetFactoryInstance() {
return g_factory.Pointer();
}
scoped_ptr<CastSocket> CastChannelAPI::CreateCastSocket(
const std::string& extension_id, const net::IPEndPoint& ip_endpoint,
ChannelAuthType channel_auth, const base::TimeDelta& timeout) {
if (socket_for_test_.get()) {
return socket_for_test_.Pass();
} else {
return scoped_ptr<CastSocket>(
new CastSocket(extension_id,
ip_endpoint,
channel_auth,
this,
ExtensionsBrowserClient::Get()->GetNetLog(),
timeout,
logger_));
}
}
void CastChannelAPI::SetSocketForTest(scoped_ptr<CastSocket> socket_for_test) {
socket_for_test_ = socket_for_test.Pass();
}
scoped_ptr<cast_channel::CastSocket> CastChannelAPI::GetSocketForTest() {
return socket_for_test_.Pass();
}
void CastChannelAPI::OnError(const CastSocket* socket,
cast_channel::ChannelError error_state,
const cast_channel::LastErrors& last_errors) {
......@@ -367,13 +354,19 @@ bool CastChannelOpenFunction::Prepare() {
void CastChannelOpenFunction::AsyncWorkStart() {
DCHECK(api_);
DCHECK(ip_endpoint_.get());
scoped_ptr<CastSocket> socket = api_->CreateCastSocket(
extension_->id(),
*ip_endpoint_,
channel_auth_,
base::TimeDelta::FromMilliseconds(connect_info_->timeout.get()
? *connect_info_->timeout
: kDefaultConnectTimeoutMillis));
scoped_ptr<CastSocket> socket = api_->GetSocketForTest();
if (!socket.get()) {
socket.reset(new CastSocket(
extension_->id(),
*ip_endpoint_,
channel_auth_,
api_,
ExtensionsBrowserClient::Get()->GetNetLog(),
base::TimeDelta::FromMilliseconds(connect_info_->timeout.get()
? *connect_info_->timeout
: kDefaultConnectTimeoutMillis),
api_->GetLogger()));
}
new_channel_id_ = AddSocket(socket.release());
CastSocket* new_socket = GetSocket(new_channel_id_);
api_->GetLogger()->LogNewSocketEvent(*new_socket);
......@@ -424,11 +417,15 @@ bool CastChannelSendFunction::Prepare() {
}
void CastChannelSendFunction::AsyncWorkStart() {
CastSocket* socket = GetSocketOrCompleteWithError(
params_->channel.channel_id);
if (socket)
socket->SendMessage(params_->message,
base::Bind(&CastChannelSendFunction::OnSend, this));
CastSocket* socket = GetSocket(params_->channel.channel_id);
if (!socket) {
SetResultFromError(params_->channel.channel_id,
cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
AsyncWorkCompleted();
return;
}
socket->SendMessage(params_->message,
base::Bind(&CastChannelSendFunction::OnSend, this));
}
void CastChannelSendFunction::OnSend(int result) {
......@@ -455,10 +452,14 @@ bool CastChannelCloseFunction::Prepare() {
}
void CastChannelCloseFunction::AsyncWorkStart() {
CastSocket* socket = GetSocketOrCompleteWithError(
params_->channel.channel_id);
if (socket)
CastSocket* socket = GetSocket(params_->channel.channel_id);
if (!socket) {
SetResultFromError(params_->channel.channel_id,
cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
AsyncWorkCompleted();
} else {
socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
}
}
void CastChannelCloseFunction::OnClose(int result) {
......
......@@ -48,17 +48,10 @@ class CastChannelAPI : public BrowserContextKeyedAPI,
// BrowserContextKeyedAPI implementation.
static BrowserContextKeyedAPIFactory<CastChannelAPI>* GetFactoryInstance();
// Returns a new CastSocket that connects to |ip_endpoint| with authentication
// |channel_auth| and is to be owned by |extension_id|.
scoped_ptr<cast_channel::CastSocket> CreateCastSocket(
const std::string& extension_id,
const net::IPEndPoint& ip_endpoint,
cast_channel::ChannelAuthType channel_auth,
const base::TimeDelta& timeout);
// Returns a pointer to the Logger member variable.
// TODO(imcheng): Consider whether it is possible for this class to own the
// CastSockets and make this class the sole owner of Logger. Alternatively,
// CastSockets and make this class the sole owner of Logger.
// Alternatively,
// consider making Logger not ref-counted by passing a weak
// reference of Logger to the CastSockets instead.
scoped_refptr<cast_channel::Logger> GetLogger();
......@@ -67,6 +60,10 @@ class CastChannelAPI : public BrowserContextKeyedAPI,
// testing.
void SetSocketForTest(scoped_ptr<cast_channel::CastSocket> socket_for_test);
// Returns a test CastSocket instance, if it is defined.
// Otherwise returns a scoped_ptr with a NULL ptr value.
scoped_ptr<cast_channel::CastSocket> GetSocketForTest();
private:
friend class BrowserContextKeyedAPIFactory<CastChannelAPI>;
friend class ::CastChannelAPITest;
......
......@@ -62,6 +62,17 @@ bool MessageInfoToCastMessage(const MessageInfo& message,
return message_proto->IsInitialized();
}
bool IsCastMessageValid(const CastMessage& message_proto) {
if (message_proto.namespace_().empty() || message_proto.source_id().empty() ||
message_proto.destination_id().empty()) {
return false;
}
return (message_proto.payload_type() == CastMessage_PayloadType_STRING &&
message_proto.has_payload_utf8()) ||
(message_proto.payload_type() == CastMessage_PayloadType_BINARY &&
message_proto.has_payload_binary());
}
bool CastMessageToMessageInfo(const CastMessage& message_proto,
MessageInfo* message) {
DCHECK(message);
......
......@@ -19,6 +19,9 @@ struct MessageInfo;
bool MessageInfoToCastMessage(const MessageInfo& message,
CastMessage* message_proto);
// Checks if the contents of |message_proto| are semantically valid.
bool IsCastMessageValid(const CastMessage& message_proto);
// Fills |message| from |message_proto| and returns true on success.
bool CastMessageToMessageInfo(const CastMessage& message_proto,
MessageInfo* message);
......
......@@ -209,9 +209,8 @@ void CastSocket::Connect(const net::CompletionCallback& callback) {
void CastSocket::PostTaskToStartConnectLoop(int result) {
DCHECK(CalledOnValidThread());
DCHECK(connect_loop_callback_.IsCancelled());
connect_loop_callback_.Reset(base::Bind(&CastSocket::DoConnectLoop,
base::Unretained(this),
result));
connect_loop_callback_.Reset(
base::Bind(&CastSocket::DoConnectLoop, base::Unretained(this), result));
base::MessageLoop::current()->PostTask(FROM_HERE,
connect_loop_callback_.callback());
}
......@@ -647,8 +646,8 @@ int CastSocket::DoWriteError(int result) {
void CastSocket::PostTaskToStartReadLoop() {
DCHECK(CalledOnValidThread());
DCHECK(read_loop_callback_.IsCancelled());
read_loop_callback_.Reset(base::Bind(&CastSocket::StartReadLoop,
base::Unretained(this)));
read_loop_callback_.Reset(
base::Bind(&CastSocket::StartReadLoop, base::Unretained(this)));
base::MessageLoop::current()->PostTask(FROM_HERE,
read_loop_callback_.callback());
}
......@@ -862,7 +861,8 @@ void CastSocket::SetWriteState(proto::WriteState write_state) {
}
CastSocket::WriteRequest::WriteRequest(const net::CompletionCallback& callback)
: callback(callback) { }
: callback(callback) {
}
bool CastSocket::WriteRequest::SetContent(const CastMessage& message_proto) {
DCHECK(!io_buffer.get());
......@@ -876,7 +876,9 @@ bool CastSocket::WriteRequest::SetContent(const CastMessage& message_proto) {
return true;
}
CastSocket::WriteRequest::~WriteRequest() { }
CastSocket::WriteRequest::~WriteRequest() {
}
} // namespace cast_channel
} // namespace core_api
} // namespace extensions
......
......@@ -47,11 +47,12 @@ class MessageFramer;
//
// NOTE: Not called "CastChannel" to reduce confusion with the generated API
// code.
// TODO(kmarshall): Inherit from CastSocket and rename to CastSocketImpl.
class CastSocket : public ApiResource {
public:
// Object to be informed of incoming messages and errors. The CastSocket that
// owns the delegate must not be deleted by it, only by the ApiResourceManager
// or in the callback to Close().
// Object to be informed of incoming messages and errors. The CastSocket
// that owns the delegate must not be deleted by it, only by the
// ApiResourceManager or in the callback to Close().
class Delegate {
public:
// An error occurred on the channel. |last_errors| contains the last errors
......
......@@ -80,8 +80,8 @@ class MockCastSocketDelegate : public CastSocket::Delegate {
void(const CastSocket* socket,
ChannelError error,
const LastErrors& last_errors));
MOCK_METHOD2(OnMessage, void(const CastSocket* socket,
const MessageInfo& message));
MOCK_METHOD2(OnMessage,
void(const CastSocket* socket, const MessageInfo& message));
};
class MockTCPSocket : public net::TCPClientSocket {
......@@ -204,8 +204,7 @@ class TestCastSocket : public CastSocket {
return msg.length() - MessageFramer::MessageHeader::header_size();
}
virtual ~TestCastSocket() {
}
virtual ~TestCastSocket() {}
// Helpers to set mock results for various operations.
void SetupTcp1Connect(net::IoMode mode, int result) {
......
This diff is collapsed.
// Copyright 2014 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 EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_TRANSPORT_H_
#define EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_TRANSPORT_H_
#include <queue>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "extensions/browser/api/cast_channel/logger.h"
#include "extensions/common/api/cast_channel.h"
#include "net/base/completion_callback.h"
namespace net {
class DrainableIOBuffer;
class IPEndPoint;
class IOBuffer;
class DrainableIOBuffer;
class GrowableIOBuffer;
} // namespace net
namespace extensions {
namespace core_api {
namespace cast_channel {
class CastMessage;
struct LastErrors;
class Logger;
class MessageFramer;
// TODO(kmarshall): Migrate CastSocket to new interface.
// Redirect references to CastSocket in logger.h to this interface once
// the interface is promoted to cast_socket.h.
class CastSocketInterface {
public:
CastSocketInterface() {}
virtual ~CastSocketInterface() {}
// Writes at least one, and up to |size| bytes to the socket.
// Returns net::ERR_IO_PENDING if the operation will complete
// asynchronously, in which case |callback| will be invoked
// on completion.
// Asynchronous writes are cancleled if the CastSocket is deleted.
// All values <= zero indicate an error.
virtual int Write(net::IOBuffer* buffer,
size_t size,
const net::CompletionCallback& callback) = 0;
// Reads at least one, and up to |size| bytes from the socket.
// Returns net::ERR_IO_PENDING if the operation will complete
// asynchronously, in which case |callback| will be invoked
// on completion.
// All values <= zero indicate an error.
virtual int Read(net::IOBuffer* buf,
int buf_len,
const net::CompletionCallback& callback) = 0;
virtual void CloseWithError(ChannelError error) = 0;
virtual const net::IPEndPoint& ip_endpoint() const = 0;
virtual ChannelAuthType channel_auth() const = 0;
virtual int id() const = 0;
};
// Manager class for reading and writing messages to/from a CastSocket.
class CastTransport {
public:
// Object to be informed of incoming messages and errors.
class Delegate {
public:
// An error occurred on the channel. |last_errors| contains the last errors
// logged for the channel from the implementation.
virtual void OnError(const CastSocketInterface* socket,
ChannelError error_state,
const LastErrors& last_errors) = 0;
// A message was received on the channel.
virtual void OnMessage(const CastSocketInterface* socket,
const CastMessage& message) = 0;
protected:
virtual ~Delegate() {}
};
// Adds a CastMessage read/write layer to a socket.
// Message read events are propagated to the owner via |read_delegate|.
// The CastTransport object should be deleted prior to the
// underlying socket being deleted.
CastTransport(CastSocketInterface* socket,
Delegate* read_delegate,
scoped_refptr<Logger> logger);
virtual ~CastTransport();
// Sends a CastMessage to |socket_|.
// |message|: The message to send.
// |callback|: Callback to be invoked when the write operation has finished.
void SendMessage(const CastMessage& message,
const net::CompletionCallback& callback);
// Starts reading messages from |socket_|.
void StartReadLoop();
private:
// Internal write states.
enum WriteState {
WRITE_STATE_NONE,
WRITE_STATE_WRITE,
WRITE_STATE_WRITE_COMPLETE,
WRITE_STATE_DO_CALLBACK,
WRITE_STATE_ERROR,
};
// Internal read states.
enum ReadState {
READ_STATE_NONE,
READ_STATE_READ,
READ_STATE_READ_COMPLETE,
READ_STATE_DO_CALLBACK,
READ_STATE_ERROR,
};
// Holds a message to be written to the socket. |callback| is invoked when the
// message is fully written or an error occurrs.
struct WriteRequest {
explicit WriteRequest(const std::string& namespace_,
const std::string& payload,
const net::CompletionCallback& callback);
~WriteRequest();
// Namespace of the serialized message.
std::string message_namespace;
// Write completion callback, invoked when the operation has completed or
// failed.
net::CompletionCallback callback;
// Buffer with outgoing data.
scoped_refptr<net::DrainableIOBuffer> io_buffer;
};
static proto::ReadState ReadStateToProto(CastTransport::ReadState state);
static proto::WriteState WriteStateToProto(CastTransport::WriteState state);
static proto::ErrorState ErrorStateToProto(ChannelError state);
// Terminates all in-flight write callbacks with error code ERR_FAILED.
void FlushWriteQueue();
// Main method that performs write flow state transitions.
void OnWriteResult(int result);
// Each of the below Do* method is executed in the corresponding
// write state. For example when write state is WRITE_STATE_WRITE_COMPLETE
// DowriteComplete is called, and so on.
int DoWrite();
int DoWriteComplete(int result);
int DoWriteCallback();
int DoWriteError(int result);
// Main method that performs write flow state transitions.
void OnReadResult(int result);
// Each of the below Do* method is executed in the corresponding
// write state. For example when write state is READ_STATE_READ_COMPLETE
// DoReadComplete is called, and so on.
int DoRead();
int DoReadComplete(int result);
int DoReadCallback();
int DoReadError(int result);
void SetReadState(ReadState read_state);
void SetWriteState(WriteState write_state);
void SetErrorState(ChannelError error_state);
// Queue of pending writes. The message at the front of the queue is the one
// being written.
std::queue<WriteRequest> write_queue_;
// Buffer used for read operations. Reused for every read.
scoped_refptr<net::GrowableIOBuffer> read_buffer_;
// Constructs and parses the wire representation of message frames.
scoped_ptr<MessageFramer> framer_;
// Last message received on the socket.
scoped_ptr<CastMessage> current_message_;
// Socket used for I/O operations.
CastSocketInterface* const socket_;
// Methods for communicating message receipt and error status to client code.
Delegate* const read_delegate_;
// Write flow state machine state.
WriteState write_state_;
// Read flow state machine state.
ReadState read_state_;
// Most recent error that occurred during read or write operation, if any.
ChannelError error_state_;
scoped_refptr<Logger> logger_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(CastTransport);
};
} // namespace cast_channel
} // namespace core_api
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_TRANSPORT_H_
This diff is collapsed.
......@@ -361,6 +361,10 @@
'browser/api/cast_channel/cast_message_util.h',
'browser/api/cast_channel/cast_socket.cc',
'browser/api/cast_channel/cast_socket.h',
'browser/api/cast_channel/cast_framer.cc',
'browser/api/cast_channel/cast_framer.h',
'browser/api/cast_channel/cast_transport.h',
'browser/api/cast_channel/cast_transport.cc',
'browser/api/cast_channel/logger.cc',
'browser/api/cast_channel/logger.h',
'browser/api/cast_channel/logger_util.cc',
......@@ -1072,6 +1076,7 @@
'browser/api/cast_channel/cast_channel_api_unittest.cc',
'browser/api/cast_channel/cast_framer_unittest.cc',
'browser/api/cast_channel/cast_socket_unittest.cc',
'browser/api/cast_channel/cast_transport_unittest.cc',
'browser/api/cast_channel/logger_unittest.cc',
'browser/api/declarative/declarative_rule_unittest.cc',
'browser/api/declarative/deduping_factory_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment