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 19namespace IPC { 20 21namespace { 22 23class 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 49void ChannelMojo::ChannelInfoDeleter::operator()( 50 mojo::embedder::ChannelInfo* ptr) const { 51 mojo::embedder::DestroyChannelOnIOThread(ptr); 52} 53 54//------------------------------------------------------------------------------ 55 56// static 57scoped_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 66scoped_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 75scoped_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 82ChannelMojo::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 106ChannelMojo::~ChannelMojo() { 107 Close(); 108} 109 110void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) { 111 delegate_ = delegate->ToWeakPtr(); 112 delegate_->OnChannelCreated(weak_factory_.GetWeakPtr()); 113} 114 115void 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 138bool ChannelMojo::Connect() { 139 DCHECK(!message_reader_); 140 DCHECK(!control_reader_); 141 return bootstrap_->Connect(); 142} 143 144void ChannelMojo::Close() { 145 control_reader_.reset(); 146 message_reader_.reset(); 147 channel_info_.reset(); 148} 149 150void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) { 151 InitControlReader(handle.Pass()); 152 control_reader_->Connect(); 153} 154 155void ChannelMojo::OnBootstrapError() { 156 listener_->OnChannelError(); 157} 158 159void 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 178void ChannelMojo::OnPipeClosed(internal::MessagePipeReader* reader) { 179 Close(); 180} 181 182void ChannelMojo::OnPipeError(internal::MessagePipeReader* reader) { 183 listener_->OnChannelError(); 184} 185 186 187bool 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 196base::ProcessId ChannelMojo::GetPeerPID() const { 197 return peer_pid_; 198} 199 200base::ProcessId ChannelMojo::GetSelfPID() const { 201 return base::GetCurrentProcId(); 202} 203 204void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) { 205 bootstrap_->OnClientLaunched(handle); 206} 207 208void 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) 215int ChannelMojo::GetClientFileDescriptor() const { 216 return bootstrap_->GetClientFileDescriptor(); 217} 218 219int ChannelMojo::TakeClientFileDescriptor() { 220 return bootstrap_->TakeClientFileDescriptor(); 221} 222 223// static 224MojoResult 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 246MojoResult 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