summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/chromium/src/chrome')
-rw-r--r--ipc/chromium/src/chrome/common/child_process.cc30
-rw-r--r--ipc/chromium/src/chrome/common/child_process.h46
-rw-r--r--ipc/chromium/src/chrome/common/child_process_host.cc79
-rw-r--r--ipc/chromium/src/chrome/common/child_process_host.h79
-rw-r--r--ipc/chromium/src/chrome/common/child_thread.cc54
-rw-r--r--ipc/chromium/src/chrome/common/child_thread.h56
-rw-r--r--ipc/chromium/src/chrome/common/chrome_switches.cc18
-rw-r--r--ipc/chromium/src/chrome/common/chrome_switches.h22
-rw-r--r--ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc123
-rw-r--r--ipc/chromium/src/chrome/common/file_descriptor_set_posix.h106
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel.cc41
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel.h179
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel_posix.cc958
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel_posix.h182
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel_win.cc630
-rw-r--r--ipc/chromium/src/chrome/common/ipc_channel_win.h140
-rw-r--r--ipc/chromium/src/chrome/common/ipc_message.cc158
-rw-r--r--ipc/chromium/src/chrome/common/ipc_message.h370
-rw-r--r--ipc/chromium/src/chrome/common/ipc_message_utils.h526
-rw-r--r--ipc/chromium/src/chrome/common/mach_ipc_mac.h313
-rw-r--r--ipc/chromium/src/chrome/common/mach_ipc_mac.mm351
-rw-r--r--ipc/chromium/src/chrome/common/mach_message_source_mac.cc68
-rw-r--r--ipc/chromium/src/chrome/common/mach_message_source_mac.h61
-rw-r--r--ipc/chromium/src/chrome/common/process_watcher.h39
-rw-r--r--ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc215
-rw-r--r--ipc/chromium/src/chrome/common/process_watcher_win.cc118
-rw-r--r--ipc/chromium/src/chrome/common/transport_dib.h126
-rw-r--r--ipc/chromium/src/chrome/common/transport_dib_mac.cc67
-rw-r--r--ipc/chromium/src/chrome/common/transport_dib_win.cc74
-rw-r--r--ipc/chromium/src/chrome/common/x11_util.h19
30 files changed, 5248 insertions, 0 deletions
diff --git a/ipc/chromium/src/chrome/common/child_process.cc b/ipc/chromium/src/chrome/common/child_process.cc
new file mode 100644
index 000000000..bade255c5
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_process.cc
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/child_process.h"
+
+#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "chrome/common/child_thread.h"
+
+ChildProcess* ChildProcess::child_process_;
+
+ChildProcess::ChildProcess(ChildThread* child_thread)
+ : child_thread_(child_thread) {
+ DCHECK(!child_process_);
+ child_process_ = this;
+ if (child_thread_.get()) // null in unittests.
+ child_thread_->Run();
+}
+
+ChildProcess::~ChildProcess() {
+ DCHECK(child_process_ == this);
+
+ if (child_thread_.get())
+ child_thread_->Stop();
+
+ child_process_ = NULL;
+}
diff --git a/ipc/chromium/src/chrome/common/child_process.h b/ipc/chromium/src/chrome/common/child_process.h
new file mode 100644
index 000000000..67b759fa2
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_process.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHILD_PROCESS_H__
+#define CHROME_COMMON_CHILD_PROCESS_H__
+
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/waitable_event.h"
+#include "mozilla/UniquePtr.h"
+
+class ChildThread;
+
+
+// Base class for child processes of the browser process (i.e. renderer and
+// plugin host). This is a singleton object for each child process.
+class ChildProcess {
+ public:
+ // Child processes should have an object that derives from this class. The
+ // constructor will return once ChildThread has started.
+ explicit ChildProcess(ChildThread* child_thread);
+ virtual ~ChildProcess();
+
+ // Getter for this process' main thread.
+ ChildThread* child_thread() { return child_thread_.get(); }
+
+ // Getter for the one ChildProcess object for this process.
+ static ChildProcess* current() { return child_process_; }
+
+ private:
+ // NOTE: make sure that child_thread_ is listed before shutdown_event_, since
+ // it depends on it (indirectly through IPC::SyncChannel).
+ mozilla::UniquePtr<ChildThread> child_thread_;
+
+ // The singleton instance for this process.
+ static ChildProcess* child_process_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ChildProcess);
+};
+
+#endif // CHROME_COMMON_CHILD_PROCESS_H__
diff --git a/ipc/chromium/src/chrome/common/child_process_host.cc b/ipc/chromium/src/chrome/common/child_process_host.cc
new file mode 100644
index 000000000..ec324d2bf
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_process_host.cc
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/child_process_host.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "base/singleton.h"
+#include "base/waitable_event.h"
+#include "mozilla/ipc/ProcessChild.h"
+#include "mozilla/ipc/BrowserProcessSubThread.h"
+#include "mozilla/ipc/Transport.h"
+typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
+#include "chrome/common/process_watcher.h"
+
+using mozilla::ipc::FileDescriptor;
+
+ChildProcessHost::ChildProcessHost()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
+ opening_channel_(false) {
+}
+
+
+ChildProcessHost::~ChildProcessHost() {
+}
+
+bool ChildProcessHost::CreateChannel() {
+ channel_id_ = IPC::Channel::GenerateVerifiedChannelID(std::wstring());
+ channel_.reset(new IPC::Channel(
+ channel_id_, IPC::Channel::MODE_SERVER, &listener_));
+ if (!channel_->Connect())
+ return false;
+
+ opening_channel_ = true;
+
+ return true;
+}
+
+bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) {
+ if (channel_.get()) {
+ channel_->Close();
+ }
+ channel_ = mozilla::ipc::OpenDescriptor(aFileDescriptor, IPC::Channel::MODE_SERVER);
+ if (!channel_->Connect()) {
+ return false;
+ }
+
+ opening_channel_ = true;
+
+ return true;
+}
+
+ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
+ : host_(host) {
+}
+
+void ChildProcessHost::ListenerHook::OnMessageReceived(
+ IPC::Message&& msg) {
+ host_->OnMessageReceived(mozilla::Move(msg));
+}
+
+void ChildProcessHost::ListenerHook::OnChannelConnected(int32_t peer_pid) {
+ host_->opening_channel_ = false;
+ host_->OnChannelConnected(peer_pid);
+}
+
+void ChildProcessHost::ListenerHook::OnChannelError() {
+ host_->opening_channel_ = false;
+ host_->OnChannelError();
+}
+
+void ChildProcessHost::ListenerHook::GetQueuedMessages(std::queue<IPC::Message>& queue) {
+ host_->GetQueuedMessages(queue);
+}
diff --git a/ipc/chromium/src/chrome/common/child_process_host.h b/ipc/chromium/src/chrome/common/child_process_host.h
new file mode 100644
index 000000000..6411d3a6e
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_process_host.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHILD_PROCESS_HOST_H_
+#define CHROME_COMMON_CHILD_PROCESS_HOST_H_
+
+#include "build/build_config.h"
+
+#include <list>
+
+#include "base/basictypes.h"
+#include "chrome/common/ipc_channel.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla {
+namespace ipc {
+class FileDescriptor;
+}
+}
+
+// Plugins/workers and other child processes that live on the IO thread should
+// derive from this class.
+class ChildProcessHost : public IPC::Channel::Listener {
+ public:
+ virtual ~ChildProcessHost();
+
+ protected:
+ explicit ChildProcessHost();
+
+ // Derived classes return true if it's ok to shut down the child process.
+ virtual bool CanShutdown() = 0;
+
+ // Creates the IPC channel. Returns true iff it succeeded.
+ bool CreateChannel();
+
+ bool CreateChannel(mozilla::ipc::FileDescriptor& aFileDescriptor);
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(IPC::Message&& msg) { }
+ virtual void OnChannelConnected(int32_t peer_pid) { }
+ virtual void OnChannelError() { }
+
+ bool opening_channel() { return opening_channel_; }
+ const std::wstring& channel_id() { return channel_id_; }
+
+ const IPC::Channel& channel() const { return *channel_; }
+ IPC::Channel* channelp() const { return channel_.get(); }
+
+ private:
+ // By using an internal class as the IPC::Channel::Listener, we can intercept
+ // OnMessageReceived/OnChannelConnected and do our own processing before
+ // calling the subclass' implementation.
+ class ListenerHook : public IPC::Channel::Listener {
+ public:
+ explicit ListenerHook(ChildProcessHost* host);
+ virtual void OnMessageReceived(IPC::Message&& msg);
+ virtual void OnChannelConnected(int32_t peer_pid);
+ virtual void OnChannelError();
+ virtual void GetQueuedMessages(std::queue<IPC::Message>& queue);
+ private:
+ ChildProcessHost* host_;
+ };
+
+ ListenerHook listener_;
+
+ // True while we're waiting the channel to be opened.
+ bool opening_channel_;
+
+ // The IPC::Channel.
+ mozilla::UniquePtr<IPC::Channel> channel_;
+
+ // IPC Channel's id.
+ std::wstring channel_id_;
+};
+
+#endif // CHROME_COMMON_CHILD_PROCESS_HOST_H_
diff --git a/ipc/chromium/src/chrome/common/child_thread.cc b/ipc/chromium/src/chrome/common/child_thread.cc
new file mode 100644
index 000000000..619f73c5d
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_thread.cc
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/child_thread.h"
+
+#include "base/string_util.h"
+#include "base/command_line.h"
+#include "chrome/common/child_process.h"
+#include "chrome/common/chrome_switches.h"
+
+ChildThread::ChildThread(Thread::Options options)
+ : Thread("Chrome_ChildThread"),
+ owner_loop_(MessageLoop::current()),
+ options_(options) {
+ DCHECK(owner_loop_);
+ channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue(
+ switches::kProcessChannelID);
+}
+
+ChildThread::~ChildThread() {
+}
+
+bool ChildThread::Run() {
+ bool r = StartWithOptions(options_);
+ return r;
+}
+
+void ChildThread::OnChannelError() {
+ RefPtr<mozilla::Runnable> task = new MessageLoop::QuitTask();
+ owner_loop_->PostTask(task.forget());
+}
+
+void ChildThread::OnMessageReceived(IPC::Message&& msg) {
+}
+
+ChildThread* ChildThread::current() {
+ return ChildProcess::current()->child_thread();
+}
+
+void ChildThread::Init() {
+ channel_ = mozilla::MakeUnique<IPC::Channel>(channel_name_,
+ IPC::Channel::MODE_CLIENT,
+ this);
+
+}
+
+void ChildThread::CleanUp() {
+ // Need to destruct the SyncChannel to the browser before we go away because
+ // it caches a pointer to this thread.
+ channel_ = nullptr;
+}
diff --git a/ipc/chromium/src/chrome/common/child_thread.h b/ipc/chromium/src/chrome/common/child_thread.h
new file mode 100644
index 000000000..a36d16ec9
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/child_thread.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHILD_THREAD_H_
+#define CHROME_COMMON_CHILD_THREAD_H_
+
+#include "base/thread.h"
+#include "chrome/common/ipc_channel.h"
+#include "mozilla/UniquePtr.h"
+
+class ResourceDispatcher;
+
+// Child processes's background thread should derive from this class.
+class ChildThread : public IPC::Channel::Listener,
+ public base::Thread {
+ public:
+ // Creates the thread.
+ explicit ChildThread(Thread::Options options);
+ virtual ~ChildThread();
+
+ protected:
+ friend class ChildProcess;
+
+ // Starts the thread.
+ bool Run();
+
+ protected:
+ // Returns the one child thread.
+ static ChildThread* current();
+
+ IPC::Channel* channel() { return channel_.get(); }
+
+ // Thread implementation.
+ virtual void Init();
+ virtual void CleanUp();
+
+ private:
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(IPC::Message&& msg);
+ virtual void OnChannelError();
+
+ // The message loop used to run tasks on the thread that started this thread.
+ MessageLoop* owner_loop_;
+
+ std::wstring channel_name_;
+ mozilla::UniquePtr<IPC::Channel> channel_;
+
+ Thread::Options options_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ChildThread);
+};
+
+#endif // CHROME_COMMON_CHILD_THREAD_H_
diff --git a/ipc/chromium/src/chrome/common/chrome_switches.cc b/ipc/chromium/src/chrome/common/chrome_switches.cc
new file mode 100644
index 000000000..082d60637
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/chrome_switches.cc
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chrome_switches.h"
+
+namespace switches {
+
+// Can't find the switch you are looking for? try looking in
+// base/base_switches.cc instead.
+
+// The value of this switch tells the child process which
+// IPC channel the browser expects to use to communicate with it.
+const wchar_t kProcessChannelID[] = L"channel";
+
+} // namespace switches
diff --git a/ipc/chromium/src/chrome/common/chrome_switches.h b/ipc/chromium/src/chrome/common/chrome_switches.h
new file mode 100644
index 000000000..5dd4446a8
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/chrome_switches.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines all the command-line switches used by Chrome.
+
+#ifndef CHROME_COMMON_CHROME_SWITCHES_H__
+#define CHROME_COMMON_CHROME_SWITCHES_H__
+
+#if defined(COMPILER_MSVC)
+#include <string.h>
+#endif
+
+namespace switches {
+
+extern const wchar_t kProcessChannelID[];
+
+} // namespace switches
+
+#endif // CHROME_COMMON_CHROME_SWITCHES_H__
diff --git a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc
new file mode 100644
index 000000000..9e70ff820
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/file_descriptor_set_posix.h"
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+
+#include <unistd.h>
+
+FileDescriptorSet::FileDescriptorSet()
+ : consumed_descriptor_highwater_(0) {
+}
+
+FileDescriptorSet::~FileDescriptorSet() {
+ if (consumed_descriptor_highwater_ == descriptors_.size())
+ return;
+
+ CHROMIUM_LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors";
+ // We close all the descriptors where the close flag is set. If this
+ // message should have been transmitted, then closing those with close
+ // flags set mirrors the expected behaviour.
+ //
+ // If this message was received with more descriptors than expected
+ // (which could a DOS against the browser by a rogue renderer) then all
+ // the descriptors have their close flag set and we free all the extra
+ // kernel resources.
+ for (unsigned i = consumed_descriptor_highwater_;
+ i < descriptors_.size(); ++i) {
+ if (descriptors_[i].auto_close)
+ HANDLE_EINTR(close(descriptors_[i].fd));
+ }
+}
+
+bool FileDescriptorSet::Add(int fd) {
+ if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
+ return false;
+
+ struct base::FileDescriptor sd;
+ sd.fd = fd;
+ sd.auto_close = false;
+ descriptors_.push_back(sd);
+ return true;
+}
+
+bool FileDescriptorSet::AddAndAutoClose(int fd) {
+ if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
+ return false;
+
+ struct base::FileDescriptor sd;
+ sd.fd = fd;
+ sd.auto_close = true;
+ descriptors_.push_back(sd);
+ DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE);
+ return true;
+}
+
+int FileDescriptorSet::GetDescriptorAt(unsigned index) const {
+ if (index >= descriptors_.size())
+ return -1;
+
+ // We should always walk the descriptors in order, so it's reasonable to
+ // enforce this. Consider the case where a compromised renderer sends us
+ // the following message:
+ //
+ // ExampleMsg:
+ // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
+ //
+ // Here the renderer sent us a message which should have a descriptor, but
+ // actually sent two in an attempt to fill our fd table and kill us. By
+ // setting the index of the descriptor in the message to 1 (it should be
+ // 0), we would record a highwater of 1 and then consider all the
+ // descriptors to have been used.
+ //
+ // So we can either track of the use of each descriptor in a bitset, or we
+ // can enforce that we walk the indexes strictly in order.
+ //
+ // There's one more wrinkle: When logging messages, we may reparse them. So
+ // we have an exception: When the consumed_descriptor_highwater_ is at the
+ // end of the array and index 0 is requested, we reset the highwater value.
+ if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size())
+ consumed_descriptor_highwater_ = 0;
+
+ if (index != consumed_descriptor_highwater_)
+ return -1;
+
+ consumed_descriptor_highwater_ = index + 1;
+ return descriptors_[index].fd;
+}
+
+void FileDescriptorSet::GetDescriptors(int* buffer) const {
+ for (std::vector<base::FileDescriptor>::const_iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ *(buffer++) = i->fd;
+ }
+}
+
+void FileDescriptorSet::CommitAll() {
+ for (std::vector<base::FileDescriptor>::iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (i->auto_close)
+ HANDLE_EINTR(close(i->fd));
+ }
+ descriptors_.clear();
+ consumed_descriptor_highwater_ = 0;
+}
+
+void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) {
+ DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE);
+ DCHECK_EQ(descriptors_.size(), 0u);
+ DCHECK_EQ(consumed_descriptor_highwater_, 0u);
+
+ descriptors_.reserve(count);
+ for (unsigned i = 0; i < count; ++i) {
+ struct base::FileDescriptor sd;
+ sd.fd = buffer[i];
+ sd.auto_close = true;
+ descriptors_.push_back(sd);
+ }
+}
diff --git a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h
new file mode 100644
index 000000000..b6b153fb1
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_FILE_DESCRIPTOR_SET_POSIX_H_
+#define CHROME_COMMON_FILE_DESCRIPTOR_SET_POSIX_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_descriptor_posix.h"
+#include "nsISupportsImpl.h"
+
+// -----------------------------------------------------------------------------
+// A FileDescriptorSet is an ordered set of POSIX file descriptors. These are
+// associated with IPC messages so that descriptors can be transmitted over a
+// UNIX domain socket.
+// -----------------------------------------------------------------------------
+class FileDescriptorSet {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileDescriptorSet)
+ FileDescriptorSet();
+
+ // Mac and Linux both limit the number of file descriptors per message to
+ // slightly more than 250.
+ enum {
+ MAX_DESCRIPTORS_PER_MESSAGE = 250
+ };
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for building during message serialisation...
+
+ // Add a descriptor to the end of the set. Returns false iff the set is full.
+ bool Add(int fd);
+ // Add a descriptor to the end of the set and automatically close it after
+ // transmission. Returns false iff the set is full.
+ bool AddAndAutoClose(int fd);
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for accessing during message deserialisation...
+
+ // Return the number of descriptors
+ unsigned size() const { return descriptors_.size(); }
+ // Return true if no unconsumed descriptors remain
+ bool empty() const { return descriptors_.empty(); }
+ // Fetch the nth descriptor from the beginning of the set. Code using this
+ // /must/ access the descriptors in order, except that it may wrap from the
+ // end to index 0 again.
+ //
+ // This interface is designed for the deserialising code as it doesn't
+ // support close flags.
+ // returns: file descriptor, or -1 on error
+ int GetDescriptorAt(unsigned n) const;
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for transmission...
+
+ // Fill an array with file descriptors without 'consuming' them. CommitAll
+ // must be called after these descriptors have been transmitted.
+ // buffer: (output) a buffer of, at least, size() integers.
+ void GetDescriptors(int* buffer) const;
+ // This must be called after transmitting the descriptors returned by
+ // GetDescriptors. It marks all the descriptors as consumed and closes those
+ // which are auto-close.
+ void CommitAll();
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for receiving...
+
+ // Set the contents of the set from the given buffer. This set must be empty
+ // before calling. The auto-close flag is set on all the descriptors so that
+ // unconsumed descriptors are closed on destruction.
+ void SetDescriptors(const int* buffer, unsigned count);
+
+ // ---------------------------------------------------------------------------
+
+ private:
+ ~FileDescriptorSet();
+
+ // A vector of descriptors and close flags. If this message is sent, then
+ // these descriptors are sent as control data. After sending, any descriptors
+ // with a true flag are closed. If this message has been received, then these
+ // are the descriptors which were received and all close flags are true.
+ std::vector<base::FileDescriptor> descriptors_;
+
+ // This contains the index of the next descriptor which should be consumed.
+ // It's used in a couple of ways. Firstly, at destruction we can check that
+ // all the descriptors have been read (with GetNthDescriptor). Secondly, we
+ // can check that they are read in order.
+ mutable unsigned consumed_descriptor_highwater_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorSet);
+};
+
+#endif // CHROME_COMMON_FILE_DESCRIPTOR_SET_POSIX_H_
diff --git a/ipc/chromium/src/chrome/common/ipc_channel.cc b/ipc/chromium/src/chrome/common/ipc_channel.cc
new file mode 100644
index 000000000..3d24d57b5
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel.cc
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ipc_channel.h"
+
+#include <limits>
+
+#include "base/atomic_sequence_num.h"
+#include "base/process_util.h"
+#include "base/rand_util.h"
+#include "base/string_util.h"
+
+namespace {
+
+// Global atomic used to guarantee channel IDs are unique.
+base::StaticAtomicSequenceNumber g_last_id;
+
+} // namespace
+
+namespace IPC {
+
+// static
+std::wstring Channel::GenerateUniqueRandomChannelID() {
+ // Note: the string must start with the current process id, this is how
+ // some child processes determine the pid of the parent.
+ //
+ // This is composed of a unique incremental identifier, the process ID of
+ // the creator, an identifier for the child instance, and a strong random
+ // component. The strong random component prevents other processes from
+ // hijacking or squatting on predictable channel names.
+
+ return StringPrintf(L"%d.%u.%d",
+ base::GetCurrentProcId(),
+ g_last_id.GetNext(),
+ base::RandInt(0, std::numeric_limits<int32_t>::max()));
+}
+
+} // namespace IPC \ No newline at end of file
diff --git a/ipc/chromium/src/chrome/common/ipc_channel.h b/ipc/chromium/src/chrome/common/ipc_channel.h
new file mode 100644
index 000000000..e6b45986e
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel.h
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_CHANNEL_H_
+#define CHROME_COMMON_IPC_CHANNEL_H_
+
+#include <string>
+
+#include <queue>
+#include "chrome/common/ipc_message.h"
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+class Channel {
+ // Security tests need access to the pipe handle.
+ friend class ChannelTest;
+
+ public:
+ // Implemented by consumers of a Channel to receive messages.
+ class Listener {
+ public:
+ virtual ~Listener() {}
+
+ // Called when a message is received.
+ virtual void OnMessageReceived(Message&& message) = 0;
+
+ // Called when the channel is connected and we have received the internal
+ // Hello message from the peer.
+ virtual void OnChannelConnected(int32_t peer_pid) {}
+
+ // Called when an error is detected that causes the channel to close.
+ // This method is not called when a channel is closed normally.
+ virtual void OnChannelError() {}
+
+ // If the listener has queued messages, swap them for |queue| like so
+ // swap(impl->my_queued_messages, queue);
+ virtual void GetQueuedMessages(std::queue<Message>& queue) {}
+ };
+
+ enum Mode {
+ MODE_SERVER,
+ MODE_CLIENT
+ };
+
+ enum {
+ // The maximum message size in bytes. Attempting to receive a
+ // message of this size or bigger results in a channel error.
+ kMaximumMessageSize = 256 * 1024 * 1024,
+
+ // Ammount of data to read at once from the pipe.
+ kReadBufferSize = 4 * 1024,
+
+ // Maximum size of a message that we allow to be copied (rather than moved).
+ kMaxCopySize = 32 * 1024,
+ };
+
+ // Initialize a Channel.
+ //
+ // |channel_id| identifies the communication Channel.
+ // |mode| specifies whether this Channel is to operate in server mode or
+ // client mode. In server mode, the Channel is responsible for setting up the
+ // IPC object, whereas in client mode, the Channel merely connects to the
+ // already established IPC object.
+ // |listener| receives a callback on the current thread for each newly
+ // received message.
+ //
+ Channel(const std::wstring& channel_id, Mode mode, Listener* listener);
+
+ // XXX it would nice not to have yet more platform-specific code in
+ // here but it's just not worth the trouble.
+# if defined(OS_POSIX)
+ // Connect to a pre-created channel |fd| as |mode|.
+ Channel(int fd, Mode mode, Listener* listener);
+# elif defined(OS_WIN)
+ // Connect to a pre-created channel as |mode|. Clients connect to
+ // the pre-existing server pipe, and servers take over |server_pipe|.
+ Channel(const std::wstring& channel_id, void* server_pipe,
+ Mode mode, Listener* listener);
+# endif
+
+ ~Channel();
+
+ // Connect the pipe. On the server side, this will initiate
+ // waiting for connections. On the client, it attempts to
+ // connect to a pre-existing pipe. Note, calling Connect()
+ // will not block the calling thread and may complete
+ // asynchronously.
+ bool Connect();
+
+ // Close this Channel explicitly. May be called multiple times.
+ void Close();
+
+ // Modify the Channel's listener.
+ Listener* set_listener(Listener* listener);
+
+ // Send a message over the Channel to the listener on the other end.
+ //
+ // |message| must be allocated using operator new. This object will be
+ // deleted once the contents of the Message have been sent.
+ //
+ // If you Send() a message on a Close()'d channel, we delete the message
+ // immediately.
+ bool Send(Message* message);
+
+ // Unsound_IsClosed() and Unsound_NumQueuedMessages() are safe to call from
+ // any thread, but the value returned may be out of date, because we don't
+ // use any synchronization when reading or writing it.
+ bool Unsound_IsClosed() const;
+ uint32_t Unsound_NumQueuedMessages() const;
+
+#if defined(OS_POSIX)
+ // On POSIX an IPC::Channel wraps a socketpair(), this method returns the
+ // FD # for the client end of the socket and the equivalent FD# to use for
+ // mapping it into the Child process.
+ // This method may only be called on the server side of a channel.
+ //
+ // If the kTestingChannelID flag is specified on the command line then
+ // a named FIFO is used as the channel transport mechanism rather than a
+ // socketpair() in which case this method returns -1 for both parameters.
+ void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
+
+ // Return the file descriptor for communication with the peer.
+ int GetFileDescriptor() const;
+
+ // Reset the file descriptor for communication with the peer.
+ void ResetFileDescriptor(int fd);
+
+ // Close the client side of the socketpair.
+ void CloseClientFileDescriptor();
+
+#elif defined(OS_WIN)
+ // Return the server pipe handle.
+ void* GetServerPipeHandle() const;
+#endif // defined(OS_POSIX)
+
+ // Generates a channel ID that's non-predictable and unique.
+ static std::wstring GenerateUniqueRandomChannelID();
+
+ // Generates a channel ID that, if passed to the client as a shared secret,
+ // will validate that the client's authenticity. On platforms that do not
+ // require additional validation this is simply calls GenerateUniqueRandomChannelID().
+ // For portability the prefix should not include the \ character.
+ static std::wstring GenerateVerifiedChannelID(const std::wstring& prefix);
+
+ private:
+ // PIMPL to which all channel calls are delegated.
+ class ChannelImpl;
+ ChannelImpl *channel_impl_;
+
+ enum {
+#if defined(OS_MACOSX)
+ // If the channel receives a message that contains file descriptors, then
+ // it will reply back with this message, indicating that the message has
+ // been received. The sending channel can then close any descriptors that
+ // had been marked as auto_close. This works around a sendmsg() bug on BSD
+ // where the kernel can eagerly close file descriptors that are in message
+ // queues but not yet delivered.
+ RECEIVED_FDS_MESSAGE_TYPE = kuint16max - 1,
+#endif
+
+ // The Hello message is internal to the Channel class. It is sent
+ // by the peer when the channel is connected. The message contains
+ // just the process id (pid). The message has a special routing_id
+ // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE).
+ HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16_t),
+ // to avoid conflicting with normal
+ // message types, which are enumeration
+ // constants starting from 0.
+ };
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_IPC_CHANNEL_H_
diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
new file mode 100644
index 000000000..0d3a2b16c
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -0,0 +1,958 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ipc_channel_posix.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#if defined(OS_MACOSX)
+#include <sched.h>
+#endif
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+
+#include <string>
+#include <map>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/lock.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/singleton.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/file_descriptor_set_posix.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/UniquePtr.h"
+
+#ifdef MOZ_FAULTY
+#include "mozilla/ipc/Faulty.h"
+#endif
+
+// Work around possible OS limitations.
+static const size_t kMaxIOVecSize = 256;
+
+#ifdef MOZ_TASK_TRACER
+#include "GeckoTaskTracerImpl.h"
+using namespace mozilla::tasktracer;
+#endif
+
+namespace IPC {
+
+// IPC channels on Windows use named pipes (CreateNamedPipe()) with
+// channel ids as the pipe names. Channels on POSIX use anonymous
+// Unix domain sockets created via socketpair() as pipes. These don't
+// quite line up.
+//
+// When creating a child subprocess, the parent side of the fork
+// arranges it such that the initial control channel ends up on the
+// magic file descriptor kClientChannelFd in the child. Future
+// connections (file descriptors) can then be passed via that
+// connection via sendmsg().
+
+//------------------------------------------------------------------------------
+namespace {
+
+// The PipeMap class works around this quirk related to unit tests:
+//
+// When running as a server, we install the client socket in a
+// specific file descriptor number (@kClientChannelFd). However, we
+// also have to support the case where we are running unittests in the
+// same process. (We do not support forking without execing.)
+//
+// Case 1: normal running
+// The IPC server object will install a mapping in PipeMap from the
+// name which it was given to the client pipe. When forking the client, the
+// GetClientFileDescriptorMapping will ensure that the socket is installed in
+// the magic slot (@kClientChannelFd). The client will search for the
+// mapping, but it won't find any since we are in a new process. Thus the
+// magic fd number is returned. Once the client connects, the server will
+// close its copy of the client socket and remove the mapping.
+//
+// Case 2: unittests - client and server in the same process
+// The IPC server will install a mapping as before. The client will search
+// for a mapping and find out. It duplicates the file descriptor and
+// connects. Once the client connects, the server will close the original
+// copy of the client socket and remove the mapping. Thus, when the client
+// object closes, it will close the only remaining copy of the client socket
+// in the fd table and the server will see EOF on its side.
+//
+// TODO(port): a client process cannot connect to multiple IPC channels with
+// this scheme.
+
+class PipeMap {
+ public:
+ // Lookup a given channel id. Return -1 if not found.
+ int Lookup(const std::string& channel_id) {
+ AutoLock locked(lock_);
+
+ ChannelToFDMap::const_iterator i = map_.find(channel_id);
+ if (i == map_.end())
+ return -1;
+ return i->second;
+ }
+
+ // Remove the mapping for the given channel id. No error is signaled if the
+ // channel_id doesn't exist
+ void Remove(const std::string& channel_id) {
+ AutoLock locked(lock_);
+
+ ChannelToFDMap::iterator i = map_.find(channel_id);
+ if (i != map_.end())
+ map_.erase(i);
+ }
+
+ // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
+ // mapping if one already exists for the given channel_id
+ void Insert(const std::string& channel_id, int fd) {
+ AutoLock locked(lock_);
+ DCHECK(fd != -1);
+
+ ChannelToFDMap::const_iterator i = map_.find(channel_id);
+ CHECK(i == map_.end()) << "Creating second IPC server for '"
+ << channel_id
+ << "' while first still exists";
+ map_[channel_id] = fd;
+ }
+
+ private:
+ Lock lock_;
+ typedef std::map<std::string, int> ChannelToFDMap;
+ ChannelToFDMap map_;
+};
+
+// This is the file descriptor number that a client process expects to find its
+// IPC socket.
+static const int kClientChannelFd = 3;
+
+// Used to map a channel name to the equivalent FD # in the client process.
+int ChannelNameToClientFD(const std::string& channel_id) {
+ // See the large block comment above PipeMap for the reasoning here.
+ const int fd = Singleton<PipeMap>()->Lookup(channel_id);
+ if (fd != -1)
+ return dup(fd);
+
+ // If we don't find an entry, we assume that the correct value has been
+ // inserted in the magic slot.
+ return kClientChannelFd;
+}
+
+//------------------------------------------------------------------------------
+const size_t kMaxPipeNameLength = sizeof(((sockaddr_un*)0)->sun_path);
+
+bool SetCloseOnExec(int fd) {
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return false;
+
+ flags |= FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, flags) == -1)
+ return false;
+
+ return true;
+}
+
+} // namespace
+//------------------------------------------------------------------------------
+
+Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
+ Listener* listener)
+ : factory_(this) {
+ Init(mode, listener);
+
+ if (!CreatePipe(channel_id, mode)) {
+ // The pipe may have been closed already.
+ CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
+ "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
+ " mode error(" << strerror(errno) << ").";
+ }
+}
+
+Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
+ : factory_(this) {
+ Init(mode, listener);
+ pipe_ = fd;
+ waiting_connect_ = (MODE_SERVER == mode);
+
+ EnqueueHelloMessage();
+}
+
+void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
+ DCHECK(kControlBufferSlopBytes >= CMSG_SPACE(0));
+
+ mode_ = mode;
+ is_blocked_on_write_ = false;
+ partial_write_iter_.reset();
+ input_buf_offset_ = 0;
+ server_listen_pipe_ = -1;
+ pipe_ = -1;
+ client_pipe_ = -1;
+ listener_ = listener;
+ waiting_connect_ = true;
+ processing_incoming_ = false;
+ closed_ = false;
+#if defined(OS_MACOSX)
+ last_pending_fd_id_ = 0;
+#endif
+ output_queue_length_ = 0;
+}
+
+bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
+ Mode mode) {
+ DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
+
+ // socketpair()
+ pipe_name_ = WideToASCII(channel_id);
+ if (mode == MODE_SERVER) {
+ int pipe_fds[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
+ mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeSocketPairErrno", errno);
+ return false;
+ }
+ // Set both ends to be non-blocking.
+ if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
+ fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
+ mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeFcntlErrno", errno);
+ HANDLE_EINTR(close(pipe_fds[0]));
+ HANDLE_EINTR(close(pipe_fds[1]));
+ return false;
+ }
+
+ if (!SetCloseOnExec(pipe_fds[0]) ||
+ !SetCloseOnExec(pipe_fds[1])) {
+ mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeCloExecErrno", errno);
+ HANDLE_EINTR(close(pipe_fds[0]));
+ HANDLE_EINTR(close(pipe_fds[1]));
+ return false;
+ }
+
+ pipe_ = pipe_fds[0];
+ client_pipe_ = pipe_fds[1];
+
+ if (pipe_name_.length()) {
+ Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
+ }
+ } else {
+ pipe_ = ChannelNameToClientFD(pipe_name_);
+ DCHECK(pipe_ > 0);
+ waiting_connect_ = false;
+ }
+
+ // Create the Hello message to be sent when Connect is called
+ return EnqueueHelloMessage();
+}
+
+/**
+ * Reset the file descriptor for communication with the peer.
+ */
+void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
+ NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
+
+ EnqueueHelloMessage();
+}
+
+bool Channel::ChannelImpl::EnqueueHelloMessage() {
+ mozilla::UniquePtr<Message> msg(new Message(MSG_ROUTING_NONE,
+ HELLO_MESSAGE_TYPE));
+ if (!msg->WriteInt(base::GetCurrentProcId())) {
+ Close();
+ return false;
+ }
+
+ OutputQueuePush(msg.release());
+ return true;
+}
+
+bool Channel::ChannelImpl::Connect() {
+ if (pipe_ == -1) {
+ return false;
+ }
+
+ MessageLoopForIO::current()->WatchFileDescriptor(
+ pipe_,
+ true,
+ MessageLoopForIO::WATCH_READ,
+ &read_watcher_,
+ this);
+ waiting_connect_ = false;
+
+ if (!waiting_connect_)
+ return ProcessOutgoingMessages();
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessIncomingMessages() {
+ struct msghdr msg = {0};
+ struct iovec iov;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = input_cmsg_buf_;
+
+ for (;;) {
+ msg.msg_controllen = sizeof(input_cmsg_buf_);
+
+ if (pipe_ == -1)
+ return false;
+
+ // In some cases the beginning of a message will be stored in input_buf_. We
+ // don't want to overwrite that, so we store the new data after it.
+ iov.iov_base = input_buf_ + input_buf_offset_;
+ iov.iov_len = Channel::kReadBufferSize - input_buf_offset_;
+
+ // Read from pipe.
+ // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
+ // is waiting on the pipe.
+ ssize_t bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+
+ if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ return true;
+ } else {
+ CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
+ return false;
+ }
+ } else if (bytes_read == 0) {
+ // The pipe has closed...
+ Close();
+ return false;
+ }
+ DCHECK(bytes_read);
+
+ if (client_pipe_ != -1) {
+ Singleton<PipeMap>()->Remove(pipe_name_);
+ HANDLE_EINTR(close(client_pipe_));
+ client_pipe_ = -1;
+ }
+
+ // a pointer to an array of |num_wire_fds| file descriptors from the read
+ const int* wire_fds = NULL;
+ unsigned num_wire_fds = 0;
+
+ // walk the list of control messages and, if we find an array of file
+ // descriptors, save a pointer to the array
+
+ // This next if statement is to work around an OSX issue where
+ // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
+ // Here's a test case:
+ //
+ // int main() {
+ // struct msghdr msg;
+ // msg.msg_control = &msg;
+ // msg.msg_controllen = 0;
+ // if (CMSG_FIRSTHDR(&msg))
+ // printf("Bug found!\n");
+ // }
+ if (msg.msg_controllen > 0) {
+ // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
+ // and will return a pointer into nowhere.
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+ DCHECK(payload_len % sizeof(int) == 0);
+ wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ num_wire_fds = payload_len / 4;
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ CHROMIUM_LOG(ERROR) << "SCM_RIGHTS message was truncated"
+ << " cmsg_len:" << cmsg->cmsg_len
+ << " fd:" << pipe_;
+ for (unsigned i = 0; i < num_wire_fds; ++i)
+ HANDLE_EINTR(close(wire_fds[i]));
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ // Process messages from input buffer.
+ const char *p = input_buf_;
+ const char *end = input_buf_ + input_buf_offset_ + bytes_read;
+
+ // A pointer to an array of |num_fds| file descriptors which includes any
+ // fds that have spilled over from a previous read.
+ const int* fds;
+ unsigned num_fds;
+ unsigned fds_i = 0; // the index of the first unused descriptor
+
+ if (input_overflow_fds_.empty()) {
+ fds = wire_fds;
+ num_fds = num_wire_fds;
+ } else {
+ const size_t prev_size = input_overflow_fds_.size();
+ input_overflow_fds_.resize(prev_size + num_wire_fds);
+ memcpy(&input_overflow_fds_[prev_size], wire_fds,
+ num_wire_fds * sizeof(int));
+ fds = &input_overflow_fds_[0];
+ num_fds = input_overflow_fds_.size();
+ }
+
+ // The data for the message we're currently reading consists of any data
+ // stored in incoming_message_ followed by data in input_buf_ (followed by
+ // other messages).
+
+ while (p < end) {
+ // Try to figure out how big the message is. Size is 0 if we haven't read
+ // enough of the header to know the size.
+ uint32_t message_length = 0;
+ if (incoming_message_.isSome()) {
+ message_length = incoming_message_.ref().size();
+ } else {
+ message_length = Message::MessageSize(p, end);
+ }
+
+ if (!message_length) {
+ // We haven't seen the full message header.
+ MOZ_ASSERT(incoming_message_.isNothing());
+
+ // Move everything we have to the start of the buffer. We'll finish
+ // reading this message when we get more data. For now we leave it in
+ // input_buf_.
+ memmove(input_buf_, p, end - p);
+ input_buf_offset_ = end - p;
+
+ break;
+ }
+
+ input_buf_offset_ = 0;
+
+ bool partial;
+ if (incoming_message_.isSome()) {
+ // We already have some data for this message stored in
+ // incoming_message_. We want to append the new data there.
+ Message& m = incoming_message_.ref();
+
+ // How much data from this message remains to be added to
+ // incoming_message_?
+ MOZ_ASSERT(message_length > m.CurrentSize());
+ uint32_t remaining = message_length - m.CurrentSize();
+
+ // How much data from this message is stored in input_buf_?
+ uint32_t in_buf = std::min(remaining, uint32_t(end - p));
+
+ m.InputBytes(p, in_buf);
+ p += in_buf;
+
+ // Are we done reading this message?
+ partial = in_buf != remaining;
+ } else {
+ // How much data from this message is stored in input_buf_?
+ uint32_t in_buf = std::min(message_length, uint32_t(end - p));
+
+ incoming_message_.emplace(p, in_buf);
+ p += in_buf;
+
+ // Are we done reading this message?
+ partial = in_buf != message_length;
+ }
+
+ if (partial) {
+ break;
+ }
+
+ Message& m = incoming_message_.ref();
+
+ if (m.header()->num_fds) {
+ // the message has file descriptors
+ const char* error = NULL;
+ if (m.header()->num_fds > num_fds - fds_i) {
+ // the message has been completely received, but we didn't get
+ // enough file descriptors.
+ error = "Message needs unreceived descriptors";
+ }
+
+ if (m.header()->num_fds >
+ FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
+ // There are too many descriptors in this message
+ error = "Message requires an excessive number of descriptors";
+ }
+
+ if (error) {
+ CHROMIUM_LOG(WARNING) << error
+ << " channel:" << this
+ << " message-type:" << m.type()
+ << " header()->num_fds:" << m.header()->num_fds
+ << " num_fds:" << num_fds
+ << " fds_i:" << fds_i;
+ // close the existing file descriptors so that we don't leak them
+ for (unsigned i = fds_i; i < num_fds; ++i)
+ HANDLE_EINTR(close(fds[i]));
+ input_overflow_fds_.clear();
+ // abort the connection
+ return false;
+ }
+
+#if defined(OS_MACOSX)
+ // Send a message to the other side, indicating that we are now
+ // responsible for closing the descriptor.
+ Message *fdAck = new Message(MSG_ROUTING_NONE,
+ RECEIVED_FDS_MESSAGE_TYPE);
+ DCHECK(m.fd_cookie() != 0);
+ fdAck->set_fd_cookie(m.fd_cookie());
+ OutputQueuePush(fdAck);
+#endif
+
+ m.file_descriptor_set()->SetDescriptors(
+ &fds[fds_i], m.header()->num_fds);
+ fds_i += m.header()->num_fds;
+ }
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "received message on channel @" << this <<
+ " with type " << m.type();
+#endif
+
+#ifdef MOZ_TASK_TRACER
+ AutoSaveCurTraceInfo saveCurTraceInfo;
+ SetCurTraceInfo(m.header()->source_event_id,
+ m.header()->parent_task_id,
+ m.header()->source_event_type);
+#endif
+
+ if (m.routing_id() == MSG_ROUTING_NONE &&
+ m.type() == HELLO_MESSAGE_TYPE) {
+ // The Hello message contains only the process id.
+ listener_->OnChannelConnected(MessageIterator(m).NextInt());
+#if defined(OS_MACOSX)
+ } else if (m.routing_id() == MSG_ROUTING_NONE &&
+ m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
+ DCHECK(m.fd_cookie() != 0);
+ CloseDescriptors(m.fd_cookie());
+#endif
+ } else {
+ listener_->OnMessageReceived(mozilla::Move(m));
+ }
+
+ incoming_message_.reset();
+ }
+
+ input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
+
+ // When the input data buffer is empty, the overflow fds should be too. If
+ // this is not the case, we probably have a rogue renderer which is trying
+ // to fill our descriptor table.
+ if (incoming_message_.isNothing() && input_buf_offset_ == 0 && !input_overflow_fds_.empty()) {
+ // We close these descriptors in Close()
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessOutgoingMessages() {
+ DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
+ // no connection?
+ is_blocked_on_write_ = false;
+
+ if (output_queue_.empty())
+ return true;
+
+ if (pipe_ == -1)
+ return false;
+
+ // Write out all the messages we can till the write blocks or there are no
+ // more outgoing messages.
+ while (!output_queue_.empty()) {
+#ifdef MOZ_FAULTY
+ Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
+#endif
+ Message* msg = output_queue_.front();
+
+ struct msghdr msgh = {0};
+
+ static const int tmp = CMSG_SPACE(sizeof(
+ int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
+ char buf[tmp];
+
+ if (partial_write_iter_.isNothing()) {
+ Pickle::BufferList::IterImpl iter(msg->Buffers());
+ partial_write_iter_.emplace(iter);
+ }
+
+ if (partial_write_iter_.value().Data() == msg->Buffers().Start() &&
+ !msg->file_descriptor_set()->empty()) {
+ // This is the first chunk of a message which has descriptors to send
+ struct cmsghdr *cmsg;
+ const unsigned num_fds = msg->file_descriptor_set()->size();
+
+ if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
+ CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
+ // This should not be reached.
+ return false;
+ }
+
+ msgh.msg_control = buf;
+ msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
+ msg->file_descriptor_set()->GetDescriptors(
+ reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+ msgh.msg_controllen = cmsg->cmsg_len;
+
+ msg->header()->num_fds = num_fds;
+#if defined(OS_MACOSX)
+ msg->set_fd_cookie(++last_pending_fd_id_);
+#endif
+ }
+
+ struct iovec iov[kMaxIOVecSize];
+ size_t iov_count = 0;
+ size_t amt_to_write = 0;
+
+ // How much of this message have we written so far?
+ Pickle::BufferList::IterImpl iter = partial_write_iter_.value();
+
+ // Store the unwritten part of the first segment to write into the iovec.
+ iov[0].iov_base = const_cast<char*>(iter.Data());
+ iov[0].iov_len = iter.RemainingInSegment();
+ amt_to_write += iov[0].iov_len;
+ iter.Advance(msg->Buffers(), iov[0].iov_len);
+ iov_count++;
+
+ // Store remaining segments to write into iovec.
+ while (!iter.Done()) {
+ char* data = iter.Data();
+ size_t size = iter.RemainingInSegment();
+
+ // Don't add more than kMaxIOVecSize to the iovec so that we avoid
+ // OS-dependent limits.
+ if (iov_count < kMaxIOVecSize) {
+ iov[iov_count].iov_base = data;
+ iov[iov_count].iov_len = size;
+ iov_count++;
+ }
+ amt_to_write += size;
+ iter.Advance(msg->Buffers(), size);
+ }
+
+ msgh.msg_iov = iov;
+ msgh.msg_iovlen = iov_count;
+
+ ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
+
+#if !defined(OS_MACOSX)
+ // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
+ // message.
+ if (bytes_written > 0)
+ msg->file_descriptor_set()->CommitAll();
+#endif
+
+ if (bytes_written < 0) {
+ switch (errno) {
+ case EAGAIN:
+ // Not an error; the sendmsg would have blocked, so return to the
+ // event loop and try again later.
+ break;
+#if defined(OS_MACOSX)
+ // (Note: this comment is copied from https://crrev.com/86c3d9ef4fdf6;
+ // see also bug 1142693 comment #73.)
+ //
+ // On OS X if sendmsg() is trying to send fds between processes and
+ // there isn't enough room in the output buffer to send the fd
+ // structure over atomically then EMSGSIZE is returned.
+ //
+ // EMSGSIZE presents a problem since the system APIs can only call us
+ // when there's room in the socket buffer and not when there is
+ // "enough" room.
+ //
+ // The current behavior is to return to the event loop when EMSGSIZE
+ // is received and hopefull service another FD. This is however still
+ // technically a busy wait since the event loop will call us right
+ // back until the receiver has read enough data to allow passing the
+ // FD over atomically.
+ case EMSGSIZE:
+ // Because this is likely to result in a busy-wait, we'll try to make
+ // it easier for the receiver to make progress.
+ sched_yield();
+ break;
+#endif
+ default:
+ CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
+ return false;
+ }
+ }
+
+ if (static_cast<size_t>(bytes_written) != amt_to_write) {
+ // If write() fails with EAGAIN then bytes_written will be -1.
+ if (bytes_written > 0) {
+ partial_write_iter_.ref().AdvanceAcrossSegments(msg->Buffers(), bytes_written);
+ }
+
+ // Tell libevent to call us back once things are unblocked.
+ is_blocked_on_write_ = true;
+ MessageLoopForIO::current()->WatchFileDescriptor(
+ pipe_,
+ false, // One shot
+ MessageLoopForIO::WATCH_WRITE,
+ &write_watcher_,
+ this);
+ return true;
+ } else {
+ partial_write_iter_.reset();
+
+#if defined(OS_MACOSX)
+ if (!msg->file_descriptor_set()->empty())
+ pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(),
+ msg->file_descriptor_set()));
+#endif
+
+ // Message sent OK!
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
+ " with type " << msg->type();
+#endif
+ OutputQueuePop();
+ delete msg;
+ }
+ }
+ return true;
+}
+
+bool Channel::ChannelImpl::Send(Message* message) {
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "sending message @" << message << " on channel @" << this
+ << " with type " << message->type()
+ << " (" << output_queue_.size() << " in queue)";
+#endif
+
+
+ // If the channel has been closed, ProcessOutgoingMessages() is never going
+ // to pop anything off output_queue; output_queue will only get emptied when
+ // the channel is destructed. We might as well delete message now, instead
+ // of waiting for the channel to be destructed.
+ if (closed_) {
+ if (mozilla::ipc::LoggingEnabled()) {
+ fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
+ message->name());
+ }
+ delete message;
+ return false;
+ }
+
+ OutputQueuePush(message);
+ if (!waiting_connect_) {
+ if (!is_blocked_on_write_) {
+ if (!ProcessOutgoingMessages())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
+ int *dest_fd) const {
+ DCHECK(mode_ == MODE_SERVER);
+ *src_fd = client_pipe_;
+ *dest_fd = kClientChannelFd;
+}
+
+void Channel::ChannelImpl::CloseClientFileDescriptor() {
+ if (client_pipe_ != -1) {
+ Singleton<PipeMap>()->Remove(pipe_name_);
+ HANDLE_EINTR(close(client_pipe_));
+ client_pipe_ = -1;
+ }
+}
+
+// Called by libevent when we can read from th pipe without blocking.
+void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
+ if (!waiting_connect_ && fd == pipe_) {
+ if (!ProcessIncomingMessages()) {
+ Close();
+ listener_->OnChannelError();
+ // The OnChannelError() call may delete this, so we need to exit now.
+ return;
+ }
+ }
+}
+
+#if defined(OS_MACOSX)
+void Channel::ChannelImpl::CloseDescriptors(uint32_t pending_fd_id)
+{
+ DCHECK(pending_fd_id != 0);
+ for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
+ i != pending_fds_.end();
+ i++) {
+ if ((*i).id == pending_fd_id) {
+ (*i).fds->CommitAll();
+ pending_fds_.erase(i);
+ return;
+ }
+ }
+ DCHECK(false) << "pending_fd_id not in our list!";
+}
+#endif
+
+void Channel::ChannelImpl::OutputQueuePush(Message* msg)
+{
+#ifdef MOZ_TASK_TRACER
+ // Save the current TaskTracer info into the message header.
+ GetCurTraceInfo(&msg->header()->source_event_id,
+ &msg->header()->parent_task_id,
+ &msg->header()->source_event_type);
+#endif
+ output_queue_.push(msg);
+ output_queue_length_++;
+}
+
+void Channel::ChannelImpl::OutputQueuePop()
+{
+ output_queue_.pop();
+ output_queue_length_--;
+}
+
+// Called by libevent when we can write to the pipe without blocking.
+void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
+ if (!ProcessOutgoingMessages()) {
+ Close();
+ listener_->OnChannelError();
+ }
+}
+
+void Channel::ChannelImpl::Close() {
+ // Close can be called multiple times, so we need to make sure we're
+ // idempotent.
+
+ // Unregister libevent for the listening socket and close it.
+ server_listen_connection_watcher_.StopWatchingFileDescriptor();
+
+ if (server_listen_pipe_ != -1) {
+ HANDLE_EINTR(close(server_listen_pipe_));
+ server_listen_pipe_ = -1;
+ }
+
+ // Unregister libevent for the FIFO and close it.
+ read_watcher_.StopWatchingFileDescriptor();
+ write_watcher_.StopWatchingFileDescriptor();
+ if (pipe_ != -1) {
+ HANDLE_EINTR(close(pipe_));
+ pipe_ = -1;
+ }
+ if (client_pipe_ != -1) {
+ Singleton<PipeMap>()->Remove(pipe_name_);
+ HANDLE_EINTR(close(client_pipe_));
+ client_pipe_ = -1;
+ }
+
+ while (!output_queue_.empty()) {
+ Message* m = output_queue_.front();
+ OutputQueuePop();
+ delete m;
+ }
+
+ // Close any outstanding, received file descriptors
+ for (std::vector<int>::iterator
+ i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
+ HANDLE_EINTR(close(*i));
+ }
+ input_overflow_fds_.clear();
+
+#if defined(OS_MACOSX)
+ for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
+ i != pending_fds_.end();
+ i++) {
+ (*i).fds->CommitAll();
+ }
+ pending_fds_.clear();
+#endif
+
+ closed_ = true;
+}
+
+bool Channel::ChannelImpl::Unsound_IsClosed() const
+{
+ return closed_;
+}
+
+uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const
+{
+ return output_queue_length_;
+}
+
+//------------------------------------------------------------------------------
+// Channel's methods simply call through to ChannelImpl.
+Channel::Channel(const std::wstring& channel_id, Mode mode,
+ Listener* listener)
+ : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
+ MOZ_COUNT_CTOR(IPC::Channel);
+}
+
+Channel::Channel(int fd, Mode mode, Listener* listener)
+ : channel_impl_(new ChannelImpl(fd, mode, listener)) {
+ MOZ_COUNT_CTOR(IPC::Channel);
+}
+
+Channel::~Channel() {
+ MOZ_COUNT_DTOR(IPC::Channel);
+ delete channel_impl_;
+}
+
+bool Channel::Connect() {
+ return channel_impl_->Connect();
+}
+
+void Channel::Close() {
+ channel_impl_->Close();
+}
+
+Channel::Listener* Channel::set_listener(Listener* listener) {
+ return channel_impl_->set_listener(listener);
+}
+
+bool Channel::Send(Message* message) {
+ return channel_impl_->Send(message);
+}
+
+void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
+ return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
+}
+
+void Channel::ResetFileDescriptor(int fd) {
+ channel_impl_->ResetFileDescriptor(fd);
+}
+
+int Channel::GetFileDescriptor() const {
+ return channel_impl_->GetFileDescriptor();
+}
+
+void Channel::CloseClientFileDescriptor() {
+ channel_impl_->CloseClientFileDescriptor();
+}
+
+bool Channel::Unsound_IsClosed() const {
+ return channel_impl_->Unsound_IsClosed();
+}
+
+uint32_t Channel::Unsound_NumQueuedMessages() const {
+ return channel_impl_->Unsound_NumQueuedMessages();
+}
+
+// static
+std::wstring Channel::GenerateVerifiedChannelID(const std::wstring& prefix) {
+ // A random name is sufficient validation on posix systems, so we don't need
+ // an additional shared secret.
+
+ std::wstring id = prefix;
+ if (!id.empty())
+ id.append(L".");
+
+ return id.append(GenerateUniqueRandomChannelID());
+}
+
+} // namespace IPC
diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.h b/ipc/chromium/src/chrome/common/ipc_channel_posix.h
new file mode 100644
index 000000000..1dfa33057
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.h
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_CHANNEL_POSIX_H_
+#define CHROME_COMMON_IPC_CHANNEL_POSIX_H_
+
+#include "chrome/common/ipc_channel.h"
+
+#include <sys/socket.h> // for CMSG macros
+
+#include <queue>
+#include <string>
+#include <vector>
+#include <list>
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "chrome/common/file_descriptor_set_posix.h"
+
+#include "nsAutoPtr.h"
+
+#include "mozilla/Maybe.h"
+
+namespace IPC {
+
+// An implementation of ChannelImpl for POSIX systems that works via
+// socketpairs. See the .cc file for an overview of the implementation.
+class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
+ public:
+ // Mirror methods of Channel, see ipc_channel.h for description.
+ ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
+ ChannelImpl(int fd, Mode mode, Listener* listener);
+ ~ChannelImpl() { Close(); }
+ bool Connect();
+ void Close();
+ Listener* set_listener(Listener* listener) {
+ Listener* old = listener_;
+ listener_ = listener;
+ return old;
+ }
+ bool Send(Message* message);
+ void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
+
+ void ResetFileDescriptor(int fd);
+
+ int GetFileDescriptor() const {
+ return pipe_;
+ }
+ void CloseClientFileDescriptor();
+
+ // See the comment in ipc_channel.h for info on Unsound_IsClosed() and
+ // Unsound_NumQueuedMessages().
+ bool Unsound_IsClosed() const;
+ uint32_t Unsound_NumQueuedMessages() const;
+
+ private:
+ void Init(Mode mode, Listener* listener);
+ bool CreatePipe(const std::wstring& channel_id, Mode mode);
+ bool EnqueueHelloMessage();
+
+ bool ProcessIncomingMessages();
+ bool ProcessOutgoingMessages();
+
+ // MessageLoopForIO::Watcher implementation.
+ virtual void OnFileCanReadWithoutBlocking(int fd);
+ virtual void OnFileCanWriteWithoutBlocking(int fd);
+
+#if defined(OS_MACOSX)
+ void CloseDescriptors(uint32_t pending_fd_id);
+#endif
+
+ void OutputQueuePush(Message* msg);
+ void OutputQueuePop();
+
+ Mode mode_;
+
+ // After accepting one client connection on our server socket we want to
+ // stop listening.
+ MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_;
+ MessageLoopForIO::FileDescriptorWatcher read_watcher_;
+ MessageLoopForIO::FileDescriptorWatcher write_watcher_;
+
+ // Indicates whether we're currently blocked waiting for a write to complete.
+ bool is_blocked_on_write_;
+
+ // If sending a message blocks then we use this iterator to keep track of
+ // where in the message we are. It gets reset when the message is finished
+ // sending.
+ mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;
+
+ int server_listen_pipe_;
+ int pipe_;
+ int client_pipe_; // The client end of our socketpair().
+
+ // The "name" of our pipe. On Windows this is the global identifier for
+ // the pipe. On POSIX it's used as a key in a local map of file descriptors.
+ std::string pipe_name_;
+
+ Listener* listener_;
+
+ // Messages to be sent are queued here.
+ std::queue<Message*> output_queue_;
+
+ // We read from the pipe into this buffer
+ char input_buf_[Channel::kReadBufferSize];
+ size_t input_buf_offset_;
+
+ // We want input_cmsg_buf_ to be big enough to hold
+ // CMSG_SPACE(Channel::kReadBufferSize) bytes (see the comment below for an
+ // explanation of where Channel::kReadBufferSize comes from). However,
+ // CMSG_SPACE is apparently not a constant on Macs, so we can't use it in the
+ // array size. Consequently, we pick a number here that is at least
+ // CMSG_SPACE(0) on all platforms. And we assert at runtime, in
+ // Channel::ChannelImpl::Init, that it's big enough.
+ enum {
+ kControlBufferSlopBytes = 32
+ };
+
+ // This is a control message buffer large enough to hold all the file
+ // descriptors that will be read in when reading Channel::kReadBufferSize
+ // bytes of data. Message::WriteFileDescriptor always writes one word of
+ // data for every file descriptor added to the message, so kReadBufferSize
+ // bytes of data can never be accompanied by more than
+ // kReadBufferSize / sizeof(int) file descriptors. Since a file descriptor
+ // takes sizeof(int) bytes, the control buffer must be
+ // Channel::kReadBufferSize bytes. We add kControlBufferSlopBytes bytes
+ // for the control header.
+ char input_cmsg_buf_[Channel::kReadBufferSize + kControlBufferSlopBytes];
+
+ // Large incoming messages that span multiple pipe buffers get built-up in the
+ // buffers of this message.
+ mozilla::Maybe<Message> incoming_message_;
+ std::vector<int> input_overflow_fds_;
+
+ // In server-mode, we have to wait for the client to connect before we
+ // can begin reading. We make use of the input_state_ when performing
+ // the connect operation in overlapped mode.
+ bool waiting_connect_;
+
+ // This flag is set when processing incoming messages. It is used to
+ // avoid recursing through ProcessIncomingMessages, which could cause
+ // problems. TODO(darin): make this unnecessary
+ bool processing_incoming_;
+
+ // This flag is set after we've closed the channel.
+ bool closed_;
+
+#if defined(OS_MACOSX)
+ struct PendingDescriptors {
+ uint32_t id;
+ RefPtr<FileDescriptorSet> fds;
+
+ PendingDescriptors() : id(0) { }
+ PendingDescriptors(uint32_t id, FileDescriptorSet *fds)
+ : id(id),
+ fds(fds)
+ { }
+ };
+
+ std::list<PendingDescriptors> pending_fds_;
+
+ // A generation ID for RECEIVED_FD messages.
+ uint32_t last_pending_fd_id_;
+#endif
+
+ // This variable is updated so it matches output_queue_.size(), except we can
+ // read output_queue_length_ from any thread (if we're OK getting an
+ // occasional out-of-date or bogus value). We use output_queue_length_ to
+ // implement Unsound_NumQueuedMessages.
+ size_t output_queue_length_;
+
+ ScopedRunnableMethodFactory<ChannelImpl> factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_IPC_CHANNEL_POSIX_H_
diff --git a/ipc/chromium/src/chrome/common/ipc_channel_win.cc b/ipc/chromium/src/chrome/common/ipc_channel_win.cc
new file mode 100644
index 000000000..158fb4df5
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.cc
@@ -0,0 +1,630 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ipc_channel_win.h"
+
+#include <windows.h>
+#include <sstream>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/rand_util.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+
+// ChannelImpl is used on the IPC thread, but constructed on a different thread,
+// so it has to hold the nsAutoOwningThread as a pointer, and we need a slightly
+// different macro.
+#ifdef DEBUG
+#define ASSERT_OWNINGTHREAD(_class) \
+ if (nsAutoOwningThread* owningThread = _mOwningThread.get()) { \
+ NS_CheckThreadSafe(owningThread->GetThread(), #_class " not thread-safe"); \
+ }
+#else
+#define ASSERT_OWNINGTHREAD(_class) ((void)0)
+#endif
+
+namespace IPC {
+//------------------------------------------------------------------------------
+
+Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) {
+ memset(&context.overlapped, 0, sizeof(context.overlapped));
+ context.handler = channel;
+}
+
+Channel::ChannelImpl::State::~State() {
+ COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context),
+ starts_with_io_context);
+}
+
+//------------------------------------------------------------------------------
+
+Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
+ Listener* listener)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)),
+ shared_secret_(0),
+ waiting_for_shared_secret_(false) {
+ Init(mode, listener);
+
+ if (!CreatePipe(channel_id, mode)) {
+ // The pipe may have been closed already.
+ CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
+ "\" in " << (mode == 0 ? "server" : "client") << " mode.";
+ }
+}
+
+Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id,
+ HANDLE server_pipe,
+ Mode mode, Listener* listener)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)),
+ shared_secret_(0),
+ waiting_for_shared_secret_(false) {
+ Init(mode, listener);
+
+ if (mode == MODE_SERVER) {
+ // Use the existing handle that was dup'd to us
+ pipe_ = server_pipe;
+ EnqueueHelloMessage();
+ } else {
+ // Take the normal init path to connect to the server pipe
+ CreatePipe(channel_id, mode);
+ }
+}
+
+void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
+ pipe_ = INVALID_HANDLE_VALUE;
+ listener_ = listener;
+ waiting_connect_ = (mode == MODE_SERVER);
+ processing_incoming_ = false;
+ closed_ = false;
+ output_queue_length_ = 0;
+ input_buf_offset_ = 0;
+}
+
+void Channel::ChannelImpl::OutputQueuePush(Message* msg)
+{
+ output_queue_.push(msg);
+ output_queue_length_++;
+}
+
+void Channel::ChannelImpl::OutputQueuePop()
+{
+ output_queue_.pop();
+ output_queue_length_--;
+}
+
+HANDLE Channel::ChannelImpl::GetServerPipeHandle() const {
+ return pipe_;
+}
+
+void Channel::ChannelImpl::Close() {
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+
+ bool waited = false;
+ if (input_state_.is_pending || output_state_.is_pending) {
+ CancelIo(pipe_);
+ waited = true;
+ }
+
+ // Closing the handle at this point prevents us from issuing more requests
+ // form OnIOCompleted().
+ if (pipe_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipe_);
+ pipe_ = INVALID_HANDLE_VALUE;
+ }
+
+ while (input_state_.is_pending || output_state_.is_pending) {
+ MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
+ }
+
+ while (!output_queue_.empty()) {
+ Message* m = output_queue_.front();
+ OutputQueuePop();
+ delete m;
+ }
+
+#ifdef DEBUG
+ _mOwningThread = nullptr;
+#endif
+ closed_ = true;
+}
+
+bool Channel::ChannelImpl::Send(Message* message) {
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "sending message @" << message << " on channel @" << this
+ << " with type " << message->type()
+ << " (" << output_queue_.size() << " in queue)";
+#endif
+
+
+ if (closed_) {
+ if (mozilla::ipc::LoggingEnabled()) {
+ fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
+ message->name());
+ }
+ delete message;
+ return false;
+ }
+
+ OutputQueuePush(message);
+ // ensure waiting to write
+ if (!waiting_connect_) {
+ if (!output_state_.is_pending) {
+ if (!ProcessOutgoingMessages(NULL, 0))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+const std::wstring Channel::ChannelImpl::PipeName(
+ const std::wstring& channel_id, int32_t* secret) const {
+ MOZ_ASSERT(secret);
+
+ std::wostringstream ss;
+ ss << L"\\\\.\\pipe\\chrome.";
+
+ // Prevent the shared secret from ending up in the pipe name.
+ size_t index = channel_id.find_first_of(L'\\');
+ if (index != std::string::npos) {
+ StringToInt(channel_id.substr(index + 1), secret);
+ ss << channel_id.substr(0, index - 1);
+ } else {
+ // This case is here to support predictable named pipes in tests.
+ *secret = 0;
+ ss << channel_id;
+ }
+ return ss.str();
+}
+
+bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
+ Mode mode) {
+ DCHECK(pipe_ == INVALID_HANDLE_VALUE);
+ const std::wstring pipe_name = PipeName(channel_id, &shared_secret_);
+ if (mode == MODE_SERVER) {
+ waiting_for_shared_secret_ = !!shared_secret_;
+ pipe_ = CreateNamedPipeW(pipe_name.c_str(),
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ 1, // number of pipe instances
+ // output buffer size (XXX tune)
+ Channel::kReadBufferSize,
+ // input buffer size (XXX tune)
+ Channel::kReadBufferSize,
+ 5000, // timeout in milliseconds (XXX tune)
+ NULL);
+ } else {
+ pipe_ = CreateFileW(pipe_name.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ }
+ if (pipe_ == INVALID_HANDLE_VALUE) {
+ // If this process is being closed, the pipe may be gone already.
+ CHROMIUM_LOG(WARNING) << "failed to create pipe: " << GetLastError();
+ return false;
+ }
+
+ // Create the Hello message to be sent when Connect is called
+ return EnqueueHelloMessage();
+}
+
+bool Channel::ChannelImpl::EnqueueHelloMessage() {
+ mozilla::UniquePtr<Message> m = mozilla::MakeUnique<Message>(MSG_ROUTING_NONE,
+ HELLO_MESSAGE_TYPE);
+
+ // If we're waiting for our shared secret from the other end's hello message
+ // then don't give the game away by sending it in ours.
+ int32_t secret = waiting_for_shared_secret_ ? 0 : shared_secret_;
+
+ // Also, don't send if the value is zero (for IPC backwards compatability).
+ if (!m->WriteInt(GetCurrentProcessId()) ||
+ (secret && !m->WriteUInt32(secret)))
+ {
+ CloseHandle(pipe_);
+ pipe_ = INVALID_HANDLE_VALUE;
+ return false;
+ }
+
+ OutputQueuePush(m.release());
+ return true;
+}
+
+bool Channel::ChannelImpl::Connect() {
+#ifdef DEBUG
+ if (!_mOwningThread) {
+ _mOwningThread = mozilla::MakeUnique<nsAutoOwningThread>();
+ }
+#endif
+
+ if (pipe_ == INVALID_HANDLE_VALUE)
+ return false;
+
+ MessageLoopForIO::current()->RegisterIOHandler(pipe_, this);
+
+ // Check to see if there is a client connected to our pipe...
+ if (waiting_connect_)
+ ProcessConnection();
+
+ if (!input_state_.is_pending) {
+ // Complete setup asynchronously. By not setting input_state_.is_pending
+ // to true, we indicate to OnIOCompleted that this is the special
+ // initialization signal.
+ MessageLoopForIO::current()->PostTask(factory_.NewRunnableMethod(
+ &Channel::ChannelImpl::OnIOCompleted, &input_state_.context, 0, 0));
+ }
+
+ if (!waiting_connect_)
+ ProcessOutgoingMessages(NULL, 0);
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessConnection() {
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+ if (input_state_.is_pending)
+ input_state_.is_pending = false;
+
+ // Do we have a client connected to our pipe?
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped);
+
+ DWORD err = GetLastError();
+ if (ok) {
+ // Uhm, the API documentation says that this function should never
+ // return success when used in overlapped mode.
+ NOTREACHED();
+ return false;
+ }
+
+ switch (err) {
+ case ERROR_IO_PENDING:
+ input_state_.is_pending = true;
+ break;
+ case ERROR_PIPE_CONNECTED:
+ waiting_connect_ = false;
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessIncomingMessages(
+ MessageLoopForIO::IOContext* context,
+ DWORD bytes_read) {
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+ if (input_state_.is_pending) {
+ input_state_.is_pending = false;
+ DCHECK(context);
+
+ if (!context || !bytes_read)
+ return false;
+ } else {
+ // This happens at channel initialization.
+ DCHECK(!bytes_read && context == &input_state_.context);
+ }
+
+ for (;;) {
+ if (bytes_read == 0) {
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ // Read from pipe...
+ BOOL ok = ReadFile(pipe_,
+ input_buf_ + input_buf_offset_,
+ Channel::kReadBufferSize - input_buf_offset_,
+ &bytes_read,
+ &input_state_.context.overlapped);
+ if (!ok) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ input_state_.is_pending = true;
+ return true;
+ }
+ CHROMIUM_LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+ input_state_.is_pending = true;
+ return true;
+ }
+ DCHECK(bytes_read);
+
+ // Process messages from input buffer.
+
+ const char *p = input_buf_;
+ const char *end = input_buf_ + input_buf_offset_ + bytes_read;
+
+ while (p < end) {
+ // Try to figure out how big the message is. Size is 0 if we haven't read
+ // enough of the header to know the size.
+ uint32_t message_length = 0;
+ if (incoming_message_.isSome()) {
+ message_length = incoming_message_.ref().size();
+ } else {
+ message_length = Message::MessageSize(p, end);
+ }
+
+ if (!message_length) {
+ // We haven't seen the full message header.
+ MOZ_ASSERT(incoming_message_.isNothing());
+
+ // Move everything we have to the start of the buffer. We'll finish
+ // reading this message when we get more data. For now we leave it in
+ // input_buf_.
+ memmove(input_buf_, p, end - p);
+ input_buf_offset_ = end - p;
+
+ break;
+ }
+
+ input_buf_offset_ = 0;
+
+ bool partial;
+ if (incoming_message_.isSome()) {
+ // We already have some data for this message stored in
+ // incoming_message_. We want to append the new data there.
+ Message& m = incoming_message_.ref();
+
+ // How much data from this message remains to be added to
+ // incoming_message_?
+ MOZ_ASSERT(message_length > m.CurrentSize());
+ uint32_t remaining = message_length - m.CurrentSize();
+
+ // How much data from this message is stored in input_buf_?
+ uint32_t in_buf = std::min(remaining, uint32_t(end - p));
+
+ m.InputBytes(p, in_buf);
+ p += in_buf;
+
+ // Are we done reading this message?
+ partial = in_buf != remaining;
+ } else {
+ // How much data from this message is stored in input_buf_?
+ uint32_t in_buf = std::min(message_length, uint32_t(end - p));
+
+ incoming_message_.emplace(p, in_buf);
+ p += in_buf;
+
+ // Are we done reading this message?
+ partial = in_buf != message_length;
+ }
+
+ if (partial) {
+ break;
+ }
+
+ Message& m = incoming_message_.ref();
+
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "received message on channel @" << this <<
+ " with type " << m.type();
+#endif
+ if (m.routing_id() == MSG_ROUTING_NONE &&
+ m.type() == HELLO_MESSAGE_TYPE) {
+ // The Hello message contains the process id and must include the
+ // shared secret, if we are waiting for it.
+ MessageIterator it = MessageIterator(m);
+ int32_t claimed_pid = it.NextInt();
+ if (waiting_for_shared_secret_ && (it.NextInt() != shared_secret_)) {
+ NOTREACHED();
+ // Something went wrong. Abort connection.
+ Close();
+ listener_->OnChannelError();
+ return false;
+ }
+ waiting_for_shared_secret_ = false;
+ listener_->OnChannelConnected(claimed_pid);
+ } else {
+ listener_->OnMessageReceived(mozilla::Move(m));
+ }
+
+ incoming_message_.reset();
+ }
+
+ bytes_read = 0; // Get more data.
+ }
+
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessOutgoingMessages(
+ MessageLoopForIO::IOContext* context,
+ DWORD bytes_written) {
+ DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
+ // no connection?
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+
+ if (output_state_.is_pending) {
+ DCHECK(context);
+ output_state_.is_pending = false;
+ if (!context || bytes_written == 0) {
+ DWORD err = GetLastError();
+ CHROMIUM_LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+ // Message was sent.
+ DCHECK(!output_queue_.empty());
+ Message* m = output_queue_.front();
+
+ MOZ_RELEASE_ASSERT(partial_write_iter_.isSome());
+ Pickle::BufferList::IterImpl& iter = partial_write_iter_.ref();
+ iter.Advance(m->Buffers(), bytes_written);
+ if (iter.Done()) {
+ partial_write_iter_.reset();
+ OutputQueuePop();
+ delete m;
+ }
+ }
+
+ if (output_queue_.empty())
+ return true;
+
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ // Write to pipe...
+ Message* m = output_queue_.front();
+
+ if (partial_write_iter_.isNothing()) {
+ Pickle::BufferList::IterImpl iter(m->Buffers());
+ partial_write_iter_.emplace(iter);
+ }
+
+ Pickle::BufferList::IterImpl& iter = partial_write_iter_.ref();
+ BOOL ok = WriteFile(pipe_,
+ iter.Data(),
+ iter.RemainingInSegment(),
+ &bytes_written,
+ &output_state_.context.overlapped);
+ if (!ok) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ output_state_.is_pending = true;
+
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "sent pending message @" << m << " on channel @" <<
+ this << " with type " << m->type();
+#endif
+
+ return true;
+ }
+ CHROMIUM_LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+ DLOG(INFO) << "sent message @" << m << " on channel @" << this <<
+ " with type " << m->type();
+#endif
+
+ output_state_.is_pending = true;
+ return true;
+}
+
+void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error) {
+ bool ok;
+ ASSERT_OWNINGTHREAD(ChannelImpl);
+ if (context == &input_state_.context) {
+ if (waiting_connect_) {
+ if (!ProcessConnection())
+ return;
+ // We may have some messages queued up to send...
+ if (!output_queue_.empty() && !output_state_.is_pending)
+ ProcessOutgoingMessages(NULL, 0);
+ if (input_state_.is_pending)
+ return;
+ // else, fall-through and look for incoming messages...
+ }
+ // we don't support recursion through OnMessageReceived yet!
+ DCHECK(!processing_incoming_);
+ processing_incoming_ = true;
+ ok = ProcessIncomingMessages(context, bytes_transfered);
+ processing_incoming_ = false;
+ } else {
+ DCHECK(context == &output_state_.context);
+ ok = ProcessOutgoingMessages(context, bytes_transfered);
+ }
+ if (!ok && INVALID_HANDLE_VALUE != pipe_) {
+ // We don't want to re-enter Close().
+ Close();
+ listener_->OnChannelError();
+ }
+}
+
+bool Channel::ChannelImpl::Unsound_IsClosed() const
+{
+ return closed_;
+}
+
+uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const
+{
+ return output_queue_length_;
+}
+
+//------------------------------------------------------------------------------
+// Channel's methods simply call through to ChannelImpl.
+Channel::Channel(const std::wstring& channel_id, Mode mode,
+ Listener* listener)
+ : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
+ MOZ_COUNT_CTOR(IPC::Channel);
+}
+
+Channel::Channel(const std::wstring& channel_id, void* server_pipe,
+ Mode mode, Listener* listener)
+ : channel_impl_(new ChannelImpl(channel_id, server_pipe, mode, listener)) {
+ MOZ_COUNT_CTOR(IPC::Channel);
+}
+
+Channel::~Channel() {
+ MOZ_COUNT_DTOR(IPC::Channel);
+ delete channel_impl_;
+}
+
+bool Channel::Connect() {
+ return channel_impl_->Connect();
+}
+
+void Channel::Close() {
+ channel_impl_->Close();
+}
+
+void* Channel::GetServerPipeHandle() const {
+ return channel_impl_->GetServerPipeHandle();
+}
+
+Channel::Listener* Channel::set_listener(Listener* listener) {
+ return channel_impl_->set_listener(listener);
+}
+
+bool Channel::Send(Message* message) {
+ return channel_impl_->Send(message);
+}
+
+bool Channel::Unsound_IsClosed() const {
+ return channel_impl_->Unsound_IsClosed();
+}
+
+uint32_t Channel::Unsound_NumQueuedMessages() const {
+ return channel_impl_->Unsound_NumQueuedMessages();
+}
+
+// static
+std::wstring Channel::GenerateVerifiedChannelID(const std::wstring& prefix) {
+ // Windows pipes can be enumerated by low-privileged processes. So, we
+ // append a strong random value after the \ character. This value is not
+ // included in the pipe name, but sent as part of the client hello, to
+ // prevent hijacking the pipe name to spoof the client.
+ std::wstring id = prefix;
+ if (!id.empty())
+ id.append(L".");
+ int secret;
+ do { // Guarantee we get a non-zero value.
+ secret = base::RandInt(0, std::numeric_limits<int>::max());
+ } while (secret == 0);
+ id.append(GenerateUniqueRandomChannelID());
+ return id.append(StringPrintf(L"\\%d", secret));
+}
+
+} // namespace IPC
diff --git a/ipc/chromium/src/chrome/common/ipc_channel_win.h b/ipc/chromium/src/chrome/common/ipc_channel_win.h
new file mode 100644
index 000000000..1d5cd7aa2
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_CHANNEL_WIN_H_
+#define CHROME_COMMON_IPC_CHANNEL_WIN_H_
+
+#include "chrome/common/ipc_channel.h"
+
+#include <queue>
+#include <string>
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "nsISupportsImpl.h"
+
+#include "mozilla/Maybe.h"
+
+namespace IPC {
+
+class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
+ public:
+ // Mirror methods of Channel, see ipc_channel.h for description.
+ ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
+ ChannelImpl(const std::wstring& channel_id, HANDLE server_pipe,
+ Mode mode, Listener* listener);
+ ~ChannelImpl() {
+ if (pipe_ != INVALID_HANDLE_VALUE) {
+ Close();
+ }
+ }
+ bool Connect();
+ void Close();
+ HANDLE GetServerPipeHandle() const;
+ Listener* set_listener(Listener* listener) {
+ Listener* old = listener_;
+ listener_ = listener;
+ return old;
+ }
+ bool Send(Message* message);
+
+ // See the comment in ipc_channel.h for info on Unsound_IsClosed() and
+ // Unsound_NumQueuedMessages().
+ bool Unsound_IsClosed() const;
+ uint32_t Unsound_NumQueuedMessages() const;
+
+ private:
+ void Init(Mode mode, Listener* listener);
+
+ void OutputQueuePush(Message* msg);
+ void OutputQueuePop();
+
+ const std::wstring PipeName(const std::wstring& channel_id,
+ int32_t* secret) const;
+ bool CreatePipe(const std::wstring& channel_id, Mode mode);
+ bool EnqueueHelloMessage();
+
+ bool ProcessConnection();
+ bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context,
+ DWORD bytes_read);
+ bool ProcessOutgoingMessages(MessageLoopForIO::IOContext* context,
+ DWORD bytes_written);
+
+ // MessageLoop::IOHandler implementation.
+ virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error);
+ private:
+ struct State {
+ explicit State(ChannelImpl* channel);
+ ~State();
+ MessageLoopForIO::IOContext context;
+ bool is_pending;
+ };
+
+ State input_state_;
+ State output_state_;
+
+ HANDLE pipe_;
+
+ Listener* listener_;
+
+ // Messages to be sent are queued here.
+ std::queue<Message*> output_queue_;
+
+ // If sending a message blocks then we use this iterator to keep track of
+ // where in the message we are. It gets reset when the message is finished
+ // sending.
+ mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;
+
+ // We read from the pipe into this buffer
+ char input_buf_[Channel::kReadBufferSize];
+ size_t input_buf_offset_;
+
+ // Large incoming messages that span multiple pipe buffers get built-up in the
+ // buffers of this message.
+ mozilla::Maybe<Message> incoming_message_;
+
+ // In server-mode, we have to wait for the client to connect before we
+ // can begin reading. We make use of the input_state_ when performing
+ // the connect operation in overlapped mode.
+ bool waiting_connect_;
+
+ // This flag is set when processing incoming messages. It is used to
+ // avoid recursing through ProcessIncomingMessages, which could cause
+ // problems. TODO(darin): make this unnecessary
+ bool processing_incoming_;
+
+ // This flag is set after Close() is run on the channel.
+ bool closed_;
+
+ // This variable is updated so it matches output_queue_.size(), except we can
+ // read output_queue_length_ from any thread (if we're OK getting an
+ // occasional out-of-date or bogus value). We use output_queue_length_ to
+ // implement Unsound_NumQueuedMessages.
+ size_t output_queue_length_;
+
+ ScopedRunnableMethodFactory<ChannelImpl> factory_;
+
+ // This is a unique per-channel value used to authenticate the client end of
+ // a connection. If the value is non-zero, the client passes it in the hello
+ // and the host validates. (We don't send the zero value to preserve IPC
+ // compatibility with existing clients that don't validate the channel.)
+ int32_t shared_secret_;
+
+ // In server-mode, we wait for the channel at the other side of the pipe to
+ // send us back our shared secret, if we are using one.
+ bool waiting_for_shared_secret_;
+
+#ifdef DEBUG
+ mozilla::UniquePtr<nsAutoOwningThread> _mOwningThread;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_IPC_CHANNEL_WIN_H_
diff --git a/ipc/chromium/src/chrome/common/ipc_message.cc b/ipc/chromium/src/chrome/common/ipc_message.cc
new file mode 100644
index 000000000..b8b3ee353
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_message.cc
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ipc_message.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include "chrome/common/file_descriptor_set_posix.h"
+#endif
+#ifdef MOZ_TASK_TRACER
+#include "GeckoTaskTracer.h"
+#endif
+
+#include "mozilla/Move.h"
+
+#ifdef MOZ_TASK_TRACER
+using namespace mozilla::tasktracer;
+#endif
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+Message::~Message() {
+ MOZ_COUNT_DTOR(IPC::Message);
+}
+
+Message::Message()
+ : Pickle(sizeof(Header)) {
+ MOZ_COUNT_CTOR(IPC::Message);
+ header()->routing = header()->type = header()->flags = 0;
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+#endif
+#ifdef MOZ_TASK_TRACER
+ header()->source_event_id = 0;
+ header()->parent_task_id = 0;
+ header()->source_event_type = SourceEventType::Unknown;
+#endif
+ InitLoggingVariables();
+}
+
+Message::Message(int32_t routing_id, msgid_t type, NestedLevel nestedLevel, PriorityValue priority,
+ MessageCompression compression, const char* const aName)
+ : Pickle(sizeof(Header)) {
+ MOZ_COUNT_CTOR(IPC::Message);
+ header()->routing = routing_id;
+ header()->type = type;
+ header()->flags = nestedLevel;
+ if (priority == HIGH_PRIORITY)
+ header()->flags |= PRIO_BIT;
+ if (compression == COMPRESSION_ENABLED)
+ header()->flags |= COMPRESS_BIT;
+ else if (compression == COMPRESSION_ALL)
+ header()->flags |= COMPRESSALL_BIT;
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+#endif
+ header()->interrupt_remote_stack_depth_guess = static_cast<uint32_t>(-1);
+ header()->interrupt_local_stack_depth = static_cast<uint32_t>(-1);
+ header()->seqno = 0;
+#if defined(OS_MACOSX)
+ header()->cookie = 0;
+#endif
+#ifdef MOZ_TASK_TRACER
+ header()->source_event_id = 0;
+ header()->parent_task_id = 0;
+ header()->source_event_type = SourceEventType::Unknown;
+#endif
+ InitLoggingVariables(aName);
+}
+
+Message::Message(const char* data, int data_len)
+ : Pickle(sizeof(Header), data, data_len)
+{
+ MOZ_COUNT_CTOR(IPC::Message);
+ InitLoggingVariables();
+}
+
+Message::Message(Message&& other) : Pickle(mozilla::Move(other)) {
+ MOZ_COUNT_CTOR(IPC::Message);
+ InitLoggingVariables(other.name_);
+#if defined(OS_POSIX)
+ file_descriptor_set_ = other.file_descriptor_set_.forget();
+#endif
+#ifdef MOZ_TASK_TRACER
+ header()->source_event_id = other.header()->source_event_id;
+ header()->parent_task_id = other.header()->parent_task_id;
+ header()->source_event_type = other.header()->source_event_type;
+#endif
+}
+
+void Message::InitLoggingVariables(const char* const aName) {
+ name_ = aName;
+}
+
+Message& Message::operator=(Message&& other) {
+ *static_cast<Pickle*>(this) = mozilla::Move(other);
+ InitLoggingVariables(other.name_);
+#if defined(OS_POSIX)
+ file_descriptor_set_.swap(other.file_descriptor_set_);
+#endif
+#ifdef MOZ_TASK_TRACER
+ std::swap(header()->source_event_id, other.header()->source_event_id);
+ std::swap(header()->parent_task_id, other.header()->parent_task_id);
+ std::swap(header()->source_event_type, other.header()->source_event_type);
+#endif
+ return *this;
+}
+
+
+#if defined(OS_POSIX)
+bool Message::WriteFileDescriptor(const base::FileDescriptor& descriptor) {
+ // We write the index of the descriptor so that we don't have to
+ // keep the current descriptor as extra decoding state when deserialising.
+ // Also, we rely on each file descriptor being accompanied by sizeof(int)
+ // bytes of data in the message. See the comment for input_cmsg_buf_.
+ WriteInt(file_descriptor_set()->size());
+ if (descriptor.auto_close) {
+ return file_descriptor_set()->AddAndAutoClose(descriptor.fd);
+ } else {
+ return file_descriptor_set()->Add(descriptor.fd);
+ }
+}
+
+bool Message::ReadFileDescriptor(PickleIterator* iter,
+ base::FileDescriptor* descriptor) const {
+ int descriptor_index;
+ if (!ReadInt(iter, &descriptor_index))
+ return false;
+
+ FileDescriptorSet* file_descriptor_set = file_descriptor_set_.get();
+ if (!file_descriptor_set)
+ return false;
+
+ descriptor->fd = file_descriptor_set->GetDescriptorAt(descriptor_index);
+ descriptor->auto_close = false;
+
+ return descriptor->fd >= 0;
+}
+
+void Message::EnsureFileDescriptorSet() {
+ if (file_descriptor_set_.get() == NULL)
+ file_descriptor_set_ = new FileDescriptorSet;
+}
+
+uint32_t Message::num_fds() const {
+ return file_descriptor_set() ? file_descriptor_set()->size() : 0;
+}
+
+#endif
+
+} // namespace IPC
diff --git a/ipc/chromium/src/chrome/common/ipc_message.h b/ipc/chromium/src/chrome/common/ipc_message.h
new file mode 100644
index 000000000..60cec5f13
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -0,0 +1,370 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_MESSAGE_H__
+#define CHROME_COMMON_IPC_MESSAGE_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/pickle.h"
+
+#ifdef MOZ_TASK_TRACER
+#include "GeckoTaskTracer.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "nsAutoPtr.h"
+#endif
+
+namespace base {
+struct FileDescriptor;
+}
+
+class FileDescriptorSet;
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+class Channel;
+class Message;
+struct LogData;
+
+class Message : public Pickle {
+ public:
+ typedef uint32_t msgid_t;
+
+ enum NestedLevel {
+ NOT_NESTED = 1,
+ NESTED_INSIDE_SYNC = 2,
+ NESTED_INSIDE_CPOW = 3
+ };
+
+ enum PriorityValue {
+ NORMAL_PRIORITY,
+ HIGH_PRIORITY,
+ };
+
+ enum MessageCompression {
+ COMPRESSION_NONE,
+ COMPRESSION_ENABLED,
+ COMPRESSION_ALL
+ };
+
+ virtual ~Message();
+
+ Message();
+
+ // Initialize a message with a user-defined type, priority value, and
+ // destination WebView ID.
+ Message(int32_t routing_id,
+ msgid_t type,
+ NestedLevel nestedLevel = NOT_NESTED,
+ PriorityValue priority = NORMAL_PRIORITY,
+ MessageCompression compression = COMPRESSION_NONE,
+ const char* const name="???");
+
+ Message(const char* data, int data_len);
+
+ Message(const Message& other) = delete;
+ Message(Message&& other);
+ Message& operator=(const Message& other) = delete;
+ Message& operator=(Message&& other);
+
+ NestedLevel nested_level() const {
+ return static_cast<NestedLevel>(header()->flags & NESTED_MASK);
+ }
+
+ void set_nested_level(NestedLevel nestedLevel) {
+ DCHECK((nestedLevel & ~NESTED_MASK) == 0);
+ header()->flags = (header()->flags & ~NESTED_MASK) | nestedLevel;
+ }
+
+ PriorityValue priority() const {
+ if (header()->flags & PRIO_BIT) {
+ return HIGH_PRIORITY;
+ }
+ return NORMAL_PRIORITY;
+ }
+
+ void set_priority(PriorityValue prio) {
+ header()->flags &= ~PRIO_BIT;
+ if (prio == HIGH_PRIORITY) {
+ header()->flags |= PRIO_BIT;
+ }
+ }
+
+ // True if this is a synchronous message.
+ bool is_sync() const {
+ return (header()->flags & SYNC_BIT) != 0;
+ }
+
+ // True if this is a synchronous message.
+ bool is_interrupt() const {
+ return (header()->flags & INTERRUPT_BIT) != 0;
+ }
+
+ // True if compression is enabled for this message.
+ MessageCompression compress_type() const {
+ return (header()->flags & COMPRESS_BIT) ?
+ COMPRESSION_ENABLED :
+ (header()->flags & COMPRESSALL_BIT) ?
+ COMPRESSION_ALL :
+ COMPRESSION_NONE;
+ }
+
+ // Set this on a reply to a synchronous message.
+ void set_reply() {
+ header()->flags |= REPLY_BIT;
+ }
+
+ bool is_reply() const {
+ return (header()->flags & REPLY_BIT) != 0;
+ }
+
+ // Set this on a reply to a synchronous message to indicate that no receiver
+ // was found.
+ void set_reply_error() {
+ header()->flags |= REPLY_ERROR_BIT;
+ }
+
+ bool is_reply_error() const {
+ return (header()->flags & REPLY_ERROR_BIT) != 0;
+ }
+
+ msgid_t type() const {
+ return header()->type;
+ }
+
+ int32_t routing_id() const {
+ return header()->routing;
+ }
+
+ void set_routing_id(int32_t new_id) {
+ header()->routing = new_id;
+ }
+
+ int32_t transaction_id() const {
+ return header()->txid;
+ }
+
+ void set_transaction_id(int32_t txid) {
+ header()->txid = txid;
+ }
+
+ uint32_t interrupt_remote_stack_depth_guess() const {
+ return header()->interrupt_remote_stack_depth_guess;
+ }
+
+ void set_interrupt_remote_stack_depth_guess(uint32_t depth) {
+ DCHECK(is_interrupt());
+ header()->interrupt_remote_stack_depth_guess = depth;
+ }
+
+ uint32_t interrupt_local_stack_depth() const {
+ return header()->interrupt_local_stack_depth;
+ }
+
+ void set_interrupt_local_stack_depth(uint32_t depth) {
+ DCHECK(is_interrupt());
+ header()->interrupt_local_stack_depth = depth;
+ }
+
+ int32_t seqno() const {
+ return header()->seqno;
+ }
+
+ void set_seqno(int32_t aSeqno) {
+ header()->seqno = aSeqno;
+ }
+
+ const char* name() const {
+ return name_;
+ }
+
+ void set_name(const char* const aName) {
+ name_ = aName;
+ }
+
+#if defined(OS_POSIX)
+ uint32_t num_fds() const;
+#endif
+
+ template<class T>
+ static bool Dispatch(const Message* msg, T* obj, void (T::*func)()) {
+ (obj->*func)();
+ return true;
+ }
+
+ template<class T>
+ static bool Dispatch(const Message* msg, T* obj, void (T::*func)() const) {
+ (obj->*func)();
+ return true;
+ }
+
+ template<class T>
+ static bool Dispatch(const Message* msg, T* obj,
+ void (T::*func)(const Message&)) {
+ (obj->*func)(*msg);
+ return true;
+ }
+
+ template<class T>
+ static bool Dispatch(const Message* msg, T* obj,
+ void (T::*func)(const Message&) const) {
+ (obj->*func)(*msg);
+ return true;
+ }
+
+ // Used for async messages with no parameters.
+ static void Log(const Message* msg, std::wstring* l) {
+ }
+
+ // Figure out how big the message starting at range_start is. Returns 0 if
+ // there's no enough data to determine (i.e., if [range_start, range_end) does
+ // not contain enough of the message header to know the size).
+ static uint32_t MessageSize(const char* range_start, const char* range_end) {
+ return Pickle::MessageSize(sizeof(Header), range_start, range_end);
+ }
+
+#if defined(OS_POSIX)
+ // On POSIX, a message supports reading / writing FileDescriptor objects.
+ // This is used to pass a file descriptor to the peer of an IPC channel.
+
+ // Add a descriptor to the end of the set. Returns false iff the set is full.
+ bool WriteFileDescriptor(const base::FileDescriptor& descriptor);
+ // Get a file descriptor from the message. Returns false on error.
+ // iter: a Pickle iterator to the current location in the message.
+ bool ReadFileDescriptor(PickleIterator* iter, base::FileDescriptor* descriptor) const;
+
+#if defined(OS_MACOSX)
+ void set_fd_cookie(uint32_t cookie) {
+ header()->cookie = cookie;
+ }
+ uint32_t fd_cookie() const {
+ return header()->cookie;
+ }
+#endif
+#endif
+
+
+ friend class Channel;
+ friend class MessageReplyDeserializer;
+ friend class SyncMessage;
+
+ void set_sync() {
+ header()->flags |= SYNC_BIT;
+ }
+
+ void set_interrupt() {
+ header()->flags |= INTERRUPT_BIT;
+ }
+
+#if !defined(OS_MACOSX)
+ protected:
+#endif
+
+ // flags
+ enum {
+ NESTED_MASK = 0x0003,
+ PRIO_BIT = 0x0004,
+ SYNC_BIT = 0x0008,
+ REPLY_BIT = 0x0010,
+ REPLY_ERROR_BIT = 0x0020,
+ INTERRUPT_BIT = 0x0040,
+ COMPRESS_BIT = 0x0080,
+ COMPRESSALL_BIT = 0x0100,
+ };
+
+ struct Header : Pickle::Header {
+ int32_t routing; // ID of the view that this message is destined for
+ msgid_t type; // specifies the user-defined message type
+ uint32_t flags; // specifies control flags for the message
+#if defined(OS_POSIX)
+ uint32_t num_fds; // the number of descriptors included with this message
+# if defined(OS_MACOSX)
+ uint32_t cookie; // cookie to ACK that the descriptors have been read.
+# endif
+#endif
+ union {
+ // For Interrupt messages, a guess at what the *other* side's stack depth is.
+ uint32_t interrupt_remote_stack_depth_guess;
+
+ // For RPC and Urgent messages, a transaction ID for message ordering.
+ int32_t txid;
+ };
+ // The actual local stack depth.
+ uint32_t interrupt_local_stack_depth;
+ // Sequence number
+ int32_t seqno;
+#ifdef MOZ_TASK_TRACER
+ uint64_t source_event_id;
+ uint64_t parent_task_id;
+ mozilla::tasktracer::SourceEventType source_event_type;
+#endif
+ };
+
+ Header* header() {
+ return headerT<Header>();
+ }
+ const Header* header() const {
+ return headerT<Header>();
+ }
+
+ void InitLoggingVariables(const char* const name="???");
+
+#if defined(OS_POSIX)
+ // The set of file descriptors associated with this message.
+ RefPtr<FileDescriptorSet> file_descriptor_set_;
+
+ // Ensure that a FileDescriptorSet is allocated
+ void EnsureFileDescriptorSet();
+
+ FileDescriptorSet* file_descriptor_set() {
+ EnsureFileDescriptorSet();
+ return file_descriptor_set_.get();
+ }
+ const FileDescriptorSet* file_descriptor_set() const {
+ return file_descriptor_set_.get();
+ }
+#endif
+
+ const char* name_;
+
+};
+
+class MessageInfo {
+public:
+ typedef uint32_t msgid_t;
+
+ explicit MessageInfo(const Message& aMsg)
+ : mSeqno(aMsg.seqno()), mType(aMsg.type()) {}
+
+ int32_t seqno() const { return mSeqno; }
+ msgid_t type() const { return mType; }
+
+private:
+ int32_t mSeqno;
+ msgid_t mType;
+};
+
+//------------------------------------------------------------------------------
+
+} // namespace IPC
+
+enum SpecialRoutingIDs {
+ // indicates that we don't have a routing ID yet.
+ MSG_ROUTING_NONE = kint32min,
+
+ // indicates a general message not sent to a particular tab.
+ MSG_ROUTING_CONTROL = kint32max
+};
+
+#define IPC_REPLY_ID 0xFFF0 // Special message id for replies
+#define IPC_LOGGING_ID 0xFFF1 // Special message id for logging
+
+#endif // CHROME_COMMON_IPC_MESSAGE_H__
diff --git a/ipc/chromium/src/chrome/common/ipc_message_utils.h b/ipc/chromium/src/chrome/common/ipc_message_utils.h
new file mode 100644
index 000000000..e8ea9ad3a
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_MESSAGE_UTILS_H_
+#define CHROME_COMMON_IPC_MESSAGE_UTILS_H_
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base/file_path.h"
+#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/time.h"
+
+#if defined(OS_POSIX)
+#include "chrome/common/file_descriptor_set_posix.h"
+#endif
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/transport_dib.h"
+
+namespace IPC {
+
+//-----------------------------------------------------------------------------
+// An iterator class for reading the fields contained within a Message.
+
+class MessageIterator {
+ public:
+ explicit MessageIterator(const Message& m) : msg_(m), iter_(m) {
+ }
+ int NextInt() const {
+ int val;
+ if (!msg_.ReadInt(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+ intptr_t NextIntPtr() const {
+ intptr_t val;
+ if (!msg_.ReadIntPtr(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+ const std::string NextString() const {
+ std::string val;
+ if (!msg_.ReadString(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+ const std::wstring NextWString() const {
+ std::wstring val;
+ if (!msg_.ReadWString(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+ private:
+ const Message& msg_;
+ mutable PickleIterator iter_;
+};
+
+//-----------------------------------------------------------------------------
+// ParamTraits specializations, etc.
+//
+// The full set of types ParamTraits is specialized upon contains *possibly*
+// repeated types: unsigned long may be uint32_t or size_t, unsigned long long
+// may be uint64_t or size_t, nsresult may be uint32_t, and so on. You can't
+// have ParamTraits<unsigned int> *and* ParamTraits<uint32_t> if unsigned int
+// is uint32_t -- that's multiple definitions, and you can only have one.
+//
+// You could use #ifs and macro conditions to avoid duplicates, but they'd be
+// hairy: heavily dependent upon OS and compiler author choices, forced to
+// address all conflicts by hand. Happily there's a better way. The basic
+// idea looks like this, where T -> U represents T inheriting from U:
+//
+// class ParamTraits<P>
+// |
+// --> class ParamTraits1<P>
+// |
+// --> class ParamTraits2<P>
+// |
+// --> class ParamTraitsN<P> // or however many levels
+//
+// The default specialization of ParamTraits{M}<P> is an empty class that
+// inherits from ParamTraits{M + 1}<P> (or nothing in the base case).
+//
+// Now partition the set of parameter types into sets without duplicates.
+// Assign each set of types to a level M. Then specialize ParamTraitsM for
+// each of those types. A reference to ParamTraits<P> will consist of some
+// number of empty classes inheriting in sequence, ending in a non-empty
+// ParamTraits{N}<P>. It's okay for the parameter types to be duplicative:
+// either name of a type will resolve to the same ParamTraits{N}<P>.
+//
+// The nice thing is that because templates are instantiated lazily, if we
+// indeed have uint32_t == unsigned int, say, with the former in level N and
+// the latter in M > N, ParamTraitsM<unsigned int> won't be created (as long as
+// nobody uses ParamTraitsM<unsigned int>, but why would you), and no duplicate
+// code will be compiled or extra symbols generated. It's as efficient at
+// runtime as manually figuring out and avoiding conflicts by #ifs.
+//
+// The scheme we follow below names the various classes according to the types
+// in them, and the number of ParamTraits levels is larger, but otherwise it's
+// exactly the above idea.
+//
+
+template <class P> struct ParamTraits;
+
+template <class P>
+static inline void WriteParam(Message* m, const P& p) {
+ ParamTraits<P>::Write(m, p);
+}
+
+template <class P>
+static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, PickleIterator* iter,
+ P* p) {
+ return ParamTraits<P>::Read(m, iter, p);
+}
+
+template <class P>
+static inline void LogParam(const P& p, std::wstring* l) {
+ ParamTraits<P>::Log(p, l);
+}
+
+// Fundamental types.
+
+template <class P>
+struct ParamTraitsFundamental {};
+
+template <>
+struct ParamTraitsFundamental<bool> {
+ typedef bool param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteBool(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadBool(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(p ? L"true" : L"false");
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<int> {
+ typedef int param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadInt(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%d", p));
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<long> {
+ typedef long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteLong(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadLong(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%l", p));
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<unsigned long> {
+ typedef unsigned long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteULong(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadULong(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%ul", p));
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<long long> {
+ typedef long long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadBytesInto(iter, r, sizeof(*r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%ll", p));
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<unsigned long long> {
+ typedef unsigned long long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadBytesInto(iter, r, sizeof(*r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%ull", p));
+ }
+};
+
+template <>
+struct ParamTraitsFundamental<double> {
+ typedef double param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteDouble(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadDouble(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"e", p));
+ }
+};
+
+// Fixed-size <stdint.h> types.
+
+template <class P>
+struct ParamTraitsFixed : ParamTraitsFundamental<P> {};
+
+template <>
+struct ParamTraitsFixed<int16_t> {
+ typedef int16_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt16(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadInt16(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%hd", p));
+ }
+};
+
+template <>
+struct ParamTraitsFixed<uint16_t> {
+ typedef uint16_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteUInt16(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadUInt16(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%hu", p));
+ }
+};
+
+template <>
+struct ParamTraitsFixed<uint32_t> {
+ typedef uint32_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteUInt32(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadUInt32(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%u", p));
+ }
+};
+
+template <>
+struct ParamTraitsFixed<int64_t> {
+ typedef int64_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt64(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadInt64(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%" PRId64L, p));
+ }
+};
+
+template <>
+struct ParamTraitsFixed<uint64_t> {
+ typedef uint64_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt64(static_cast<int64_t>(p));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadInt64(iter, reinterpret_cast<int64_t*>(r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%" PRIu64L, p));
+ }
+};
+
+// Other standard C types.
+
+template <class P>
+struct ParamTraitsLibC : ParamTraitsFixed<P> {};
+
+template <>
+struct ParamTraitsLibC<size_t> {
+ typedef size_t param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteSize(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadSize(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%u", p));
+ }
+};
+
+// std::* types.
+
+template <class P>
+struct ParamTraitsStd : ParamTraitsLibC<P> {};
+
+template <>
+struct ParamTraitsStd<std::string> {
+ typedef std::string param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteString(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadString(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(UTF8ToWide(p));
+ }
+};
+
+template <>
+struct ParamTraitsStd<std::wstring> {
+ typedef std::wstring param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteWString(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadWString(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(p);
+ }
+};
+
+template <class K, class V>
+struct ParamTraitsStd<std::map<K, V> > {
+ typedef std::map<K, V> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ WriteParam(m, iter->first);
+ WriteParam(m, iter->second);
+ }
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ int size;
+ if (!ReadParam(m, iter, &size) || size < 0)
+ return false;
+ for (int i = 0; i < size; ++i) {
+ K k;
+ if (!ReadParam(m, iter, &k))
+ return false;
+ V& value = (*r)[k];
+ if (!ReadParam(m, iter, &value))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"<std::map>");
+ }
+};
+
+// Windows-specific types.
+
+template <class P>
+struct ParamTraitsWindows : ParamTraitsStd<P> {};
+
+#if defined(OS_WIN)
+template <>
+struct ParamTraitsWindows<HANDLE> {
+ typedef HANDLE param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ DCHECK_EQ(sizeof(param_type), sizeof(intptr_t));
+ return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"0x%X", p));
+ }
+};
+
+template <>
+struct ParamTraitsWindows<HWND> {
+ typedef HWND param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ DCHECK_EQ(sizeof(param_type), sizeof(intptr_t));
+ return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"0x%X", p));
+ }
+};
+#endif // defined(OS_WIN)
+
+// Various ipc/chromium types.
+
+template <class P>
+struct ParamTraitsIPC : ParamTraitsWindows<P> {};
+
+#if defined(OS_POSIX)
+// FileDescriptors may be serialised over IPC channels on POSIX. On the
+// receiving side, the FileDescriptor is a valid duplicate of the file
+// descriptor which was transmitted: *it is not just a copy of the integer like
+// HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In
+// this case, the receiving end will see a value of -1. *Zero is a valid file
+// descriptor*.
+//
+// The received file descriptor will have the |auto_close| flag set to true. The
+// code which handles the message is responsible for taking ownership of it.
+// File descriptors are OS resources and must be closed when no longer needed.
+//
+// When sending a file descriptor, the file descriptor must be valid at the time
+// of transmission. Since transmission is not synchronous, one should consider
+// dup()ing any file descriptors to be transmitted and setting the |auto_close|
+// flag, which causes the file descriptor to be closed after writing.
+template<>
+struct ParamTraitsIPC<base::FileDescriptor> {
+ typedef base::FileDescriptor param_type;
+ static void Write(Message* m, const param_type& p) {
+ const bool valid = p.fd >= 0;
+ WriteParam(m, valid);
+
+ if (valid) {
+ if (!m->WriteFileDescriptor(p)) {
+ NOTREACHED() << "Too many file descriptors for one message!";
+ }
+ }
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ bool valid;
+ if (!ReadParam(m, iter, &valid))
+ return false;
+
+ if (!valid) {
+ r->fd = -1;
+ r->auto_close = false;
+ return true;
+ }
+
+ return m->ReadFileDescriptor(iter, r);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ if (p.auto_close) {
+ l->append(StringPrintf(L"FD(%d auto-close)", p.fd));
+ } else {
+ l->append(StringPrintf(L"FD(%d)", p.fd));
+ }
+ }
+};
+#endif // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+template<>
+struct ParamTraitsIPC<TransportDIB::Id> {
+ typedef TransportDIB::Id param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.handle);
+ WriteParam(m, p.sequence_num);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return (ReadParam(m, iter, &r->handle) &&
+ ReadParam(m, iter, &r->sequence_num));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"TransportDIB(");
+ LogParam(p.handle, l);
+ l->append(L", ");
+ LogParam(p.sequence_num, l);
+ l->append(L")");
+ }
+};
+#endif
+
+// Mozilla-specific types.
+
+template <class P>
+struct ParamTraitsMozilla : ParamTraitsIPC<P> {};
+
+template <>
+struct ParamTraitsMozilla<nsresult> {
+ typedef nsresult param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteUInt32(static_cast<uint32_t>(p));
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadUInt32(iter, reinterpret_cast<uint32_t*>(r));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"%u", static_cast<uint32_t>(p)));
+ }
+};
+
+// Finally, ParamTraits itself.
+
+template <class P> struct ParamTraits : ParamTraitsMozilla<P> {};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_IPC_MESSAGE_UTILS_H_
diff --git a/ipc/chromium/src/chrome/common/mach_ipc_mac.h b/ipc/chromium/src/chrome/common/mach_ipc_mac.h
new file mode 100644
index 000000000..b44327765
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.h
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MACH_IPC_MAC_H_
+#define BASE_MACH_IPC_MAC_H_
+
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <servers/bootstrap.h>
+#include <sys/types.h>
+
+#include "base/basictypes.h"
+
+//==============================================================================
+// DISCUSSION:
+//
+// The three main classes of interest are
+//
+// MachMessage: a wrapper for a mach message of the following form
+// mach_msg_header_t
+// mach_msg_body_t
+// optional descriptors
+// optional extra message data
+//
+// MachReceiveMessage and MachSendMessage subclass MachMessage
+// and are used instead of MachMessage which is an abstract base class
+//
+// ReceivePort:
+// Represents a mach port for which we have receive rights
+//
+// MachPortSender:
+// Represents a mach port for which we have send rights
+//
+// Here's an example to receive a message on a server port:
+//
+// // This creates our named server port
+// ReceivePort receivePort("com.Google.MyService");
+//
+// MachReceiveMessage message;
+// kern_return_t result = receivePort.WaitForMessage(&message, 0);
+//
+// if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
+// mach_port_t task = message.GetTranslatedPort(0);
+// mach_port_t thread = message.GetTranslatedPort(1);
+//
+// char *messageString = message.GetData();
+//
+// printf("message string = %s\n", messageString);
+// }
+//
+// Here is an example of using these classes to send a message to this port:
+//
+// // send to already named port
+// MachPortSender sender("com.Google.MyService");
+// MachSendMessage message(57); // our message ID is 57
+//
+// // add some ports to be translated for us
+// message.AddDescriptor(mach_task_self()); // our task
+// message.AddDescriptor(mach_thread_self()); // this thread
+//
+// char messageString[] = "Hello server!\n";
+// message.SetData(messageString, strlen(messageString)+1);
+// // timeout 1000ms
+// kern_return_t result = sender.SendMessage(message, 1000);
+//
+
+#define PRINT_MACH_RESULT(result_, message_) \
+ printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
+
+//==============================================================================
+// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
+// with convenient constructors and accessors
+class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
+ public:
+ // General-purpose constructor
+ MachMsgPortDescriptor(mach_port_t in_name,
+ mach_msg_type_name_t in_disposition) {
+ name = in_name;
+ pad1 = 0;
+ pad2 = 0;
+ disposition = in_disposition;
+ type = MACH_MSG_PORT_DESCRIPTOR;
+ }
+
+ // For passing send rights to a port
+ explicit MachMsgPortDescriptor(mach_port_t in_name) {
+ name = in_name;
+ pad1 = 0;
+ pad2 = 0;
+ disposition = MACH_MSG_TYPE_PORT_SEND;
+ type = MACH_MSG_PORT_DESCRIPTOR;
+ }
+
+ // Copy constructor
+ MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
+ name = desc.name;
+ pad1 = desc.pad1;
+ pad2 = desc.pad2;
+ disposition = desc.disposition;
+ type = desc.type;
+ }
+
+ mach_port_t GetMachPort() const {
+ return name;
+ }
+
+ mach_msg_type_name_t GetDisposition() const {
+ return disposition;
+ }
+
+ // For convenience
+ operator mach_port_t() const {
+ return GetMachPort();
+ }
+};
+
+//==============================================================================
+// MachMessage: a wrapper for a mach message
+// (mach_msg_header_t, mach_msg_body_t, extra data)
+//
+// This considerably simplifies the construction of a message for sending
+// and the getting at relevant data and descriptors for the receiver.
+//
+// This class can be initialized using external storage of an arbitrary size
+// or it can manage storage internally.
+// 1. If storage is allocated internally, the combined size of the descriptors
+// plus data must be less than 1024. But as a benefit no memory allocation is
+// necessary.
+// 2. For external storage, a buffer of at least EmptyMessageSize() must be
+// provided.
+//
+// A MachMessage object is used by ReceivePort::WaitForMessage
+// and MachPortSender::SendMessage
+//
+class MachMessage {
+ public:
+
+ virtual ~MachMessage();
+
+ // The receiver of the message can retrieve the raw data this way
+ u_int8_t *GetData() {
+ return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
+ }
+
+ u_int32_t GetDataLength();
+
+ // The message ID may be used as a code identifying the type of message
+ void SetMessageID(int32_t message_id);
+
+ int32_t GetMessageID();
+
+ // Adds a descriptor (typically a mach port) to be translated
+ // returns true if successful, otherwise not enough space
+ bool AddDescriptor(const MachMsgPortDescriptor &desc);
+
+ int GetDescriptorCount() const {
+ return storage_->body.msgh_descriptor_count;
+ }
+ MachMsgPortDescriptor *GetDescriptor(int n);
+
+ // Convenience method which gets the mach port described by the descriptor
+ mach_port_t GetTranslatedPort(int n);
+
+ // A simple message is one with no descriptors
+ bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
+
+ // Sets raw data for the message (returns false if not enough space)
+ bool SetData(const void* data, int32_t data_length);
+
+ protected:
+ // Consider this an abstract base class - must create an actual instance
+ // of MachReceiveMessage or MachSendMessage
+ MachMessage();
+
+ // Constructor for use with preallocate storage.
+ // storage_length must be >= EmptyMessageSize()
+ MachMessage(void *storage, size_t storage_length);
+
+ friend class ReceivePort;
+ friend class MachPortSender;
+
+ // Represents raw data in our message
+ struct MessageDataPacket {
+ int32_t id; // little-endian
+ int32_t data_length; // little-endian
+ u_int8_t data[1]; // actual size limited by storage_length_bytes_
+ };
+
+ MessageDataPacket* GetDataPacket();
+
+ void SetDescriptorCount(int n);
+ void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
+
+ // Returns total message size setting msgh_size in the header to this value
+ int CalculateSize();
+
+ // Returns total storage size that this object can grow to, this is inclusive
+ // of the mach header.
+ size_t MaxSize() const { return storage_length_bytes_; }
+
+ protected:
+ mach_msg_header_t *Head() { return &(storage_->head); }
+
+ private:
+ struct MachMessageData {
+ mach_msg_header_t head;
+ mach_msg_body_t body;
+ // descriptors and data may be embedded here.
+ u_int8_t padding[1024];
+ };
+
+ // kEmptyMessageSize needs to have the definition of MachMessageData before
+ // it.
+ public:
+ // The size of an empty message with no data.
+ static const size_t kEmptyMessageSize = sizeof(mach_msg_header_t) +
+ sizeof(mach_msg_body_t) +
+ sizeof(MessageDataPacket);
+
+ private:
+ MachMessageData *storage_;
+ size_t storage_length_bytes_;
+ bool own_storage_; // Is storage owned by this object?
+};
+
+//==============================================================================
+// MachReceiveMessage and MachSendMessage are useful to separate the idea
+// of a mach message being sent and being received, and adds increased type
+// safety:
+// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
+// MachPortSender::SendMessage() only accepts a MachSendMessage
+
+//==============================================================================
+class MachReceiveMessage : public MachMessage {
+ public:
+ MachReceiveMessage() : MachMessage() {}
+ MachReceiveMessage(void *storage, size_t storage_length)
+ : MachMessage(storage, storage_length) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
+};
+
+//==============================================================================
+class MachSendMessage : public MachMessage {
+ public:
+ explicit MachSendMessage(int32_t message_id);
+ MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
+
+ private:
+ void Initialize(int32_t message_id);
+
+ DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
+};
+
+//==============================================================================
+// Represents a mach port for which we have receive rights
+class ReceivePort {
+ public:
+ // Creates a new mach port for receiving messages and registers a name for it
+ explicit ReceivePort(const char *receive_port_name);
+
+ // Given an already existing mach port, use it. We take ownership of the
+ // port and deallocate it in our destructor.
+ explicit ReceivePort(mach_port_t receive_port);
+
+ // Create a new mach port for receiving messages
+ ReceivePort();
+
+ ~ReceivePort();
+
+ // Waits on the mach port until message received or timeout
+ kern_return_t WaitForMessage(MachReceiveMessage *out_message,
+ mach_msg_timeout_t timeout);
+
+ kern_return_t SendMessageToSelf(MachSendMessage& msg,
+ mach_msg_timeout_t timeout);
+
+ // The underlying mach port that we wrap
+ mach_port_t GetPort() const { return port_; }
+
+ private:
+ mach_port_t port_;
+ kern_return_t init_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReceivePort);
+};
+
+//==============================================================================
+// Represents a mach port for which we have send rights
+class MachPortSender {
+ public:
+ // get a port with send rights corresponding to a named registered service
+ explicit MachPortSender(const char *receive_port_name);
+
+
+ // Given an already existing mach port, use it.
+ explicit MachPortSender(mach_port_t send_port);
+
+ kern_return_t SendMessage(MachSendMessage &message,
+ mach_msg_timeout_t timeout);
+
+ private:
+ mach_port_t send_port_;
+ kern_return_t init_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(MachPortSender);
+};
+
+#endif // BASE_MACH_IPC_MAC_H_
diff --git a/ipc/chromium/src/chrome/common/mach_ipc_mac.mm b/ipc/chromium/src/chrome/common/mach_ipc_mac.mm
new file mode 100644
index 000000000..aa1813094
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.mm
@@ -0,0 +1,351 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/mach_ipc_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include <stdio.h>
+#include "base/logging.h"
+
+//==============================================================================
+MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
+ Initialize(message_id);
+}
+
+MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
+ int32_t message_id)
+ : MachMessage(storage, storage_length) {
+ Initialize(message_id);
+}
+
+void MachSendMessage::Initialize(int32_t message_id) {
+ Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+
+ // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
+ Head()->msgh_local_port = MACH_PORT_NULL;
+ Head()->msgh_reserved = 0;
+ Head()->msgh_id = 0;
+
+ SetDescriptorCount(0); // start out with no descriptors
+
+ SetMessageID(message_id);
+ SetData(NULL, 0); // client may add data later
+}
+
+//==============================================================================
+MachMessage::MachMessage()
+ : storage_(new MachMessageData), // Allocate storage_ ourselves
+ storage_length_bytes_(sizeof(MachMessageData)),
+ own_storage_(true) {
+ memset(storage_, 0, storage_length_bytes_);
+}
+
+//==============================================================================
+MachMessage::MachMessage(void *storage, size_t storage_length)
+ : storage_(static_cast<MachMessageData*>(storage)),
+ storage_length_bytes_(storage_length),
+ own_storage_(false) {
+ DCHECK(storage);
+ DCHECK(storage_length >= kEmptyMessageSize);
+}
+
+//==============================================================================
+MachMessage::~MachMessage() {
+ if (own_storage_) {
+ delete storage_;
+ storage_ = NULL;
+ }
+}
+
+
+u_int32_t MachMessage::GetDataLength() {
+ return EndianU32_LtoN(GetDataPacket()->data_length);
+}
+
+ // The message ID may be used as a code identifying the type of message
+void MachMessage::SetMessageID(int32_t message_id) {
+ GetDataPacket()->id = EndianU32_NtoL(message_id);
+}
+
+int32_t MachMessage::GetMessageID() {
+ return EndianU32_LtoN(GetDataPacket()->id);
+}
+
+
+//==============================================================================
+// returns true if successful
+bool MachMessage::SetData(const void* data,
+ int32_t data_length) {
+ // Enforce the fact that it's only safe to call this method once on a
+ // message.
+ DCHECK(GetDataPacket()->data_length == 0);
+
+ // first check to make sure we have enough space
+ int size = CalculateSize();
+ int new_size = size + data_length;
+
+ if ((unsigned)new_size > storage_length_bytes_) {
+ return false; // not enough space
+ }
+
+ GetDataPacket()->data_length = EndianU32_NtoL(data_length);
+ if (data) memcpy(GetDataPacket()->data, data, data_length);
+
+ // Update the Mach header with the new aligned size of the message.
+ CalculateSize();
+
+ return true;
+}
+
+//==============================================================================
+// calculates and returns the total size of the message
+// Currently, the entire message MUST fit inside of the MachMessage
+// messsage size <= EmptyMessageSize()
+int MachMessage::CalculateSize() {
+ int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
+
+ // add space for MessageDataPacket
+ int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
+ size += 2*sizeof(int32_t) + alignedDataLength;
+
+ // add space for descriptors
+ size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
+
+ Head()->msgh_size = size;
+
+ return size;
+}
+
+//==============================================================================
+MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
+ int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
+ MessageDataPacket *packet =
+ reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
+
+ return packet;
+}
+
+//==============================================================================
+void MachMessage::SetDescriptor(int n,
+ const MachMsgPortDescriptor &desc) {
+ MachMsgPortDescriptor *desc_array =
+ reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
+ desc_array[n] = desc;
+}
+
+//==============================================================================
+// returns true if successful otherwise there was not enough space
+bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
+ // first check to make sure we have enough space
+ int size = CalculateSize();
+ int new_size = size + sizeof(MachMsgPortDescriptor);
+
+ if ((unsigned)new_size > storage_length_bytes_) {
+ return false; // not enough space
+ }
+
+ // unfortunately, we need to move the data to allow space for the
+ // new descriptor
+ u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
+ bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
+
+ SetDescriptor(GetDescriptorCount(), desc);
+ SetDescriptorCount(GetDescriptorCount() + 1);
+
+ CalculateSize();
+
+ return true;
+}
+
+//==============================================================================
+void MachMessage::SetDescriptorCount(int n) {
+ storage_->body.msgh_descriptor_count = n;
+
+ if (n > 0) {
+ Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
+ } else {
+ Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
+ }
+}
+
+//==============================================================================
+MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
+ if (n < GetDescriptorCount()) {
+ MachMsgPortDescriptor *desc =
+ reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
+ return desc + n;
+ }
+
+ return nil;
+}
+
+//==============================================================================
+mach_port_t MachMessage::GetTranslatedPort(int n) {
+ if (n < GetDescriptorCount()) {
+ return GetDescriptor(n)->GetMachPort();
+ }
+ return MACH_PORT_NULL;
+}
+
+#pragma mark -
+
+//==============================================================================
+// create a new mach port for receiving messages and register a name for it
+ReceivePort::ReceivePort(const char *receive_port_name) {
+ mach_port_t current_task = mach_task_self();
+
+ init_result_ = mach_port_allocate(current_task,
+ MACH_PORT_RIGHT_RECEIVE,
+ &port_);
+
+ if (init_result_ != KERN_SUCCESS)
+ return;
+
+ init_result_ = mach_port_insert_right(current_task,
+ port_,
+ port_,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ if (init_result_ != KERN_SUCCESS)
+ return;
+
+ NSPort *ns_port = [NSMachPort portWithMachPort:port_];
+ NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
+ [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
+}
+
+//==============================================================================
+// create a new mach port for receiving messages
+ReceivePort::ReceivePort() {
+ mach_port_t current_task = mach_task_self();
+
+ init_result_ = mach_port_allocate(current_task,
+ MACH_PORT_RIGHT_RECEIVE,
+ &port_);
+
+ if (init_result_ != KERN_SUCCESS)
+ return;
+
+ init_result_ = mach_port_insert_right(current_task,
+ port_,
+ port_,
+ MACH_MSG_TYPE_MAKE_SEND);
+}
+
+//==============================================================================
+// Given an already existing mach port, use it. We take ownership of the
+// port and deallocate it in our destructor.
+ReceivePort::ReceivePort(mach_port_t receive_port)
+ : port_(receive_port),
+ init_result_(KERN_SUCCESS) {
+}
+
+//==============================================================================
+ReceivePort::~ReceivePort() {
+ if (init_result_ == KERN_SUCCESS)
+ mach_port_deallocate(mach_task_self(), port_);
+}
+
+//==============================================================================
+kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
+ mach_msg_timeout_t timeout) {
+ if (!out_message) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ // return any error condition encountered in constructor
+ if (init_result_ != KERN_SUCCESS)
+ return init_result_;
+
+ out_message->Head()->msgh_bits = 0;
+ out_message->Head()->msgh_local_port = port_;
+ out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
+ out_message->Head()->msgh_reserved = 0;
+ out_message->Head()->msgh_id = 0;
+
+ kern_return_t result = mach_msg(out_message->Head(),
+ MACH_RCV_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_RCV_TIMEOUT),
+ 0,
+ out_message->MaxSize(),
+ port_,
+ timeout, // timeout in ms
+ MACH_PORT_NULL);
+
+ return result;
+}
+
+//==============================================================================
+// send a message to this port
+kern_return_t ReceivePort::SendMessageToSelf(MachSendMessage& message, mach_msg_timeout_t timeout) {
+ if (message.Head()->msgh_size == 0) {
+ NOTREACHED();
+ return KERN_INVALID_VALUE; // just for safety -- never should occur
+ };
+
+ if (init_result_ != KERN_SUCCESS)
+ return init_result_;
+
+ message.Head()->msgh_remote_port = port_;
+ message.Head()->msgh_bits
+ = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ kern_return_t result = mach_msg(message.Head(),
+ MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
+ message.Head()->msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ timeout, // timeout in ms
+ MACH_PORT_NULL);
+
+ return result;
+
+}
+
+
+#pragma mark -
+
+//==============================================================================
+// get a port with send rights corresponding to a named registered service
+MachPortSender::MachPortSender(const char *receive_port_name) {
+ mach_port_t bootstrap_port = 0;
+ init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+
+ if (init_result_ != KERN_SUCCESS)
+ return;
+
+ init_result_ = bootstrap_look_up(bootstrap_port,
+ const_cast<char*>(receive_port_name),
+ &send_port_);
+}
+
+//==============================================================================
+MachPortSender::MachPortSender(mach_port_t send_port)
+ : send_port_(send_port),
+ init_result_(KERN_SUCCESS) {
+}
+
+//==============================================================================
+kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
+ mach_msg_timeout_t timeout) {
+ if (message.Head()->msgh_size == 0) {
+ NOTREACHED();
+ return KERN_INVALID_VALUE; // just for safety -- never should occur
+ };
+
+ if (init_result_ != KERN_SUCCESS)
+ return init_result_;
+
+ message.Head()->msgh_remote_port = send_port_;
+
+ kern_return_t result = mach_msg(message.Head(),
+ MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
+ message.Head()->msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ timeout, // timeout in ms
+ MACH_PORT_NULL);
+
+ return result;
+}
diff --git a/ipc/chromium/src/chrome/common/mach_message_source_mac.cc b/ipc/chromium/src/chrome/common/mach_message_source_mac.cc
new file mode 100644
index 000000000..7ab2b6074
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/mach_message_source_mac.cc
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/mach_message_source_mac.h"
+
+#include "base/logging.h"
+
+MachMessageSource::MachMessageSource(mach_port_t port,
+ MachPortListener* msg_listener,
+ bool* success) {
+ DCHECK(msg_listener);
+ DCHECK(success);
+ DCHECK(port != MACH_PORT_NULL);
+
+ CFMachPortContext port_context = {0};
+ port_context.info = msg_listener;
+
+ scoped_cftyperef<CFMachPortRef> cf_mach_port_ref(
+ CFMachPortCreateWithPort(kCFAllocatorDefault,
+ port,
+ MachMessageSource::OnReceiveMachMessage,
+ &port_context,
+ NULL));
+
+ if (cf_mach_port_ref.get() == NULL) {
+ CHROMIUM_LOG(WARNING) << "CFMachPortCreate failed";
+ *success = false;
+ return;
+ }
+
+ // Create a RL source.
+ machport_runloop_ref_.reset(
+ CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
+ cf_mach_port_ref.get(),
+ 0));
+
+ if (machport_runloop_ref_.get() == NULL) {
+ CHROMIUM_LOG(WARNING) << "CFMachPortCreateRunLoopSource failed";
+ *success = false;
+ return;
+ }
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(),
+ machport_runloop_ref_.get(),
+ kCFRunLoopCommonModes);
+ *success = true;
+}
+
+MachMessageSource::~MachMessageSource() {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ machport_runloop_ref_.get(),
+ kCFRunLoopCommonModes);
+}
+
+// static
+void MachMessageSource::OnReceiveMachMessage(CFMachPortRef port, void* msg,
+ CFIndex size, void* closure) {
+ MachPortListener *msg_listener = static_cast<MachPortListener*>(closure);
+ size_t msg_size = (size < 0) ? 0 : static_cast<size_t>(size);
+ DCHECK(msg && msg_size > 0); // this should never happen!
+
+ if (msg_listener && msg && msg_size > 0) {
+ msg_listener->OnMachMessageReceived(msg, msg_size);
+ }
+}
diff --git a/ipc/chromium/src/chrome/common/mach_message_source_mac.h b/ipc/chromium/src/chrome/common/mach_message_source_mac.h
new file mode 100644
index 000000000..57e8461ca
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/mach_message_source_mac.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_
+#define CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include "base/scoped_cftyperef.h"
+
+// Handles registering and cleaning up after a CFRunloopSource for a Mach port.
+// Messages received on the port are piped through to a delegate.
+//
+// Example:
+// class MyListener : public MachMessageSource::MachPortListener {
+// public:
+// void OnMachMessageReceived(void* mach_msg, size_t size) {
+// printf("received message on Mach port\n");
+// }
+// };
+//
+// mach_port_t a_port = ...;
+// MyListener listener;
+// bool success = false;
+// MachMessageSource message_source(port, listener, &success);
+//
+// if (!success) {
+// exit(1); // Couldn't register mach runloop source.
+// }
+//
+// CFRunLoopRun(); // Process messages on runloop...
+class MachMessageSource {
+ public:
+ // Classes that want to listen on a Mach port can implement
+ // OnMachMessageReceived, |mach_msg| is a pointer to the raw message data and
+ // |size| is the buffer size;
+ class MachPortListener {
+ public:
+ virtual void OnMachMessageReceived(void* mach_msg, size_t size) = 0;
+ };
+
+ // |listener| is a week reference passed to CF, it needs to remain in
+ // existence till this object is destroeyd.
+ MachMessageSource(mach_port_t port,
+ MachPortListener* listener,
+ bool* success);
+ ~MachMessageSource();
+
+ private:
+ // Called by CF when a new message arrives on the Mach port.
+ static void OnReceiveMachMessage(CFMachPortRef port, void* msg, CFIndex size,
+ void* closure);
+
+ scoped_cftyperef<CFRunLoopSourceRef> machport_runloop_ref_;
+ DISALLOW_COPY_AND_ASSIGN(MachMessageSource);
+};
+
+#endif // CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_
diff --git a/ipc/chromium/src/chrome/common/process_watcher.h b/ipc/chromium/src/chrome/common/process_watcher.h
new file mode 100644
index 000000000..5bc6c02b5
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/process_watcher.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PROCESS_WATCHER_H_
+#define CHROME_COMMON_PROCESS_WATCHER_H_
+
+#include "base/basictypes.h"
+#include "base/process_util.h"
+
+class ProcessWatcher {
+ public:
+ // This method ensures that the specified process eventually terminates, and
+ // then it closes the given process handle.
+ //
+ // It assumes that the process has already been signalled to exit, and it
+ // begins by waiting a small amount of time for it to exit. If the process
+ // does not appear to have exited, then this function starts to become
+ // aggressive about ensuring that the process terminates.
+ //
+ // This method does not block the calling thread.
+ //
+ // NOTE: The process handle must have been opened with the PROCESS_TERMINATE
+ // and SYNCHRONIZE permissions.
+ //
+ static void EnsureProcessTerminated(base::ProcessHandle process_handle
+ , bool force=true
+ );
+
+ private:
+ // Do not instantiate this class.
+ ProcessWatcher();
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessWatcher);
+};
+
+#endif // CHROME_COMMON_PROCESS_WATCHER_H_
diff --git a/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc b/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc
new file mode 100644
index 000000000..5abe143c1
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+
+#include "chrome/common/process_watcher.h"
+
+// Maximum amount of time (in milliseconds) to wait for the process to exit.
+// XXX/cjones: fairly arbitrary, chosen to match process_watcher_win.cc
+static const int kMaxWaitMs = 2000;
+
+namespace {
+
+bool
+IsProcessDead(pid_t process)
+{
+ bool exited = false;
+ // don't care if the process crashed, just if it exited
+ base::DidProcessCrash(&exited, process);
+ return exited;
+}
+
+
+class ChildReaper : public base::MessagePumpLibevent::SignalEvent,
+ public base::MessagePumpLibevent::SignalWatcher
+{
+public:
+ explicit ChildReaper(pid_t process) : process_(process)
+ {
+ }
+
+ virtual ~ChildReaper()
+ {
+ // subclasses should have cleaned up |process_| already
+ DCHECK(!process_);
+
+ // StopCatching() is implicit
+ }
+
+ // @override
+ virtual void OnSignal(int sig)
+ {
+ DCHECK(SIGCHLD == sig);
+ DCHECK(process_);
+
+ // this may be the SIGCHLD for a process other than |process_|
+ if (IsProcessDead(process_)) {
+ process_ = 0;
+ StopCatching();
+ }
+ }
+
+protected:
+ void WaitForChildExit()
+ {
+ DCHECK(process_);
+ HANDLE_EINTR(waitpid(process_, NULL, 0));
+ }
+
+ pid_t process_;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ChildReaper);
+};
+
+
+// Fear the reaper
+class ChildGrimReaper : public ChildReaper,
+ public mozilla::Runnable
+{
+public:
+ explicit ChildGrimReaper(pid_t process) : ChildReaper(process)
+ {
+ }
+
+ virtual ~ChildGrimReaper()
+ {
+ if (process_)
+ KillProcess();
+ }
+
+ NS_IMETHOD Run() override
+ {
+ // we may have already been signaled by the time this runs
+ if (process_)
+ KillProcess();
+
+ return NS_OK;
+ }
+
+private:
+ void KillProcess()
+ {
+ DCHECK(process_);
+
+ if (IsProcessDead(process_)) {
+ process_ = 0;
+ return;
+ }
+
+ if (0 == kill(process_, SIGKILL)) {
+ // XXX this will block for whatever amount of time it takes the
+ // XXX OS to tear down the process's resources. might need to
+ // XXX rethink this if it proves expensive
+ WaitForChildExit();
+ }
+ else {
+ CHROMIUM_LOG(ERROR) << "Failed to deliver SIGKILL to " << process_ << "!"
+ << "("<< errno << ").";
+ }
+ process_ = 0;
+ }
+
+ DISALLOW_EVIL_CONSTRUCTORS(ChildGrimReaper);
+};
+
+
+class ChildLaxReaper : public ChildReaper,
+ public MessageLoop::DestructionObserver
+{
+public:
+ explicit ChildLaxReaper(pid_t process) : ChildReaper(process)
+ {
+ }
+
+ virtual ~ChildLaxReaper()
+ {
+ // WillDestroyCurrentMessageLoop() should have reaped process_ already
+ DCHECK(!process_);
+ }
+
+ // @override
+ virtual void OnSignal(int sig)
+ {
+ ChildReaper::OnSignal(sig);
+
+ if (!process_) {
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ delete this;
+ }
+ }
+
+ // @override
+ virtual void WillDestroyCurrentMessageLoop()
+ {
+ DCHECK(process_);
+
+ WaitForChildExit();
+ process_ = 0;
+
+ // XXX don't think this is necessary, since destruction can only
+ // be observed once, but can't hurt
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ delete this;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ChildLaxReaper);
+};
+
+} // namespace <anon>
+
+
+/**
+ * Do everything possible to ensure that |process| has been reaped
+ * before this process exits.
+ *
+ * |grim| decides how strict to be with the child's shutdown.
+ *
+ * | child exit timeout | upon parent shutdown:
+ * +--------------------+----------------------------------
+ * force=true | 2 seconds | kill(child, SIGKILL)
+ * force=false | infinite | waitpid(child)
+ *
+ * If a child process doesn't shut down properly, and |grim=false|
+ * used, then the parent will wait on the child forever. So,
+ * |force=false| is expected to be used when an external entity can be
+ * responsible for terminating hung processes, e.g. automated test
+ * harnesses.
+ */
+void
+ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process,
+ bool force)
+{
+ DCHECK(process != base::GetCurrentProcId());
+ DCHECK(process > 0);
+
+ if (IsProcessDead(process))
+ return;
+
+ MessageLoopForIO* loop = MessageLoopForIO::current();
+ if (force) {
+ RefPtr<ChildGrimReaper> reaper = new ChildGrimReaper(process);
+
+ loop->CatchSignal(SIGCHLD, reaper, reaper);
+ // |loop| takes ownership of |reaper|
+ loop->PostDelayedTask(reaper.forget(), kMaxWaitMs);
+ } else {
+ ChildLaxReaper* reaper = new ChildLaxReaper(process);
+
+ loop->CatchSignal(SIGCHLD, reaper, reaper);
+ // |reaper| destroys itself after destruction notification
+ loop->AddDestructionObserver(reaper);
+ }
+}
diff --git a/ipc/chromium/src/chrome/common/process_watcher_win.cc b/ipc/chromium/src/chrome/common/process_watcher_win.cc
new file mode 100644
index 000000000..fccb83999
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/process_watcher_win.cc
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/process_watcher.h"
+
+#include "base/message_loop.h"
+#include "base/object_watcher.h"
+#include "base/sys_info.h"
+
+// Maximum amount of time (in milliseconds) to wait for the process to exit.
+static const int kWaitInterval = 2000;
+
+namespace {
+
+class ChildReaper : public mozilla::Runnable,
+ public base::ObjectWatcher::Delegate,
+ public MessageLoop::DestructionObserver {
+ public:
+ explicit ChildReaper(base::ProcessHandle process, bool force)
+ : process_(process), force_(force) {
+ watcher_.StartWatching(process_, this);
+ }
+
+ virtual ~ChildReaper() {
+ if (process_) {
+ KillProcess();
+ DCHECK(!process_) << "Make sure to close the handle.";
+ }
+ }
+
+ // MessageLoop::DestructionObserver -----------------------------------------
+
+ virtual void WillDestroyCurrentMessageLoop()
+ {
+ MOZ_ASSERT(!force_);
+ if (process_) {
+ WaitForSingleObject(process_, INFINITE);
+ base::CloseProcessHandle(process_);
+ process_ = 0;
+
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ delete this;
+ }
+ }
+
+ // Task ---------------------------------------------------------------------
+
+ NS_IMETHOD Run() override {
+ MOZ_ASSERT(force_);
+ if (process_) {
+ KillProcess();
+ }
+ return NS_OK;
+ }
+
+ // MessageLoop::Watcher -----------------------------------------------------
+
+ virtual void OnObjectSignaled(HANDLE object) {
+ // When we're called from KillProcess, the ObjectWatcher may still be
+ // watching. the process handle, so make sure it has stopped.
+ watcher_.StopWatching();
+
+ base::CloseProcessHandle(process_);
+ process_ = 0;
+
+ if (!force_) {
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ delete this;
+ }
+ }
+
+ private:
+ void KillProcess() {
+ MOZ_ASSERT(force_);
+
+ // OK, time to get frisky. We don't actually care when the process
+ // terminates. We just care that it eventually terminates, and that's what
+ // TerminateProcess should do for us. Don't check for the result code since
+ // it fails quite often. This should be investigated eventually.
+ TerminateProcess(process_, base::PROCESS_END_PROCESS_WAS_HUNG);
+
+ // Now, just cleanup as if the process exited normally.
+ OnObjectSignaled(process_);
+ }
+
+ // The process that we are watching.
+ base::ProcessHandle process_;
+
+ base::ObjectWatcher watcher_;
+
+ bool force_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ChildReaper);
+};
+
+} // namespace
+
+// static
+void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process, bool force) {
+ DCHECK(process != GetCurrentProcess());
+
+ // If already signaled, then we are done!
+ if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
+ base::CloseProcessHandle(process);
+ return;
+ }
+
+ MessageLoopForIO* loop = MessageLoopForIO::current();
+ if (force) {
+ RefPtr<mozilla::Runnable> task = new ChildReaper(process, force);
+ loop->PostDelayedTask(task.forget(), kWaitInterval);
+ } else {
+ loop->AddDestructionObserver(new ChildReaper(process, force));
+ }
+}
diff --git a/ipc/chromium/src/chrome/common/transport_dib.h b/ipc/chromium/src/chrome/common/transport_dib.h
new file mode 100644
index 000000000..b1e5c0fab
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/transport_dib.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_TRANSPORT_DIB_H_
+#define CHROME_COMMON_TRANSPORT_DIB_H_
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_BSD)
+#include "base/shared_memory.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_LINUX)
+#include "chrome/common/x11_util.h"
+#endif
+
+// -----------------------------------------------------------------------------
+// A TransportDIB is a block of memory that is used to transport pixels
+// between processes: from the renderer process to the browser, and
+// between renderer and plugin processes.
+// -----------------------------------------------------------------------------
+class TransportDIB {
+ public:
+ ~TransportDIB();
+
+ // Two typedefs are defined. A Handle is the type which can be sent over
+ // the wire so that the remote side can map the transport DIB. The Id typedef
+ // is sufficient to identify the transport DIB when you know that the remote
+ // side already may have it mapped.
+#if defined(OS_WIN)
+ typedef HANDLE Handle;
+ // On Windows, the Id type includes a sequence number (epoch) to solve an ABA
+ // issue:
+ // 1) Process A creates a transport DIB with HANDLE=1 and sends to B.
+ // 2) Process B maps the transport DIB and caches 1 -> DIB.
+ // 3) Process A closes the transport DIB and creates a new one. The new DIB
+ // is also assigned HANDLE=1.
+ // 4) Process A sends the Handle to B, but B incorrectly believes that it
+ // already has it cached.
+ struct HandleAndSequenceNum {
+ HandleAndSequenceNum()
+ : handle(NULL),
+ sequence_num(0) {
+ }
+
+ HandleAndSequenceNum(HANDLE h, uint32_t seq_num)
+ : handle(h),
+ sequence_num(seq_num) {
+ }
+
+ bool operator< (const HandleAndSequenceNum& other) const {
+ // Use the lexicographic order on the tuple <handle, sequence_num>.
+ if (other.handle != handle)
+ return other.handle < handle;
+ return other.sequence_num < sequence_num;
+ }
+
+ HANDLE handle;
+ uint32_t sequence_num;
+ };
+ typedef HandleAndSequenceNum Id;
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+ typedef base::SharedMemoryHandle Handle;
+ // On Mac, the inode number of the backing file is used as an id.
+ typedef base::SharedMemoryId Id;
+#elif defined(OS_LINUX)
+ typedef int Handle; // These two ints are SysV IPC shared memory keys
+ typedef int Id;
+#endif
+
+ // Create a new TransportDIB
+ // size: the minimum size, in bytes
+ // epoch: Windows only: a global counter. See comment above.
+ // returns: NULL on failure
+ static TransportDIB* Create(size_t size, uint32_t sequence_num);
+
+ // Map the referenced transport DIB. Returns NULL on failure.
+ static TransportDIB* Map(Handle transport_dib);
+
+ // Return a pointer to the shared memory
+ void* memory() const;
+
+ // Return the maximum size of the shared memory. This is not the amount of
+ // data which is valid, you have to know that via other means, this is simply
+ // the maximum amount that /could/ be valid.
+ size_t size() const { return size_; }
+
+ // Return the identifier which can be used to refer to this shared memory
+ // on the wire.
+ Id id() const;
+
+ // Return a handle to the underlying shared memory. This can be sent over the
+ // wire to give this transport DIB to another process.
+ Handle handle() const;
+
+#if defined(OS_LINUX)
+ // Map the shared memory into the X server and return an id for the shared
+ // segment.
+ XID MapToX(Display* connection);
+#endif
+
+ private:
+ TransportDIB();
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_BSD)
+ explicit TransportDIB(base::SharedMemoryHandle dib);
+ base::SharedMemory shared_memory_;
+#elif defined(OS_LINUX)
+ int key_; // SysV shared memory id
+ void* address_; // mapped address
+ XID x_shm_; // X id for the shared segment
+ Display* display_; // connection to the X server
+#endif
+#ifdef OS_WIN
+ uint32_t sequence_num_;
+#endif
+ size_t size_; // length, in bytes
+};
+
+class MessageLoop;
+
+#endif // CHROME_COMMON_TRANSPORT_DIB_H_
diff --git a/ipc/chromium/src/chrome/common/transport_dib_mac.cc b/ipc/chromium/src/chrome/common/transport_dib_mac.cc
new file mode 100644
index 000000000..feb78b207
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/transport_dib_mac.cc
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/transport_dib.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/shared_memory.h"
+
+TransportDIB::TransportDIB()
+ : size_(0) {
+}
+
+TransportDIB::TransportDIB(TransportDIB::Handle dib)
+ : shared_memory_(dib, false /* read write */),
+ size_(0) {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32_t sequence_num) {
+ TransportDIB* dib = new TransportDIB;
+ if (!dib->shared_memory_.Create("", false /* read write */,
+ false /* do not open existing */, size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
+ TransportDIB* dib = new TransportDIB(handle);
+ struct stat st;
+ fstat(handle.fd, &st);
+
+ if (!dib->shared_memory_.Map(st.st_size)) {
+ delete dib;
+ HANDLE_EINTR(close(handle.fd));
+ return nullptr;
+ }
+
+ dib->size_ = st.st_size;
+
+ return dib;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return shared_memory_.id();
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
diff --git a/ipc/chromium/src/chrome/common/transport_dib_win.cc b/ipc/chromium/src/chrome/common/transport_dib_win.cc
new file mode 100644
index 000000000..3ab789847
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/transport_dib_win.cc
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+#include "chrome/common/transport_dib.h"
+
+TransportDIB::TransportDIB() {
+}
+
+TransportDIB::~TransportDIB() {
+}
+
+TransportDIB::TransportDIB(HANDLE handle)
+ : shared_memory_(handle, false /* read write */) {
+}
+
+// static
+TransportDIB* TransportDIB::Create(size_t size, uint32_t sequence_num) {
+ size_t allocation_granularity = base::SysInfo::VMAllocationGranularity();
+ size = size / allocation_granularity + 1;
+ size = size * allocation_granularity;
+
+ TransportDIB* dib = new TransportDIB;
+
+ if (!dib->shared_memory_.Create("", false /* read write */,
+ true /* open existing */, size)) {
+ delete dib;
+ return NULL;
+ }
+
+ dib->size_ = size;
+ dib->sequence_num_ = sequence_num;
+
+ return dib;
+}
+
+// static
+TransportDIB* TransportDIB::Map(TransportDIB::Handle handle) {
+ TransportDIB* dib = new TransportDIB(handle);
+ if (!dib->shared_memory_.Map(0 /* map whole shared memory segment */)) {
+ CHROMIUM_LOG(ERROR) << "Failed to map transport DIB"
+ << " handle:" << handle
+ << " error:" << GetLastError();
+ delete dib;
+ return NULL;
+ }
+
+ // There doesn't seem to be any way to find the size of the shared memory
+ // region! GetFileSize indicates that the handle is invalid. Thus, we
+ // conservatively set the size to the maximum and hope that the renderer
+ // isn't about to ask us to read off the end of the array.
+ dib->size_ = std::numeric_limits<size_t>::max();
+
+ return dib;
+}
+
+void* TransportDIB::memory() const {
+ return shared_memory_.memory();
+}
+
+TransportDIB::Handle TransportDIB::handle() const {
+ return shared_memory_.handle();
+}
+
+TransportDIB::Id TransportDIB::id() const {
+ return Id(shared_memory_.handle(), sequence_num_);
+}
diff --git a/ipc/chromium/src/chrome/common/x11_util.h b/ipc/chromium/src/chrome/common/x11_util.h
new file mode 100644
index 000000000..688178356
--- /dev/null
+++ b/ipc/chromium/src/chrome/common/x11_util.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_X11_UTIL_H_
+#define CHROME_COMMON_X11_UTIL_H_
+
+// This file declares utility functions for X11 (Linux only).
+//
+// These functions do not require the Xlib headers to be included (which is why
+// we use a void* for Visual*). The Xlib headers are highly polluting so we try
+// hard to limit their spread into the rest of the code.
+
+typedef unsigned long XID;
+typedef struct _XDisplay Display;
+
+#endif // CHROME_COMMON_X11_UTIL_H_