blob: 791a97026ab3150f03282c7b0e9b146700ee84a6 [file] [log] [blame]
morrita@chromium.org15996aa2014-08-05 08:44:17 +09001// 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"
morrita42bda252014-09-12 04:06:29 +090011#include "ipc/mojo/ipc_channel_mojo_readers.h"
morrita7c48ab82014-09-24 06:16:00 +090012#include "ipc/mojo/ipc_mojo_bootstrap.h"
jamesr8dddfa22014-10-03 13:26:48 +090013#include "mojo/edk/embedder/embedder.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090014
15#if defined(OS_POSIX) && !defined(OS_NACL)
16#include "ipc/file_descriptor_set_posix.h"
17#endif
18
19namespace IPC {
20
21namespace {
22
morrita@chromium.org15996aa2014-08-05 08:44:17 +090023class MojoChannelFactory : public ChannelFactory {
24 public:
morrita98b6e4a2014-09-26 12:20:48 +090025 MojoChannelFactory(ChannelMojo::Delegate* delegate,
morrita7c48ab82014-09-24 06:16:00 +090026 ChannelHandle channel_handle,
27 Channel::Mode mode)
morrita98b6e4a2014-09-26 12:20:48 +090028 : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090029
mostynbd41cdbb2014-10-07 16:17:16 +090030 virtual std::string GetName() const override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090031 return channel_handle_.name;
32 }
33
mostynbd41cdbb2014-10-07 16:17:16 +090034 virtual scoped_ptr<Channel> BuildChannel(Listener* listener) override {
morrita98b6e4a2014-09-26 12:20:48 +090035 return ChannelMojo::Create(delegate_, channel_handle_, mode_, listener)
morrita7c48ab82014-09-24 06:16:00 +090036 .PassAs<Channel>();
morrita@chromium.org15996aa2014-08-05 08:44:17 +090037 }
38
39 private:
morrita98b6e4a2014-09-26 12:20:48 +090040 ChannelMojo::Delegate* delegate_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090041 ChannelHandle channel_handle_;
42 Channel::Mode mode_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090043};
44
morrita@chromium.org15996aa2014-08-05 08:44:17 +090045} // namespace
46
47//------------------------------------------------------------------------------
48
morrita@chromium.org15996aa2014-08-05 08:44:17 +090049void ChannelMojo::ChannelInfoDeleter::operator()(
50 mojo::embedder::ChannelInfo* ptr) const {
51 mojo::embedder::DestroyChannelOnIOThread(ptr);
52}
53
54//------------------------------------------------------------------------------
55
56// static
morrita98b6e4a2014-09-26 12:20:48 +090057scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojo::Delegate* delegate,
morrita7c48ab82014-09-24 06:16:00 +090058 const ChannelHandle& channel_handle,
59 Mode mode,
60 Listener* listener) {
morrita98b6e4a2014-09-26 12:20:48 +090061 return make_scoped_ptr(
62 new ChannelMojo(delegate, channel_handle, mode, listener));
morrita@chromium.org15996aa2014-08-05 08:44:17 +090063}
64
65// static
morrita7c48ab82014-09-24 06:16:00 +090066scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
morrita98b6e4a2014-09-26 12:20:48 +090067 ChannelMojo::Delegate* delegate,
morrita7c48ab82014-09-24 06:16:00 +090068 const ChannelHandle& channel_handle) {
morrita98b6e4a2014-09-26 12:20:48 +090069 return make_scoped_ptr(new MojoChannelFactory(
70 delegate, channel_handle, Channel::MODE_SERVER))
morrita7c48ab82014-09-24 06:16:00 +090071 .PassAs<ChannelFactory>();
morrita@chromium.org15996aa2014-08-05 08:44:17 +090072}
73
morrita7c48ab82014-09-24 06:16:00 +090074// 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
morrita98b6e4a2014-09-26 12:20:48 +090082ChannelMojo::ChannelMojo(ChannelMojo::Delegate* delegate,
morrita7c48ab82014-09-24 06:16:00 +090083 const ChannelHandle& handle,
morrita42bda252014-09-12 04:06:29 +090084 Mode mode,
morrita7c48ab82014-09-24 06:16:00 +090085 Listener* listener)
morrita98b6e4a2014-09-26 12:20:48 +090086 : mode_(mode),
morrita42bda252014-09-12 04:06:29 +090087 listener_(listener),
anujk.sharma8461adf2014-08-28 15:49:02 +090088 peer_pid_(base::kNullProcessId),
89 weak_factory_(this) {
morrita7c48ab82014-09-24 06:16:00 +090090 // Create MojoBootstrap after all members are set as it touches
91 // ChannelMojo from a different thread.
92 bootstrap_ = MojoBootstrap::Create(handle, mode, this);
morrita98b6e4a2014-09-26 12:20:48 +090093 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.org15996aa2014-08-05 08:44:17 +0900104}
105
106ChannelMojo::~ChannelMojo() {
107 Close();
morrita98b6e4a2014-09-26 12:20:48 +0900108}
morrita7c48ab82014-09-24 06:16:00 +0900109
morrita98b6e4a2014-09-26 12:20:48 +0900110void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) {
111 delegate_ = delegate->ToWeakPtr();
112 delegate_->OnChannelCreated(weak_factory_.GetWeakPtr());
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900113}
114
morrita7c48ab82014-09-24 06:16:00 +0900115void ChannelMojo::InitControlReader(
116 mojo::embedder::ScopedPlatformHandle handle) {
117 DCHECK(base::MessageLoopForIO::IsCurrent());
viettrungluu@chromium.org0e2787c2014-08-13 06:44:01 +0900118 mojo::embedder::ChannelInfo* channel_info;
119 mojo::ScopedMessagePipeHandle control_pipe =
morrita7c48ab82014-09-24 06:16:00 +0900120 mojo::embedder::CreateChannelOnIOThread(handle.Pass(), &channel_info);
viettrungluu@chromium.org0e2787c2014-08-13 06:44:01 +0900121 channel_info_.reset(channel_info);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900122
viettrungluu@chromium.org0e2787c2014-08-13 06:44:01 +0900123 switch (mode_) {
124 case MODE_SERVER:
morrita42bda252014-09-12 04:06:29 +0900125 control_reader_.reset(
126 new internal::ServerControlReader(control_pipe.Pass(), this));
viettrungluu@chromium.org0e2787c2014-08-13 06:44:01 +0900127 break;
128 case MODE_CLIENT:
morrita42bda252014-09-12 04:06:29 +0900129 control_reader_.reset(
130 new internal::ClientControlReader(control_pipe.Pass(), this));
viettrungluu@chromium.org0e2787c2014-08-13 06:44:01 +0900131 break;
132 default:
133 NOTREACHED();
134 break;
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900135 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900136}
137
138bool ChannelMojo::Connect() {
139 DCHECK(!message_reader_);
morrita7c48ab82014-09-24 06:16:00 +0900140 DCHECK(!control_reader_);
141 return bootstrap_->Connect();
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900142}
143
144void ChannelMojo::Close() {
145 control_reader_.reset();
146 message_reader_.reset();
147 channel_info_.reset();
148}
149
morrita7c48ab82014-09-24 06:16:00 +0900150void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) {
151 InitControlReader(handle.Pass());
152 control_reader_->Connect();
153}
154
155void ChannelMojo::OnBootstrapError() {
156 listener_->OnChannelError();
157}
158
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900159void ChannelMojo::OnConnected(mojo::ScopedMessagePipeHandle pipe) {
morrita42bda252014-09-12 04:06:29 +0900160 message_reader_ =
161 make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900162
163 for (size_t i = 0; i < pending_messages_.size(); ++i) {
morritafa3ab752014-09-16 12:20:48 +0900164 bool sent = message_reader_->Send(make_scoped_ptr(pending_messages_[i]));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900165 pending_messages_[i] = NULL;
morritafa3ab752014-09-16 12:20:48 +0900166 if (!sent) {
167 pending_messages_.clear();
168 listener_->OnChannelError();
169 return;
170 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900171 }
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 {
morrita7c48ab82014-09-24 06:16:00 +0900201 return base::GetCurrentProcId();
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900202}
203
morrita7c48ab82014-09-24 06:16:00 +0900204void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
205 bootstrap_->OnClientLaunched(handle);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900206}
207
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900208void 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}
morrita42bda252014-09-12 04:06:29 +0900222
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
morritaab207252014-09-25 05:11:45 +0900237 bool ok = message->file_descriptor_set()->AddToOwn(
238 base::ScopedFD(platform_handle.release().fd));
morrita42bda252014-09-12 04:06:29 +0900239 DCHECK(ok);
240 }
241
242 return MOJO_RESULT_OK;
243}
244
245// static
246MojoResult ChannelMojo::ReadFromFileDescriptorSet(
morritaab207252014-09-25 05:11:45 +0900247 Message* message,
morrita42bda252014-09-12 04:06:29 +0900248 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.
morritaab207252014-09-25 05:11:45 +0900252 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]);
morrita42bda252014-09-12 04:06:29 +0900258 if (-1 == fd_to_send) {
259 DPLOG(WARNING) << "Failed to dup FD to transmit.";
morritaab207252014-09-25 05:11:45 +0900260 fdset->CommitAll();
morrita42bda252014-09-12 04:06:29 +0900261 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;
morritaab207252014-09-25 05:11:45 +0900272 fdset->CommitAll();
morrita42bda252014-09-12 04:06:29 +0900273 return wrap_result;
274 }
275
276 handles->push_back(wrapped_handle);
277 }
morritaab207252014-09-25 05:11:45 +0900278
279 fdset->CommitAll();
morrita42bda252014-09-12 04:06:29 +0900280 }
281
282 return MOJO_RESULT_OK;
283}
284
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900285#endif // defined(OS_POSIX) && !defined(OS_NACL)
286
287} // namespace IPC