Mojo: Refactor PlatformChannel stuff.

- Remove PlatformServerChannel/PlatformClientChannel.
- Add PlatformChannelPair (move stuff formerly in PlatformServerChannel
  into this).

It became apparent that my previous plan to make this work on Windows
wasn't work nicely. On the one hand, on Vista+, we can basically make
things work like POSIX (created the channels in the parent and connect
them, and send a channel to a child). On the other, on XP, to be secure
you need to do more work (the channels aren't connected or authenticated
initially), so you'd need much more machinery (to wait for connection,
to authenticate, etc.).

So I'll go for a different mechanism to make things work on XP. The
assumption from the Mojo embedder API will be that it's given a channel
handle that's already been connected, authenticated, etc. (which will be
taken care of by other means). This will add flexibility in other ways
as well (e.g., make Mojo IPC more happily coexist with Chrome IPC -- you
should be able to pass a handle over Chrome IPC to set up Mojo IPC).

Still to do: Move PlatformChannelPair into its own files.

R=darin@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244223 0039d316-1c4b-4281-b951-d872f2087c98
parent 84c06f09
......@@ -29,21 +29,22 @@ void MultiprocessTestBase::SetUp() {
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
platform_server_channel =
system::PlatformServerChannel::Create("TestChannel");
platform_channel_pair_.reset(new system::PlatformChannelPair());
server_platform_channel = platform_channel_pair_->CreateServerChannel();
#endif
}
void MultiprocessTestBase::TearDown() {
CHECK_EQ(test_child_handle_, base::kNullProcessHandle);
platform_server_channel.reset();
server_platform_channel.reset();
platform_channel_pair_.reset();
MultiProcessTest::TearDown();
}
void MultiprocessTestBase::StartChild(const std::string& test_child_name) {
CHECK(platform_server_channel.get());
CHECK(platform_channel_pair_.get());
CHECK(!test_child_name.empty());
CHECK_EQ(test_child_handle_, base::kNullProcessHandle);
......@@ -52,8 +53,8 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) {
#if defined(OS_POSIX)
CommandLine unused(CommandLine::NO_PROGRAM);
base::FileHandleMappingVector fds_to_map;
platform_server_channel->GetDataNeededToPassClientChannelToChildProcess(
&unused, &fds_to_map);
platform_channel_pair_->PrepareToPassClientChannelToChildProcess(&unused,
&fds_to_map);
test_child_handle_ = SpawnChild(test_child_main, fds_to_map, false);
#elif defined(OS_WIN)
test_child_handle_ = SpawnChild(test_child_main, false);
......@@ -62,7 +63,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) {
#endif
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
platform_server_channel->ChildProcessLaunched();
platform_channel_pair_->ChildProcessLaunched();
#endif
CHECK_NE(test_child_handle_, base::kNullProcessHandle);
......@@ -82,14 +83,14 @@ int MultiprocessTestBase::WaitForChildShutdown() {
CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname,
bool debug_on_start) {
CHECK(platform_server_channel.get());
CHECK(platform_channel_pair_.get());
CommandLine command_line =
base::MultiProcessTest::MakeCmdLine(procname, debug_on_start);
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
base::FileHandleMappingVector unused;
platform_server_channel->GetDataNeededToPassClientChannelToChildProcess(
platform_channel_pair_->PrepareToPassClientChannelToChildProcess(
&command_line, &unused);
#endif
return command_line;
......@@ -100,16 +101,16 @@ void MultiprocessTestBase::ChildSetup() {
CHECK(CommandLine::InitializedForCurrentProcess());
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
platform_client_channel =
system::PlatformClientChannel::CreateFromParentProcess(
client_platform_channel =
system::PlatformChannelPair::CreateClientChannelFromParentProcess(
*CommandLine::ForCurrentProcess());
CHECK(platform_client_channel.get());
CHECK(client_platform_channel.get());
#endif
}
// static
scoped_ptr<system::PlatformClientChannel>
MultiprocessTestBase::platform_client_channel;
scoped_ptr<system::PlatformChannel>
MultiprocessTestBase::client_platform_channel;
} // namespace test
} // namespace mojo
......@@ -40,15 +40,17 @@ class MultiprocessTestBase : public base::MultiProcessTest {
static void ChildSetup();
// For use in the main process:
scoped_ptr<system::PlatformServerChannel> platform_server_channel;
scoped_ptr<system::PlatformChannel> server_platform_channel;
// For use (and only valid) in the child process:
static scoped_ptr<system::PlatformClientChannel> platform_client_channel;
static scoped_ptr<system::PlatformChannel> client_platform_channel;
private:
virtual CommandLine MakeCmdLine(const std::string& procname,
bool debug_on_start) OVERRIDE;
scoped_ptr<system::PlatformChannelPair> platform_channel_pair_;
// Valid after |StartChild()| and before |WaitForChildShutdown()|.
base::ProcessHandle test_child_handle_;
......
......@@ -24,8 +24,8 @@ class MultiprocessTestBaseTest : public test::MultiprocessTestBase {
TEST_F(MultiprocessTestBaseTest, RunChild) {
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
EXPECT_TRUE(platform_server_channel.get());
EXPECT_TRUE(platform_server_channel->is_valid());
EXPECT_TRUE(server_platform_channel.get());
EXPECT_TRUE(server_platform_channel->is_valid());
#endif
StartChild("RunChild");
EXPECT_EQ(123, WaitForChildShutdown());
......@@ -34,8 +34,8 @@ TEST_F(MultiprocessTestBaseTest, RunChild) {
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) {
// TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX)
CHECK(MultiprocessTestBaseTest::platform_client_channel.get());
CHECK(MultiprocessTestBaseTest::platform_client_channel->is_valid());
CHECK(MultiprocessTestBaseTest::client_platform_channel.get());
CHECK(MultiprocessTestBaseTest::client_platform_channel->is_valid());
#endif
return 123;
}
......@@ -50,14 +50,14 @@ TEST_F(MultiprocessTestBaseTest, TestChildMainNotFound) {
#if defined(OS_POSIX)
TEST_F(MultiprocessTestBaseTest, PassedChannelPosix) {
EXPECT_TRUE(platform_server_channel.get());
EXPECT_TRUE(platform_server_channel->is_valid());
EXPECT_TRUE(server_platform_channel.get());
EXPECT_TRUE(server_platform_channel->is_valid());
StartChild("PassedChannelPosix");
// Take ownership of the FD.
mojo::system::PlatformChannelHandle channel =
platform_server_channel->PassHandle();
platform_server_channel.reset();
server_platform_channel->PassHandle();
server_platform_channel.reset();
int fd = channel.fd;
// The FD should be non-blocking. Check this.
......@@ -81,13 +81,13 @@ TEST_F(MultiprocessTestBaseTest, PassedChannelPosix) {
}
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannelPosix) {
CHECK(MultiprocessTestBaseTest::platform_client_channel.get());
CHECK(MultiprocessTestBaseTest::platform_client_channel->is_valid());
CHECK(MultiprocessTestBaseTest::client_platform_channel.get());
CHECK(MultiprocessTestBaseTest::client_platform_channel->is_valid());
// Take ownership of the FD.
mojo::system::PlatformChannelHandle channel =
MultiprocessTestBaseTest::platform_client_channel->PassHandle();
MultiprocessTestBaseTest::platform_client_channel.reset();
MultiprocessTestBaseTest::client_platform_channel->PassHandle();
MultiprocessTestBaseTest::client_platform_channel.reset();
int fd = channel.fd;
// The FD should still be non-blocking. Check this.
......
......@@ -122,7 +122,7 @@ class MultiprocessMessagePipeTest : public mojo::test::MultiprocessTestBase {
}
void Init(scoped_refptr<MessagePipe> mp) {
io_thread_wrapper_.Init(platform_server_channel.get(), mp);
io_thread_wrapper_.Init(server_platform_channel.get(), mp);
}
private:
......@@ -152,14 +152,14 @@ MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) {
// not including any "quitquitquit" message, modulo 100.
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) {
IOThreadWrapper io_thread_wrapper;
PlatformClientChannel* const platform_client_channel =
MultiprocessMessagePipeTest::platform_client_channel.get();
CHECK(platform_client_channel);
CHECK(platform_client_channel->is_valid());
PlatformChannel* const client_platform_channel =
MultiprocessMessagePipeTest::client_platform_channel.get();
CHECK(client_platform_channel);
CHECK(client_platform_channel->is_valid());
scoped_refptr<MessagePipe> mp(new MessagePipe(
scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
io_thread_wrapper.Init(platform_client_channel, mp);
io_thread_wrapper.Init(client_platform_channel, mp);
const std::string quitquitquit("quitquitquit");
int rv = 0;
......
......@@ -13,6 +13,15 @@ PlatformChannel::~PlatformChannel() {
handle_.CloseIfNecessary();
}
// static
scoped_ptr<PlatformChannel> PlatformChannel::CreateFromHandle(
const PlatformChannelHandle& handle) {
DCHECK(handle.is_valid());
scoped_ptr<PlatformChannel> rv(new PlatformChannel());
*rv->mutable_handle() = handle;
return rv.Pass();
}
PlatformChannelHandle PlatformChannel::PassHandle() {
DCHECK(is_valid());
PlatformChannelHandle rv = handle_;
......@@ -23,18 +32,34 @@ PlatformChannelHandle PlatformChannel::PassHandle() {
PlatformChannel::PlatformChannel() {
}
PlatformServerChannel::PlatformServerChannel(const std::string& name)
: name_(name) {
DCHECK(!name_.empty());
// -----------------------------------------------------------------------------
PlatformChannelPair::~PlatformChannelPair() {
server_handle_.CloseIfNecessary();
client_handle_.CloseIfNecessary();
}
// Static factory method.
// static
scoped_ptr<PlatformClientChannel> PlatformClientChannel::CreateFromHandle(
const PlatformChannelHandle& handle) {
DCHECK(handle.is_valid());
scoped_ptr<PlatformClientChannel> rv(new PlatformClientChannel());
*rv->mutable_handle() = handle;
scoped_ptr<PlatformChannel> PlatformChannelPair::CreateServerChannel() {
if (!server_handle_.is_valid()) {
LOG(WARNING) << "Server handle invalid";
return scoped_ptr<PlatformChannel>();
}
scoped_ptr<PlatformChannel> rv =
PlatformChannel::CreateFromHandle(server_handle_);
server_handle_ = PlatformChannelHandle();
return rv.Pass();
}
scoped_ptr<PlatformChannel> PlatformChannelPair::CreateClientChannel() {
if (!client_handle_.is_valid()) {
LOG(WARNING) << "Client handle invalid";
return scoped_ptr<PlatformChannel>();
}
scoped_ptr<PlatformChannel> rv =
PlatformChannel::CreateFromHandle(client_handle_);
client_handle_ = PlatformChannelHandle();
return rv.Pass();
}
......
......@@ -5,9 +5,6 @@
#ifndef MOJO_SYSTEM_PLATFORM_CHANNEL_H_
#define MOJO_SYSTEM_PLATFORM_CHANNEL_H_
#include <string>
#include <utility>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/launch.h"
......@@ -23,6 +20,11 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformChannel {
public:
virtual ~PlatformChannel();
// Creates a channel if you already have the underlying handle for it, taking
// ownership of |handle|.
static scoped_ptr<PlatformChannel> CreateFromHandle(
const PlatformChannelHandle& handle);
// Returns the channel's handle, passing ownership.
PlatformChannelHandle PassHandle();
......@@ -39,71 +41,57 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformChannel {
DISALLOW_COPY_AND_ASSIGN(PlatformChannel);
};
class PlatformClientChannel;
// A server channel has an "implicit" client channel created with it. This may
// be a real channel (in the case of POSIX, in which case there's an actual FD
// for it) or fake.
// - That client channel may then be used in-process (e.g., for single process
// tests) by getting a |PlatformClientChannel| using |CreateClientChannel()|.
// - Or it may be "passed" to a new child process using
// |GetDataNeededToPassClientChannelToChildProcess()|, etc. (see below). The
// child process would then get a |PlatformClientChannel| by using
// |PlatformClientChannel::CreateFromParentProcess()|.
// - In both these cases, "ownership" of the client channel is transferred (to
// the |PlatformClientChannel| or the child process).
// TODO(vtl): Add ways of passing it to other existing processes.
class MOJO_SYSTEM_IMPL_EXPORT PlatformServerChannel : public PlatformChannel {
// This is used to create a pair of connected |PlatformChannel|s. The resulting
// channels can then be used in the same process (e.g., in tests) or between
// processes. (The "server" channel is the one that will be used in the process
// that created the pair, whereas the "client" channel is the one that will be
// used in a different process.)
//
// This class provides facilities for passing the client channel to a child
// process. The parent should call |PrepareToPassClientChannelToChildProcess()|
// to get the data needed to do this, spawn the child using that data, and then
// call |ChildProcessLaunched()|. Note that on Windows this facility (will) only
// work on Vista and later (TODO(vtl)).
//
// Note: |PlatformChannelPair()|, |CreateClientChannelFromParentProcess()|,
// |PrepareToPassClientChannelToChildProcess()|, and |ChildProcessLaunched()|
// have platform-specific implementations.
class MOJO_SYSTEM_IMPL_EXPORT PlatformChannelPair {
public:
virtual ~PlatformServerChannel() {}
static scoped_ptr<PlatformServerChannel> Create(const std::string& name);
// For in-process use, from a server channel you can make a corresponding
// client channel.
virtual scoped_ptr<PlatformClientChannel> CreateClientChannel() = 0;
PlatformChannelPair();
~PlatformChannelPair();
// This transfers ownership of the server channel to the caller. Returns null
// on failure.
scoped_ptr<PlatformChannel> CreateServerChannel();
// For in-process use (e.g., in tests). This transfers ownership of the client
// channel to the caller. Returns null on failure.
scoped_ptr<PlatformChannel> CreateClientChannel();
// To be called in the child process, after the parent process called
// |PrepareToPassClientChannelToChildProcess()| and launched the child (using
// the provided data), to create a client channel connected to the server
// channel (in the parent process). Returns null on failure.
static scoped_ptr<PlatformChannel> CreateClientChannelFromParentProcess(
const CommandLine& command_line);
// Prepares to pass the client channel to a new child process, to be launched
// using |LaunchProcess()| (from base/launch.h). Modifies |*command_line| and
// |*file_handle_mapping| as needed. (|file_handle_mapping| may be null on
// platforms that don't need it, like Windows.)
virtual void GetDataNeededToPassClientChannelToChildProcess(
void PrepareToPassClientChannelToChildProcess(
CommandLine* command_line,
base::FileHandleMappingVector* file_handle_mapping) const = 0;
base::FileHandleMappingVector* file_handle_mapping) const;
// To be called once the child process has been successfully launched, to do
// any cleanup necessary.
virtual void ChildProcessLaunched() = 0;
const std::string& name() const { return name_; }
protected:
explicit PlatformServerChannel(const std::string& name);
private:
const std::string name_;
DISALLOW_COPY_AND_ASSIGN(PlatformServerChannel);
};
class MOJO_SYSTEM_IMPL_EXPORT PlatformClientChannel : public PlatformChannel {
public:
virtual ~PlatformClientChannel() {}
// Creates a client channel if you already have the underlying handle for it.
// Note: This takes ownership of |handle|.
static scoped_ptr<PlatformClientChannel> CreateFromHandle(
const PlatformChannelHandle& handle);
// To be called to get a client channel passed from the parent process, using
// |PlatformServerChannel::GetDataNeededToPassClientChannelToChildProcess()|,
// etc. Returns null on failure.
static scoped_ptr<PlatformClientChannel> CreateFromParentProcess(
const CommandLine& command_line);
void ChildProcessLaunched();
private:
PlatformClientChannel() {}
PlatformChannelHandle server_handle_;
PlatformChannelHandle client_handle_;
DISALLOW_COPY_AND_ASSIGN(PlatformClientChannel);
DISALLOW_COPY_AND_ASSIGN(PlatformChannelPair);
};
} // namespace system
......
......@@ -10,7 +10,6 @@
#include <unistd.h>
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/posix/global_descriptors.h"
#include "base/strings/string_number_conversions.h"
......@@ -32,58 +31,40 @@ bool IsTargetDescriptorUsed(
return false;
}
class PlatformServerChannelPosix : public PlatformServerChannel {
public:
PlatformServerChannelPosix(const std::string& name);
virtual ~PlatformServerChannelPosix();
// |PlatformServerChannel| implementation:
virtual scoped_ptr<PlatformClientChannel> CreateClientChannel() OVERRIDE;
virtual void GetDataNeededToPassClientChannelToChildProcess(
CommandLine* command_line,
base::FileHandleMappingVector* file_handle_mapping) const OVERRIDE;
virtual void ChildProcessLaunched() OVERRIDE;
private:
PlatformChannelHandle client_handle_;
DISALLOW_COPY_AND_ASSIGN(PlatformServerChannelPosix);
};
} // namespace
PlatformServerChannelPosix::PlatformServerChannelPosix(
const std::string& name)
: PlatformServerChannel(name) {
PlatformChannelPair::PlatformChannelPair() {
// Create the Unix domain socket and set the ends to nonblocking.
int fds[2];
// TODO(vtl): Maybe fail gracefully if |socketpair()| fails.
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
mutable_handle()->fd = fds[0];
DCHECK(is_valid());
server_handle_.fd = fds[0];
DCHECK(server_handle_.is_valid());
client_handle_.fd = fds[1];
DCHECK(client_handle_.is_valid());
}
PlatformServerChannelPosix::~PlatformServerChannelPosix() {
client_handle_.CloseIfNecessary();
}
scoped_ptr<PlatformClientChannel>
PlatformServerChannelPosix::CreateClientChannel() {
if (!client_handle_.is_valid()) {
NOTREACHED();
return scoped_ptr<PlatformClientChannel>();
// static
scoped_ptr<PlatformChannel>
PlatformChannelPair::CreateClientChannelFromParentProcess(
const CommandLine& command_line) {
std::string client_fd_string =
command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch);
int client_fd = -1;
if (client_fd_string.empty() ||
!base::StringToInt(client_fd_string, &client_fd) ||
client_fd < base::GlobalDescriptors::kBaseDescriptor) {
LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch;
return scoped_ptr<PlatformChannel>();
}
scoped_ptr<PlatformClientChannel> rv =
PlatformClientChannel::CreateFromHandle(client_handle_);
DCHECK(rv->is_valid());
client_handle_ = PlatformChannelHandle();
return rv.Pass();
return PlatformChannel::CreateFromHandle(PlatformChannelHandle(client_fd));
}
void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess(
void PlatformChannelPair::PrepareToPassClientChannelToChildProcess(
CommandLine* command_line,
base::FileHandleMappingVector* file_handle_mapping) const {
DCHECK(command_line);
......@@ -116,42 +97,10 @@ void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess(
base::IntToString(target_fd));
}
void PlatformServerChannelPosix::ChildProcessLaunched() {
void PlatformChannelPair::ChildProcessLaunched() {
DCHECK(client_handle_.is_valid());
client_handle_.CloseIfNecessary();
}
} // namespace
// -----------------------------------------------------------------------------
// Static factory method declared in platform_channel.h.
// static
scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create(
const std::string& name) {
return scoped_ptr<PlatformServerChannel>(
new PlatformServerChannelPosix(name));
}
// -----------------------------------------------------------------------------
// Static factory method declared in platform_channel.h.
// static
scoped_ptr<PlatformClientChannel>
PlatformClientChannel::CreateFromParentProcess(
const CommandLine& command_line) {
std::string client_fd_string =
command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch);
int client_fd = -1;
if (client_fd_string.empty() ||
!base::StringToInt(client_fd_string, &client_fd) ||
client_fd < base::GlobalDescriptors::kBaseDescriptor) {
LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch;
return scoped_ptr<PlatformClientChannel>();
}
return CreateFromHandle(PlatformChannelHandle(client_fd));
}
} // namespace system
} // namespace mojo
......@@ -77,12 +77,13 @@ class RawChannelPosixTest : public testing::Test {
io_thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
scoped_ptr<PlatformServerChannel> server_channel(
PlatformServerChannel::Create("channel"));
PlatformChannelPair channel_pair;
scoped_ptr<PlatformChannel> server_channel(
channel_pair.CreateServerChannel());
CHECK(server_channel.get());
CHECK(server_channel->is_valid());
scoped_ptr<PlatformClientChannel> client_channel(
server_channel->CreateClientChannel());
scoped_ptr<PlatformChannel> client_channel(
channel_pair.CreateClientChannel());
CHECK(client_channel.get());
CHECK(client_channel->is_valid());
......
......@@ -91,17 +91,13 @@ class RemoteMessagePipeTest : public testing::Test {
void SetUpOnIOThread() {
CHECK_EQ(base::MessageLoop::current(), io_thread_message_loop());
scoped_ptr<PlatformServerChannel> server_channel(
PlatformServerChannel::Create("channel"));
CHECK(server_channel.get());
CHECK(server_channel->is_valid());
scoped_ptr<PlatformClientChannel> client_channel(
server_channel->CreateClientChannel());
CHECK(client_channel.get());
CHECK(client_channel->is_valid());
platform_channels_[0] = server_channel.PassAs<PlatformChannel>();
platform_channels_[1] = client_channel.PassAs<PlatformChannel>();
PlatformChannelPair channel_pair;
platform_channels_[0] = channel_pair.CreateServerChannel();
CHECK(platform_channels_[0].get());
CHECK(platform_channels_[0]->is_valid());
platform_channels_[1] = channel_pair.CreateClientChannel();
CHECK(platform_channels_[1].get());
CHECK(platform_channels_[1]->is_valid());
}
void CreateAndInitChannel(unsigned channel_index) {
......
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