morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 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" |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 11 | #include "ipc/mojo/ipc_channel_mojo_readers.h" |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 12 | #include "ipc/mojo/ipc_mojo_bootstrap.h" |
jamesr | 8dddfa2 | 2014-10-03 13:26:48 +0900 | [diff] [blame] | 13 | #include "mojo/edk/embedder/embedder.h" |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 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 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 23 | class MojoChannelFactory : public ChannelFactory { |
| 24 | public: |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 25 | MojoChannelFactory(ChannelMojo::Delegate* delegate, |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 26 | ChannelHandle channel_handle, |
| 27 | Channel::Mode mode) |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 28 | : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {} |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 29 | |
mostynb | d41cdbb | 2014-10-07 16:17:16 +0900 | [diff] [blame^] | 30 | virtual std::string GetName() const override { |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 31 | return channel_handle_.name; |
| 32 | } |
| 33 | |
mostynb | d41cdbb | 2014-10-07 16:17:16 +0900 | [diff] [blame^] | 34 | virtual scoped_ptr<Channel> BuildChannel(Listener* listener) override { |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 35 | return ChannelMojo::Create(delegate_, channel_handle_, mode_, listener) |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 36 | .PassAs<Channel>(); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | private: |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 40 | ChannelMojo::Delegate* delegate_; |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 41 | ChannelHandle channel_handle_; |
| 42 | Channel::Mode mode_; |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 43 | }; |
| 44 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 45 | } // namespace |
| 46 | |
| 47 | //------------------------------------------------------------------------------ |
| 48 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 49 | void ChannelMojo::ChannelInfoDeleter::operator()( |
| 50 | mojo::embedder::ChannelInfo* ptr) const { |
| 51 | mojo::embedder::DestroyChannelOnIOThread(ptr); |
| 52 | } |
| 53 | |
| 54 | //------------------------------------------------------------------------------ |
| 55 | |
| 56 | // static |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 57 | scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojo::Delegate* delegate, |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 58 | const ChannelHandle& channel_handle, |
| 59 | Mode mode, |
| 60 | Listener* listener) { |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 61 | return make_scoped_ptr( |
| 62 | new ChannelMojo(delegate, channel_handle, mode, listener)); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | // static |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 66 | scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory( |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 67 | ChannelMojo::Delegate* delegate, |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 68 | const ChannelHandle& channel_handle) { |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 69 | return make_scoped_ptr(new MojoChannelFactory( |
| 70 | delegate, channel_handle, Channel::MODE_SERVER)) |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 71 | .PassAs<ChannelFactory>(); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 72 | } |
| 73 | |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 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 | |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 82 | ChannelMojo::ChannelMojo(ChannelMojo::Delegate* delegate, |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 83 | const ChannelHandle& handle, |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 84 | Mode mode, |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 85 | Listener* listener) |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 86 | : mode_(mode), |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 87 | listener_(listener), |
anujk.sharma | 8461adf | 2014-08-28 15:49:02 +0900 | [diff] [blame] | 88 | peer_pid_(base::kNullProcessId), |
| 89 | weak_factory_(this) { |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 90 | // Create MojoBootstrap after all members are set as it touches |
| 91 | // ChannelMojo from a different thread. |
| 92 | bootstrap_ = MojoBootstrap::Create(handle, mode, this); |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 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 | } |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | ChannelMojo::~ChannelMojo() { |
| 107 | Close(); |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 108 | } |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 109 | |
morrita | 98b6e4a | 2014-09-26 12:20:48 +0900 | [diff] [blame] | 110 | void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) { |
| 111 | delegate_ = delegate->ToWeakPtr(); |
| 112 | delegate_->OnChannelCreated(weak_factory_.GetWeakPtr()); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 113 | } |
| 114 | |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 115 | void ChannelMojo::InitControlReader( |
| 116 | mojo::embedder::ScopedPlatformHandle handle) { |
| 117 | DCHECK(base::MessageLoopForIO::IsCurrent()); |
viettrungluu@chromium.org | 0e2787c | 2014-08-13 06:44:01 +0900 | [diff] [blame] | 118 | mojo::embedder::ChannelInfo* channel_info; |
| 119 | mojo::ScopedMessagePipeHandle control_pipe = |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 120 | mojo::embedder::CreateChannelOnIOThread(handle.Pass(), &channel_info); |
viettrungluu@chromium.org | 0e2787c | 2014-08-13 06:44:01 +0900 | [diff] [blame] | 121 | channel_info_.reset(channel_info); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 122 | |
viettrungluu@chromium.org | 0e2787c | 2014-08-13 06:44:01 +0900 | [diff] [blame] | 123 | switch (mode_) { |
| 124 | case MODE_SERVER: |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 125 | control_reader_.reset( |
| 126 | new internal::ServerControlReader(control_pipe.Pass(), this)); |
viettrungluu@chromium.org | 0e2787c | 2014-08-13 06:44:01 +0900 | [diff] [blame] | 127 | break; |
| 128 | case MODE_CLIENT: |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 129 | control_reader_.reset( |
| 130 | new internal::ClientControlReader(control_pipe.Pass(), this)); |
viettrungluu@chromium.org | 0e2787c | 2014-08-13 06:44:01 +0900 | [diff] [blame] | 131 | break; |
| 132 | default: |
| 133 | NOTREACHED(); |
| 134 | break; |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 135 | } |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | bool ChannelMojo::Connect() { |
| 139 | DCHECK(!message_reader_); |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 140 | DCHECK(!control_reader_); |
| 141 | return bootstrap_->Connect(); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | void ChannelMojo::Close() { |
| 145 | control_reader_.reset(); |
| 146 | message_reader_.reset(); |
| 147 | channel_info_.reset(); |
| 148 | } |
| 149 | |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 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 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 159 | void ChannelMojo::OnConnected(mojo::ScopedMessagePipeHandle pipe) { |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 160 | message_reader_ = |
| 161 | make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this)); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 162 | |
| 163 | for (size_t i = 0; i < pending_messages_.size(); ++i) { |
morrita | fa3ab75 | 2014-09-16 12:20:48 +0900 | [diff] [blame] | 164 | bool sent = message_reader_->Send(make_scoped_ptr(pending_messages_[i])); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 165 | pending_messages_[i] = NULL; |
morrita | fa3ab75 | 2014-09-16 12:20:48 +0900 | [diff] [blame] | 166 | if (!sent) { |
| 167 | pending_messages_.clear(); |
| 168 | listener_->OnChannelError(); |
| 169 | return; |
| 170 | } |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 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 { |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 201 | return base::GetCurrentProcId(); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 202 | } |
| 203 | |
morrita | 7c48ab8 | 2014-09-24 06:16:00 +0900 | [diff] [blame] | 204 | void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) { |
| 205 | bootstrap_->OnClientLaunched(handle); |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 206 | } |
| 207 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 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 | } |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 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 | |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 237 | bool ok = message->file_descriptor_set()->AddToOwn( |
| 238 | base::ScopedFD(platform_handle.release().fd)); |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 239 | DCHECK(ok); |
| 240 | } |
| 241 | |
| 242 | return MOJO_RESULT_OK; |
| 243 | } |
| 244 | |
| 245 | // static |
| 246 | MojoResult ChannelMojo::ReadFromFileDescriptorSet( |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 247 | Message* message, |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 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. |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 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]); |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 258 | if (-1 == fd_to_send) { |
| 259 | DPLOG(WARNING) << "Failed to dup FD to transmit."; |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 260 | fdset->CommitAll(); |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 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; |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 272 | fdset->CommitAll(); |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 273 | return wrap_result; |
| 274 | } |
| 275 | |
| 276 | handles->push_back(wrapped_handle); |
| 277 | } |
morrita | ab20725 | 2014-09-25 05:11:45 +0900 | [diff] [blame] | 278 | |
| 279 | fdset->CommitAll(); |
morrita | 42bda25 | 2014-09-12 04:06:29 +0900 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | return MOJO_RESULT_OK; |
| 283 | } |
| 284 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 285 | #endif // defined(OS_POSIX) && !defined(OS_NACL) |
| 286 | |
| 287 | } // namespace IPC |