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
19namespace IPC {
20
21namespace {
22
23class MojoChannelFactory : public ChannelFactory {
24 public:
25  MojoChannelFactory(ChannelMojo::Delegate* delegate,
26                     ChannelHandle channel_handle,
27                     Channel::Mode mode)
28      : delegate_(delegate), channel_handle_(channel_handle), mode_(mode) {}
29
30  virtual std::string GetName() const OVERRIDE {
31    return channel_handle_.name;
32  }
33
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
49void ChannelMojo::ChannelInfoDeleter::operator()(
50    mojo::embedder::ChannelInfo* ptr) const {
51  mojo::embedder::DestroyChannelOnIOThread(ptr);
52}
53
54//------------------------------------------------------------------------------
55
56// static
57scoped_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
66scoped_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
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
82ChannelMojo::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
106ChannelMojo::~ChannelMojo() {
107  Close();
108}
109
110void ChannelMojo::InitDelegate(ChannelMojo::Delegate* delegate) {
111  delegate_ = delegate->ToWeakPtr();
112  delegate_->OnChannelCreated(weak_factory_.GetWeakPtr());
113}
114
115void 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
138bool ChannelMojo::Connect() {
139  DCHECK(!message_reader_);
140  DCHECK(!control_reader_);
141  return bootstrap_->Connect();
142}
143
144void ChannelMojo::Close() {
145  control_reader_.reset();
146  message_reader_.reset();
147  channel_info_.reset();
148}
149
150void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) {
151  InitControlReader(handle.Pass());
152  control_reader_->Connect();
153}
154
155void ChannelMojo::OnBootstrapError() {
156  listener_->OnChannelError();
157}
158
159void 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
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 {
201  return base::GetCurrentProcId();
202}
203
204void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
205  bootstrap_->OnClientLaunched(handle);
206}
207
208void 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}
222
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
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
246MojoResult 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