Home | History | Annotate | Download | only in mojo
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ipc/mojo/ipc_mojo_bootstrap.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/process/process_handle.h"
      9 #include "ipc/ipc_message_utils.h"
     10 #include "ipc/ipc_platform_file.h"
     11 #include "mojo/embedder/platform_channel_pair.h"
     12 
     13 namespace IPC {
     14 
     15 namespace {
     16 
     17 // MojoBootstrap for the server process. You should create the instance
     18 // using MojoBootstrap::Create().
     19 class IPC_MOJO_EXPORT MojoServerBootstrap : public MojoBootstrap {
     20  public:
     21   MojoServerBootstrap();
     22 
     23   virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
     24 
     25  private:
     26   void SendClientPipe();
     27   void SendClientPipeIfReady();
     28 
     29   // Listener implementations
     30   virtual bool OnMessageReceived(const Message& message) OVERRIDE;
     31   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
     32 
     33   mojo::embedder::ScopedPlatformHandle server_pipe_;
     34   base::ProcessHandle client_process_;
     35   bool connected_;
     36 
     37   DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap);
     38 };
     39 
     40 MojoServerBootstrap::MojoServerBootstrap()
     41     : client_process_(base::kNullProcessHandle), connected_(false) {
     42 }
     43 
     44 void MojoServerBootstrap::SendClientPipe() {
     45   DCHECK_EQ(state(), STATE_INITIALIZED);
     46   DCHECK_NE(client_process_, base::kNullProcessHandle);
     47   DCHECK(connected_);
     48 
     49   mojo::embedder::PlatformChannelPair channel_pair;
     50   server_pipe_ = channel_pair.PassServerHandle();
     51   PlatformFileForTransit client_pipe = GetFileHandleForProcess(
     52 #if defined(OS_POSIX)
     53       channel_pair.PassClientHandle().release().fd,
     54 #else
     55       channel_pair.PassClientHandle().release().handle,
     56 #endif
     57       client_process_,
     58       true);
     59   CHECK(client_pipe != IPC::InvalidPlatformFileForTransit());
     60   scoped_ptr<Message> message(new Message());
     61   ParamTraits<PlatformFileForTransit>::Write(message.get(), client_pipe);
     62   Send(message.release());
     63 
     64   set_state(STATE_WAITING_ACK);
     65 }
     66 
     67 void MojoServerBootstrap::SendClientPipeIfReady() {
     68   // Is the client launched?
     69   if (client_process_ == base::kNullProcessHandle)
     70     return;
     71   // Has the bootstrap channel been made?
     72   if (!connected_)
     73     return;
     74   SendClientPipe();
     75 }
     76 
     77 void MojoServerBootstrap::OnClientLaunched(base::ProcessHandle process) {
     78   DCHECK_EQ(state(), STATE_INITIALIZED);
     79   DCHECK_NE(process, base::kNullProcessHandle);
     80   client_process_ = process;
     81   SendClientPipeIfReady();
     82 }
     83 
     84 void MojoServerBootstrap::OnChannelConnected(int32 peer_pid) {
     85   DCHECK_EQ(state(), STATE_INITIALIZED);
     86   connected_ = true;
     87   SendClientPipeIfReady();
     88 }
     89 
     90 bool MojoServerBootstrap::OnMessageReceived(const Message&) {
     91   DCHECK_EQ(state(), STATE_WAITING_ACK);
     92   set_state(STATE_READY);
     93 
     94   delegate()->OnPipeAvailable(
     95       mojo::embedder::ScopedPlatformHandle(server_pipe_.release()));
     96 
     97   return true;
     98 }
     99 
    100 // MojoBootstrap for client processes. You should create the instance
    101 // using MojoBootstrap::Create().
    102 class IPC_MOJO_EXPORT MojoClientBootstrap : public MojoBootstrap {
    103  public:
    104   MojoClientBootstrap();
    105 
    106   virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
    107 
    108  private:
    109   // Listener implementations
    110   virtual bool OnMessageReceived(const Message& message) OVERRIDE;
    111   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap);
    114 };
    115 
    116 MojoClientBootstrap::MojoClientBootstrap() {
    117 }
    118 
    119 bool MojoClientBootstrap::OnMessageReceived(const Message& message) {
    120   PlatformFileForTransit pipe;
    121   PickleIterator iter(message);
    122   if (!ParamTraits<PlatformFileForTransit>::Read(&message, &iter, &pipe)) {
    123     DLOG(WARNING) << "Failed to read a file handle from bootstrap channel.";
    124     message.set_dispatch_error();
    125     return false;
    126   }
    127 
    128   // Sends ACK back.
    129   Send(new Message());
    130   set_state(STATE_READY);
    131   delegate()->OnPipeAvailable(
    132       mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
    133           PlatformFileForTransitToPlatformFile(pipe))));
    134 
    135   return true;
    136 }
    137 
    138 void MojoClientBootstrap::OnClientLaunched(base::ProcessHandle process) {
    139   // This notification should happen only on server processes.
    140   NOTREACHED();
    141 }
    142 
    143 void MojoClientBootstrap::OnChannelConnected(int32 peer_pid) {
    144 }
    145 
    146 }  // namespace
    147 
    148 // MojoBootstrap
    149 
    150 // static
    151 scoped_ptr<MojoBootstrap> MojoBootstrap::Create(ChannelHandle handle,
    152                                                 Channel::Mode mode,
    153                                                 Delegate* delegate) {
    154   CHECK(mode == Channel::MODE_CLIENT || mode == Channel::MODE_SERVER);
    155   scoped_ptr<MojoBootstrap> self =
    156       mode == Channel::MODE_CLIENT
    157           ? scoped_ptr<MojoBootstrap>(new MojoClientBootstrap())
    158           : scoped_ptr<MojoBootstrap>(new MojoServerBootstrap());
    159   scoped_ptr<Channel> bootstrap_channel =
    160       Channel::Create(handle, mode, self.get());
    161   self->Init(bootstrap_channel.Pass(), delegate);
    162   return self.Pass();
    163 }
    164 
    165 MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) {
    166 }
    167 
    168 MojoBootstrap::~MojoBootstrap() {
    169 }
    170 
    171 void MojoBootstrap::Init(scoped_ptr<Channel> channel, Delegate* delegate) {
    172   channel_ = channel.Pass();
    173   delegate_ = delegate;
    174 }
    175 
    176 bool MojoBootstrap::Connect() {
    177   return channel_->Connect();
    178 }
    179 
    180 void MojoBootstrap::OnBadMessageReceived(const Message& message) {
    181   delegate_->OnBootstrapError();
    182 }
    183 
    184 void MojoBootstrap::OnChannelError() {
    185   if (state_ == STATE_READY)
    186     return;
    187   DLOG(WARNING) << "Detected error on Mojo bootstrap channel.";
    188   delegate()->OnBootstrapError();
    189 }
    190 
    191 bool MojoBootstrap::Send(Message* message) {
    192   return channel_->Send(message);
    193 }
    194 
    195 #if defined(OS_POSIX) && !defined(OS_NACL)
    196 int MojoBootstrap::GetClientFileDescriptor() const {
    197   return channel_->GetClientFileDescriptor();
    198 }
    199 
    200 int MojoBootstrap::TakeClientFileDescriptor() {
    201   return channel_->TakeClientFileDescriptor();
    202 }
    203 #endif  // defined(OS_POSIX) && !defined(OS_NACL)
    204 
    205 }  // namespace IPC
    206