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