• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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