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:
MojoChannelFactory(ChannelMojo::Delegate * delegate,ChannelHandle channel_handle,Channel::Mode mode)25 MojoChannelFactory(ChannelMojo::Delegate* delegate,
26 ChannelHandle channel_handle,
27 Channel::Mode mode)
28 : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {}
29
GetName() const30 virtual std::string GetName() const OVERRIDE {
31 return channel_handle_.name;
32 }
33
BuildChannel(Listener * listener)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
operator ()(mojo::embedder::ChannelInfo * ptr) const49 void ChannelMojo::ChannelInfoDeleter::operator()(
50 mojo::embedder::ChannelInfo* ptr) const {
51 mojo::embedder::DestroyChannelOnIOThread(ptr);
52 }
53
54 //------------------------------------------------------------------------------
55
56 // static
Create(ChannelMojo::Delegate * delegate,const ChannelHandle & channel_handle,Mode mode,Listener * listener)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
CreateServerFactory(ChannelMojo::Delegate * delegate,const ChannelHandle & channel_handle)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
CreateClientFactory(const ChannelHandle & channel_handle)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
ChannelMojo(ChannelMojo::Delegate * delegate,const ChannelHandle & handle,Mode mode,Listener * listener)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
~ChannelMojo()106 ChannelMojo::~ChannelMojo() {
107 Close();
108 }
109
InitDelegate(ChannelMojo::Delegate * delegate)110 void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) {
111 delegate_ = delegate->ToWeakPtr();
112 delegate_->OnChannelCreated(weak_factory_.GetWeakPtr());
113 }
114
InitControlReader(mojo::embedder::ScopedPlatformHandle handle)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
Connect()138 bool ChannelMojo::Connect() {
139 DCHECK(!message_reader_);
140 DCHECK(!control_reader_);
141 return bootstrap_->Connect();
142 }
143
Close()144 void ChannelMojo::Close() {
145 control_reader_.reset();
146 message_reader_.reset();
147 channel_info_.reset();
148 }
149
OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle)150 void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) {
151 InitControlReader(handle.Pass());
152 control_reader_->Connect();
153 }
154
OnBootstrapError()155 void ChannelMojo::OnBootstrapError() {
156 listener_->OnChannelError();
157 }
158
OnConnected(mojo::ScopedMessagePipeHandle pipe)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
OnPipeClosed(internal::MessagePipeReader * reader)178 void ChannelMojo::OnPipeClosed(internal::MessagePipeReader* reader) {
179 Close();
180 }
181
OnPipeError(internal::MessagePipeReader * reader)182 void ChannelMojo::OnPipeError(internal::MessagePipeReader* reader) {
183 listener_->OnChannelError();
184 }
185
186
Send(Message * message)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
GetPeerPID() const196 base::ProcessId ChannelMojo::GetPeerPID() const {
197 return peer_pid_;
198 }
199
GetSelfPID() const200 base::ProcessId ChannelMojo::GetSelfPID() const {
201 return base::GetCurrentProcId();
202 }
203
OnClientLaunched(base::ProcessHandle handle)204 void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
205 bootstrap_->OnClientLaunched(handle);
206 }
207
OnMessageReceived(Message & message)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)
GetClientFileDescriptor() const215 int ChannelMojo::GetClientFileDescriptor() const {
216 return bootstrap_->GetClientFileDescriptor();
217 }
218
TakeClientFileDescriptor()219 int ChannelMojo::TakeClientFileDescriptor() {
220 return bootstrap_->TakeClientFileDescriptor();
221 }
222
223 // static
WriteToFileDescriptorSet(const std::vector<MojoHandle> & handle_buffer,Message * message)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
ReadFromFileDescriptorSet(Message * message,std::vector<MojoHandle> * handles)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