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_channel_mojo.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/lazy_instance.h"
     10 #include "ipc/ipc_listener.h"
     11 #include "ipc/mojo/ipc_channel_mojo_readers.h"
     12 #include "ipc/mojo/ipc_mojo_bootstrap.h"
     13 #include "mojo/embedder/embedder.h"
     14 
     15 #if defined(OS_POSIX) && !defined(OS_NACL)
     16 #include "ipc/file_descriptor_set_posix.h"
     17 #endif
     18 
     19 namespace IPC {
     20 
     21 namespace {
     22 
     23 class MojoChannelFactory : public ChannelFactory {
     24  public:
     25   MojoChannelFactory(ChannelMojo::Delegate* delegate,
     26                      ChannelHandle channel_handle,
     27                      Channel::Mode mode)
     28       : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {}
     29 
     30   virtual std::string GetName() const OVERRIDE {
     31     return channel_handle_.name;
     32   }
     33 
     34   virtual scoped_ptr<Channel> BuildChannel(Listener* listener) OVERRIDE {
     35     return ChannelMojo::Create(delegate_, channel_handle_, mode_, listener)
     36         .PassAs<Channel>();
     37   }
     38 
     39  private:
     40   ChannelMojo::Delegate* delegate_;
     41   ChannelHandle channel_handle_;
     42   Channel::Mode mode_;
     43 };
     44 
     45 } // namespace
     46 
     47 //------------------------------------------------------------------------------
     48 
     49 void ChannelMojo::ChannelInfoDeleter::operator()(
     50     mojo::embedder::ChannelInfo* ptr) const {
     51   mojo::embedder::DestroyChannelOnIOThread(ptr);
     52 }
     53 
     54 //------------------------------------------------------------------------------
     55 
     56 // static
     57 scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojo::Delegate* delegate,
     58                                             const ChannelHandle& channel_handle,
     59                                             Mode mode,
     60                                             Listener* listener) {
     61   return make_scoped_ptr(
     62       new ChannelMojo(delegate, channel_handle, mode, listener));
     63 }
     64 
     65 // static
     66 scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
     67     ChannelMojo::Delegate* delegate,
     68     const ChannelHandle& channel_handle) {
     69   return make_scoped_ptr(new MojoChannelFactory(
     70                              delegate, channel_handle, Channel::MODE_SERVER))
     71       .PassAs<ChannelFactory>();
     72 }
     73 
     74 // static
     75 scoped_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
     76     const ChannelHandle& channel_handle) {
     77   return make_scoped_ptr(
     78              new MojoChannelFactory(NULL, channel_handle, Channel::MODE_CLIENT))
     79       .PassAs<ChannelFactory>();
     80 }
     81 
     82 ChannelMojo::ChannelMojo(ChannelMojo::Delegate* delegate,
     83                          const ChannelHandle& handle,
     84                          Mode mode,
     85                          Listener* listener)
     86     : mode_(mode),
     87       listener_(listener),
     88       peer_pid_(base::kNullProcessId),
     89       weak_factory_(this) {
     90   // Create MojoBootstrap after all members are set as it touches
     91   // ChannelMojo from a different thread.
     92   bootstrap_ = MojoBootstrap::Create(handle, mode, this);
     93   if (delegate) {
     94     if (delegate->GetIOTaskRunner() ==
     95         base::MessageLoop::current()->message_loop_proxy()) {
     96       InitDelegate(delegate);
     97     } else {
     98       delegate->GetIOTaskRunner()->PostTask(
     99           FROM_HERE,
    100           base::Bind(
    101               &ChannelMojo::InitDelegate, base::Unretained(this), delegate));
    102     }
    103   }
    104 }
    105 
    106 ChannelMojo::~ChannelMojo() {
    107   Close();
    108 }
    109 
    110 void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) {
    111   delegate_ = delegate->ToWeakPtr();
    112   delegate_->OnChannelCreated(weak_factory_.GetWeakPtr());
    113 }
    114 
    115 void ChannelMojo::InitControlReader(
    116     mojo::embedder::ScopedPlatformHandle handle) {
    117   DCHECK(base::MessageLoopForIO::IsCurrent());
    118   mojo::embedder::ChannelInfo* channel_info;
    119   mojo::ScopedMessagePipeHandle control_pipe =
    120       mojo::embedder::CreateChannelOnIOThread(handle.Pass(), &channel_info);
    121   channel_info_.reset(channel_info);
    122 
    123   switch (mode_) {
    124     case MODE_SERVER:
    125       control_reader_.reset(
    126           new internal::ServerControlReader(control_pipe.Pass(), this));
    127       break;
    128     case MODE_CLIENT:
    129       control_reader_.reset(
    130           new internal::ClientControlReader(control_pipe.Pass(), this));
    131       break;
    132     default:
    133       NOTREACHED();
    134       break;
    135   }
    136 }
    137 
    138 bool ChannelMojo::Connect() {
    139   DCHECK(!message_reader_);
    140   DCHECK(!control_reader_);
    141   return bootstrap_->Connect();
    142 }
    143 
    144 void ChannelMojo::Close() {
    145   control_reader_.reset();
    146   message_reader_.reset();
    147   channel_info_.reset();
    148 }
    149 
    150 void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) {
    151   InitControlReader(handle.Pass());
    152   control_reader_->Connect();
    153 }
    154 
    155 void ChannelMojo::OnBootstrapError() {
    156   listener_->OnChannelError();
    157 }
    158 
    159 void ChannelMojo::OnConnected(mojo::ScopedMessagePipeHandle pipe) {
    160   message_reader_ =
    161       make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this));
    162 
    163   for (size_t i = 0; i < pending_messages_.size(); ++i) {
    164     bool sent = message_reader_->Send(make_scoped_ptr(pending_messages_[i]));
    165     pending_messages_[i] = NULL;
    166     if (!sent) {
    167       pending_messages_.clear();
    168       listener_->OnChannelError();
    169       return;
    170     }
    171   }
    172 
    173   pending_messages_.clear();
    174 
    175   listener_->OnChannelConnected(GetPeerPID());
    176 }
    177 
    178 void ChannelMojo::OnPipeClosed(internal::MessagePipeReader* reader) {
    179   Close();
    180 }
    181 
    182 void ChannelMojo::OnPipeError(internal::MessagePipeReader* reader) {
    183   listener_->OnChannelError();
    184 }
    185 
    186 
    187 bool ChannelMojo::Send(Message* message) {
    188   if (!message_reader_) {
    189     pending_messages_.push_back(message);
    190     return true;
    191   }
    192 
    193   return message_reader_->Send(make_scoped_ptr(message));
    194 }
    195 
    196 base::ProcessId ChannelMojo::GetPeerPID() const {
    197   return peer_pid_;
    198 }
    199 
    200 base::ProcessId ChannelMojo::GetSelfPID() const {
    201   return base::GetCurrentProcId();
    202 }
    203 
    204 void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
    205   bootstrap_->OnClientLaunched(handle);
    206 }
    207 
    208 void ChannelMojo::OnMessageReceived(Message& message) {
    209   listener_->OnMessageReceived(message);
    210   if (message.dispatch_error())
    211     listener_->OnBadMessageReceived(message);
    212 }
    213 
    214 #if defined(OS_POSIX) && !defined(OS_NACL)
    215 int ChannelMojo::GetClientFileDescriptor() const {
    216   return bootstrap_->GetClientFileDescriptor();
    217 }
    218 
    219 int ChannelMojo::TakeClientFileDescriptor() {
    220   return bootstrap_->TakeClientFileDescriptor();
    221 }
    222 
    223 // static
    224 MojoResult ChannelMojo::WriteToFileDescriptorSet(
    225     const std::vector<MojoHandle>& handle_buffer,
    226     Message* message) {
    227   for (size_t i = 0; i < handle_buffer.size(); ++i) {
    228     mojo::embedder::ScopedPlatformHandle platform_handle;
    229     MojoResult unwrap_result = mojo::embedder::PassWrappedPlatformHandle(
    230         handle_buffer[i], &platform_handle);
    231     if (unwrap_result != MOJO_RESULT_OK) {
    232       DLOG(WARNING) << "Pipe failed to covert handles. Closing: "
    233                     << unwrap_result;
    234       return unwrap_result;
    235     }
    236 
    237     bool ok = message->file_descriptor_set()->AddToOwn(
    238         base::ScopedFD(platform_handle.release().fd));
    239     DCHECK(ok);
    240   }
    241 
    242   return MOJO_RESULT_OK;
    243 }
    244 
    245 // static
    246 MojoResult ChannelMojo::ReadFromFileDescriptorSet(
    247     Message* message,
    248     std::vector<MojoHandle>* handles) {
    249   // We dup() the handles in IPC::Message to transmit.
    250   // IPC::FileDescriptorSet has intricate lifecycle semantics
    251   // of FDs, so just to dup()-and-own them is the safest option.
    252   if (message->HasFileDescriptors()) {
    253     FileDescriptorSet* fdset = message->file_descriptor_set();
    254     std::vector<base::PlatformFile> fds_to_send(fdset->size());
    255     fdset->PeekDescriptors(&fds_to_send[0]);
    256     for (size_t i = 0; i < fds_to_send.size(); ++i) {
    257       int fd_to_send = dup(fds_to_send[i]);
    258       if (-1 == fd_to_send) {
    259         DPLOG(WARNING) << "Failed to dup FD to transmit.";
    260         fdset->CommitAll();
    261         return MOJO_RESULT_UNKNOWN;
    262       }
    263 
    264       MojoHandle wrapped_handle;
    265       MojoResult wrap_result = CreatePlatformHandleWrapper(
    266           mojo::embedder::ScopedPlatformHandle(
    267               mojo::embedder::PlatformHandle(fd_to_send)),
    268           &wrapped_handle);
    269       if (MOJO_RESULT_OK != wrap_result) {
    270         DLOG(WARNING) << "Pipe failed to wrap handles. Closing: "
    271                       << wrap_result;
    272         fdset->CommitAll();
    273         return wrap_result;
    274       }
    275 
    276       handles->push_back(wrapped_handle);
    277     }
    278 
    279     fdset->CommitAll();
    280   }
    281 
    282   return MOJO_RESULT_OK;
    283 }
    284 
    285 #endif  // defined(OS_POSIX) && !defined(OS_NACL)
    286 
    287 }  // namespace IPC
    288