summaryrefslogtreecommitdiffstats
path: root/chromium/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ipc')
-rw-r--r--chromium/ipc/BUILD.gn178
-rw-r--r--chromium/ipc/OWNERS1
-rw-r--r--chromium/ipc/ipc.gyp38
-rw-r--r--chromium/ipc/ipc.gypi5
-rw-r--r--chromium/ipc/ipc_channel.h114
-rw-r--r--chromium/ipc/ipc_channel_common.cc47
-rw-r--r--chromium/ipc/ipc_channel_factory.cc10
-rw-r--r--chromium/ipc/ipc_channel_nacl.cc91
-rw-r--r--chromium/ipc/ipc_channel_nacl.h21
-rw-r--r--chromium/ipc/ipc_channel_posix.cc158
-rw-r--r--chromium/ipc/ipc_channel_posix.h47
-rw-r--r--chromium/ipc/ipc_channel_posix_unittest.cc202
-rw-r--r--chromium/ipc/ipc_channel_proxy.cc155
-rw-r--r--chromium/ipc/ipc_channel_proxy.h69
-rw-r--r--chromium/ipc/ipc_channel_proxy_unittest.cc441
-rw-r--r--chromium/ipc/ipc_channel_proxy_unittest_messages.h44
-rw-r--r--chromium/ipc/ipc_channel_reader.cc7
-rw-r--r--chromium/ipc/ipc_channel_unittest.cc12
-rw-r--r--chromium/ipc/ipc_channel_win.cc82
-rw-r--r--chromium/ipc/ipc_channel_win.h33
-rw-r--r--chromium/ipc/ipc_forwarding_message_filter.cc1
-rw-r--r--chromium/ipc/ipc_forwarding_message_filter.h7
-rw-r--r--chromium/ipc/ipc_fuzzing_tests.cc75
-rw-r--r--chromium/ipc/ipc_listener.h3
-rw-r--r--chromium/ipc/ipc_message.cc17
-rw-r--r--chromium/ipc/ipc_message.h48
-rw-r--r--chromium/ipc/ipc_message_macros.h160
-rw-r--r--chromium/ipc/ipc_message_start.h17
-rw-r--r--chromium/ipc/ipc_message_unittest.cc79
-rw-r--r--chromium/ipc/ipc_message_utils.cc18
-rw-r--r--chromium/ipc/ipc_message_utils.h79
-rw-r--r--chromium/ipc/ipc_multiprocess_test.cc7
-rw-r--r--chromium/ipc/ipc_nacl.gyp (renamed from chromium/ipc/ipc_untrusted.gyp)8
-rw-r--r--chromium/ipc/ipc_perftests.cc24
-rw-r--r--chromium/ipc/ipc_platform_file.cc5
-rw-r--r--chromium/ipc/ipc_platform_file.h19
-rw-r--r--chromium/ipc/ipc_send_fds_test.cc19
-rw-r--r--chromium/ipc/ipc_switches.cc5
-rw-r--r--chromium/ipc/ipc_switches.h1
-rw-r--r--chromium/ipc/ipc_sync_channel.cc50
-rw-r--r--chromium/ipc/ipc_sync_channel.h35
-rw-r--r--chromium/ipc/ipc_sync_channel_unittest.cc209
-rw-r--r--chromium/ipc/ipc_sync_message_filter.cc15
-rw-r--r--chromium/ipc/ipc_sync_message_filter.h12
-rw-r--r--chromium/ipc/ipc_test_base.cc26
-rw-r--r--chromium/ipc/ipc_test_sink.cc29
-rw-r--r--chromium/ipc/ipc_test_sink.h8
-rw-r--r--chromium/ipc/message_filter.cc35
-rw-r--r--chromium/ipc/message_filter.h67
-rw-r--r--chromium/ipc/message_filter_router.cc92
-rw-r--r--chromium/ipc/message_filter_router.h42
-rw-r--r--chromium/ipc/sync_socket_unittest.cc10
-rw-r--r--chromium/ipc/unix_domain_socket_util.cc43
53 files changed, 2008 insertions, 1012 deletions
diff --git a/chromium/ipc/BUILD.gn b/chromium/ipc/BUILD.gn
new file mode 100644
index 00000000000..3bff55ee528
--- /dev/null
+++ b/chromium/ipc/BUILD.gn
@@ -0,0 +1,178 @@
+# 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.
+
+component("ipc") {
+ sources = [
+ "file_descriptor_set_posix.cc",
+ "file_descriptor_set_posix.h",
+ "ipc_channel.cc",
+ "ipc_channel.h",
+ "ipc_channel_common.cc",
+ "ipc_channel_factory.cc",
+ "ipc_channel_factory.h",
+ "ipc_channel_handle.h",
+ "ipc_channel_nacl.cc",
+ "ipc_channel_nacl.h",
+ "ipc_channel_posix.cc",
+ "ipc_channel_posix.h",
+ "ipc_channel_proxy.cc",
+ "ipc_channel_proxy.h",
+ "ipc_channel_reader.cc",
+ "ipc_channel_reader.h",
+ "ipc_channel_win.cc",
+ "ipc_channel_win.h",
+ "ipc_descriptors.h",
+ "ipc_export.h",
+ "ipc_forwarding_message_filter.cc",
+ "ipc_forwarding_message_filter.h",
+ "ipc_listener.h",
+ "ipc_logging.cc",
+ "ipc_logging.h",
+ "ipc_message.cc",
+ "ipc_message.h",
+ "ipc_message_macros.h",
+ "ipc_message_start.h",
+ "ipc_message_utils.cc",
+ "ipc_message_utils.h",
+ "ipc_param_traits.h",
+ "ipc_platform_file.cc",
+ "ipc_platform_file.h",
+ "ipc_sender.h",
+ "ipc_switches.cc",
+ "ipc_switches.h",
+ "ipc_sync_channel.cc",
+ "ipc_sync_channel.h",
+ "ipc_sync_message.cc",
+ "ipc_sync_message.h",
+ "ipc_sync_message_filter.cc",
+ "ipc_sync_message_filter.h",
+ "message_filter.cc",
+ "message_filter.h",
+ "message_filter_router.cc",
+ "message_filter_router.h",
+ "param_traits_log_macros.h",
+ "param_traits_macros.h",
+ "param_traits_read_macros.h",
+ "param_traits_write_macros.h",
+ "struct_constructor_macros.h",
+ "struct_destructor_macros.h",
+ "unix_domain_socket_util.cc",
+ "unix_domain_socket_util.h",
+ ]
+
+ if (!is_nacl) {
+ sources -= [
+ "ipc_channel_nacl.cc",
+ "ipc_channel_nacl.h",
+ ]
+ }
+
+ if (is_win || is_ios) {
+ sources -= [
+ "ipc_channel_factory.cc",
+ "unix_domain_socket_util.cc",
+ ]
+ }
+
+ defines = [ "IPC_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ # TODO(viettrungluu): Needed for base/lazy_instance.h, which is suspect.
+ "//base/third_party/dynamic_annotations",
+ ]
+}
+
+# TODO(dpranke): crbug.com/360936. Get this to build and run on Android.
+if (!is_android) {
+ test("ipc_tests") {
+ sources = [
+ "file_descriptor_set_posix_unittest.cc",
+ "ipc_channel_posix_unittest.cc",
+ "ipc_channel_unittest.cc",
+ "ipc_fuzzing_tests.cc",
+ "ipc_message_unittest.cc",
+ "ipc_message_utils_unittest.cc",
+ "ipc_send_fds_test.cc",
+ "ipc_sync_channel_unittest.cc",
+ "ipc_sync_message_unittest.cc",
+ "ipc_sync_message_unittest.h",
+ "ipc_test_base.cc",
+ "ipc_test_base.h",
+ "sync_socket_unittest.cc",
+ "unix_domain_socket_util_unittest.cc",
+ ]
+
+ if (is_win || is_ios) {
+ sources -= [ "unix_domain_socket_util_unittest.cc" ]
+ }
+
+ # TODO(brettw) hook up Android testing.
+ #if (is_android && gtest_target_type == "shared_library") {
+ # deps += "/testing/android/native_test.gyp:native_testNative_code"
+ #}
+
+ # TODO(brettw) hook up tcmalloc to this target.
+ #if (is_posix && !is_mac && !is_android) {
+ # if (use_allocator!="none") {
+ # deps += "/base/allocator"
+ # }
+ #}
+
+ deps = [
+ ":ipc",
+ ":test_support_ipc",
+ "//base",
+ "//base:i18n",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ test("ipc_perftests") {
+ sources = [
+ "ipc_perftests.cc",
+ "ipc_test_base.cc",
+ "ipc_test_base.h",
+ ]
+
+ # TODO(brettw) hook up Android testing.
+ #if (is_android && gtest_target_type == "shared_library") {
+ # deps += "/testing/android/native_test.gyp:native_testNative_code"
+ #}
+
+ # TODO(brettw) hook up tcmalloc to this target.
+ #if (is_posix && !is_mac && !is_android) {
+ # if (use_allocator!="none") {
+ # deps += "//base/allocator"
+ # }
+ #}
+
+ deps = [
+ ":ipc",
+ ":test_support_ipc",
+ "//base",
+ "//base:i18n",
+ "//base/test:test_support",
+ "//base/test:test_support_perf",
+ "//testing/gtest",
+ ]
+ }
+}
+
+static_library("test_support_ipc") {
+ sources = [
+ "ipc_multiprocess_test.cc",
+ "ipc_multiprocess_test.h",
+ "ipc_test_sink.cc",
+ "ipc_test_sink.h",
+ ]
+ deps = [
+ ":ipc",
+ "//base",
+ "//testing/gtest",
+ ]
+}
+
diff --git a/chromium/ipc/OWNERS b/chromium/ipc/OWNERS
index 37a61fa0463..f929594d23e 100644
--- a/chromium/ipc/OWNERS
+++ b/chromium/ipc/OWNERS
@@ -11,7 +11,6 @@ dmichael@chromium.org
# New IPC message files require a security review to avoid introducing
# new sandbox escapes.
per-file ipc_message_start.h=set noparent
-per-file ipc_message_start.h=cdn@chromium.org
per-file ipc_message_start.h=cevans@chromium.org
per-file ipc_message_start.h=dcheng@chromium.org
per-file ipc_message_start.h=jln@chromium.org
diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp
index ace836b3a1b..a6e92691f11 100644
--- a/chromium/ipc/ipc.gyp
+++ b/chromium/ipc/ipc.gyp
@@ -46,6 +46,7 @@
'sources': [
'file_descriptor_set_posix_unittest.cc',
'ipc_channel_posix_unittest.cc',
+ 'ipc_channel_proxy_unittest.cc',
'ipc_channel_unittest.cc',
'ipc_fuzzing_tests.cc',
'ipc_message_unittest.cc',
@@ -61,24 +62,19 @@
'unix_domain_socket_util_unittest.cc',
],
'conditions': [
- ['toolkit_uses_gtk == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:gtk',
- ],
- }],
['OS == "win" or OS == "ios"', {
'sources!': [
'unix_domain_socket_util_unittest.cc',
],
}],
- ['OS == "android" and gtest_target_type == "shared_library"', {
+ ['OS == "android"', {
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
],
}],
['os_posix == 1 and OS != "mac" and OS != "android"', {
'conditions': [
- ['linux_use_tcmalloc==1', {
+ ['use_allocator!="none"', {
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
],
@@ -109,19 +105,14 @@
'ipc_test_base.h',
],
'conditions': [
- ['toolkit_uses_gtk == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:gtk',
- ],
- }],
- ['OS == "android" and gtest_target_type == "shared_library"', {
+ ['OS == "android"', {
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
],
}],
['os_posix == 1 and OS != "mac" and OS != "android"', {
'conditions': [
- ['linux_use_tcmalloc==1', {
+ ['use_allocator!="none"', {
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
],
@@ -156,7 +147,7 @@
'ipc_target': 1,
},
'dependencies': [
- '../base/base.gyp:base_nacl_win64',
+ '../base/base.gyp:base_win64',
# TODO(viettrungluu): Needed for base/lazy_instance.h, which is
# suspect.
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
@@ -176,10 +167,7 @@
},
],
}],
- # Special target to wrap a gtest_target_type==shared_library
- # ipc_tests into an android apk for execution.
- # See base.gyp for TODO(jrg)s about this strategy.
- ['OS == "android" and gtest_target_type == "shared_library"', {
+ ['OS == "android"', {
'targets': [
{
'target_name': 'ipc_tests_apk',
@@ -189,7 +177,17 @@
],
'variables': {
'test_suite_name': 'ipc_tests',
- 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ipc_tests<(SHARED_LIB_SUFFIX)',
+ },
+ 'includes': [ '../build/apk_test.gypi' ],
+ },
+ {
+ 'target_name': 'ipc_perftests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'ipc_perftests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'ipc_perftests',
},
'includes': [ '../build/apk_test.gypi' ],
}],
diff --git a/chromium/ipc/ipc.gypi b/chromium/ipc/ipc.gypi
index ba80e421404..e7d5cc63f3b 100644
--- a/chromium/ipc/ipc.gypi
+++ b/chromium/ipc/ipc.gypi
@@ -15,6 +15,7 @@
'file_descriptor_set_posix.h',
'ipc_channel.cc',
'ipc_channel.h',
+ 'ipc_channel_common.cc',
'ipc_channel_factory.cc',
'ipc_channel_factory.h',
'ipc_channel_handle.h',
@@ -53,6 +54,10 @@
'ipc_sync_message.h',
'ipc_sync_message_filter.cc',
'ipc_sync_message_filter.h',
+ 'message_filter.cc',
+ 'message_filter.h',
+ 'message_filter_router.cc',
+ 'message_filter_router.h',
'param_traits_log_macros.h',
'param_traits_macros.h',
'param_traits_read_macros.h',
diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h
index 7e09a806f7a..bca3ea066c3 100644
--- a/chromium/ipc/ipc_channel.h
+++ b/chromium/ipc/ipc_channel.h
@@ -55,21 +55,15 @@ class IPC_EXPORT Channel : public Sender {
};
// Some Standard Modes
+ // TODO(morrita): These are under deprecation work. You should use Create*()
+ // functions instead.
enum Mode {
MODE_NONE = MODE_NO_FLAG,
MODE_SERVER = MODE_SERVER_FLAG,
MODE_CLIENT = MODE_CLIENT_FLAG,
- // Channels on Windows are named by default and accessible from other
- // processes. On POSIX channels are anonymous by default and not accessible
- // from other processes. Named channels work via named unix domain sockets.
- // On Windows MODE_NAMED_SERVER is equivalent to MODE_SERVER and
- // MODE_NAMED_CLIENT is equivalent to MODE_CLIENT.
MODE_NAMED_SERVER = MODE_SERVER_FLAG | MODE_NAMED_FLAG,
MODE_NAMED_CLIENT = MODE_CLIENT_FLAG | MODE_NAMED_FLAG,
#if defined(OS_POSIX)
- // An "open" named server accepts connections from ANY client.
- // The caller must then implement their own access-control based on the
- // client process' user Id.
MODE_OPEN_NAMED_SERVER = MODE_OPEN_ACCESS_FLAG | MODE_SERVER_FLAG |
MODE_NAMED_FLAG
#endif
@@ -106,15 +100,48 @@ class IPC_EXPORT Channel : public Sender {
// the file descriptor in the channel handle is != -1, the channel takes
// ownership of the file descriptor and will close it appropriately, otherwise
// it will create a new descriptor internally.
- // |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 IPC::ChannelHandle &channel_handle, Mode mode,
- Listener* listener);
+ // There are four type of modes how channels operate:
+ //
+ // - Server and named server: In these modes, the Channel is
+ // responsible for settingb up the IPC object
+ // - An "open" named server: It accepts connections from ANY client.
+ // The caller must then implement their own access-control based on the
+ // client process' user Id.
+ // - Client and named client: In these mode, the Channel merely
+ // connects to the already established IPC object.
+ //
+ // Each mode has its own Create*() API to create the Channel object.
+ //
+ // TODO(morrita): Replace CreateByModeForProxy() with one of above Create*().
+ //
+ static scoped_ptr<Channel> Create(
+ const IPC::ChannelHandle &channel_handle, Mode mode,Listener* listener);
+
+ static scoped_ptr<Channel> CreateClient(
+ const IPC::ChannelHandle &channel_handle, Listener* listener);
+
+ // Channels on Windows are named by default and accessible from other
+ // processes. On POSIX channels are anonymous by default and not accessible
+ // from other processes. Named channels work via named unix domain sockets.
+ // On Windows MODE_NAMED_SERVER is equivalent to MODE_SERVER and
+ // MODE_NAMED_CLIENT is equivalent to MODE_CLIENT.
+ static scoped_ptr<Channel> CreateNamedServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener);
+ static scoped_ptr<Channel> CreateNamedClient(
+ const IPC::ChannelHandle &channel_handle, Listener* listener);
+#if defined(OS_POSIX)
+ // An "open" named server accepts connections from ANY client.
+ // The caller must then implement their own access-control based on the
+ // client process' user Id.
+ static scoped_ptr<Channel> CreateOpenNamedServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener);
+#endif
+ static scoped_ptr<Channel> CreateServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener);
+
virtual ~Channel();
@@ -123,14 +150,14 @@ class IPC_EXPORT Channel : public Sender {
// connect to a pre-existing pipe. Note, calling Connect()
// will not block the calling thread and may complete
// asynchronously.
- bool Connect() WARN_UNUSED_RESULT;
+ virtual bool Connect() WARN_UNUSED_RESULT = 0;
// Close this Channel explicitly. May be called multiple times.
// On POSIX calling close on an IPC channel that listens for connections will
// cause it to close any accepted connections, and it will stop listening for
// new connections. If you just want to close the currently accepted
// connection and listen for new ones, use ResetToAcceptingConnectionState.
- void Close();
+ virtual void Close() = 0;
// Get the process ID for the connected peer.
//
@@ -141,45 +168,25 @@ class IPC_EXPORT Channel : public Sender {
// in response to a message from the remote side (which guarantees that it's
// been connected), or you wait for the "connected" notification on the
// listener.
- base::ProcessId peer_pid() const;
+ virtual base::ProcessId GetPeerPID() const = 0;
// 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.
- virtual bool Send(Message* message) OVERRIDE;
+ virtual bool Send(Message* message) = 0;
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) && !defined(OS_NACL)
// On POSIX an IPC::Channel wraps a socketpair(), this method returns the
// FD # for the client end of the socket.
// This method may only be called on the server side of a channel.
// This method can be called on any thread.
- int GetClientFileDescriptor() const;
+ virtual int GetClientFileDescriptor() const = 0;
// Same as GetClientFileDescriptor, but transfers the ownership of the
// file descriptor to the caller.
// This method can be called on any thread.
- int TakeClientFileDescriptor();
-
- // On POSIX an IPC::Channel can either wrap an established socket, or it
- // can wrap a socket that is listening for connections. Currently an
- // IPC::Channel that listens for connections can only accept one connection
- // at a time.
-
- // Returns true if the channel supports listening for connections.
- bool AcceptsConnections() const;
-
- // Returns true if the channel supports listening for connections and is
- // currently connected.
- bool HasAcceptedConnection() const;
-
- // Returns true if the peer process' effective user id can be determined, in
- // which case the supplied peer_euid is updated with it.
- bool GetPeerEuid(uid_t* peer_euid) const;
-
- // Closes any currently connected socket, and returns to a listening state
- // for more connections.
- void ResetToAcceptingConnectionState();
+ virtual int TakeClientFileDescriptor() = 0;
#endif // defined(OS_POSIX) && !defined(OS_NACL)
// Returns true if a named server channel is initialized on the given channel
@@ -204,19 +211,22 @@ class IPC_EXPORT Channel : public Sender {
static void SetGlobalPid(int pid);
#endif
- protected:
- // Used in Chrome by the TestSink to provide a dummy channel implementation
- // for testing. TestSink overrides the "interesting" functions in Channel so
- // no actual implementation is needed. This will cause un-overridden calls to
- // segfault. Do not use outside of test code!
- Channel() : channel_impl_(0) { }
-
- private:
- // PIMPL to which all channel calls are delegated.
- class ChannelImpl;
- ChannelImpl *channel_impl_;
+#if defined(OS_ANDROID)
+ // Most tests are single process and work the same on all platforms. However
+ // in some cases we want to test multi-process, and Android differs in that it
+ // can't 'exec' after forking. This callback resets any data in the forked
+ // process such that it acts similar to if it was exec'd, for tests.
+ static void NotifyProcessForkedForTesting();
+#endif
+
};
+#if defined(OS_POSIX)
+// SocketPair() creates a pair of socket FDs suitable for using with
+// IPC::Channel.
+IPC_EXPORT bool SocketPair(int* fd1, int* fd2);
+#endif
+
} // namespace IPC
#endif // IPC_IPC_CHANNEL_H_
diff --git a/chromium/ipc/ipc_channel_common.cc b/chromium/ipc/ipc_channel_common.cc
new file mode 100644
index 00000000000..d7347cc7a1b
--- /dev/null
+++ b/chromium/ipc/ipc_channel_common.cc
@@ -0,0 +1,47 @@
+// Copyright 2014 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 "ipc/ipc_channel.h"
+
+namespace IPC {
+
+// static
+scoped_ptr<Channel> Channel::CreateClient(
+ const IPC::ChannelHandle &channel_handle, Listener* listener) {
+ return Channel::Create(channel_handle, Channel::MODE_CLIENT, listener);
+}
+
+// static
+scoped_ptr<Channel> Channel::CreateNamedServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener) {
+ return Channel::Create(channel_handle, Channel::MODE_NAMED_SERVER, listener);
+}
+
+// static
+scoped_ptr<Channel> Channel::CreateNamedClient(
+ const IPC::ChannelHandle &channel_handle, Listener* listener) {
+ return Channel::Create(channel_handle, Channel::MODE_NAMED_CLIENT, listener);
+}
+
+#if defined(OS_POSIX)
+// static
+scoped_ptr<Channel> Channel::CreateOpenNamedServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener) {
+ return Channel::Create(channel_handle,
+ Channel::MODE_OPEN_NAMED_SERVER,
+ listener);
+}
+#endif
+
+// static
+scoped_ptr<Channel> Channel::CreateServer(
+ const IPC::ChannelHandle &channel_handle, Listener* listener) {
+ return Channel::Create(channel_handle, Channel::MODE_SERVER, listener);
+}
+
+Channel::~Channel() {
+}
+
+} // namespace IPC
+
diff --git a/chromium/ipc/ipc_channel_factory.cc b/chromium/ipc/ipc_channel_factory.cc
index 5c24284f95d..244024c2f6d 100644
--- a/chromium/ipc/ipc_channel_factory.cc
+++ b/chromium/ipc/ipc_channel_factory.cc
@@ -5,6 +5,7 @@
#include "ipc/ipc_channel_factory.h"
#include "base/file_util.h"
+#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "ipc/unix_domain_socket_util.h"
@@ -51,21 +52,20 @@ void ChannelFactory::OnFileCanReadWithoutBlocking(int fd) {
delegate_->OnListenError();
return;
}
+ base::ScopedFD scoped_fd(new_fd);
- if (new_fd < 0) {
+ if (!scoped_fd.is_valid()) {
// The accept() failed, but not in such a way that the factory needs to be
// shut down.
return;
}
- file_util::ScopedFD scoped_fd(&new_fd);
-
// Verify that the IPC channel peer is running as the same user.
- if (!IsPeerAuthorized(new_fd))
+ if (!IsPeerAuthorized(scoped_fd.get()))
return;
ChannelHandle handle(std::string(),
- base::FileDescriptor(*scoped_fd.release(), true));
+ base::FileDescriptor(scoped_fd.release(), true));
delegate_->OnClientConnected(handle);
}
diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc
index 1ecd5718245..0928ba63305 100644
--- a/chromium/ipc/ipc_channel_nacl.cc
+++ b/chromium/ipc/ipc_channel_nacl.cc
@@ -17,6 +17,7 @@
#include "base/task_runner_util.h"
#include "base/threading/simple_thread.h"
#include "ipc/file_descriptor_set_posix.h"
+#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
#include "native_client/src/public/imc_syscalls.h"
#include "native_client/src/public/imc_types.h"
@@ -61,7 +62,7 @@ bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
} // namespace
-class Channel::ChannelImpl::ReaderThreadRunner
+class ChannelNacl::ReaderThreadRunner
: public base::DelegateSimpleThread::Delegate {
public:
// |pipe|: A file descriptor from which we will read using imc_recvmsg.
@@ -90,7 +91,7 @@ class Channel::ChannelImpl::ReaderThreadRunner
DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
};
-Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner(
+ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
int pipe,
base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
base::Callback<void ()> failure_callback,
@@ -101,7 +102,7 @@ Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner(
main_message_loop_(main_message_loop) {
}
-void Channel::ChannelImpl::ReaderThreadRunner::Run() {
+void ChannelNacl::ReaderThreadRunner::Run() {
while (true) {
scoped_ptr<MessageContents> msg_contents(new MessageContents);
bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
@@ -117,9 +118,9 @@ void Channel::ChannelImpl::ReaderThreadRunner::Run() {
}
}
-Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
- Mode mode,
- Listener* listener)
+ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
+ Mode mode,
+ Listener* listener)
: ChannelReader(listener),
mode_(mode),
waiting_connect_(true),
@@ -134,13 +135,19 @@ Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
}
}
-Channel::ChannelImpl::~ChannelImpl() {
+ChannelNacl::~ChannelNacl() {
Close();
}
-bool Channel::ChannelImpl::Connect() {
+base::ProcessId ChannelNacl::GetPeerPID() const {
+ // This shouldn't actually get used in the untrusted side of the proxy, and we
+ // don't have the real pid anyway.
+ return -1;
+}
+
+bool ChannelNacl::Connect() {
if (pipe_ == -1) {
- DLOG(INFO) << "Channel creation failed: " << pipe_name_;
+ DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
return false;
}
@@ -152,9 +159,9 @@ bool Channel::ChannelImpl::Connect() {
reader_thread_runner_.reset(
new ReaderThreadRunner(
pipe_,
- base::Bind(&Channel::ChannelImpl::DidRecvMsg,
+ base::Bind(&ChannelNacl::DidRecvMsg,
weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&Channel::ChannelImpl::ReadDidFail,
+ base::Bind(&ChannelNacl::ReadDidFail,
weak_ptr_factory_.GetWeakPtr()),
base::MessageLoopProxy::current()));
reader_thread_.reset(
@@ -164,10 +171,14 @@ bool Channel::ChannelImpl::Connect() {
waiting_connect_ = false;
// If there were any messages queued before connection, send them.
ProcessOutgoingMessages();
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+ base::Bind(&ChannelNacl::CallOnChannelConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
return true;
}
-void Channel::ChannelImpl::Close() {
+void ChannelNacl::Close() {
// For now, we assume that at shutdown, the reader thread will be woken with
// a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
// might simply be killed with no chance to clean up anyway :-).
@@ -184,7 +195,7 @@ void Channel::ChannelImpl::Close() {
output_queue_.clear();
}
-bool Channel::ChannelImpl::Send(Message* message) {
+bool ChannelNacl::Send(Message* message) {
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type();
scoped_ptr<Message> message_ptr(message);
@@ -201,7 +212,7 @@ bool Channel::ChannelImpl::Send(Message* message) {
return true;
}
-void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
+void ChannelNacl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
// Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
// the reader thread after Close is called. If so, we ignore it.
if (pipe_ == -1)
@@ -222,11 +233,11 @@ void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
ProcessIncomingMessages();
}
-void Channel::ChannelImpl::ReadDidFail() {
+void ChannelNacl::ReadDidFail() {
Close();
}
-bool Channel::ChannelImpl::CreatePipe(
+bool ChannelNacl::CreatePipe(
const IPC::ChannelHandle& channel_handle) {
DCHECK(pipe_ == -1);
@@ -245,7 +256,7 @@ bool Channel::ChannelImpl::CreatePipe(
return true;
}
-bool Channel::ChannelImpl::ProcessOutgoingMessages() {
+bool ChannelNacl::ProcessOutgoingMessages() {
DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
// no connection?
if (output_queue_.empty())
@@ -293,7 +304,11 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
return true;
}
-Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
+void ChannelNacl::CallOnChannelConnected() {
+ listener()->OnChannelConnected(GetPeerPID());
+}
+
+ChannelNacl::ReadState ChannelNacl::ReadData(
char* buffer,
int buffer_len,
int* bytes_read) {
@@ -324,7 +339,7 @@ Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
return READ_SUCCEEDED;
}
-bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
+bool ChannelNacl::WillDispatchInputMessage(Message* msg) {
uint16 header_fds = msg->header()->num_fds;
CHECK(header_fds == input_fds_.size());
if (header_fds == 0)
@@ -339,46 +354,24 @@ bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
return true;
}
-bool Channel::ChannelImpl::DidEmptyInputBuffers() {
+bool ChannelNacl::DidEmptyInputBuffers() {
// When the input data buffer is empty, the fds should be too.
return input_fds_.empty();
}
-void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
+void ChannelNacl::HandleInternalMessage(const Message& msg) {
// The trusted side IPC::Channel should handle the "hello" handshake; we
// should not receive the "Hello" message.
NOTREACHED();
}
-//------------------------------------------------------------------------------
-// Channel's methods simply call through to ChannelImpl.
-
-Channel::Channel(const IPC::ChannelHandle& channel_handle,
- Mode mode,
- Listener* listener)
- : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
-}
-
-Channel::~Channel() {
- delete channel_impl_;
-}
-
-bool Channel::Connect() {
- return channel_impl_->Connect();
-}
-
-void Channel::Close() {
- channel_impl_->Close();
-}
-
-base::ProcessId Channel::peer_pid() const {
- // This shouldn't actually get used in the untrusted side of the proxy, and we
- // don't have the real pid anyway.
- return -1;
-}
+// Channel's methods
-bool Channel::Send(Message* message) {
- return channel_impl_->Send(message);
+// static
+scoped_ptr<Channel> Channel::Create(
+ const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
+ return scoped_ptr<Channel>(
+ new ChannelNacl(channel_handle, mode, listener));
}
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_nacl.h b/chromium/ipc/ipc_channel_nacl.h
index a21730eb813..c47892d25c4 100644
--- a/chromium/ipc/ipc_channel_nacl.h
+++ b/chromium/ipc/ipc_channel_nacl.h
@@ -22,7 +22,7 @@ namespace IPC {
// descriptors).
struct MessageContents;
-// Similar to the Posix version of ChannelImpl but for Native Client code.
+// Similar to the ChannelPosix but for Native Client code.
// This is somewhat different because sendmsg/recvmsg here do not follow POSIX
// semantics. Instead, they are implemented by a custom embedding of
// NaClDescCustom. See NaClIPCAdapter for the trusted-side implementation.
@@ -31,18 +31,20 @@ struct MessageContents;
// sharing handles. We also currently do not support passing file descriptors or
// named pipes, and we use background threads to emulate signaling when we can
// read or write without blocking.
-class Channel::ChannelImpl : public internal::ChannelReader {
+class ChannelNacl : public Channel,
+ public internal::ChannelReader {
public:
// Mirror methods of Channel, see ipc_channel.h for description.
- ChannelImpl(const IPC::ChannelHandle& channel_handle,
+ ChannelNacl(const IPC::ChannelHandle& channel_handle,
Mode mode,
Listener* listener);
- virtual ~ChannelImpl();
+ virtual ~ChannelNacl();
// Channel implementation.
- bool Connect();
- void Close();
- bool Send(Message* message);
+ virtual base::ProcessId GetPeerPID() const OVERRIDE;
+ virtual bool Connect() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual bool Send(Message* message) OVERRIDE;
// Posted to the main thread by ReaderThreadRunner.
void DidRecvMsg(scoped_ptr<MessageContents> contents);
@@ -53,6 +55,7 @@ class Channel::ChannelImpl : public internal::ChannelReader {
bool CreatePipe(const IPC::ChannelHandle& channel_handle);
bool ProcessOutgoingMessages();
+ void CallOnChannelConnected();
// ChannelReader implementation.
virtual ReadState ReadData(char* buffer,
@@ -108,9 +111,9 @@ class Channel::ChannelImpl : public internal::ChannelReader {
// called. Normally after we're connected, the queue is empty.
std::deque<linked_ptr<Message> > output_queue_;
- base::WeakPtrFactory<ChannelImpl> weak_ptr_factory_;
+ base::WeakPtrFactory<ChannelNacl> weak_ptr_factory_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelNacl);
};
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc
index 87885329001..8ddf73a2442 100644
--- a/chromium/ipc/ipc_channel_posix.cc
+++ b/chromium/ipc/ipc_channel_posix.cc
@@ -135,6 +135,9 @@ class PipeMap {
ChannelToFDMap map_;
friend struct DefaultSingletonTraits<PipeMap>;
+#if defined(OS_ANDROID)
+ friend void ::IPC::Channel::NotifyProcessForkedForTesting();
+#endif
};
//------------------------------------------------------------------------------
@@ -159,14 +162,23 @@ bool SocketWriteErrorIsRecoverable() {
}
} // namespace
+
+#if defined(OS_ANDROID)
+// When we fork for simple tests on Android, we can't 'exec', so we need to
+// reset these entries manually to get the expected testing behavior.
+void Channel::NotifyProcessForkedForTesting() {
+ PipeMap::GetInstance()->map_.clear();
+}
+#endif
+
//------------------------------------------------------------------------------
#if defined(OS_LINUX)
-int Channel::ChannelImpl::global_pid_ = 0;
+int ChannelPosix::global_pid_ = 0;
#endif // OS_LINUX
-Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
- Mode mode, Listener* listener)
+ChannelPosix::ChannelPosix(const IPC::ChannelHandle& channel_handle,
+ Mode mode, Listener* listener)
: ChannelReader(listener),
mode_(mode),
peer_pid_(base::kNullProcessId),
@@ -191,7 +203,7 @@ Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
}
}
-Channel::ChannelImpl::~ChannelImpl() {
+ChannelPosix::~ChannelPosix() {
Close();
}
@@ -219,7 +231,7 @@ bool SocketPair(int* fd1, int* fd2) {
return true;
}
-bool Channel::ChannelImpl::CreatePipe(
+bool ChannelPosix::CreatePipe(
const IPC::ChannelHandle& channel_handle) {
DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
@@ -227,7 +239,7 @@ bool Channel::ChannelImpl::CreatePipe(
// 1) It's a channel wrapping a pipe that is given to us.
// 2) It's for a named channel, so we create it.
// 3) It's for a client that we implement ourself. This is used
- // in unittesting.
+ // in single-process unittesting.
// 4) It's the initial IPC channel:
// 4a) Client side: Pull the pipe out of the GlobalDescriptors set.
// 4b) Server side: create the pipe.
@@ -325,9 +337,9 @@ bool Channel::ChannelImpl::CreatePipe(
return true;
}
-bool Channel::ChannelImpl::Connect() {
+bool ChannelPosix::Connect() {
if (server_listen_pipe_ == -1 && pipe_ == -1) {
- DLOG(INFO) << "Channel creation failed: " << pipe_name_;
+ DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
return false;
}
@@ -347,7 +359,7 @@ bool Channel::ChannelImpl::Connect() {
return did_connect;
}
-void Channel::ChannelImpl::CloseFileDescriptors(Message* msg) {
+void ChannelPosix::CloseFileDescriptors(Message* msg) {
#if defined(OS_MACOSX)
// There is a bug on OSX which makes it dangerous to close
// a file descriptor while it is in transit. So instead we
@@ -368,7 +380,7 @@ void Channel::ChannelImpl::CloseFileDescriptors(Message* msg) {
#endif
}
-bool Channel::ChannelImpl::ProcessOutgoingMessages() {
+bool ChannelPosix::ProcessOutgoingMessages() {
DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
// no connection?
if (output_queue_.empty())
@@ -464,15 +476,19 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
CloseFileDescriptors(msg);
if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
+ // We can't close the pipe here, because calling OnChannelError
+ // may destroy this object, and that would be bad if we are
+ // called from Send(). Instead, we return false and hope the
+ // caller will close the pipe. If they do not, the pipe will
+ // still be closed next time OnFileCanReadWithoutBlocking is
+ // called.
#if defined(OS_MACOSX)
// On OSX writing to a pipe with no listener returns EPERM.
if (errno == EPERM) {
- Close();
return false;
}
#endif // OS_MACOSX
if (errno == EPIPE) {
- Close();
return false;
}
PLOG(ERROR) << "pipe error on "
@@ -510,7 +526,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
return true;
}
-bool Channel::ChannelImpl::Send(Message* message) {
+bool ChannelPosix::Send(Message* message) {
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type()
<< " (" << output_queue_.size() << " in queue)";
@@ -528,12 +544,12 @@ bool Channel::ChannelImpl::Send(Message* message) {
return true;
}
-int Channel::ChannelImpl::GetClientFileDescriptor() {
+int ChannelPosix::GetClientFileDescriptor() const {
base::AutoLock lock(client_pipe_lock_);
return client_pipe_;
}
-int Channel::ChannelImpl::TakeClientFileDescriptor() {
+int ChannelPosix::TakeClientFileDescriptor() {
base::AutoLock lock(client_pipe_lock_);
int fd = client_pipe_;
if (client_pipe_ != -1) {
@@ -543,7 +559,7 @@ int Channel::ChannelImpl::TakeClientFileDescriptor() {
return fd;
}
-void Channel::ChannelImpl::CloseClientFileDescriptor() {
+void ChannelPosix::CloseClientFileDescriptor() {
base::AutoLock lock(client_pipe_lock_);
if (client_pipe_ != -1) {
PipeMap::GetInstance()->Remove(pipe_name_);
@@ -553,20 +569,20 @@ void Channel::ChannelImpl::CloseClientFileDescriptor() {
}
}
-bool Channel::ChannelImpl::AcceptsConnections() const {
+bool ChannelPosix::AcceptsConnections() const {
return server_listen_pipe_ != -1;
}
-bool Channel::ChannelImpl::HasAcceptedConnection() const {
+bool ChannelPosix::HasAcceptedConnection() const {
return AcceptsConnections() && pipe_ != -1;
}
-bool Channel::ChannelImpl::GetPeerEuid(uid_t* peer_euid) const {
+bool ChannelPosix::GetPeerEuid(uid_t* peer_euid) const {
DCHECK(!(mode_ & MODE_SERVER) || HasAcceptedConnection());
return IPC::GetPeerEuid(pipe_, peer_euid);
}
-void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
+void ChannelPosix::ResetToAcceptingConnectionState() {
// Unregister libevent for the unix domain socket and close it.
read_watcher_.StopWatchingFileDescriptor();
write_watcher_.StopWatchingFileDescriptor();
@@ -610,20 +626,20 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
}
// static
-bool Channel::ChannelImpl::IsNamedServerInitialized(
+bool ChannelPosix::IsNamedServerInitialized(
const std::string& channel_id) {
return base::PathExists(base::FilePath(channel_id));
}
#if defined(OS_LINUX)
// static
-void Channel::ChannelImpl::SetGlobalPid(int pid) {
+void ChannelPosix::SetGlobalPid(int pid) {
global_pid_ = pid;
}
#endif // OS_LINUX
// Called by libevent when we can read from the pipe without blocking.
-void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
+void ChannelPosix::OnFileCanReadWithoutBlocking(int fd) {
if (fd == server_listen_pipe_) {
int new_pipe = 0;
if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) ||
@@ -680,7 +696,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
// If we're a server and handshaking, then we want to make sure that we
// only send our handshake message after we've processed the client's.
// This gives us a chance to kill the client if the incoming handshake
- // is invalid. This also flushes any closefd messagse.
+ // is invalid. This also flushes any closefd messages.
if (!is_blocked_on_write_) {
if (!ProcessOutgoingMessages()) {
ClosePipeOnError();
@@ -689,7 +705,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
}
// Called by libevent when we can write to the pipe without blocking.
-void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
+void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) {
DCHECK_EQ(pipe_, fd);
is_blocked_on_write_ = false;
if (!ProcessOutgoingMessages()) {
@@ -697,7 +713,7 @@ void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
}
}
-bool Channel::ChannelImpl::AcceptConnection() {
+bool ChannelPosix::AcceptConnection() {
base::MessageLoopForIO::current()->WatchFileDescriptor(
pipe_, true, base::MessageLoopForIO::WATCH_READ, &read_watcher_, this);
QueueHelloMessage();
@@ -717,7 +733,7 @@ bool Channel::ChannelImpl::AcceptConnection() {
}
}
-void Channel::ChannelImpl::ClosePipeOnError() {
+void ChannelPosix::ClosePipeOnError() {
if (HasAcceptedConnection()) {
ResetToAcceptingConnectionState();
listener()->OnChannelError();
@@ -731,7 +747,7 @@ void Channel::ChannelImpl::ClosePipeOnError() {
}
}
-int Channel::ChannelImpl::GetHelloMessageProcId() {
+int ChannelPosix::GetHelloMessageProcId() {
int pid = base::GetCurrentProcId();
#if defined(OS_LINUX)
// Our process may be in a sandbox with a separate PID namespace.
@@ -742,7 +758,7 @@ int Channel::ChannelImpl::GetHelloMessageProcId() {
return pid;
}
-void Channel::ChannelImpl::QueueHelloMessage() {
+void ChannelPosix::QueueHelloMessage() {
// Create the Hello message
scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
HELLO_MESSAGE_TYPE,
@@ -763,7 +779,7 @@ void Channel::ChannelImpl::QueueHelloMessage() {
output_queue_.push(msg.release());
}
-Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
+ChannelPosix::ReadState ChannelPosix::ReadData(
char* buffer,
int buffer_len,
int* bytes_read) {
@@ -821,7 +837,7 @@ Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
}
#if defined(IPC_USES_READWRITE)
-bool Channel::ChannelImpl::ReadFileDescriptorsFromFDPipe() {
+bool ChannelPosix::ReadFileDescriptorsFromFDPipe() {
char dummy;
struct iovec fd_pipe_iov = { &dummy, 1 };
@@ -846,7 +862,7 @@ bool Channel::ChannelImpl::ReadFileDescriptorsFromFDPipe() {
//
// This will read from the input_fds_ (READWRITE mode only) and read more
// handles from the FD pipe if necessary.
-bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
+bool ChannelPosix::WillDispatchInputMessage(Message* msg) {
uint16 header_fds = msg->header()->num_fds;
if (!header_fds)
return true; // Nothing to do.
@@ -886,14 +902,14 @@ bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
return true;
}
-bool Channel::ChannelImpl::DidEmptyInputBuffers() {
+bool ChannelPosix::DidEmptyInputBuffers() {
// When the input data buffer is empty, the fds should be too. If this is
// not the case, we probably have a rogue renderer which is trying to fill
// our descriptor table.
return input_fds_.empty();
}
-bool Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr(msghdr* msg) {
+bool ChannelPosix::ExtractFileDescriptorsFromMsghdr(msghdr* msg) {
// Check that there are any control messages. On OSX, CMSG_FIRSTHDR will
// return an invalid non-NULL pointer in the case that controllen == 0.
if (msg->msg_controllen == 0)
@@ -925,7 +941,7 @@ bool Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr(msghdr* msg) {
return true;
}
-void Channel::ChannelImpl::ClearInputFDs() {
+void ChannelPosix::ClearInputFDs() {
for (size_t i = 0; i < input_fds_.size(); ++i) {
if (IGNORE_EINTR(close(input_fds_[i])) < 0)
PLOG(ERROR) << "close ";
@@ -933,7 +949,7 @@ void Channel::ChannelImpl::ClearInputFDs() {
input_fds_.clear();
}
-void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) {
+void ChannelPosix::QueueCloseFDMessage(int fd, int hops) {
switch (hops) {
case 1:
case 2: {
@@ -955,7 +971,7 @@ void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) {
}
}
-void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
+void ChannelPosix::HandleInternalMessage(const Message& msg) {
// The Hello message contains only the process id.
PickleIterator iter(msg);
@@ -1009,7 +1025,7 @@ void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
}
}
-void Channel::ChannelImpl::Close() {
+void ChannelPosix::Close() {
// Close can be called multiple time, so we need to make sure we're
// idempotent.
@@ -1030,61 +1046,18 @@ void Channel::ChannelImpl::Close() {
CloseClientFileDescriptor();
}
-//------------------------------------------------------------------------------
-// Channel's methods simply call through to ChannelImpl.
-Channel::Channel(const IPC::ChannelHandle& channel_handle, Mode mode,
- Listener* listener)
- : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
-}
-
-Channel::~Channel() {
- delete channel_impl_;
-}
-
-bool Channel::Connect() {
- return channel_impl_->Connect();
-}
-
-void Channel::Close() {
- if (channel_impl_)
- channel_impl_->Close();
-}
-
-base::ProcessId Channel::peer_pid() const {
- return channel_impl_->peer_pid();
-}
-
-bool Channel::Send(Message* message) {
- return channel_impl_->Send(message);
+base::ProcessId ChannelPosix::GetPeerPID() const {
+ return peer_pid_;
}
-int Channel::GetClientFileDescriptor() const {
- return channel_impl_->GetClientFileDescriptor();
-}
-
-int Channel::TakeClientFileDescriptor() {
- return channel_impl_->TakeClientFileDescriptor();
-}
-
-bool Channel::AcceptsConnections() const {
- return channel_impl_->AcceptsConnections();
-}
-
-bool Channel::HasAcceptedConnection() const {
- return channel_impl_->HasAcceptedConnection();
-}
-
-bool Channel::GetPeerEuid(uid_t* peer_euid) const {
- return channel_impl_->GetPeerEuid(peer_euid);
-}
-
-void Channel::ResetToAcceptingConnectionState() {
- channel_impl_->ResetToAcceptingConnectionState();
-}
+//------------------------------------------------------------------------------
+// Channel's methods
// static
-bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
- return ChannelImpl::IsNamedServerInitialized(channel_id);
+scoped_ptr<Channel> Channel::Create(
+ const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
+ return make_scoped_ptr(new ChannelPosix(
+ channel_handle, mode, listener)).PassAs<Channel>();
}
// static
@@ -1100,10 +1073,15 @@ std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
}
+bool Channel::IsNamedServerInitialized(
+ const std::string& channel_id) {
+ return ChannelPosix::IsNamedServerInitialized(channel_id);
+}
+
#if defined(OS_LINUX)
// static
void Channel::SetGlobalPid(int pid) {
- ChannelImpl::SetGlobalPid(pid);
+ ChannelPosix::SetGlobalPid(pid);
}
#endif // OS_LINUX
diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h
index 1e587c13eb0..7f17b2fc487 100644
--- a/chromium/ipc/ipc_channel_posix.h
+++ b/chromium/ipc/ipc_channel_posix.h
@@ -49,24 +49,39 @@
namespace IPC {
-class Channel::ChannelImpl : public internal::ChannelReader,
- public base::MessageLoopForIO::Watcher {
+class IPC_EXPORT ChannelPosix : public Channel,
+ public internal::ChannelReader,
+ public base::MessageLoopForIO::Watcher {
public:
- // Mirror methods of Channel, see ipc_channel.h for description.
- ChannelImpl(const IPC::ChannelHandle& channel_handle, Mode mode,
- Listener* listener);
- virtual ~ChannelImpl();
- bool Connect();
- void Close();
- bool Send(Message* message);
- int GetClientFileDescriptor();
- int TakeClientFileDescriptor();
- void CloseClientFileDescriptor();
+ ChannelPosix(const IPC::ChannelHandle& channel_handle, Mode mode,
+ Listener* listener);
+ virtual ~ChannelPosix();
+
+ // Channel implementation
+ virtual bool Connect() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual bool Send(Message* message) OVERRIDE;
+ virtual base::ProcessId GetPeerPID() const OVERRIDE;
+ virtual int GetClientFileDescriptor() const OVERRIDE;
+ virtual int TakeClientFileDescriptor() OVERRIDE;
+
+ // Returns true if the channel supports listening for connections.
bool AcceptsConnections() const;
+
+ // Returns true if the channel supports listening for connections and is
+ // currently connected.
bool HasAcceptedConnection() const;
- bool GetPeerEuid(uid_t* peer_euid) const;
+
+ // Closes any currently connected socket, and returns to a listening state
+ // for more connections.
void ResetToAcceptingConnectionState();
- base::ProcessId peer_pid() const { return peer_pid_; }
+
+ // Returns true if the peer process' effective user id can be determined, in
+ // which case the supplied peer_euid is updated with it.
+ bool GetPeerEuid(uid_t* peer_euid) const;
+
+ void CloseClientFileDescriptor();
+
static bool IsNamedServerInitialized(const std::string& channel_id);
#if defined(OS_LINUX)
static void SetGlobalPid(int pid);
@@ -144,7 +159,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
// For a server, the client end of our socketpair() -- the other end of our
// pipe_ that is passed to the client.
int client_pipe_;
- base::Lock client_pipe_lock_; // Lock that protects |client_pipe_|.
+ mutable base::Lock client_pipe_lock_; // Lock that protects |client_pipe_|.
#if defined(IPC_USES_READWRITE)
// Linux/BSD use a dedicated socketpair() for passing file descriptors.
@@ -202,7 +217,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
static int global_pid_;
#endif // OS_LINUX
- DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelPosix);
};
} // namespace IPC
diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc
index dbd854e16c6..a4b4f8dbb95 100644
--- a/chromium/ipc/ipc_channel_posix_unittest.cc
+++ b/chromium/ipc/ipc_channel_posix_unittest.cc
@@ -41,7 +41,9 @@ class IPCChannelPosixTestListener : public IPC::Listener {
};
IPCChannelPosixTestListener(bool quit_only_on_message)
- : status_(DISCONNECTED), quit_only_on_message_(quit_only_on_message) {}
+ : status_(DISCONNECTED),
+ quit_only_on_message_(quit_only_on_message) {
+ }
virtual ~IPCChannelPosixTestListener() {}
@@ -61,9 +63,7 @@ class IPCChannelPosixTestListener : public IPC::Listener {
virtual void OnChannelError() OVERRIDE {
status_ = CHANNEL_ERROR;
- if (!quit_only_on_message_) {
- QuitRunLoop();
- }
+ QuitRunLoop();
}
virtual void OnChannelDenied() OVERRIDE {
@@ -83,7 +83,13 @@ class IPCChannelPosixTestListener : public IPC::Listener {
STATUS status() { return status_; }
void QuitRunLoop() {
- base::MessageLoopForIO::current()->QuitNow();
+ base::MessageLoopForIO* loop = base::MessageLoopForIO::current();
+ if (loop->is_running()) {
+ loop->QuitNow();
+ } else {
+ // Die as soon as Run is called.
+ loop->PostTask(FROM_HERE, loop->QuitClosure());
+ }
}
private:
@@ -186,7 +192,7 @@ void IPCChannelPosixTest::SpinRunLoop(base::TimeDelta delay) {
// in the case of a bad test. Usually, the run loop will quit sooner than
// that because all tests use a IPCChannelPosixTestListener which quits the
// current run loop on any channel activity.
- loop->PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), delay);
+ loop->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay);
loop->Run();
}
@@ -198,12 +204,13 @@ TEST_F(IPCChannelPosixTest, BasicListen) {
IPC::ChannelHandle handle(kChannelName);
SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER);
unlink(handle.name.c_str());
- IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
- ASSERT_TRUE(channel.Connect());
- ASSERT_TRUE(channel.AcceptsConnections());
- ASSERT_FALSE(channel.HasAcceptedConnection());
- channel.ResetToAcceptingConnectionState();
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ scoped_ptr<IPC::ChannelPosix> channel(
+ new IPC::ChannelPosix(handle, IPC::Channel::MODE_NAMED_SERVER, NULL));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_TRUE(channel->AcceptsConnections());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
+ channel->ResetToAcceptingConnectionState();
+ ASSERT_FALSE(channel->HasAcceptedConnection());
}
TEST_F(IPCChannelPosixTest, BasicConnected) {
@@ -215,17 +222,66 @@ TEST_F(IPCChannelPosixTest, BasicConnected) {
base::FileDescriptor fd(pipe_fds[0], false);
IPC::ChannelHandle handle(socket_name, fd);
- IPC::Channel channel(handle, IPC::Channel::MODE_SERVER, NULL);
- ASSERT_TRUE(channel.Connect());
- ASSERT_FALSE(channel.AcceptsConnections());
- channel.Close();
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ handle, IPC::Channel::MODE_SERVER, NULL));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_FALSE(channel->AcceptsConnections());
+ channel->Close();
ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0);
// Make sure that we can use the socket that is created for us by
// a standard channel.
- IPC::Channel channel2(socket_name, IPC::Channel::MODE_SERVER, NULL);
- ASSERT_TRUE(channel2.Connect());
- ASSERT_FALSE(channel2.AcceptsConnections());
+ scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
+ socket_name, IPC::Channel::MODE_SERVER, NULL));
+ ASSERT_TRUE(channel2->Connect());
+ ASSERT_FALSE(channel2->AcceptsConnections());
+}
+
+// If a connection closes right before a Send() call, we may end up closing
+// the connection without notifying the listener, which can cause hangs in
+// sync_message_filter and others. Make sure the listener is notified.
+TEST_F(IPCChannelPosixTest, SendHangTest) {
+ IPCChannelPosixTestListener out_listener(true);
+ IPCChannelPosixTestListener in_listener(true);
+ IPC::ChannelHandle in_handle("IN");
+ scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix(
+ in_handle, IPC::Channel::MODE_SERVER, &in_listener));
+ base::FileDescriptor out_fd(
+ in_chan->TakeClientFileDescriptor(), false);
+ IPC::ChannelHandle out_handle("OUT", out_fd);
+ scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix(
+ out_handle, IPC::Channel::MODE_CLIENT, &out_listener));
+ ASSERT_TRUE(in_chan->Connect());
+ ASSERT_TRUE(out_chan->Connect());
+ in_chan->Close(); // simulate remote process dying at an unfortunate time.
+ // Send will fail, because it cannot write the message.
+ ASSERT_FALSE(out_chan->Send(new IPC::Message(
+ 0, // routing_id
+ kQuitMessage, // message type
+ IPC::Message::PRIORITY_NORMAL)));
+ SpinRunLoop(TestTimeouts::action_max_timeout());
+ ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
+}
+
+// If a connection closes right before a Connect() call, we may end up closing
+// the connection without notifying the listener, which can cause hangs in
+// sync_message_filter and others. Make sure the listener is notified.
+TEST_F(IPCChannelPosixTest, AcceptHangTest) {
+ IPCChannelPosixTestListener out_listener(true);
+ IPCChannelPosixTestListener in_listener(true);
+ IPC::ChannelHandle in_handle("IN");
+ scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix(
+ in_handle, IPC::Channel::MODE_SERVER, &in_listener));
+ base::FileDescriptor out_fd(
+ in_chan->TakeClientFileDescriptor(), false);
+ IPC::ChannelHandle out_handle("OUT", out_fd);
+ scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix(
+ out_handle, IPC::Channel::MODE_CLIENT, &out_listener));
+ ASSERT_TRUE(in_chan->Connect());
+ in_chan->Close(); // simulate remote process dying at an unfortunate time.
+ ASSERT_FALSE(out_chan->Connect());
+ SpinRunLoop(TestTimeouts::action_max_timeout());
+ ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
}
TEST_F(IPCChannelPosixTest, AdvancedConnected) {
@@ -233,27 +289,27 @@ TEST_F(IPCChannelPosixTest, AdvancedConnected) {
IPCChannelPosixTestListener listener(false);
IPC::ChannelHandle chan_handle(GetConnectionSocketName());
SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
- ASSERT_TRUE(channel.Connect());
- ASSERT_TRUE(channel.AcceptsConnections());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_TRUE(channel->AcceptsConnections());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
- false);
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
ASSERT_TRUE(handle);
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
- ASSERT_TRUE(channel.HasAcceptedConnection());
+ ASSERT_TRUE(channel->HasAcceptedConnection());
IPC::Message* message = new IPC::Message(0, // routing_id
kQuitMessage, // message type
IPC::Message::PRIORITY_NORMAL);
- channel.Send(message);
+ channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
int exit_code = 0;
EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
EXPECT_EQ(0, exit_code);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
}
TEST_F(IPCChannelPosixTest, ResetState) {
@@ -263,44 +319,44 @@ TEST_F(IPCChannelPosixTest, ResetState) {
IPCChannelPosixTestListener listener(false);
IPC::ChannelHandle chan_handle(GetConnectionSocketName());
SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
- ASSERT_TRUE(channel.Connect());
- ASSERT_TRUE(channel.AcceptsConnections());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_TRUE(channel->AcceptsConnections());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
- false);
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
ASSERT_TRUE(handle);
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
- ASSERT_TRUE(channel.HasAcceptedConnection());
- channel.ResetToAcceptingConnectionState();
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ ASSERT_TRUE(channel->HasAcceptedConnection());
+ channel->ResetToAcceptingConnectionState();
+ ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc",
- false);
+ base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc");
ASSERT_TRUE(handle2);
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
- ASSERT_TRUE(channel.HasAcceptedConnection());
+ ASSERT_TRUE(channel->HasAcceptedConnection());
IPC::Message* message = new IPC::Message(0, // routing_id
kQuitMessage, // message type
IPC::Message::PRIORITY_NORMAL);
- channel.Send(message);
+ channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
EXPECT_TRUE(base::KillProcess(handle, 0, false));
int exit_code = 0;
EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
EXPECT_EQ(0, exit_code);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
}
TEST_F(IPCChannelPosixTest, BadChannelName) {
// Test empty name
IPC::ChannelHandle handle("");
- IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
- ASSERT_FALSE(channel.Connect());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ handle, IPC::Channel::MODE_NAMED_SERVER, NULL));
+ ASSERT_FALSE(channel->Connect());
// Test name that is too long.
const char *kTooLongName = "This_is_a_very_long_name_to_proactively_implement"
@@ -312,8 +368,9 @@ TEST_F(IPCChannelPosixTest, BadChannelName) {
"leading-edge_processes";
EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength);
IPC::ChannelHandle handle2(kTooLongName);
- IPC::Channel channel2(handle2, IPC::Channel::MODE_NAMED_SERVER, NULL);
- EXPECT_FALSE(channel2.Connect());
+ scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
+ handle2, IPC::Channel::MODE_NAMED_SERVER, NULL));
+ EXPECT_FALSE(channel2->Connect());
}
TEST_F(IPCChannelPosixTest, MultiConnection) {
@@ -322,35 +379,34 @@ TEST_F(IPCChannelPosixTest, MultiConnection) {
IPCChannelPosixTestListener listener(false);
IPC::ChannelHandle chan_handle(GetConnectionSocketName());
SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
- ASSERT_TRUE(channel.Connect());
- ASSERT_TRUE(channel.AcceptsConnections());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_TRUE(channel->AcceptsConnections());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
- base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
- false);
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
ASSERT_TRUE(handle);
SpinRunLoop(TestTimeouts::action_max_timeout());
ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
- ASSERT_TRUE(channel.HasAcceptedConnection());
- base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc",
- false);
+ ASSERT_TRUE(channel->HasAcceptedConnection());
+ base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc");
ASSERT_TRUE(handle2);
SpinRunLoop(TestTimeouts::action_max_timeout());
int exit_code = 0;
EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
EXPECT_EQ(exit_code, 0);
ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
- ASSERT_TRUE(channel.HasAcceptedConnection());
+ ASSERT_TRUE(channel->HasAcceptedConnection());
IPC::Message* message = new IPC::Message(0, // routing_id
kQuitMessage, // message type
IPC::Message::PRIORITY_NORMAL);
- channel.Send(message);
+ channel->Send(message);
SpinRunLoop(TestTimeouts::action_timeout());
EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
EXPECT_EQ(exit_code, 0);
ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
- ASSERT_FALSE(channel.HasAcceptedConnection());
+ ASSERT_FALSE(channel->HasAcceptedConnection());
}
TEST_F(IPCChannelPosixTest, DoubleServer) {
@@ -358,18 +414,21 @@ TEST_F(IPCChannelPosixTest, DoubleServer) {
IPCChannelPosixTestListener listener(false);
IPCChannelPosixTestListener listener2(false);
IPC::ChannelHandle chan_handle(GetConnectionSocketName());
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_SERVER, &listener);
- IPC::Channel channel2(chan_handle, IPC::Channel::MODE_SERVER, &listener2);
- ASSERT_TRUE(channel.Connect());
- ASSERT_FALSE(channel2.Connect());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_SERVER, &listener));
+ scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_SERVER, &listener2));
+ ASSERT_TRUE(channel->Connect());
+ ASSERT_FALSE(channel2->Connect());
}
TEST_F(IPCChannelPosixTest, BadMode) {
// Test setting up two servers with a bad mode.
IPCChannelPosixTestListener listener(false);
IPC::ChannelHandle chan_handle(GetConnectionSocketName());
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_NONE, &listener);
- ASSERT_FALSE(channel.Connect());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_NONE, &listener));
+ ASSERT_FALSE(channel->Connect());
}
TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
@@ -379,10 +438,11 @@ TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
ASSERT_TRUE(base::DeleteFile(base::FilePath(connection_socket_name), false));
ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
connection_socket_name));
- IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized(
connection_socket_name));
- channel.Close();
+ channel->Close();
ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
connection_socket_name));
}
@@ -393,8 +453,9 @@ MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) {
IPCChannelPosixTestListener listener(true);
IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
- IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
- EXPECT_TRUE(channel.Connect());
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ handle, IPC::Channel::MODE_NAMED_CLIENT, &listener));
+ EXPECT_TRUE(channel->Connect());
IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status());
return 0;
@@ -406,14 +467,15 @@ MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) {
IPCChannelPosixTestListener listener(false);
IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
- IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
+ scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
+ handle, IPC::Channel::MODE_NAMED_CLIENT, &listener));
// In this case connect may succeed or fail depending on if the packet
// actually gets sent at sendmsg. Since we never delay on send, we may not
// see the error. However even if connect succeeds, eventually we will get an
// error back since the channel will be closed when we attempt to read from
// it.
- bool connected = channel.Connect();
+ bool connected = channel->Connect();
if (connected) {
IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc
index 18ed3041336..7441c6543b6 100644
--- a/chromium/ipc/ipc_channel_proxy.cc
+++ b/chromium/ipc/ipc_channel_proxy.cc
@@ -2,52 +2,43 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ipc/ipc_channel_proxy.h"
+
#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
-#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_utils.h"
+#include "ipc/message_filter.h"
+#include "ipc/message_filter_router.h"
namespace IPC {
//------------------------------------------------------------------------------
-ChannelProxy::MessageFilter::MessageFilter() {}
-
-void ChannelProxy::MessageFilter::OnFilterAdded(Channel* channel) {}
-
-void ChannelProxy::MessageFilter::OnFilterRemoved() {}
-
-void ChannelProxy::MessageFilter::OnChannelConnected(int32 peer_pid) {}
-
-void ChannelProxy::MessageFilter::OnChannelError() {}
-
-void ChannelProxy::MessageFilter::OnChannelClosing() {}
-
-bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) {
- return false;
-}
-
-ChannelProxy::MessageFilter::~MessageFilter() {}
-
-//------------------------------------------------------------------------------
-
ChannelProxy::Context::Context(Listener* listener,
base::SingleThreadTaskRunner* ipc_task_runner)
: listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
listener_(listener),
ipc_task_runner_(ipc_task_runner),
channel_connected_called_(false),
+ message_filter_router_(new MessageFilterRouter()),
peer_pid_(base::kNullProcessId) {
DCHECK(ipc_task_runner_.get());
+ // The Listener thread where Messages are handled must be a separate thread
+ // to avoid oversubscribing the IO thread. If you trigger this error, you
+ // need to either:
+ // 1) Create the ChannelProxy on a different thread, or
+ // 2) Just use Channel
+ // Note, we currently make an exception for a NULL listener. That usage
+ // basically works, but is outside the intent of ChannelProxy. This support
+ // will disappear, so please don't rely on it. See crbug.com/364241
+ DCHECK(!listener || (ipc_task_runner_.get() != listener_task_runner_.get()));
}
ChannelProxy::Context::~Context() {
@@ -59,26 +50,29 @@ void ChannelProxy::Context::ClearIPCTaskRunner() {
void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle,
const Channel::Mode& mode) {
- DCHECK(channel_.get() == NULL);
+ DCHECK(!channel_);
channel_id_ = handle.name;
- channel_.reset(new Channel(handle, mode, this));
+ channel_ = Channel::Create(handle, mode, this);
}
bool ChannelProxy::Context::TryFilters(const Message& message) {
+ DCHECK(message_filter_router_);
#ifdef IPC_MESSAGE_LOG_ENABLED
Logging* logger = Logging::GetInstance();
if (logger->Enabled())
logger->OnPreDispatchMessage(message);
#endif
- for (size_t i = 0; i < filters_.size(); ++i) {
- if (filters_[i]->OnMessageReceived(message)) {
+ if (message_filter_router_->TryFilters(message)) {
+ if (message.dispatch_error()) {
+ listener_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Context::OnDispatchBadMessage, this, message));
+ }
#ifdef IPC_MESSAGE_LOG_ENABLED
- if (logger->Enabled())
- logger->OnPostDispatchMessage(message, channel_id_);
+ if (logger->Enabled())
+ logger->OnPostDispatchMessage(message, channel_id_);
#endif
- return true;
- }
+ return true;
}
return false;
}
@@ -93,10 +87,6 @@ bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
// Called on the IPC::Channel thread
bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
- // NOTE: This code relies on the listener's message loop not going away while
- // this thread is active. That should be a reasonable assumption, but it
- // feels risky. We may want to invent some more indirect way of referring to
- // a MessageLoop if this becomes a problem.
listener_task_runner_->PostTask(
FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));
return true;
@@ -104,17 +94,15 @@ bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
+ // We cache off the peer_pid so it can be safely accessed from both threads.
+ peer_pid_ = channel_->GetPeerPID();
+
// Add any pending filters. This avoids a race condition where someone
// creates a ChannelProxy, calls AddFilter, and then right after starts the
// peer process. The IO thread could receive a message before the task to add
// the filter is run on the IO thread.
OnAddFilter();
- // We cache off the peer_pid so it can be safely accessed from both threads.
- peer_pid_ = channel_->peer_pid();
- for (size_t i = 0; i < filters_.size(); ++i)
- filters_[i]->OnChannelConnected(peer_pid);
-
// See above comment about using listener_task_runner_ here.
listener_task_runner_->PostTask(
FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
@@ -151,7 +139,7 @@ void ChannelProxy::Context::OnChannelOpened() {
void ChannelProxy::Context::OnChannelClosed() {
// It's okay for IPC::ChannelProxy::Close to be called more than once, which
// would result in this branch being taken.
- if (!channel_.get())
+ if (!channel_)
return;
for (size_t i = 0; i < filters_.size(); ++i) {
@@ -160,7 +148,11 @@ void ChannelProxy::Context::OnChannelClosed() {
}
// We don't need the filters anymore.
+ message_filter_router_->Clear();
filters_.clear();
+ // We don't need the lock, because at this point, the listener thread can't
+ // access it any more.
+ pending_filters_.clear();
channel_.reset();
@@ -175,16 +167,24 @@ void ChannelProxy::Context::Clear() {
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
- if (!channel_.get()) {
+ if (!channel_) {
OnChannelClosed();
return;
}
+
if (!channel_->Send(message.release()))
OnChannelError();
}
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnAddFilter() {
+ // Our OnChannelConnected method has not yet been called, so we can't be
+ // sure that channel_ is valid yet. When OnChannelConnected *is* called,
+ // it invokes OnAddFilter, so any pending filter(s) will be added at that
+ // time.
+ if (peer_pid_ == base::kNullProcessId)
+ return;
+
std::vector<scoped_refptr<MessageFilter> > new_filters;
{
base::AutoLock auto_lock(pending_filters_lock_);
@@ -194,21 +194,34 @@ void ChannelProxy::Context::OnAddFilter() {
for (size_t i = 0; i < new_filters.size(); ++i) {
filters_.push_back(new_filters[i]);
- // If the channel has already been created, then we need to send this
- // message so that the filter gets access to the Channel.
- if (channel_.get())
- new_filters[i]->OnFilterAdded(channel_.get());
- // Ditto for if the channel has been connected.
- if (peer_pid_)
- new_filters[i]->OnChannelConnected(peer_pid_);
+ message_filter_router_->AddFilter(new_filters[i].get());
+
+ // The channel has already been created and connected, so we need to
+ // inform the filters right now.
+ new_filters[i]->OnFilterAdded(channel_.get());
+ new_filters[i]->OnChannelConnected(peer_pid_);
}
}
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
- if (!channel_.get())
+ if (peer_pid_ == base::kNullProcessId) {
+ // The channel is not yet connected, so any filters are still pending.
+ base::AutoLock auto_lock(pending_filters_lock_);
+ for (size_t i = 0; i < pending_filters_.size(); ++i) {
+ if (pending_filters_[i].get() == filter) {
+ filter->OnFilterRemoved();
+ pending_filters_.erase(pending_filters_.begin() + i);
+ return;
+ }
+ }
+ return;
+ }
+ if (!channel_)
return; // The filters have already been deleted.
+ message_filter_router_->RemoveFilter(filter);
+
for (size_t i = 0; i < filters_.size(); ++i) {
if (filters_[i].get() == filter) {
filter->OnFilterRemoved();
@@ -234,10 +247,10 @@ void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
Logging* logger = Logging::GetInstance();
std::string name;
logger->GetMessageText(message.type(), &name, &message, NULL);
- TRACE_EVENT1("task", "ChannelProxy::Context::OnDispatchMessage",
+ TRACE_EVENT1("ipc", "ChannelProxy::Context::OnDispatchMessage",
"name", name);
#else
- TRACE_EVENT2("task", "ChannelProxy::Context::OnDispatchMessage",
+ TRACE_EVENT2("ipc", "ChannelProxy::Context::OnDispatchMessage",
"class", IPC_MESSAGE_ID_CLASS(message.type()),
"line", IPC_MESSAGE_ID_LINE(message.type()));
#endif
@@ -258,6 +271,8 @@ void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
#endif
listener_->OnMessageReceived(message);
+ if (message.dispatch_error())
+ listener_->OnBadMessageReceived(message);
#ifdef IPC_MESSAGE_LOG_ENABLED
if (logger->Enabled())
@@ -281,15 +296,23 @@ void ChannelProxy::Context::OnDispatchError() {
listener_->OnChannelError();
}
+// Called on the listener's thread
+void ChannelProxy::Context::OnDispatchBadMessage(const Message& message) {
+ if (listener_)
+ listener_->OnBadMessageReceived(message);
+}
+
//-----------------------------------------------------------------------------
-ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle,
- Channel::Mode mode,
- Listener* listener,
- base::SingleThreadTaskRunner* ipc_task_runner)
- : context_(new Context(listener, ipc_task_runner)),
- did_init_(false) {
- Init(channel_handle, mode, true);
+// static
+scoped_ptr<ChannelProxy> ChannelProxy::Create(
+ const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner) {
+ scoped_ptr<ChannelProxy> channel(new ChannelProxy(listener, ipc_task_runner));
+ channel->Init(channel_handle, mode, true);
+ return channel.Pass();
}
ChannelProxy::ChannelProxy(Context* context)
@@ -297,6 +320,11 @@ ChannelProxy::ChannelProxy(Context* context)
did_init_(false) {
}
+ChannelProxy::ChannelProxy(Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner)
+ : context_(new Context(listener, ipc_task_runner)), did_init_(false) {
+}
+
ChannelProxy::~ChannelProxy() {
DCHECK(CalledOnValidThread());
@@ -408,15 +436,6 @@ int ChannelProxy::TakeClientFileDescriptor() {
DCHECK(channel) << context_.get()->channel_id_;
return channel->TakeClientFileDescriptor();
}
-
-bool ChannelProxy::GetPeerEuid(uid_t* peer_euid) const {
- DCHECK(CalledOnValidThread());
-
- Channel* channel = context_.get()->channel_.get();
- // Channel must have been created first.
- DCHECK(channel) << context_.get()->channel_id_;
- return channel->GetPeerEuid(peer_euid);
-}
#endif
//-----------------------------------------------------------------------------
diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h
index 1f5ecf450df..2e483acbf4d 100644
--- a/chromium/ipc/ipc_channel_proxy.h
+++ b/chromium/ipc/ipc_channel_proxy.h
@@ -22,6 +22,8 @@ class SingleThreadTaskRunner;
namespace IPC {
+class MessageFilter;
+class MessageFilterRouter;
class SendCallbackHelper;
//-----------------------------------------------------------------------------
@@ -54,47 +56,6 @@ class SendCallbackHelper;
//
class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
public:
-
- // A class that receives messages on the thread where the IPC channel is
- // running. It can choose to prevent the default action for an IPC message.
- class IPC_EXPORT MessageFilter
- : public base::RefCountedThreadSafe<MessageFilter> {
- public:
- MessageFilter();
-
- // Called on the background thread to provide the filter with access to the
- // channel. Called when the IPC channel is initialized or when AddFilter
- // is called if the channel is already initialized.
- virtual void OnFilterAdded(Channel* channel);
-
- // Called on the background thread when the filter has been removed from
- // the ChannelProxy and when the Channel is closing. After a filter is
- // removed, it will not be called again.
- virtual void OnFilterRemoved();
-
- // Called to inform the filter that the IPC channel is connected and we
- // have received the internal Hello message from the peer.
- virtual void OnChannelConnected(int32 peer_pid);
-
- // Called when there is an error on the channel, typically that the channel
- // has been closed.
- virtual void OnChannelError();
-
- // Called to inform the filter that the IPC channel will be destroyed.
- // OnFilterRemoved is called immediately after this.
- virtual void OnChannelClosing();
-
- // Return true to indicate that the message was handled, or false to let
- // the message be handled in the default way.
- virtual bool OnMessageReceived(const Message& message);
-
- protected:
- virtual ~MessageFilter();
-
- private:
- friend class base::RefCountedThreadSafe<MessageFilter>;
- };
-
// Initializes a channel proxy. The channel_handle and mode parameters are
// passed directly to the underlying IPC::Channel. The listener is called on
// the thread that creates the ChannelProxy. The filter's OnMessageReceived
@@ -103,10 +64,11 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// on the background thread. Any message not handled by the filter will be
// dispatched to the listener. The given task runner correspond to a thread
// on which IPC::Channel is created and used (e.g. IO thread).
- ChannelProxy(const IPC::ChannelHandle& channel_handle,
- Channel::Mode mode,
- Listener* listener,
- base::SingleThreadTaskRunner* ipc_task_runner);
+ static scoped_ptr<ChannelProxy> Create(
+ const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner);
virtual ~ChannelProxy();
@@ -121,7 +83,7 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// background thread processes the command to close the channel. It is ok to
// call this method multiple times. Redundant calls are ignored.
//
- // WARNING: The MessageFilter object held by the ChannelProxy is also
+ // WARNING: MessageFilter objects held by the ChannelProxy is also
// released asynchronously, and it may in fact have its final reference
// released on the background thread. The caller should be careful to deal
// with / allow for this possibility.
@@ -148,13 +110,12 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// Get the process ID for the connected peer.
// Returns base::kNullProcessId if the peer is not connected yet.
- base::ProcessId peer_pid() const { return context_->peer_pid_; }
+ base::ProcessId GetPeerPID() const { return context_->peer_pid_; }
#if defined(OS_POSIX) && !defined(OS_NACL)
// Calls through to the underlying channel's methods.
int GetClientFileDescriptor();
int TakeClientFileDescriptor();
- bool GetPeerEuid(uid_t* peer_euid) const;
#endif // defined(OS_POSIX)
protected:
@@ -163,6 +124,9 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// to the internal state.
ChannelProxy(Context* context);
+ ChannelProxy(Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner);
+
// Used internally to hold state that is referenced on the IPC thread.
class Context : public base::RefCountedThreadSafe<Context>,
public Listener {
@@ -219,6 +183,7 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
void AddFilter(MessageFilter* filter);
void OnDispatchConnected();
void OnDispatchError();
+ void OnDispatchBadMessage(const Message& message);
scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
Listener* listener_;
@@ -226,10 +191,18 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// List of filters. This is only accessed on the IPC thread.
std::vector<scoped_refptr<MessageFilter> > filters_;
scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
+
+ // Note, channel_ may be set on the Listener thread or the IPC thread.
+ // But once it has been set, it must only be read or cleared on the IPC
+ // thread.
scoped_ptr<Channel> channel_;
std::string channel_id_;
bool channel_connected_called_;
+ // Routes a given message to a proper subset of |filters_|, depending
+ // on which message classes a filter might support.
+ scoped_ptr<MessageFilterRouter> message_filter_router_;
+
// Holds filters between the AddFilter call on the listerner thread and the
// IPC thread when they're added to filters_.
std::vector<scoped_refptr<MessageFilter> > pending_filters_;
diff --git a/chromium/ipc/ipc_channel_proxy_unittest.cc b/chromium/ipc/ipc_channel_proxy_unittest.cc
new file mode 100644
index 00000000000..81b65ec21c4
--- /dev/null
+++ b/chromium/ipc/ipc_channel_proxy_unittest.cc
@@ -0,0 +1,441 @@
+// Copyright 2014 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 "build/build_config.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/pickle.h"
+#include "base/threading/thread.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_test_base.h"
+#include "ipc/message_filter.h"
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "ipc/ipc_channel_proxy_unittest_messages.h"
+} // namespace IPC
+
+
+namespace {
+
+class QuitListener : public IPC::Listener {
+ public:
+ QuitListener() : bad_message_received_(false) {}
+ virtual ~QuitListener() {}
+
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ IPC_BEGIN_MESSAGE_MAP(QuitListener, message)
+ IPC_MESSAGE_HANDLER(WorkerMsg_Quit, OnQuit)
+ IPC_MESSAGE_HANDLER(TestMsg_BadMessage, OnBadMessage)
+ IPC_END_MESSAGE_MAP()
+ return true;
+ }
+
+ virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE {
+ bad_message_received_ = true;
+ }
+
+ void OnQuit() {
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ void OnBadMessage(const BadType& bad_type) {
+ // Should never be called since IPC wouldn't be deserialized correctly.
+ CHECK(false);
+ }
+
+ bool bad_message_received_;
+};
+
+class ChannelReflectorListener : public IPC::Listener {
+ public:
+ ChannelReflectorListener() : channel_(NULL) {}
+ virtual ~ChannelReflectorListener() {}
+
+ void Init(IPC::Channel* channel) {
+ DCHECK(!channel_);
+ channel_ = channel;
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ IPC_BEGIN_MESSAGE_MAP(ChannelReflectorListener, message)
+ IPC_MESSAGE_HANDLER(TestMsg_Bounce, OnTestBounce)
+ IPC_MESSAGE_HANDLER(TestMsg_SendBadMessage, OnSendBadMessage)
+ IPC_MESSAGE_HANDLER(UtilityMsg_Bounce, OnUtilityBounce)
+ IPC_MESSAGE_HANDLER(WorkerMsg_Bounce, OnBounce)
+ IPC_MESSAGE_HANDLER(WorkerMsg_Quit, OnQuit)
+ IPC_END_MESSAGE_MAP()
+ return true;
+ }
+
+ void OnTestBounce() {
+ channel_->Send(new TestMsg_Bounce());
+ }
+
+ void OnSendBadMessage() {
+ channel_->Send(new TestMsg_BadMessage(BadType()));
+ }
+
+ void OnUtilityBounce() {
+ channel_->Send(new UtilityMsg_Bounce());
+ }
+
+ void OnBounce() {
+ channel_->Send(new WorkerMsg_Bounce());
+ }
+
+ void OnQuit() {
+ channel_->Send(new WorkerMsg_Quit());
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ private:
+ IPC::Channel* channel_;
+};
+
+class MessageCountFilter : public IPC::MessageFilter {
+ public:
+ enum FilterEvent {
+ NONE,
+ FILTER_ADDED,
+ CHANNEL_CONNECTED,
+ CHANNEL_ERROR,
+ CHANNEL_CLOSING,
+ FILTER_REMOVED
+ };
+ MessageCountFilter()
+ : messages_received_(0),
+ supported_message_class_(0),
+ is_global_filter_(true),
+ last_filter_event_(NONE),
+ message_filtering_enabled_(false) {}
+
+ MessageCountFilter(uint32 supported_message_class)
+ : messages_received_(0),
+ supported_message_class_(supported_message_class),
+ is_global_filter_(false),
+ last_filter_event_(NONE),
+ message_filtering_enabled_(false) {}
+
+ virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
+ EXPECT_TRUE(sender);
+ EXPECT_EQ(NONE, last_filter_event_);
+ last_filter_event_ = FILTER_ADDED;
+ }
+
+ virtual void OnChannelConnected(int32_t peer_pid) OVERRIDE {
+ EXPECT_EQ(FILTER_ADDED, last_filter_event_);
+ EXPECT_NE(static_cast<int32_t>(base::kNullProcessId), peer_pid);
+ last_filter_event_ = CHANNEL_CONNECTED;
+ }
+
+ virtual void OnChannelError() OVERRIDE {
+ EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
+ last_filter_event_ = CHANNEL_ERROR;
+ }
+
+ virtual void OnChannelClosing() OVERRIDE {
+ // We may or may not have gotten OnChannelError; if not, the last event has
+ // to be OnChannelConnected.
+ if (last_filter_event_ != CHANNEL_ERROR)
+ EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
+ last_filter_event_ = CHANNEL_CLOSING;
+ }
+
+ virtual void OnFilterRemoved() OVERRIDE {
+ // If the channel didn't get a chance to connect, we might see the
+ // OnFilterRemoved event with no other events preceding it. We still want
+ // OnFilterRemoved to be called to allow for deleting the Filter.
+ if (last_filter_event_ != NONE)
+ EXPECT_EQ(CHANNEL_CLOSING, last_filter_event_);
+ last_filter_event_ = FILTER_REMOVED;
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ // We should always get the OnFilterAdded and OnChannelConnected events
+ // prior to any messages.
+ EXPECT_EQ(CHANNEL_CONNECTED, last_filter_event_);
+
+ if (!is_global_filter_) {
+ EXPECT_EQ(supported_message_class_, IPC_MESSAGE_CLASS(message));
+ }
+ ++messages_received_;
+
+ if (!message_filtering_enabled_)
+ return false;
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(MessageCountFilter, message)
+ IPC_MESSAGE_HANDLER(TestMsg_BadMessage, OnBadMessage)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+ }
+
+ void OnBadMessage(const BadType& bad_type) {
+ // Should never be called since IPC wouldn't be deserialized correctly.
+ CHECK(false);
+ }
+
+ virtual bool GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const OVERRIDE {
+ if (is_global_filter_)
+ return false;
+ supported_message_classes->push_back(supported_message_class_);
+ return true;
+ }
+
+ void set_message_filtering_enabled(bool enabled) {
+ message_filtering_enabled_ = enabled;
+ }
+
+ size_t messages_received() const { return messages_received_; }
+ FilterEvent last_filter_event() const { return last_filter_event_; }
+
+ private:
+ virtual ~MessageCountFilter() {}
+
+ size_t messages_received_;
+ uint32 supported_message_class_;
+ bool is_global_filter_;
+
+ FilterEvent last_filter_event_;
+ bool message_filtering_enabled_;
+};
+
+class IPCChannelProxyTest : public IPCTestBase {
+ public:
+ IPCChannelProxyTest() {}
+ virtual ~IPCChannelProxyTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ IPCTestBase::SetUp();
+
+ Init("ChannelProxyClient");
+
+ thread_.reset(new base::Thread("ChannelProxyTestServerThread"));
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ thread_->StartWithOptions(options);
+
+ listener_.reset(new QuitListener());
+ CreateChannelProxy(listener_.get(), thread_->message_loop_proxy().get());
+
+ ASSERT_TRUE(StartClient());
+ }
+
+ virtual void TearDown() {
+ DestroyChannelProxy();
+ thread_.reset();
+ listener_.reset();
+ IPCTestBase::TearDown();
+ }
+
+ void SendQuitMessageAndWaitForIdle() {
+ sender()->Send(new WorkerMsg_Quit);
+ base::MessageLoop::current()->Run();
+ EXPECT_TRUE(WaitForClientShutdown());
+ }
+
+ bool DidListenerGetBadMessage() {
+ return listener_->bad_message_received_;
+ }
+
+ private:
+ scoped_ptr<base::Thread> thread_;
+ scoped_ptr<QuitListener> listener_;
+};
+
+TEST_F(IPCChannelProxyTest, MessageClassFilters) {
+ // Construct a filter per message class.
+ std::vector<scoped_refptr<MessageCountFilter> > class_filters;
+ class_filters.push_back(make_scoped_refptr(
+ new MessageCountFilter(TestMsgStart)));
+ class_filters.push_back(make_scoped_refptr(
+ new MessageCountFilter(UtilityMsgStart)));
+ for (size_t i = 0; i < class_filters.size(); ++i)
+ channel_proxy()->AddFilter(class_filters[i].get());
+
+ // Send a message for each class; each filter should receive just one message.
+ sender()->Send(new TestMsg_Bounce());
+ sender()->Send(new UtilityMsg_Bounce());
+
+ // Send some messages not assigned to a specific or valid message class.
+ sender()->Send(new WorkerMsg_Bounce);
+
+ // Each filter should have received just the one sent message of the
+ // corresponding class.
+ SendQuitMessageAndWaitForIdle();
+ for (size_t i = 0; i < class_filters.size(); ++i)
+ EXPECT_EQ(1U, class_filters[i]->messages_received());
+}
+
+TEST_F(IPCChannelProxyTest, GlobalAndMessageClassFilters) {
+ // Add a class and global filter.
+ scoped_refptr<MessageCountFilter> class_filter(
+ new MessageCountFilter(TestMsgStart));
+ class_filter->set_message_filtering_enabled(false);
+ channel_proxy()->AddFilter(class_filter.get());
+
+ scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter());
+ global_filter->set_message_filtering_enabled(false);
+ channel_proxy()->AddFilter(global_filter.get());
+
+ // A message of class Test should be seen by both the global filter and
+ // Test-specific filter.
+ sender()->Send(new TestMsg_Bounce);
+
+ // A message of a different class should be seen only by the global filter.
+ sender()->Send(new UtilityMsg_Bounce);
+
+ // Flush all messages.
+ SendQuitMessageAndWaitForIdle();
+
+ // The class filter should have received only the class-specific message.
+ EXPECT_EQ(1U, class_filter->messages_received());
+
+ // The global filter should have received both messages, as well as the final
+ // QUIT message.
+ EXPECT_EQ(3U, global_filter->messages_received());
+}
+
+TEST_F(IPCChannelProxyTest, FilterRemoval) {
+ // Add a class and global filter.
+ scoped_refptr<MessageCountFilter> class_filter(
+ new MessageCountFilter(TestMsgStart));
+ scoped_refptr<MessageCountFilter> global_filter(new MessageCountFilter());
+
+ // Add and remove both types of filters.
+ channel_proxy()->AddFilter(class_filter.get());
+ channel_proxy()->AddFilter(global_filter.get());
+ channel_proxy()->RemoveFilter(global_filter.get());
+ channel_proxy()->RemoveFilter(class_filter.get());
+
+ // Send some messages; they should not be seen by either filter.
+ sender()->Send(new TestMsg_Bounce);
+ sender()->Send(new UtilityMsg_Bounce);
+
+ // Ensure that the filters were removed and did not receive any messages.
+ SendQuitMessageAndWaitForIdle();
+ EXPECT_EQ(MessageCountFilter::FILTER_REMOVED,
+ global_filter->last_filter_event());
+ EXPECT_EQ(MessageCountFilter::FILTER_REMOVED,
+ class_filter->last_filter_event());
+ EXPECT_EQ(0U, class_filter->messages_received());
+ EXPECT_EQ(0U, global_filter->messages_received());
+}
+
+// The test that follow trigger DCHECKS in debug build.
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+
+TEST_F(IPCChannelProxyTest, BadMessageOnListenerThread) {
+ scoped_refptr<MessageCountFilter> class_filter(
+ new MessageCountFilter(TestMsgStart));
+ class_filter->set_message_filtering_enabled(false);
+ channel_proxy()->AddFilter(class_filter.get());
+
+ sender()->Send(new TestMsg_SendBadMessage());
+
+ SendQuitMessageAndWaitForIdle();
+ EXPECT_TRUE(DidListenerGetBadMessage());
+}
+
+TEST_F(IPCChannelProxyTest, BadMessageOnIPCThread) {
+ scoped_refptr<MessageCountFilter> class_filter(
+ new MessageCountFilter(TestMsgStart));
+ class_filter->set_message_filtering_enabled(true);
+ channel_proxy()->AddFilter(class_filter.get());
+
+ sender()->Send(new TestMsg_SendBadMessage());
+
+ SendQuitMessageAndWaitForIdle();
+ EXPECT_TRUE(DidListenerGetBadMessage());
+}
+
+class IPCChannelBadMessageTest : public IPCTestBase {
+ public:
+ IPCChannelBadMessageTest() {}
+ virtual ~IPCChannelBadMessageTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ IPCTestBase::SetUp();
+
+ Init("ChannelProxyClient");
+
+ listener_.reset(new QuitListener());
+ CreateChannel(listener_.get());
+ ASSERT_TRUE(ConnectChannel());
+
+ ASSERT_TRUE(StartClient());
+ }
+
+ virtual void TearDown() {
+ listener_.reset();
+ IPCTestBase::TearDown();
+ }
+
+ void SendQuitMessageAndWaitForIdle() {
+ sender()->Send(new WorkerMsg_Quit);
+ base::MessageLoop::current()->Run();
+ EXPECT_TRUE(WaitForClientShutdown());
+ }
+
+ bool DidListenerGetBadMessage() {
+ return listener_->bad_message_received_;
+ }
+
+ private:
+ scoped_ptr<QuitListener> listener_;
+};
+
+#if !defined(OS_WIN)
+ // TODO(jam): for some reason this is flaky on win buildbots.
+TEST_F(IPCChannelBadMessageTest, BadMessage) {
+ sender()->Send(new TestMsg_SendBadMessage());
+ SendQuitMessageAndWaitForIdle();
+ EXPECT_TRUE(DidListenerGetBadMessage());
+}
+#endif
+
+#endif
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ChannelProxyClient) {
+ base::MessageLoopForIO main_message_loop;
+ ChannelReflectorListener listener;
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName("ChannelProxyClient"),
+ &listener));
+ CHECK(channel->Connect());
+ listener.Init(channel.get());
+
+ base::MessageLoop::current()->Run();
+ return 0;
+}
+
+} // namespace
diff --git a/chromium/ipc/ipc_channel_proxy_unittest_messages.h b/chromium/ipc/ipc_channel_proxy_unittest_messages.h
new file mode 100644
index 00000000000..0108f1b7c78
--- /dev/null
+++ b/chromium/ipc/ipc_channel_proxy_unittest_messages.h
@@ -0,0 +1,44 @@
+// Copyright 2014 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 "ipc/ipc_message_macros.h"
+
+// Singly-included section for enums and custom IPC traits.
+#ifndef IPC_CHANNEL_PROXY_UNITTEST_MESSAGES_H_
+#define IPC_CHANNEL_PROXY_UNITTEST_MESSAGES_H_
+
+class BadType {
+ public:
+ BadType() {}
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<BadType> {
+ static void Write(Message* m, const BadType& p) {}
+ static bool Read(const Message* m, PickleIterator* iter, BadType* r) {
+ return false;
+ }
+ static void Log(const BadType& p, std::string* l) {}
+};
+
+}
+
+#endif // IPC_CHANNEL_PROXY_UNITTEST_MESSAGES_H_
+
+
+#define IPC_MESSAGE_START TestMsgStart
+IPC_MESSAGE_CONTROL0(TestMsg_Bounce)
+IPC_MESSAGE_CONTROL0(TestMsg_SendBadMessage)
+IPC_MESSAGE_CONTROL1(TestMsg_BadMessage, BadType)
+
+#undef IPC_MESSAGE_START
+#define IPC_MESSAGE_START UtilityMsgStart
+IPC_MESSAGE_CONTROL0(UtilityMsg_Bounce)
+
+#undef IPC_MESSAGE_START
+#define IPC_MESSAGE_START WorkerMsgStart
+IPC_MESSAGE_CONTROL0(WorkerMsg_Bounce)
+IPC_MESSAGE_CONTROL0(WorkerMsg_Quit)
diff --git a/chromium/ipc/ipc_channel_reader.cc b/chromium/ipc/ipc_channel_reader.cc
index 2ee7449ea8d..9a3cc3c50bb 100644
--- a/chromium/ipc/ipc_channel_reader.cc
+++ b/chromium/ipc/ipc_channel_reader.cc
@@ -83,9 +83,10 @@ bool ChannelReader::DispatchInputData(const char* input_data,
Logging* logger = Logging::GetInstance();
std::string name;
logger->GetMessageText(m.type(), &name, &m, NULL);
- TRACE_EVENT1("ipc", "ChannelReader::DispatchInputData", "name", name);
+ TRACE_EVENT1("ipc,toplevel", "ChannelReader::DispatchInputData",
+ "name", name);
#else
- TRACE_EVENT2("ipc", "ChannelReader::DispatchInputData",
+ TRACE_EVENT2("ipc,toplevel", "ChannelReader::DispatchInputData",
"class", IPC_MESSAGE_ID_CLASS(m.type()),
"line", IPC_MESSAGE_ID_LINE(m.type()));
#endif
@@ -94,6 +95,8 @@ bool ChannelReader::DispatchInputData(const char* input_data,
HandleInternalMessage(m);
else
listener_->OnMessageReceived(m);
+ if (m.dispatch_error())
+ listener_->OnBadMessageReceived(m);
p = message_tail;
} else {
// Last message is partial.
diff --git a/chromium/ipc/ipc_channel_unittest.cc b/chromium/ipc/ipc_channel_unittest.cc
index eea432a15e7..b9665dbed73 100644
--- a/chromium/ipc/ipc_channel_unittest.cc
+++ b/chromium/ipc/ipc_channel_unittest.cc
@@ -254,12 +254,12 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(GenericClient) {
GenericChannelListener listener;
// Set up IPC channel.
- IPC::Channel channel(IPCTestBase::GetChannelName("GenericClient"),
- IPC::Channel::MODE_CLIENT,
- &listener);
- CHECK(channel.Connect());
- listener.Init(&channel);
- Send(&channel, "hello from child");
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName("GenericClient"),
+ &listener));
+ CHECK(channel->Connect());
+ listener.Init(channel.get());
+ Send(channel.get(), "hello from child");
base::MessageLoop::current()->Run();
return 0;
diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc
index 8c08500355e..4023097bead 100644
--- a/chromium/ipc/ipc_channel_win.cc
+++ b/chromium/ipc/ipc_channel_win.cc
@@ -23,17 +23,17 @@
namespace IPC {
-Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) {
+ChannelWin::State::State(ChannelWin* 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),
+ChannelWin::State::~State() {
+ COMPILE_ASSERT(!offsetof(ChannelWin::State, context),
starts_with_io_context);
}
-Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle,
+ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
Mode mode, Listener* listener)
: ChannelReader(listener),
input_state_(this),
@@ -48,11 +48,11 @@ Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle,
CreatePipe(channel_handle, mode);
}
-Channel::ChannelImpl::~ChannelImpl() {
+ChannelWin::~ChannelWin() {
Close();
}
-void Channel::ChannelImpl::Close() {
+void ChannelWin::Close() {
if (thread_check_.get()) {
DCHECK(thread_check_->CalledOnValidThread());
}
@@ -80,7 +80,7 @@ void Channel::ChannelImpl::Close() {
}
}
-bool Channel::ChannelImpl::Send(Message* message) {
+bool ChannelWin::Send(Message* message) {
DCHECK(thread_check_->CalledOnValidThread());
DVLOG(2) << "sending message @" << message << " on channel @" << this
<< " with type " << message->type()
@@ -103,8 +103,12 @@ bool Channel::ChannelImpl::Send(Message* message) {
return true;
}
+base::ProcessId ChannelWin::GetPeerPID() const {
+ return peer_pid_;
+}
+
// static
-bool Channel::ChannelImpl::IsNamedServerInitialized(
+bool ChannelWin::IsNamedServerInitialized(
const std::string& channel_id) {
if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
return true;
@@ -113,7 +117,7 @@ bool Channel::ChannelImpl::IsNamedServerInitialized(
return GetLastError() == ERROR_SEM_TIMEOUT;
}
-Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
+ChannelWin::ReadState ChannelWin::ReadData(
char* buffer,
int buffer_len,
int* /* bytes_read */) {
@@ -145,14 +149,14 @@ Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
return READ_PENDING;
}
-bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
+bool ChannelWin::WillDispatchInputMessage(Message* msg) {
// Make sure we get a hello when client validation is required.
if (validate_client_)
return IsHelloMessage(*msg);
return true;
}
-void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
+void ChannelWin::HandleInternalMessage(const Message& msg) {
DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
// The hello message contains one parameter containing the PID.
PickleIterator it(msg);
@@ -177,13 +181,13 @@ void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
listener()->OnChannelConnected(claimed_pid);
}
-bool Channel::ChannelImpl::DidEmptyInputBuffers() {
+bool ChannelWin::DidEmptyInputBuffers() {
// We don't need to do anything here.
return true;
}
// static
-const string16 Channel::ChannelImpl::PipeName(
+const base::string16 ChannelWin::PipeName(
const std::string& channel_id, int32* secret) {
std::string name("\\\\.\\pipe\\chrome.");
@@ -192,19 +196,19 @@ const string16 Channel::ChannelImpl::PipeName(
if (index != std::string::npos) {
if (secret) // Retrieve the secret if asked for.
base::StringToInt(channel_id.substr(index + 1), secret);
- return ASCIIToWide(name.append(channel_id.substr(0, index - 1)));
+ return base::ASCIIToWide(name.append(channel_id.substr(0, index - 1)));
}
// This case is here to support predictable named pipes in tests.
if (secret)
*secret = 0;
- return ASCIIToWide(name.append(channel_id));
+ return base::ASCIIToWide(name.append(channel_id));
}
-bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
+bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
Mode mode) {
DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_);
- string16 pipe_name;
+ base::string16 pipe_name;
// If we already have a valid pipe for channel just copy it.
if (channel_handle.pipe.handle) {
DCHECK(channel_handle.name.empty());
@@ -286,7 +290,7 @@ bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
return true;
}
-bool Channel::ChannelImpl::Connect() {
+bool ChannelWin::Connect() {
DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
if (!thread_check_.get())
@@ -307,7 +311,7 @@ bool Channel::ChannelImpl::Connect() {
// initialization signal.
base::MessageLoopForIO::current()->PostTask(
FROM_HERE,
- base::Bind(&Channel::ChannelImpl::OnIOCompleted,
+ base::Bind(&ChannelWin::OnIOCompleted,
weak_factory_.GetWeakPtr(),
&input_state_.context,
0,
@@ -319,7 +323,7 @@ bool Channel::ChannelImpl::Connect() {
return true;
}
-bool Channel::ChannelImpl::ProcessConnection() {
+bool ChannelWin::ProcessConnection() {
DCHECK(thread_check_->CalledOnValidThread());
if (input_state_.is_pending)
input_state_.is_pending = false;
@@ -356,7 +360,7 @@ bool Channel::ChannelImpl::ProcessConnection() {
return true;
}
-bool Channel::ChannelImpl::ProcessOutgoingMessages(
+bool ChannelWin::ProcessOutgoingMessages(
base::MessageLoopForIO::IOContext* context,
DWORD bytes_written) {
DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
@@ -372,7 +376,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages(
return false;
}
// Message was sent.
- DCHECK(!output_queue_.empty());
+ CHECK(!output_queue_.empty());
Message* m = output_queue_.front();
output_queue_.pop();
delete m;
@@ -413,7 +417,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages(
return true;
}
-void Channel::ChannelImpl::OnIOCompleted(
+void ChannelWin::OnIOCompleted(
base::MessageLoopForIO::IOContext* context,
DWORD bytes_transfered,
DWORD error) {
@@ -463,36 +467,18 @@ void Channel::ChannelImpl::OnIOCompleted(
}
//------------------------------------------------------------------------------
-// Channel's methods simply call through to ChannelImpl.
-Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode,
- Listener* listener)
- : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
-}
-
-Channel::~Channel() {
- delete channel_impl_;
-}
-
-bool Channel::Connect() {
- return channel_impl_->Connect();
-}
-
-void Channel::Close() {
- if (channel_impl_)
- channel_impl_->Close();
-}
+// Channel's methods
-base::ProcessId Channel::peer_pid() const {
- return channel_impl_->peer_pid();
-}
-
-bool Channel::Send(Message* message) {
- return channel_impl_->Send(message);
+// static
+scoped_ptr<Channel> Channel::Create(
+ const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
+ return scoped_ptr<Channel>(
+ new ChannelWin(channel_handle, mode, listener));
}
// static
bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
- return ChannelImpl::IsNamedServerInitialized(channel_id);
+ return ChannelWin::IsNamedServerInitialized(channel_id);
}
// static
diff --git a/chromium/ipc/ipc_channel_win.h b/chromium/ipc/ipc_channel_win.h
index a544f8be4bb..29042bf1ca3 100644
--- a/chromium/ipc/ipc_channel_win.h
+++ b/chromium/ipc/ipc_channel_win.h
@@ -21,18 +21,23 @@ class ThreadChecker;
namespace IPC {
-class Channel::ChannelImpl : public internal::ChannelReader,
- public base::MessageLoopForIO::IOHandler {
+class ChannelWin : public Channel,
+ public internal::ChannelReader,
+ public base::MessageLoopForIO::IOHandler {
public:
// Mirror methods of Channel, see ipc_channel.h for description.
- ChannelImpl(const IPC::ChannelHandle &channel_handle, Mode mode,
- Listener* listener);
- ~ChannelImpl();
- bool Connect();
- void Close();
- bool Send(Message* message);
+ ChannelWin(const IPC::ChannelHandle &channel_handle, Mode mode,
+ Listener* listener);
+ ~ChannelWin();
+
+ // Channel implementation
+ virtual bool Connect() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual bool Send(Message* message) OVERRIDE;
+ virtual base::ProcessId GetPeerPID() const OVERRIDE;
+
static bool IsNamedServerInitialized(const std::string& channel_id);
- base::ProcessId peer_pid() const { return peer_pid_; }
+
private:
// ChannelReader implementation.
@@ -43,8 +48,8 @@ class Channel::ChannelImpl : public internal::ChannelReader,
bool DidEmptyInputBuffers() OVERRIDE;
virtual void HandleInternalMessage(const Message& msg) OVERRIDE;
- static const string16 PipeName(const std::string& channel_id,
- int32* secret);
+ static const base::string16 PipeName(const std::string& channel_id,
+ int32* secret);
bool CreatePipe(const IPC::ChannelHandle &channel_handle, Mode mode);
bool ProcessConnection();
@@ -58,7 +63,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
private:
struct State {
- explicit State(ChannelImpl* channel);
+ explicit State(ChannelWin* channel);
~State();
base::MessageLoopForIO::IOContext context;
bool is_pending;
@@ -94,11 +99,11 @@ class Channel::ChannelImpl : public internal::ChannelReader,
int32 client_secret_;
- base::WeakPtrFactory<ChannelImpl> weak_factory_;
+ base::WeakPtrFactory<ChannelWin> weak_factory_;
scoped_ptr<base::ThreadChecker> thread_check_;
- DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
+ DISALLOW_COPY_AND_ASSIGN(ChannelWin);
};
} // namespace IPC
diff --git a/chromium/ipc/ipc_forwarding_message_filter.cc b/chromium/ipc/ipc_forwarding_message_filter.cc
index 342aeb718dc..9857bdf67dc 100644
--- a/chromium/ipc/ipc_forwarding_message_filter.cc
+++ b/chromium/ipc/ipc_forwarding_message_filter.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "ipc/ipc_message.h"
namespace IPC {
diff --git a/chromium/ipc/ipc_forwarding_message_filter.h b/chromium/ipc/ipc_forwarding_message_filter.h
index 919a44d7599..597fc6090ee 100644
--- a/chromium/ipc/ipc_forwarding_message_filter.h
+++ b/chromium/ipc/ipc_forwarding_message_filter.h
@@ -12,7 +12,7 @@
#include "base/callback_forward.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
-#include "ipc/ipc_channel_proxy.h"
+#include "ipc/message_filter.h"
namespace IPC {
@@ -23,7 +23,7 @@ namespace IPC {
//
// The user of this class implements ForwardingMessageFilter::Client,
// which will receive the intercepted messages, on the specified target thread.
-class IPC_EXPORT ForwardingMessageFilter : public ChannelProxy::MessageFilter {
+class IPC_EXPORT ForwardingMessageFilter : public MessageFilter {
public:
// The handler is invoked on the thread associated with
@@ -44,11 +44,10 @@ class IPC_EXPORT ForwardingMessageFilter : public ChannelProxy::MessageFilter {
void AddRoute(int routing_id, const Handler& handler);
void RemoveRoute(int routing_id);
- // ChannelProxy::MessageFilter methods:
+ // MessageFilter methods:
virtual bool OnMessageReceived(const Message& message) OVERRIDE;
private:
- friend class ChannelProxy::MessageFilter;
virtual ~ForwardingMessageFilter();
std::set<int> message_ids_to_filter_;
diff --git a/chromium/ipc/ipc_fuzzing_tests.cc b/chromium/ipc/ipc_fuzzing_tests.cc
index 3d2d497c5f8..4abcc4c6254 100644
--- a/chromium/ipc/ipc_fuzzing_tests.cc
+++ b/chromium/ipc/ipc_fuzzing_tests.cc
@@ -247,11 +247,11 @@ class FuzzerClientListener : public SimpleListener {
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(FuzzServerClient) {
base::MessageLoopForIO main_message_loop;
FuzzerServerListener listener;
- IPC::Channel channel(IPCTestBase::GetChannelName("FuzzServerClient"),
- IPC::Channel::MODE_CLIENT,
- &listener);
- CHECK(channel.Connect());
- listener.Init(&channel);
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName("FuzzServerClient"),
+ &listener));
+ CHECK(channel->Connect());
+ listener.Init(channel.get());
base::MessageLoop::current()->Run();
return 0;
}
@@ -345,69 +345,4 @@ TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
DestroyChannel();
}
-// This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros.
-class ServerMacroExTest {
- public:
- ServerMacroExTest() : unhandled_msgs_(0) {
- }
-
- virtual ~ServerMacroExTest() {
- }
-
- virtual bool OnMessageReceived(const IPC::Message& msg) {
- bool msg_is_ok = false;
- IPC_BEGIN_MESSAGE_MAP_EX(ServerMacroExTest, msg, msg_is_ok)
- IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
- IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
- IPC_MESSAGE_UNHANDLED(++unhandled_msgs_)
- IPC_END_MESSAGE_MAP_EX()
- return msg_is_ok;
- }
-
- int unhandled_msgs() const {
- return unhandled_msgs_;
- }
-
- private:
- void OnMsgClassISMessage(int value, const std::wstring& text) {
- }
- void OnMsgClassSIMessage(const std::wstring& text, int value) {
- }
-
- int unhandled_msgs_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerMacroExTest);
-};
-
-TEST_F(IPCFuzzingTest, MsgMapExMacro) {
- IPC::Message* msg = NULL;
- ServerMacroExTest server;
-
- // Test the regular messages.
- msg = new MsgClassIS(3, L"text3");
- EXPECT_TRUE(server.OnMessageReceived(*msg));
- delete msg;
- msg = new MsgClassSI(L"text2", 2);
- EXPECT_TRUE(server.OnMessageReceived(*msg));
- delete msg;
-
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
- // Test a bad message.
- msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
- IPC::Message::PRIORITY_NORMAL);
- msg->WriteInt(2);
- EXPECT_FALSE(server.OnMessageReceived(*msg));
- delete msg;
-
- msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
- IPC::Message::PRIORITY_NORMAL);
- msg->WriteInt(0x64);
- msg->WriteInt(0x32);
- EXPECT_FALSE(server.OnMessageReceived(*msg));
- delete msg;
-
- EXPECT_EQ(0, server.unhandled_msgs());
-#endif
-}
-
} // namespace
diff --git a/chromium/ipc/ipc_listener.h b/chromium/ipc/ipc_listener.h
index 9189eec7d11..733bc46d7c8 100644
--- a/chromium/ipc/ipc_listener.h
+++ b/chromium/ipc/ipc_listener.h
@@ -28,6 +28,9 @@ class IPC_EXPORT Listener {
// This method is not called when a channel is closed normally.
virtual void OnChannelError() {}
+ // Called when a message's deserialization failed.
+ virtual void OnBadMessageReceived(const Message& message) {}
+
#if defined(OS_POSIX)
// Called on the server side when a channel that listens for connections
// denies an attempt to connect.
diff --git a/chromium/ipc/ipc_message.cc b/chromium/ipc/ipc_message.cc
index cf3a65e077f..1ac4d6e3026 100644
--- a/chromium/ipc/ipc_message.cc
+++ b/chromium/ipc/ipc_message.cc
@@ -4,7 +4,7 @@
#include "ipc/ipc_message.h"
-#include "base/atomicops.h"
+#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "build/build_config.h"
@@ -14,7 +14,7 @@
namespace {
-base::subtle::Atomic32 g_ref_num = 0;
+base::StaticAtomicSequenceNumber g_ref_num;
// Create a reference number for identifying IPC messages in traces. The return
// values has the reference number stored in the upper 24 bits, leaving the low
@@ -22,7 +22,7 @@ base::subtle::Atomic32 g_ref_num = 0;
inline uint32 GetRefNumUpper24() {
base::debug::TraceLog* trace_log = base::debug::TraceLog::GetInstance();
int32 pid = trace_log ? trace_log->process_id() : 0;
- int32 count = base::subtle::NoBarrier_AtomicIncrement(&g_ref_num, 1);
+ int32 count = g_ref_num.GetNext();
// The 24 bit hash is composed of 14 bits of the count and 10 bits of the
// Process ID. With the current trace event buffer cap, the 14-bit count did
// not appear to wrap during a trace. Note that it is not a big deal if
@@ -47,7 +47,7 @@ Message::Message()
header()->num_fds = 0;
header()->pad = 0;
#endif
- InitLoggingVariables();
+ Init();
}
Message::Message(int32 routing_id, uint32 type, PriorityValue priority)
@@ -60,21 +60,22 @@ Message::Message(int32 routing_id, uint32 type, PriorityValue priority)
header()->num_fds = 0;
header()->pad = 0;
#endif
- InitLoggingVariables();
+ Init();
}
Message::Message(const char* data, int data_len) : Pickle(data, data_len) {
- InitLoggingVariables();
+ Init();
}
Message::Message(const Message& other) : Pickle(other) {
- InitLoggingVariables();
+ Init();
#if defined(OS_POSIX)
file_descriptor_set_ = other.file_descriptor_set_;
#endif
}
-void Message::InitLoggingVariables() {
+void Message::Init() {
+ dispatch_error_ = false;
#ifdef IPC_MESSAGE_LOG_ENABLED
received_time_ = 0;
dont_log_ = false;
diff --git a/chromium/ipc/ipc_message.h b/chromium/ipc/ipc_message.h
index 42090166b38..fc37d72f284 100644
--- a/chromium/ipc/ipc_message.h
+++ b/chromium/ipc/ipc_message.h
@@ -121,6 +121,14 @@ class IPC_EXPORT Message : public Pickle {
return (header()->flags & PUMPING_MSGS_BIT) != 0;
}
+ void set_dispatch_error() const {
+ dispatch_error_ = true;
+ }
+
+ bool dispatch_error() const {
+ return dispatch_error_;
+ }
+
uint32 type() const {
return header()->type;
}
@@ -141,31 +149,17 @@ class IPC_EXPORT Message : public Pickle {
// call.
void SetHeaderValues(int32 routing, uint32 type, uint32 flags);
- template<class T, class S>
- static bool Dispatch(const Message* msg, T* obj, S* sender,
+ template<class T, class S, class P>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter,
void (T::*func)()) {
(obj->*func)();
return true;
}
- template<class T, class S>
- static bool Dispatch(const Message* msg, T* obj, S* sender,
- void (T::*func)() const) {
- (obj->*func)();
- return true;
- }
-
- template<class T, class S>
- static bool Dispatch(const Message* msg, T* obj, S* sender,
- void (T::*func)(const Message&)) {
- (obj->*func)(*msg);
- return true;
- }
-
- template<class T, class S>
- static bool Dispatch(const Message* msg, T* obj, S* sender,
- void (T::*func)(const Message&) const) {
- (obj->*func)(*msg);
+ template<class T, class S, class P>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter,
+ void (T::*func)(P*)) {
+ (obj->*func)(parameter);
return true;
}
@@ -217,15 +211,20 @@ class IPC_EXPORT Message : public Pickle {
// Called to trace when message is sent.
void TraceMessageBegin() {
- TRACE_EVENT_FLOW_BEGIN0("ipc", "IPC", header()->flags);
+ TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), "IPC",
+ header()->flags);
}
// Called to trace when message is received.
void TraceMessageEnd() {
- TRACE_EVENT_FLOW_END0("ipc", "IPC", header()->flags);
+ TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), "IPC",
+ header()->flags);
}
protected:
friend class Channel;
+ friend class ChannelNacl;
+ friend class ChannelPosix;
+ friend class ChannelWin;
friend class MessageReplyDeserializer;
friend class SyncMessage;
@@ -248,7 +247,10 @@ class IPC_EXPORT Message : public Pickle {
return headerT<Header>();
}
- void InitLoggingVariables();
+ void Init();
+
+ // Used internally to support IPC::Listener::OnBadMessageReceived.
+ mutable bool dispatch_error_;
#if defined(OS_POSIX)
// The set of file descriptors associated with this message.
diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h
index c4e250cf9e6..8be5c532bf0 100644
--- a/chromium/ipc/ipc_message_macros.h
+++ b/chromium/ipc/ipc_message_macros.h
@@ -113,8 +113,8 @@
// class_some_other_class; // Another incomplete class declaration
// #endif // SOME_GUARD_MACRO
// #ifdef IPC_MESSAGE_IMPL
-// #inlcude "path/to/some_class.h" // Full class declaration
-// #inlcude "path/to/some_other_class.h" // Full class declaration
+// #include "path/to/some_class.h" // Full class declaration
+// #include "path/to/some_other_class.h" // Full class declaration
// #endif // IPC_MESSAGE_IMPL
// (.. IPC macros using some_class and some_other_class ...)
//
@@ -434,9 +434,12 @@
// The following macros define the common set of methods provided by ASYNC
// message classes.
+// This macro is for all the async IPCs that don't pass an extra parameter using
+// IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
#define IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class Method> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, Method func) { \
+ template<class T, class S, class P, class Method> \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ Method func) { \
Schema::Param p; \
if (Read(msg, &p)) { \
DispatchToMethod(obj, func, p); \
@@ -444,124 +447,86 @@
} \
return false; \
}
+
+// The following macros are for for async IPCs which have a dispatcher with an
+// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
#define IPC_ASYNC_MESSAGE_METHODS_1 \
IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, typename TA> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, \
- void (T::*func)(const Message&, TA)) { \
+ template<class T, class S, class P, typename TA> \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ void (T::*func)(P*, TA)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(*msg, p.a); \
+ (obj->*func)(parameter, p.a); \
return true; \
} \
return false; \
}
#define IPC_ASYNC_MESSAGE_METHODS_2 \
IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, typename TA, typename TB> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, \
- void (T::*func)(const Message&, TA, TB)) { \
+ template<class T, class S, class P, typename TA, typename TB> \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ void (T::*func)(P*, TA, TB)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(*msg, p.a, p.b); \
+ (obj->*func)(parameter, p.a, p.b); \
return true; \
} \
return false; \
- } \
- template<typename TA, typename TB> \
- static bool Read(const IPC::Message* msg, TA* a, TB* b) { \
- Schema::Param p; \
- if (!Read(msg, &p)) \
- return false; \
- *a = p.a; \
- *b = p.b; \
- return true; \
}
#define IPC_ASYNC_MESSAGE_METHODS_3 \
IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, typename TA, typename TB, typename TC> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, \
- void (T::*func)(const Message&, TA, TB, TC)) { \
+ template<class T, class S, class P, typename TA, typename TB, typename TC> \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ void (T::*func)(P*, TA, TB, TC)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(*msg, p.a, p.b, p.c); \
+ (obj->*func)(parameter, p.a, p.b, p.c); \
return true; \
} \
return false; \
- } \
- template<typename TA, typename TB, typename TC> \
- static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) { \
- Schema::Param p; \
- if (!Read(msg, &p)) \
- return false; \
- *a = p.a; \
- *b = p.b; \
- *c = p.c; \
- return true; \
}
#define IPC_ASYNC_MESSAGE_METHODS_4 \
IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, typename TA, typename TB, typename TC, \
+ template<class T, class S, class P, typename TA, typename TB, typename TC, \
typename TD> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, \
- void (T::*func)(const Message&, TA, TB, TC, TD)) { \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ void (T::*func)(P*, TA, TB, TC, TD)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(*msg, p.a, p.b, p.c, p.d); \
+ (obj->*func)(parameter, p.a, p.b, p.c, p.d); \
return true; \
} \
return false; \
- } \
- template<typename TA, typename TB, typename TC, typename TD> \
- static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) { \
- Schema::Param p; \
- if (!Read(msg, &p)) \
- return false; \
- *a = p.a; \
- *b = p.b; \
- *c = p.c; \
- *d = p.d; \
- return true; \
}
#define IPC_ASYNC_MESSAGE_METHODS_5 \
IPC_ASYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, typename TA, typename TB, typename TC, \
+ template<class T, class S, class P, typename TA, typename TB, typename TC, \
typename TD, typename TE> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, \
- void (T::*func)(const Message&, TA, TB, TC, TD, TE)) { \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ void (T::*func)(P*, TA, TB, TC, TD, TE)) { \
Schema::Param p; \
if (Read(msg, &p)) { \
- (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e); \
+ (obj->*func)(parameter, p.a, p.b, p.c, p.d, p.e); \
return true; \
} \
return false; \
- } \
- template<typename TA, typename TB, typename TC, typename TD, typename TE> \
- static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, \
- TE* e) { \
- Schema::Param p; \
- if (!Read(msg, &p)) \
- return false; \
- *a = p.a; \
- *b = p.b; \
- *c = p.c; \
- *d = p.d; \
- *e = p.e; \
- return true; \
}
// The following macros define the common set of methods provided by SYNC
// message classes.
#define IPC_SYNC_MESSAGE_METHODS_GENERIC \
- template<class T, class S, class Method> \
- static bool Dispatch(const Message* msg, T* obj, S* sender, Method func) { \
+ template<class T, class S, class P, class Method> \
+ static bool Dispatch(const Message* msg, T* obj, S* sender, P* parameter, \
+ Method func) { \
Schema::SendParam send_params; \
bool ok = ReadSendParam(msg, &send_params); \
return Schema::DispatchWithSendParams(ok, send_params, msg, obj, sender, \
func); \
} \
- template<class T, class Method> \
- static bool DispatchDelayReply(const Message* msg, T* obj, Method func) { \
+ template<class T, class P, class Method> \
+ static bool DispatchDelayReply(const Message* msg, T* obj, P* parameter, \
+ Method func) { \
Schema::SendParam send_params; \
bool ok = ReadSendParam(msg, &send_params); \
return Schema::DispatchDelayReplyWithSendParams(ok, send_params, msg, \
@@ -911,45 +876,48 @@
#define IPC_MESSAGE_ID_CLASS(id) ((id) >> 16)
#define IPC_MESSAGE_ID_LINE(id) ((id) & 0xffff)
-// Message crackers and handlers.
-// Prefer to use the IPC_BEGIN_MESSAGE_MAP_EX to the older macros since they
-// allow you to detect when a message could not be de-serialized. Usage:
+// Message crackers and handlers. Usage:
//
// bool MyClass::OnMessageReceived(const IPC::Message& msg) {
// bool handled = true;
-// bool msg_is_good = false;
-// IPC_BEGIN_MESSAGE_MAP_EX(MyClass, msg, msg_is_good)
+// IPC_BEGIN_MESSAGE_MAP(MyClass, msg)
// IPC_MESSAGE_HANDLER(MsgClassOne, OnMsgClassOne)
// ...more handlers here ...
// IPC_MESSAGE_HANDLER(MsgClassTen, OnMsgClassTen)
// IPC_MESSAGE_UNHANDLED(handled = false)
-// IPC_END_MESSAGE_MAP_EX()
-// if (!msg_is_good) {
-// // Signal error here or terminate offending process.
-// }
+// IPC_END_MESSAGE_MAP()
// return handled;
// }
-#define IPC_BEGIN_MESSAGE_MAP_EX(class_name, msg, msg_is_ok) \
- { \
- typedef class_name _IpcMessageHandlerClass; \
- const IPC::Message& ipc_message__ = msg; \
- bool& msg_is_ok__ = msg_is_ok; \
- switch (ipc_message__.type()) { \
-
#define IPC_BEGIN_MESSAGE_MAP(class_name, msg) \
{ \
typedef class_name _IpcMessageHandlerClass; \
+ void* param__ = NULL; \
const IPC::Message& ipc_message__ = msg; \
- bool msg_is_ok__ = true; \
- switch (ipc_message__.type()) { \
+ switch (ipc_message__.type()) {
+
+// gcc gives the following error now when using decltype so type typeof there:
+// error: identifier 'decltype' will become a keyword in C++0x [-Werror=c++0x-compat]
+#if defined(OS_WIN)
+#define IPC_DECLTYPE decltype
+#else
+#define IPC_DECLTYPE typeof
+#endif
+
+#define IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(class_name, msg, param) \
+ { \
+ typedef class_name _IpcMessageHandlerClass; \
+ IPC_DECLTYPE(param) param__ = param; \
+ const IPC::Message& ipc_message__ = msg; \
+ switch (ipc_message__.type()) {
#define IPC_MESSAGE_FORWARD(msg_class, obj, member_func) \
case msg_class::ID: { \
TRACK_RUN_IN_IPC_HANDLER(member_func); \
- msg_is_ok__ = msg_class::Dispatch(&ipc_message__, obj, this, \
- &member_func); \
+ if (!msg_class::Dispatch(&ipc_message__, obj, this, param__, \
+ &member_func)) \
+ ipc_message__.set_dispatch_error(); \
} \
break;
@@ -959,8 +927,9 @@
#define IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, obj, member_func) \
case msg_class::ID: { \
TRACK_RUN_IN_IPC_HANDLER(member_func); \
- msg_is_ok__ = msg_class::DispatchDelayReply(&ipc_message__, obj, \
- &member_func); \
+ if (!msg_class::DispatchDelayReply(&ipc_message__, obj, param__, \
+ &member_func)) \
+ ipc_message__.set_dispatch_error(); \
} \
break;
@@ -997,11 +966,6 @@
#define IPC_END_MESSAGE_MAP() \
} \
- DCHECK(msg_is_ok__); \
-}
-
-#define IPC_END_MESSAGE_MAP_EX() \
- } \
}
// This corresponds to an enum value from IPCMessageStart.
diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h
index 7ce2bdd8542..8d813a28c63 100644
--- a/chromium/ipc/ipc_message_start.h
+++ b/chromium/ipc/ipc_message_start.h
@@ -48,7 +48,7 @@ enum IPCMessageStart {
DesktopNotificationMsgStart,
GeolocationMsgStart,
AudioMsgStart,
- MIDIMsgStart,
+ MidiMsgStart,
ChromeMsgStart,
DragMsgStart,
PrintMsgStart,
@@ -66,6 +66,7 @@ enum IPCMessageStart {
GamepadMsgStart,
ShellMsgStart,
AccessibilityMsgStart,
+ PrefetchMsgStart,
PrerenderMsgStart,
ChromotingMsgStart,
OldBrowserPluginMsgStart,
@@ -92,6 +93,20 @@ enum IPCMessageStart {
EncryptedMediaMsgStart,
ServiceWorkerMsgStart,
MessagePortMsgStart,
+ EmbeddedWorkerMsgStart,
+ EmbeddedWorkerContextMsgStart,
+ CastMsgStart,
+ CdmMsgStart,
+ ScreenOrientationMsgStart,
+ MediaStreamTrackMetricsHostMsgStart,
+ ChromeExtensionMsgStart,
+ MojoMsgStart,
+ TranslateMsgStart,
+ PushMessagingMsgStart,
+ GinJavaBridgeMsgStart,
+ BatteryStatusMsgStart,
+ UtilityPrintingMsgStart,
+ AecDumpMsgStart,
LastIPCMsgStart // Must come last.
};
diff --git a/chromium/ipc/ipc_message_unittest.cc b/chromium/ipc/ipc_message_unittest.cc
index 971314a290c..5b3a78d3273 100644
--- a/chromium/ipc/ipc_message_unittest.cc
+++ b/chromium/ipc/ipc_message_unittest.cc
@@ -11,6 +11,19 @@
#include "ipc/ipc_message_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+// IPC messages for testing ----------------------------------------------------
+
+#define IPC_MESSAGE_IMPL
+#include "ipc/ipc_message_macros.h"
+
+#define IPC_MESSAGE_START TestMsgStart
+
+IPC_MESSAGE_CONTROL0(TestMsgClassEmpty)
+
+IPC_MESSAGE_CONTROL1(TestMsgClassI, int)
+
+IPC_SYNC_MESSAGE_CONTROL1_1(TestMsgClassIS, int, std::string)
+
namespace {
TEST(IPCMessageTest, ListValue) {
@@ -70,4 +83,70 @@ TEST(IPCMessageTest, DictionaryValue) {
EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output));
}
+class IPCMessageParameterTest : public testing::Test {
+ public:
+ IPCMessageParameterTest() : extra_param_("extra_param"), called_(false) {}
+
+ bool OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(IPCMessageParameterTest, message,
+ &extra_param_)
+ IPC_MESSAGE_HANDLER(TestMsgClassEmpty, OnEmpty)
+ IPC_MESSAGE_HANDLER(TestMsgClassI, OnInt)
+ //IPC_MESSAGE_HANDLER(TestMsgClassIS, OnSync)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+ }
+
+ void OnEmpty(std::string* extra_param) {
+ EXPECT_EQ(extra_param, &extra_param_);
+ called_ = true;
+ }
+
+ void OnInt(std::string* extra_param, int foo) {
+ EXPECT_EQ(extra_param, &extra_param_);
+ EXPECT_EQ(foo, 42);
+ called_ = true;
+ }
+
+ /* TODO: handle sync IPCs
+ void OnSync(std::string* extra_param, int foo, std::string* out) {
+ EXPECT_EQ(extra_param, &extra_param_);
+ EXPECT_EQ(foo, 42);
+ called_ = true;
+ *out = std::string("out");
+ }
+
+ bool Send(IPC::Message* reply) {
+ delete reply;
+ return true;
+ }*/
+
+ std::string extra_param_;
+ bool called_;
+};
+
+TEST_F(IPCMessageParameterTest, EmptyDispatcherWithParam) {
+ TestMsgClassEmpty message;
+ EXPECT_TRUE(OnMessageReceived(message));
+ EXPECT_TRUE(called_);
+}
+
+TEST_F(IPCMessageParameterTest, OneIntegerWithParam) {
+ TestMsgClassI message(42);
+ EXPECT_TRUE(OnMessageReceived(message));
+ EXPECT_TRUE(called_);
+}
+
+/* TODO: handle sync IPCs
+TEST_F(IPCMessageParameterTest, Sync) {
+ std::string output;
+ TestMsgClassIS message(42, &output);
+ EXPECT_TRUE(OnMessageReceived(message));
+ EXPECT_TRUE(called_);
+ EXPECT_EQ(output, std::string("out"));
+}*/
+
} // namespace
diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc
index 0390648f457..a67c5f5cf9e 100644
--- a/chromium/ipc/ipc_message_utils.cc
+++ b/chromium/ipc/ipc_message_utils.cc
@@ -340,12 +340,12 @@ void ParamTraits<std::string>::Log(const param_type& p, std::string* l) {
}
void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) {
- l->append(WideToUTF8(p));
+ l->append(base::WideToUTF8(p));
}
#if !defined(WCHAR_T_IS_UTF16)
void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) {
- l->append(UTF16ToUTF8(p));
+ l->append(base::UTF16ToUTF8(p));
}
#endif
@@ -555,8 +555,8 @@ void ParamTraits<base::NullableString16>::Log(const param_type& p,
l->append(")");
}
-void ParamTraits<base::PlatformFileInfo>::Write(Message* m,
- const param_type& p) {
+void ParamTraits<base::File::Info>::Write(Message* m,
+ const param_type& p) {
WriteParam(m, p.size);
WriteParam(m, p.is_directory);
WriteParam(m, p.last_modified.ToDoubleT());
@@ -564,9 +564,9 @@ void ParamTraits<base::PlatformFileInfo>::Write(Message* m,
WriteParam(m, p.creation_time.ToDoubleT());
}
-bool ParamTraits<base::PlatformFileInfo>::Read(const Message* m,
- PickleIterator* iter,
- param_type* p) {
+bool ParamTraits<base::File::Info>::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* p) {
double last_modified;
double last_accessed;
double creation_time;
@@ -584,8 +584,8 @@ bool ParamTraits<base::PlatformFileInfo>::Read(const Message* m,
return result;
}
-void ParamTraits<base::PlatformFileInfo>::Log(const param_type& p,
- std::string* l) {
+void ParamTraits<base::File::Info>::Log(const param_type& p,
+ std::string* l) {
l->append("(");
LogParam(p.size, l);
l->append(",");
diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h
index 24b38af68ee..6bfd103c6d8 100644
--- a/chromium/ipc/ipc_message_utils.h
+++ b/chromium/ipc/ipc_message_utils.h
@@ -11,9 +11,11 @@
#include <string>
#include <vector>
+#include "base/containers/small_map.h"
+#include "base/files/file.h"
#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
-#include "base/platform_file.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -474,15 +476,15 @@ struct IPC_EXPORT ParamTraits<base::NullableString16> {
};
template <>
-struct IPC_EXPORT ParamTraits<base::PlatformFileInfo> {
- typedef base::PlatformFileInfo param_type;
+struct IPC_EXPORT ParamTraits<base::File::Info> {
+ typedef base::File::Info param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, PickleIterator* iter, param_type* r);
static void Log(const param_type& p, std::string* l);
};
template <>
-struct SimilarTypeTraits<base::PlatformFileError> {
+struct SimilarTypeTraits<base::File::Error> {
typedef int Type;
};
@@ -670,6 +672,75 @@ struct ParamTraits<ScopedVector<P> > {
}
};
+template <typename NormalMap,
+ int kArraySize,
+ typename EqualKey,
+ typename MapInit>
+struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > {
+ typedef base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> param_type;
+ typedef typename param_type::key_type K;
+ typedef typename param_type::data_type V;
+ 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 (!m->ReadLength(iter, &size))
+ return false;
+ for (int i = 0; i < size; ++i) {
+ K key;
+ if (!ReadParam(m, iter, &key))
+ return false;
+ V& value = (*r)[key];
+ if (!ReadParam(m, iter, &value))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<base::SmallMap>");
+ }
+};
+
+template <class P>
+struct ParamTraits<scoped_ptr<P> > {
+ typedef scoped_ptr<P> param_type;
+ static void Write(Message* m, const param_type& p) {
+ bool valid = !!p;
+ WriteParam(m, valid);
+ if (valid)
+ WriteParam(m, *p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ bool valid = false;
+ if (!ReadParam(m, iter, &valid))
+ return false;
+
+ if (!valid) {
+ r->reset();
+ return true;
+ }
+
+ param_type temp(new P());
+ if (!ReadParam(m, iter, temp.get()))
+ return false;
+
+ r->swap(temp);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ if (p)
+ LogParam(*p, l);
+ else
+ l->append("NULL");
+ }
+};
+
// IPC types ParamTraits -------------------------------------------------------
// A ChannelHandle is basically a platform-inspecific wrapper around the
diff --git a/chromium/ipc/ipc_multiprocess_test.cc b/chromium/ipc/ipc_multiprocess_test.cc
index 8e3c03a1db6..8da67b2c8a6 100644
--- a/chromium/ipc/ipc_multiprocess_test.cc
+++ b/chromium/ipc/ipc_multiprocess_test.cc
@@ -4,6 +4,7 @@
#include "build/build_config.h"
+#include "ipc/ipc_channel.h"
#include "ipc/ipc_multiprocess_test.h"
#if defined(OS_POSIX)
@@ -14,6 +15,12 @@
namespace internal {
void MultiProcessTestIPCSetUp() {
+#if defined(OS_ANDROID)
+ // On Android we can't 'exec'. So for simple multi-process tests
+ // we need to reset some global data after forking to get the same
+ // behavior in simple multi-process tests.
+ IPC::Channel::NotifyProcessForkedForTesting();
+#endif
#if defined(OS_POSIX)
base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel,
kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
diff --git a/chromium/ipc/ipc_untrusted.gyp b/chromium/ipc/ipc_nacl.gyp
index 7b0c5483faf..3119f46cae1 100644
--- a/chromium/ipc/ipc_untrusted.gyp
+++ b/chromium/ipc/ipc_nacl.gyp
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2014 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.
@@ -14,19 +14,19 @@
['disable_nacl==0 and disable_nacl_untrusted==0', {
'targets': [
{
- 'target_name': 'ipc_untrusted',
+ 'target_name': 'ipc_nacl',
'type': 'none',
'variables': {
'ipc_target': 1,
'nacl_untrusted_build': 1,
- 'nlib_target': 'libipc_untrusted.a',
+ 'nlib_target': 'libipc_nacl.a',
'build_glibc': 0,
'build_newlib': 0,
'build_irt': 1,
},
'dependencies': [
'<(DEPTH)/native_client/tools.gyp:prep_toolchain',
- '../base/base_untrusted.gyp:base_untrusted',
+ '../base/base_nacl.gyp:base_nacl',
],
},
],
diff --git a/chromium/ipc/ipc_perftests.cc b/chromium/ipc/ipc_perftests.cc
index e7eeab9d8ea..3feabda9d10 100644
--- a/chromium/ipc/ipc_perftests.cc
+++ b/chromium/ipc/ipc_perftests.cc
@@ -230,12 +230,13 @@ TEST_F(IPCChannelPerfTest, Performance) {
ASSERT_TRUE(ConnectChannel());
ASSERT_TRUE(StartClient());
- const size_t kMsgSizeBase = 12;
- const int kMsgSizeMaxExp = 5;
- int msg_count = 100000;
- size_t msg_size = kMsgSizeBase;
- for (int i = 1; i <= kMsgSizeMaxExp; i++) {
- listener.SetTestParams(msg_count, msg_size);
+ // Test several sizes. We use 12^N for message size, and limit the message
+ // count to keep the test duration reasonable.
+ const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
+ const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
+
+ for (size_t i = 0; i < 5; i++) {
+ listener.SetTestParams(kMessageCount[i], kMsgSize[i]);
// This initial message will kick-start the ping-pong of messages.
IPC::Message* message =
@@ -247,8 +248,6 @@ TEST_F(IPCChannelPerfTest, Performance) {
// Run message loop.
base::MessageLoop::current()->Run();
-
- msg_size *= kMsgSizeBase;
}
// Send quit message.
@@ -266,11 +265,10 @@ TEST_F(IPCChannelPerfTest, Performance) {
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) {
base::MessageLoopForIO main_message_loop;
ChannelReflectorListener listener;
- IPC::Channel channel(IPCTestBase::GetChannelName("PerformanceClient"),
- IPC::Channel::MODE_CLIENT,
- &listener);
- listener.Init(&channel);
- CHECK(channel.Connect());
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName("PerformanceClient"), &listener));
+ listener.Init(channel.get());
+ CHECK(channel->Connect());
base::MessageLoop::current()->Run();
return 0;
diff --git a/chromium/ipc/ipc_platform_file.cc b/chromium/ipc/ipc_platform_file.cc
index 4a756ea6788..826d03014ed 100644
--- a/chromium/ipc/ipc_platform_file.cc
+++ b/chromium/ipc/ipc_platform_file.cc
@@ -45,4 +45,9 @@ PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile handle,
return out_handle;
}
+PlatformFileForTransit TakeFileHandleForProcess(base::File file,
+ base::ProcessHandle process) {
+ return GetFileHandleForProcess(file.TakePlatformFile(), process, true);
+}
+
} // namespace IPC
diff --git a/chromium/ipc/ipc_platform_file.h b/chromium/ipc/ipc_platform_file.h
index 553c78c522f..40bfa0da189 100644
--- a/chromium/ipc/ipc_platform_file.h
+++ b/chromium/ipc/ipc_platform_file.h
@@ -6,7 +6,7 @@
#define IPC_IPC_PLATFORM_FILE_H_
#include "base/basictypes.h"
-#include "base/platform_file.h"
+#include "base/files/file.h"
#include "base/process/process.h"
#include "ipc/ipc_export.h"
@@ -24,7 +24,7 @@ typedef base::FileDescriptor PlatformFileForTransit;
inline PlatformFileForTransit InvalidPlatformFileForTransit() {
#if defined(OS_WIN)
- return base::kInvalidPlatformFileValue;
+ return INVALID_HANDLE_VALUE;
#elif defined(OS_POSIX)
return base::FileDescriptor();
#endif
@@ -39,12 +39,27 @@ inline base::PlatformFile PlatformFileForTransitToPlatformFile(
#endif
}
+inline base::File PlatformFileForTransitToFile(
+ const PlatformFileForTransit& transit) {
+#if defined(OS_WIN)
+ return base::File(transit);
+#elif defined(OS_POSIX)
+ return base::File(transit.fd);
+#endif
+}
+
// Returns a file handle equivalent to |file| that can be used in |process|.
IPC_EXPORT PlatformFileForTransit GetFileHandleForProcess(
base::PlatformFile file,
base::ProcessHandle process,
bool close_source_handle);
+// Returns a file handle equivalent to |file| that can be used in |process|.
+// Note that this function takes ownership of |file|.
+IPC_EXPORT PlatformFileForTransit TakeFileHandleForProcess(
+ base::File file,
+ base::ProcessHandle process);
+
} // namespace IPC
#endif // IPC_IPC_PLATFORM_FILE_H_
diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc
index aeec8907a4f..1df6be98643 100644
--- a/chromium/ipc/ipc_send_fds_test.cc
+++ b/chromium/ipc/ipc_send_fds_test.cc
@@ -134,10 +134,10 @@ int SendFdsClientCommon(const std::string& test_client_name,
MyChannelDescriptorListener listener(expected_inode_num);
// Set up IPC channel.
- IPC::Channel channel(IPCTestBase::GetChannelName(test_client_name),
- IPC::Channel::MODE_CLIENT,
- &listener);
- CHECK(channel.Connect());
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName(test_client_name),
+ &listener));
+ CHECK(channel->Connect());
// Run message loop.
base::MessageLoop::current()->Run();
@@ -233,14 +233,11 @@ class PipeChannelHelper {
void Init() {
IPC::ChannelHandle in_handle("IN");
- in.reset(new IPC::Channel(in_handle,
- IPC::Channel::MODE_SERVER,
- &null_listener_));
- base::FileDescriptor out_fd(in->TakeClientFileDescriptor(), false);
+ in = IPC::Channel::CreateServer(in_handle, &null_listener_);
+ base::FileDescriptor out_fd(
+ in->TakeClientFileDescriptor(), false);
IPC::ChannelHandle out_handle("OUT", out_fd);
- out.reset(new IPC::Channel(out_handle,
- IPC::Channel::MODE_CLIENT,
- &cb_listener_));
+ out = IPC::Channel::CreateClient(out_handle, &cb_listener_);
// PostTask the connect calls to make sure the callbacks happens
// on the right threads.
in_thread_->message_loop()->PostTask(
diff --git a/chromium/ipc/ipc_switches.cc b/chromium/ipc/ipc_switches.cc
index bcb12256e54..df245f55f26 100644
--- a/chromium/ipc/ipc_switches.cc
+++ b/chromium/ipc/ipc_switches.cc
@@ -15,10 +15,5 @@ namespace switches {
// IPC channel the browser expects to use to communicate with it.
const char kProcessChannelID[] = "channel";
-// Will add kDebugOnStart to every child processes. If a value is passed, it
-// will be used as a filter to determine if the child process should have the
-// kDebugOnStart flag passed on or not.
-const char kDebugChildren[] = "debug-children";
-
} // namespace switches
diff --git a/chromium/ipc/ipc_switches.h b/chromium/ipc/ipc_switches.h
index d88afb5ba9f..c63c2024270 100644
--- a/chromium/ipc/ipc_switches.h
+++ b/chromium/ipc/ipc_switches.h
@@ -12,7 +12,6 @@
namespace switches {
IPC_EXPORT extern const char kProcessChannelID[];
-IPC_EXPORT extern const char kDebugChildren[];
} // namespace switches
diff --git a/chromium/ipc/ipc_sync_channel.cc b/chromium/ipc/ipc_sync_channel.cc
index 491b72db8a6..a7ed230e53c 100644
--- a/chromium/ipc/ipc_sync_channel.cc
+++ b/chromium/ipc/ipc_sync_channel.cc
@@ -404,25 +404,37 @@ base::WaitableEventWatcher::EventCallback
return base::Bind(&SyncChannel::SyncContext::OnWaitableEventSignaled, this);
}
-SyncChannel::SyncChannel(
+// static
+scoped_ptr<SyncChannel> SyncChannel::Create(
const IPC::ChannelHandle& channel_handle,
Channel::Mode mode,
Listener* listener,
base::SingleThreadTaskRunner* ipc_task_runner,
bool create_pipe_now,
- WaitableEvent* shutdown_event)
- : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)),
- sync_messages_with_no_timeout_allowed_(true) {
- ChannelProxy::Init(channel_handle, mode, create_pipe_now);
- StartWatching();
+ base::WaitableEvent* shutdown_event) {
+ scoped_ptr<SyncChannel> channel =
+ Create(listener, ipc_task_runner, shutdown_event);
+ channel->Init(channel_handle, mode, create_pipe_now);
+ return channel.Pass();
+}
+
+// static
+scoped_ptr<SyncChannel> SyncChannel::Create(
+ Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner,
+ WaitableEvent* shutdown_event) {
+ return make_scoped_ptr(
+ new SyncChannel(listener, ipc_task_runner, shutdown_event));
}
SyncChannel::SyncChannel(
Listener* listener,
base::SingleThreadTaskRunner* ipc_task_runner,
WaitableEvent* shutdown_event)
- : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)),
- sync_messages_with_no_timeout_allowed_(true) {
+ : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)) {
+ // The current (listener) thread must be distinct from the IPC thread, or else
+ // sending synchronous messages will deadlock.
+ DCHECK_NE(ipc_task_runner, base::ThreadTaskRunnerHandle::Get());
StartWatching();
}
@@ -434,18 +446,13 @@ void SyncChannel::SetRestrictDispatchChannelGroup(int group) {
}
bool SyncChannel::Send(Message* message) {
- return SendWithTimeout(message, base::kNoTimeout);
-}
-
-bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
#ifdef IPC_MESSAGE_LOG_ENABLED
Logging* logger = Logging::GetInstance();
std::string name;
logger->GetMessageText(message->type(), &name, message, NULL);
- TRACE_EVENT1("task", "SyncChannel::SendWithTimeout",
- "name", name);
+ TRACE_EVENT1("ipc", "SyncChannel::Send", "name", name);
#else
- TRACE_EVENT2("task", "SyncChannel::SendWithTimeout",
+ TRACE_EVENT2("ipc", "SyncChannel::Send",
"class", IPC_MESSAGE_ID_CLASS(message->type()),
"line", IPC_MESSAGE_ID_LINE(message->type()));
#endif
@@ -462,25 +469,12 @@ bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
return false;
}
- DCHECK(sync_messages_with_no_timeout_allowed_ ||
- timeout_ms != base::kNoTimeout);
SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
context->Push(sync_msg);
- int message_id = SyncMessage::GetMessageId(*sync_msg);
WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
ChannelProxy::Send(message);
- if (timeout_ms != base::kNoTimeout) {
- // We use the sync message id so that when a message times out, we don't
- // confuse it with another send that is either above/below this Send in
- // the call stack.
- context->ipc_task_runner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&SyncContext::OnSendTimeout, context.get(), message_id),
- base::TimeDelta::FromMilliseconds(timeout_ms));
- }
-
// Wait for reply, or for any other incoming synchronous messages.
// *this* might get deleted, so only call static functions at this point.
WaitForReply(context.get(), pump_messages_event);
diff --git a/chromium/ipc/ipc_sync_channel.h b/chromium/ipc/ipc_sync_channel.h
index 46ac910efdc..8984184da29 100644
--- a/chromium/ipc/ipc_sync_channel.h
+++ b/chromium/ipc/ipc_sync_channel.h
@@ -30,7 +30,7 @@ class SyncMessage;
// Overview of how the sync channel works
// --------------------------------------
// When the sending thread sends a synchronous message, we create a bunch
-// of tracking info (created in SendWithTimeout, stored in the PendingSyncMsg
+// of tracking info (created in Send, stored in the PendingSyncMsg
// structure) associated with the message that we identify by the unique
// "MessageId" on the SyncMessage. Among the things we save is the
// "Deserializer" which is provided by the sync message. This object is in
@@ -66,29 +66,26 @@ class IPC_EXPORT SyncChannel : public ChannelProxy {
// Creates and initializes a sync channel. If create_pipe_now is specified,
// the channel will be initialized synchronously.
- SyncChannel(const IPC::ChannelHandle& channel_handle,
- Channel::Mode mode,
- Listener* listener,
- base::SingleThreadTaskRunner* ipc_task_runner,
- bool create_pipe_now,
- base::WaitableEvent* shutdown_event);
+ // The naming pattern follows IPC::Channel.
+ static scoped_ptr<SyncChannel> Create(
+ const IPC::ChannelHandle& channel_handle,
+ IPC::Channel::Mode mode,
+ Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner,
+ bool create_pipe_now,
+ base::WaitableEvent* shutdown_event);
// Creates an uninitialized sync channel. Call ChannelProxy::Init to
// initialize the channel. This two-step setup allows message filters to be
// added before any messages are sent or received.
- SyncChannel(Listener* listener,
- base::SingleThreadTaskRunner* ipc_task_runner,
- base::WaitableEvent* shutdown_event);
+ static scoped_ptr<SyncChannel> Create(
+ Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner,
+ base::WaitableEvent* shutdown_event);
virtual ~SyncChannel();
virtual bool Send(Message* message) OVERRIDE;
- virtual bool SendWithTimeout(Message* message, int timeout_ms);
-
- // Whether we allow sending messages with no time-out.
- void set_sync_messages_with_no_timeout_allowed(bool value) {
- sync_messages_with_no_timeout_allowed_ = value;
- }
// Sets the dispatch group for this channel, to only allow re-entrant dispatch
// of messages to other channels in the same group.
@@ -194,6 +191,10 @@ class IPC_EXPORT SyncChannel : public ChannelProxy {
};
private:
+ SyncChannel(Listener* listener,
+ base::SingleThreadTaskRunner* ipc_task_runner,
+ base::WaitableEvent* shutdown_event);
+
void OnWaitableEventSignaled(base::WaitableEvent* arg);
SyncContext* sync_context() {
@@ -212,8 +213,6 @@ class IPC_EXPORT SyncChannel : public ChannelProxy {
// Starts the dispatch watcher.
void StartWatching();
- bool sync_messages_with_no_timeout_allowed_;
-
// Used to signal events between the IPC and listener threads.
base::WaitableEventWatcher dispatch_watcher_;
base::WaitableEventWatcher::EventCallback dispatch_watcher_callback_;
diff --git a/chromium/ipc/ipc_sync_channel_unittest.cc b/chromium/ipc/ipc_sync_channel_unittest.cc
index 30f02f7c4c7..05126b975f1 100644
--- a/chromium/ipc/ipc_sync_channel_unittest.cc
+++ b/chromium/ipc/ipc_sync_channel_unittest.cc
@@ -65,9 +65,6 @@ class Worker : public Listener, public Sender {
void AddRef() { }
void Release() { }
virtual bool Send(Message* msg) OVERRIDE { return channel_->Send(msg); }
- bool SendWithTimeout(Message* msg, int timeout_ms) {
- return channel_->SendWithTimeout(msg, timeout_ms);
- }
void WaitForChannelCreation() { channel_created_->Wait(); }
void CloseChannel() {
DCHECK(base::MessageLoop::current() == ListenerThread()->message_loop());
@@ -96,12 +93,12 @@ class Worker : public Listener, public Sender {
DCHECK(overrided_thread_ == NULL);
overrided_thread_ = overrided_thread;
}
- bool SendAnswerToLife(bool pump, int timeout, bool succeed) {
+ bool SendAnswerToLife(bool pump, bool succeed) {
int answer = 0;
SyncMessage* msg = new SyncChannelTestMsg_AnswerToLife(&answer);
if (pump)
msg->EnableMessagePumping();
- bool result = SendWithTimeout(msg, timeout);
+ bool result = Send(msg);
DCHECK_EQ(result, succeed);
DCHECK_EQ(answer, (succeed ? 42 : 0));
return result;
@@ -154,12 +151,10 @@ class Worker : public Listener, public Sender {
}
virtual SyncChannel* CreateChannel() {
- return new SyncChannel(channel_name_,
- mode_,
- this,
- ipc_thread_.message_loop_proxy().get(),
- true,
- &shutdown_event_);
+ scoped_ptr<SyncChannel> channel = SyncChannel::Create(
+ channel_name_, mode_, this, ipc_thread_.message_loop_proxy().get(),
+ true, &shutdown_event_);
+ return channel.release();
}
base::Thread* ListenerThread() {
@@ -280,7 +275,7 @@ class SimpleServer : public Worker {
: Worker(Channel::MODE_SERVER, "simpler_server"),
pump_during_send_(pump_during_send) { }
virtual void Run() OVERRIDE {
- SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
+ SendAnswerToLife(pump_during_send_, true);
Done();
}
@@ -322,14 +317,16 @@ class TwoStepServer : public Worker {
create_pipe_now_(create_pipe_now) { }
virtual void Run() OVERRIDE {
- SendAnswerToLife(false, base::kNoTimeout, true);
+ SendAnswerToLife(false, true);
Done();
}
virtual SyncChannel* CreateChannel() OVERRIDE {
- SyncChannel* channel = new SyncChannel(
- this, ipc_thread().message_loop_proxy().get(), shutdown_event());
- channel->Init(channel_name(), mode(), create_pipe_now_);
+ SyncChannel* channel =
+ SyncChannel::Create(channel_name(), mode(), this,
+ ipc_thread().message_loop_proxy().get(),
+ create_pipe_now_,
+ shutdown_event()).release();
return channel;
}
@@ -348,9 +345,11 @@ class TwoStepClient : public Worker {
}
virtual SyncChannel* CreateChannel() OVERRIDE {
- SyncChannel* channel = new SyncChannel(
- this, ipc_thread().message_loop_proxy().get(), shutdown_event());
- channel->Init(channel_name(), mode(), create_pipe_now_);
+ SyncChannel* channel =
+ SyncChannel::Create(channel_name(), mode(), this,
+ ipc_thread().message_loop_proxy().get(),
+ create_pipe_now_,
+ shutdown_event()).release();
return channel;
}
@@ -408,10 +407,10 @@ class NoHangServer : public Worker {
got_first_reply_(got_first_reply),
pump_during_send_(pump_during_send) { }
virtual void Run() OVERRIDE {
- SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
+ SendAnswerToLife(pump_during_send_, true);
got_first_reply_->Signal();
- SendAnswerToLife(pump_during_send_, base::kNoTimeout, false);
+ SendAnswerToLife(pump_during_send_, false);
Done();
}
@@ -470,7 +469,7 @@ class UnblockServer : public Worker {
msg->EnableMessagePumping();
Send(msg);
} else {
- SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
+ SendAnswerToLife(pump_during_send_, true);
}
Done();
}
@@ -541,7 +540,7 @@ class RecursiveServer : public Worker {
virtual void OnDouble(int in, int* out) OVERRIDE {
*out = in * 2;
- SendAnswerToLife(pump_second_, base::kNoTimeout, expected_send_result_);
+ SendAnswerToLife(pump_second_, expected_send_result_);
}
bool expected_send_result_, pump_first_, pump_second_;
@@ -679,7 +678,7 @@ class MultipleClient2 : public Worker {
virtual void Run() OVERRIDE {
client1_msg_received_->Wait();
- SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
+ SendAnswerToLife(pump_during_send_, true);
client1_can_reply_->Signal();
Done();
}
@@ -879,117 +878,10 @@ TEST_F(IPCSyncChannelTest, ChattyServer) {
//------------------------------------------------------------------------------
-class TimeoutServer : public Worker {
- public:
- TimeoutServer(int timeout_ms,
- std::vector<bool> timeout_seq,
- bool pump_during_send)
- : Worker(Channel::MODE_SERVER, "timeout_server"),
- timeout_ms_(timeout_ms),
- timeout_seq_(timeout_seq),
- pump_during_send_(pump_during_send) {
- }
-
- virtual void Run() OVERRIDE {
- for (std::vector<bool>::const_iterator iter = timeout_seq_.begin();
- iter != timeout_seq_.end(); ++iter) {
- SendAnswerToLife(pump_during_send_, timeout_ms_, !*iter);
- }
- Done();
- }
-
- private:
- int timeout_ms_;
- std::vector<bool> timeout_seq_;
- bool pump_during_send_;
-};
-
-class UnresponsiveClient : public Worker {
- public:
- explicit UnresponsiveClient(std::vector<bool> timeout_seq)
- : Worker(Channel::MODE_CLIENT, "unresponsive_client"),
- timeout_seq_(timeout_seq) {
- }
-
- virtual void OnAnswerDelay(Message* reply_msg) OVERRIDE {
- DCHECK(!timeout_seq_.empty());
- if (!timeout_seq_[0]) {
- SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
- Send(reply_msg);
- } else {
- // Don't reply.
- delete reply_msg;
- }
- timeout_seq_.erase(timeout_seq_.begin());
- if (timeout_seq_.empty())
- Done();
- }
-
- private:
- // Whether we should time-out or respond to the various messages we receive.
- std::vector<bool> timeout_seq_;
-};
-
-void SendWithTimeoutOK(bool pump_during_send) {
- std::vector<Worker*> workers;
- std::vector<bool> timeout_seq;
- timeout_seq.push_back(false);
- timeout_seq.push_back(false);
- timeout_seq.push_back(false);
- workers.push_back(new TimeoutServer(5000, timeout_seq, pump_during_send));
- workers.push_back(new SimpleClient());
- RunTest(workers);
-}
-
-void SendWithTimeoutTimeout(bool pump_during_send) {
- std::vector<Worker*> workers;
- std::vector<bool> timeout_seq;
- timeout_seq.push_back(true);
- timeout_seq.push_back(false);
- timeout_seq.push_back(false);
- workers.push_back(new TimeoutServer(100, timeout_seq, pump_during_send));
- workers.push_back(new UnresponsiveClient(timeout_seq));
- RunTest(workers);
-}
-
-void SendWithTimeoutMixedOKAndTimeout(bool pump_during_send) {
- std::vector<Worker*> workers;
- std::vector<bool> timeout_seq;
- timeout_seq.push_back(true);
- timeout_seq.push_back(false);
- timeout_seq.push_back(false);
- timeout_seq.push_back(true);
- timeout_seq.push_back(false);
- workers.push_back(new TimeoutServer(100, timeout_seq, pump_during_send));
- workers.push_back(new UnresponsiveClient(timeout_seq));
- RunTest(workers);
-}
-
-// Tests that SendWithTimeout does not time-out if the response comes back fast
-// enough.
-TEST_F(IPCSyncChannelTest, SendWithTimeoutOK) {
- SendWithTimeoutOK(false);
- SendWithTimeoutOK(true);
-}
-
-// Tests that SendWithTimeout does time-out.
-TEST_F(IPCSyncChannelTest, SendWithTimeoutTimeout) {
- SendWithTimeoutTimeout(false);
- SendWithTimeoutTimeout(true);
-}
-
-// Sends some message that time-out and some that succeed.
-TEST_F(IPCSyncChannelTest, SendWithTimeoutMixedOKAndTimeout) {
- SendWithTimeoutMixedOKAndTimeout(false);
- SendWithTimeoutMixedOKAndTimeout(true);
-}
-
-//------------------------------------------------------------------------------
-
void NestedCallback(Worker* server) {
// Sleep a bit so that we wake up after the reply has been received.
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(250));
- server->SendAnswerToLife(true, base::kNoTimeout, true);
+ server->SendAnswerToLife(true, true);
}
bool timeout_occurred = false;
@@ -1014,7 +906,7 @@ class DoneEventRaceServer : public Worker {
// bug, the reply message comes back and is deserialized, however the done
// event wasn't set. So we indirectly use the timeout task to notice if a
// timeout occurred.
- SendAnswerToLife(true, 10000, true);
+ SendAnswerToLife(true, true);
DCHECK(!timeout_occurred);
Done();
}
@@ -1042,8 +934,8 @@ class TestSyncMessageFilter : public SyncMessageFilter {
message_loop_(message_loop) {
}
- virtual void OnFilterAdded(Channel* channel) OVERRIDE {
- SyncMessageFilter::OnFilterAdded(channel);
+ virtual void OnFilterAdded(Sender* sender) OVERRIDE {
+ SyncMessageFilter::OnFilterAdded(sender);
message_loop_->PostTask(
FROM_HERE,
base::Bind(&TestSyncMessageFilter::SendMessageOnHelperThread, this));
@@ -1245,13 +1137,13 @@ class RestrictedDispatchClient : public Worker {
else
LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
- non_restricted_channel_.reset(
- new SyncChannel("non_restricted_channel",
- Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event()));
+ non_restricted_channel_ =
+ SyncChannel::Create("non_restricted_channel",
+ IPC::Channel::MODE_CLIENT,
+ this,
+ ipc_thread().message_loop_proxy().get(),
+ true,
+ shutdown_event());
server_->ListenerThread()->message_loop()->PostTask(
FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 2));
@@ -1517,7 +1409,6 @@ class RestrictedDispatchDeadlockClient1 : public Worker {
PossiblyDone();
}
- base::Thread* ListenerThread() { return Worker::ListenerThread(); }
private:
virtual bool OnMessageReceived(const Message& message) OVERRIDE {
IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockClient1, message)
@@ -1637,13 +1528,13 @@ class RestrictedDispatchPipeWorker : public Worker {
if (is_first())
event1_->Signal();
event2_->Wait();
- other_channel_.reset(
- new SyncChannel(other_channel_name_,
- Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event()));
+ other_channel_ =
+ SyncChannel::Create(other_channel_name_,
+ IPC::Channel::MODE_CLIENT,
+ this,
+ ipc_thread().message_loop_proxy().get(),
+ true,
+ shutdown_event());
other_channel_->SetRestrictDispatchChannelGroup(group_);
if (!is_first()) {
event1_->Signal();
@@ -1717,13 +1608,13 @@ class ReentrantReplyServer1 : public Worker {
server_ready_(server_ready) { }
virtual void Run() OVERRIDE {
- server2_channel_.reset(
- new SyncChannel("reentrant_reply2",
- Channel::MODE_CLIENT,
- this,
- ipc_thread().message_loop_proxy().get(),
- true,
- shutdown_event()));
+ server2_channel_ =
+ SyncChannel::Create("reentrant_reply2",
+ IPC::Channel::MODE_CLIENT,
+ this,
+ ipc_thread().message_loop_proxy().get(),
+ true,
+ shutdown_event());
server_ready_->Signal();
Message* msg = new SyncChannelTestMsg_Reentrant1();
server2_channel_->Send(msg);
@@ -1831,7 +1722,7 @@ class VerifiedServer : public Worker {
VLOG(1) << __FUNCTION__ << " Sending reply: " << reply_text_;
SyncChannelNestedTestMsg_String::WriteReplyParams(reply_msg, reply_text_);
Send(reply_msg);
- ASSERT_EQ(channel()->peer_pid(), base::GetCurrentProcId());
+ ASSERT_EQ(channel()->GetPeerPID(), base::GetCurrentProcId());
Done();
}
@@ -1860,7 +1751,7 @@ class VerifiedClient : public Worker {
(void)expected_text_;
VLOG(1) << __FUNCTION__ << " Received reply: " << response;
- ASSERT_EQ(channel()->peer_pid(), base::GetCurrentProcId());
+ ASSERT_EQ(channel()->GetPeerPID(), base::GetCurrentProcId());
Done();
}
diff --git a/chromium/ipc/ipc_sync_message_filter.cc b/chromium/ipc/ipc_sync_message_filter.cc
index a534c445916..e2ea1bfb1ee 100644
--- a/chromium/ipc/ipc_sync_message_filter.cc
+++ b/chromium/ipc/ipc_sync_message_filter.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/synchronization/waitable_event.h"
+#include "ipc/ipc_channel.h"
#include "ipc/ipc_sync_message.h"
using base::MessageLoopProxy;
@@ -16,7 +17,7 @@ using base::MessageLoopProxy;
namespace IPC {
SyncMessageFilter::SyncMessageFilter(base::WaitableEvent* shutdown_event)
- : channel_(NULL),
+ : sender_(NULL),
listener_loop_(MessageLoopProxy::current()),
shutdown_event_(shutdown_event) {
}
@@ -66,19 +67,19 @@ bool SyncMessageFilter::Send(Message* message) {
return pending_message.send_result;
}
-void SyncMessageFilter::OnFilterAdded(Channel* channel) {
- channel_ = channel;
+void SyncMessageFilter::OnFilterAdded(Sender* sender) {
+ sender_ = sender;
base::AutoLock auto_lock(lock_);
io_loop_ = MessageLoopProxy::current();
}
void SyncMessageFilter::OnChannelError() {
- channel_ = NULL;
+ sender_ = NULL;
SignalAllEvents();
}
void SyncMessageFilter::OnChannelClosing() {
- channel_ = NULL;
+ sender_ = NULL;
SignalAllEvents();
}
@@ -103,8 +104,8 @@ SyncMessageFilter::~SyncMessageFilter() {
}
void SyncMessageFilter::SendOnIOThread(Message* message) {
- if (channel_) {
- channel_->Send(message);
+ if (sender_) {
+ sender_->Send(message);
return;
}
diff --git a/chromium/ipc/ipc_sync_message_filter.h b/chromium/ipc/ipc_sync_message_filter.h
index dbc28345ac6..933a95eea0e 100644
--- a/chromium/ipc/ipc_sync_message_filter.h
+++ b/chromium/ipc/ipc_sync_message_filter.h
@@ -10,8 +10,9 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
-#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_sender.h"
#include "ipc/ipc_sync_message.h"
+#include "ipc/message_filter.h"
namespace base {
class MessageLoopProxy;
@@ -25,16 +26,15 @@ namespace IPC {
// support fancy features that SyncChannel does, such as handling recursion or
// receiving messages while waiting for a response. Note that this object can
// be used to send simultaneous synchronous messages from different threads.
-class IPC_EXPORT SyncMessageFilter : public ChannelProxy::MessageFilter,
- public Sender {
+class IPC_EXPORT SyncMessageFilter : public MessageFilter, public Sender {
public:
explicit SyncMessageFilter(base::WaitableEvent* shutdown_event);
// MessageSender implementation.
virtual bool Send(Message* message) OVERRIDE;
- // ChannelProxy::MessageFilter implementation.
- virtual void OnFilterAdded(Channel* channel) OVERRIDE;
+ // MessageFilter implementation.
+ virtual void OnFilterAdded(Sender* sender) OVERRIDE;
virtual void OnChannelError() OVERRIDE;
virtual void OnChannelClosing() OVERRIDE;
virtual bool OnMessageReceived(const Message& message) OVERRIDE;
@@ -48,7 +48,7 @@ class IPC_EXPORT SyncMessageFilter : public ChannelProxy::MessageFilter,
void SignalAllEvents();
// The channel to which this filter was added.
- Channel* channel_;
+ Sender* sender_;
// The process's main thread.
scoped_refptr<base::MessageLoopProxy> listener_loop_;
diff --git a/chromium/ipc/ipc_test_base.cc b/chromium/ipc/ipc_test_base.cc
index ef050a7151f..589ee98ca09 100644
--- a/chromium/ipc/ipc_test_base.cc
+++ b/chromium/ipc/ipc_test_base.cc
@@ -7,12 +7,10 @@
#include "ipc/ipc_test_base.h"
#include "base/command_line.h"
-#include "base/debug/debug_on_start_win.h"
#include "base/process/kill.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "ipc/ipc_descriptors.h"
-#include "ipc/ipc_switches.h"
#if defined(OS_POSIX)
#include "base/posix/global_descriptors.h"
@@ -71,9 +69,7 @@ void IPCTestBase::CreateChannelFromChannelHandle(
IPC::Listener* listener) {
CHECK(!channel_.get());
CHECK(!channel_proxy_.get());
- channel_.reset(new IPC::Channel(channel_handle,
- IPC::Channel::MODE_SERVER,
- listener));
+ channel_ = IPC::Channel::CreateServer(channel_handle, listener);
}
void IPCTestBase::CreateChannelProxy(
@@ -81,10 +77,10 @@ void IPCTestBase::CreateChannelProxy(
base::SingleThreadTaskRunner* ipc_task_runner) {
CHECK(!channel_.get());
CHECK(!channel_proxy_.get());
- channel_proxy_.reset(new IPC::ChannelProxy(GetChannelName(test_client_name_),
+ channel_proxy_ = IPC::ChannelProxy::Create(GetChannelName(test_client_name_),
IPC::Channel::MODE_SERVER,
listener,
- ipc_task_runner));
+ ipc_task_runner);
}
void IPCTestBase::DestroyChannelProxy() {
@@ -96,22 +92,20 @@ bool IPCTestBase::StartClient() {
DCHECK(client_process_ == base::kNullProcessHandle);
std::string test_main = test_client_name_ + "TestClientMain";
- bool debug_on_start =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
#if defined(OS_WIN)
- client_process_ = MultiProcessTest::SpawnChild(test_main, debug_on_start);
+ client_process_ = SpawnChild(test_main);
#elif defined(OS_POSIX)
base::FileHandleMappingVector fds_to_map;
- const int ipcfd = channel_.get() ? channel_->GetClientFileDescriptor() :
- channel_proxy_->GetClientFileDescriptor();
+ const int ipcfd = channel_.get()
+ ? channel_->GetClientFileDescriptor()
+ : channel_proxy_->GetClientFileDescriptor();
if (ipcfd > -1)
fds_to_map.push_back(std::pair<int, int>(ipcfd,
kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
-
- client_process_ = MultiProcessTest::SpawnChild(test_main,
- fds_to_map,
- debug_on_start);
+ base::LaunchOptions options;
+ options.fds_to_remap = &fds_to_map;
+ client_process_ = SpawnChildWithOptions(test_main, options);
#endif
return client_process_ != base::kNullProcessHandle;
diff --git a/chromium/ipc/ipc_test_sink.cc b/chromium/ipc/ipc_test_sink.cc
index 070fe1235d1..9e9d1fd3c24 100644
--- a/chromium/ipc/ipc_test_sink.cc
+++ b/chromium/ipc/ipc_test_sink.cc
@@ -21,6 +21,21 @@ bool TestSink::Send(Message* message) {
return true;
}
+bool TestSink::Connect() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void TestSink::Close() {
+ NOTIMPLEMENTED();
+}
+
+base::ProcessId TestSink::GetPeerPID() const {
+ NOTIMPLEMENTED();
+ return base::ProcessId();
+}
+
+
bool TestSink::OnMessageReceived(const Message& msg) {
ObserverListBase<Listener>::Iterator it(filter_list_);
Listener* observer;
@@ -74,4 +89,18 @@ void TestSink::RemoveFilter(Listener* filter) {
filter_list_.RemoveObserver(filter);
}
+#if defined(OS_POSIX) && !defined(OS_NACL)
+
+int TestSink::GetClientFileDescriptor() const {
+ NOTREACHED();
+ return -1;
+}
+
+int TestSink::TakeClientFileDescriptor() {
+ NOTREACHED();
+ return -1;
+}
+
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
+
} // namespace IPC
diff --git a/chromium/ipc/ipc_test_sink.h b/chromium/ipc/ipc_test_sink.h
index 78be9e75269..1a213ee1245 100644
--- a/chromium/ipc/ipc_test_sink.h
+++ b/chromium/ipc/ipc_test_sink.h
@@ -78,6 +78,14 @@ class TestSink : public Channel {
// Interface in IPC::Channel. This copies the message to the sink and then
// deletes it.
virtual bool Send(IPC::Message* message) OVERRIDE;
+ virtual bool Connect() OVERRIDE WARN_UNUSED_RESULT;
+ virtual void Close() OVERRIDE;
+ virtual base::ProcessId GetPeerPID() const OVERRIDE;
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+ virtual int GetClientFileDescriptor() const OVERRIDE;
+ virtual int TakeClientFileDescriptor() OVERRIDE;
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
// Used by the source of the messages to send the message to the sink. This
// will make a copy of the message and store it in the list.
diff --git a/chromium/ipc/message_filter.cc b/chromium/ipc/message_filter.cc
new file mode 100644
index 00000000000..ffde0f0d0f3
--- /dev/null
+++ b/chromium/ipc/message_filter.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 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 "ipc/message_filter.h"
+
+#include "base/memory/ref_counted.h"
+#include "ipc/ipc_channel.h"
+
+namespace IPC {
+
+MessageFilter::MessageFilter() {}
+
+void MessageFilter::OnFilterAdded(Sender* sender) {}
+
+void MessageFilter::OnFilterRemoved() {}
+
+void MessageFilter::OnChannelConnected(int32 peer_pid) {}
+
+void MessageFilter::OnChannelError() {}
+
+void MessageFilter::OnChannelClosing() {}
+
+bool MessageFilter::OnMessageReceived(const Message& message) {
+ return false;
+}
+
+bool MessageFilter::GetSupportedMessageClasses(
+ std::vector<uint32>* /*supported_message_classes*/) const {
+ return false;
+}
+
+MessageFilter::~MessageFilter() {}
+
+} // namespace IPC
diff --git a/chromium/ipc/message_filter.h b/chromium/ipc/message_filter.h
new file mode 100644
index 00000000000..c9ba4e84ac2
--- /dev/null
+++ b/chromium/ipc/message_filter.h
@@ -0,0 +1,67 @@
+// Copyright 2014 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 IPC_MESSAGE_FILTER_H_
+#define IPC_MESSAGE_FILTER_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "ipc/ipc_export.h"
+
+namespace IPC {
+
+class Sender;
+class Message;
+
+// A class that receives messages on the thread where the IPC channel is
+// running. It can choose to prevent the default action for an IPC message.
+class IPC_EXPORT MessageFilter
+ : public base::RefCountedThreadSafe<MessageFilter> {
+ public:
+ MessageFilter();
+
+ // Called on the background thread to provide the filter with access to the
+ // channel. Called when the IPC channel is initialized or when AddFilter
+ // is called if the channel is already initialized.
+ virtual void OnFilterAdded(Sender* sender);
+
+ // Called on the background thread when the filter has been removed from
+ // the ChannelProxy and when the Channel is closing. After a filter is
+ // removed, it will not be called again.
+ virtual void OnFilterRemoved();
+
+ // Called to inform the filter that the IPC channel is connected and we
+ // have received the internal Hello message from the peer.
+ virtual void OnChannelConnected(int32 peer_pid);
+
+ // Called when there is an error on the channel, typically that the channel
+ // has been closed.
+ virtual void OnChannelError();
+
+ // Called to inform the filter that the IPC channel will be destroyed.
+ // OnFilterRemoved is called immediately after this.
+ virtual void OnChannelClosing();
+
+ // Return true to indicate that the message was handled, or false to let
+ // the message be handled in the default way.
+ virtual bool OnMessageReceived(const Message& message);
+
+ // Called to query the Message classes supported by the filter. Return
+ // false to indicate that all message types should reach the filter, or true
+ // if the resulting contents of |supported_message_classes| may be used to
+ // selectively offer messages of a particular class to the filter.
+ virtual bool GetSupportedMessageClasses(
+ std::vector<uint32>* supported_message_classes) const;
+
+ protected:
+ virtual ~MessageFilter();
+
+ private:
+ friend class base::RefCountedThreadSafe<MessageFilter>;
+};
+
+} // namespace IPC
+
+#endif // IPC_MESSAGE_FILTER_H_
diff --git a/chromium/ipc/message_filter_router.cc b/chromium/ipc/message_filter_router.cc
new file mode 100644
index 00000000000..81e40289147
--- /dev/null
+++ b/chromium/ipc/message_filter_router.cc
@@ -0,0 +1,92 @@
+// Copyright 2014 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 "ipc/message_filter_router.h"
+
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/message_filter.h"
+
+namespace IPC {
+
+namespace {
+
+bool TryFiltersImpl(MessageFilterRouter::MessageFilters& filters,
+ const IPC::Message& message) {
+ for (size_t i = 0; i < filters.size(); ++i) {
+ if (filters[i]->OnMessageReceived(message)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RemoveFilterImpl(MessageFilterRouter::MessageFilters& filters,
+ MessageFilter* filter) {
+ MessageFilterRouter::MessageFilters::iterator it =
+ std::remove(filters.begin(), filters.end(), filter);
+ if (it == filters.end())
+ return false;
+
+ filters.erase(it, filters.end());
+ return true;
+}
+
+bool ValidMessageClass(int message_class) {
+ return message_class >= 0 && message_class < LastIPCMsgStart;
+}
+
+} // namespace
+
+MessageFilterRouter::MessageFilterRouter() {}
+MessageFilterRouter::~MessageFilterRouter() {}
+
+void MessageFilterRouter::AddFilter(MessageFilter* filter) {
+ // Determine if the filter should be applied to all messages, or only
+ // messages of a certain class.
+ std::vector<uint32> supported_message_classes;
+ if (filter->GetSupportedMessageClasses(&supported_message_classes)) {
+ DCHECK(!supported_message_classes.empty());
+ for (size_t i = 0; i < supported_message_classes.size(); ++i) {
+ const int message_class = supported_message_classes[i];
+ DCHECK(ValidMessageClass(message_class));
+ // Safely ignore repeated subscriptions to a given message class for the
+ // current filter being added.
+ if (!message_class_filters_[message_class].empty() &&
+ message_class_filters_[message_class].back() == filter) {
+ continue;
+ }
+ message_class_filters_[message_class].push_back(filter);
+ }
+ } else {
+ global_filters_.push_back(filter);
+ }
+}
+
+void MessageFilterRouter::RemoveFilter(MessageFilter* filter) {
+ if (RemoveFilterImpl(global_filters_, filter))
+ return;
+
+ for (size_t i = 0; i < arraysize(message_class_filters_); ++i)
+ RemoveFilterImpl(message_class_filters_[i], filter);
+}
+
+bool MessageFilterRouter::TryFilters(const Message& message) {
+ if (TryFiltersImpl(global_filters_, message))
+ return true;
+
+ const int message_class = IPC_MESSAGE_CLASS(message);
+ if (!ValidMessageClass(message_class))
+ return false;
+
+ return TryFiltersImpl(message_class_filters_[message_class], message);
+}
+
+void MessageFilterRouter::Clear() {
+ global_filters_.clear();
+ for (size_t i = 0; i < arraysize(message_class_filters_); ++i)
+ message_class_filters_[i].clear();
+}
+
+} // namespace IPC
diff --git a/chromium/ipc/message_filter_router.h b/chromium/ipc/message_filter_router.h
new file mode 100644
index 00000000000..183b8ebc8a9
--- /dev/null
+++ b/chromium/ipc/message_filter_router.h
@@ -0,0 +1,42 @@
+// Copyright 2014 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 IPC_MESSAGE_FILTER_ROUTER_H_
+#define IPC_MESSAGE_FILTER_ROUTER_H_
+
+#include <vector>
+
+#include "ipc/ipc_message_start.h"
+
+namespace IPC {
+
+class Message;
+class MessageFilter;
+
+class MessageFilterRouter {
+ public:
+ typedef std::vector<MessageFilter*> MessageFilters;
+
+ MessageFilterRouter();
+ ~MessageFilterRouter();
+
+ void AddFilter(MessageFilter* filter);
+ void RemoveFilter(MessageFilter* filter);
+ bool TryFilters(const Message& message);
+ void Clear();
+
+ private:
+ // List of global and selective filters; a given filter will exist in either
+ // |message_global_filters_| OR |message_class_filters_|, but not both.
+ // Note that |message_global_filters_| will be given first offering of any
+ // given message. It's the filter implementer and installer's
+ // responsibility to ensure that a filter is either global or selective to
+ // ensure proper message filtering order.
+ MessageFilters global_filters_;
+ MessageFilters message_class_filters_[LastIPCMsgStart];
+};
+
+} // namespace IPC
+
+#endif // IPC_MESSAGE_FILTER_ROUTER_H_
diff --git a/chromium/ipc/sync_socket_unittest.cc b/chromium/ipc/sync_socket_unittest.cc
index 288860713ad..5527abc4b53 100644
--- a/chromium/ipc/sync_socket_unittest.cc
+++ b/chromium/ipc/sync_socket_unittest.cc
@@ -108,11 +108,11 @@ class SyncSocketServerListener : public IPC::Listener {
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient) {
base::MessageLoopForIO main_message_loop;
SyncSocketServerListener listener;
- IPC::Channel channel(IPCTestBase::GetChannelName("SyncSocketServerClient"),
- IPC::Channel::MODE_CLIENT,
- &listener);
- EXPECT_TRUE(channel.Connect());
- listener.Init(&channel);
+ scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
+ IPCTestBase::GetChannelName("SyncSocketServerClient"),
+ &listener));
+ EXPECT_TRUE(channel->Connect());
+ listener.Init(channel.get());
base::MessageLoop::current()->Run();
return 0;
}
diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc
index 10df9b21441..c29ce929f92 100644
--- a/chromium/ipc/unix_domain_socket_util.cc
+++ b/chromium/ipc/unix_domain_socket_util.cc
@@ -13,6 +13,7 @@
#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
@@ -45,15 +46,14 @@ int MakeUnixAddrForPath(const std::string& socket_name,
}
// Create socket.
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
+ base::ScopedFD fd(socket(AF_UNIX, SOCK_STREAM, 0));
+ if (!fd.is_valid()) {
PLOG(ERROR) << "socket";
return -1;
}
- file_util::ScopedFD scoped_fd(&fd);
// Make socket non-blocking
- if (HANDLE_EINTR(fcntl(fd, F_SETFL, O_NONBLOCK)) < 0) {
+ if (HANDLE_EINTR(fcntl(fd.get(), F_SETFL, O_NONBLOCK)) < 0) {
PLOG(ERROR) << "fcntl(O_NONBLOCK)";
return -1;
}
@@ -64,7 +64,7 @@ int MakeUnixAddrForPath(const std::string& socket_name,
strncpy(unix_addr->sun_path, socket_name.c_str(), kMaxSocketNameLength);
*unix_addr_len =
offsetof(struct sockaddr_un, sun_path) + socket_name.length();
- return *scoped_fd.release();
+ return fd.release();
}
} // namespace
@@ -78,10 +78,10 @@ bool CreateServerUnixDomainSocket(const base::FilePath& socket_path,
struct sockaddr_un unix_addr;
size_t unix_addr_len;
- int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len);
- if (fd < 0)
+ base::ScopedFD fd(
+ MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len));
+ if (!fd.is_valid())
return false;
- file_util::ScopedFD scoped_fd(&fd);
// Make sure the path we need exists.
if (!base::CreateDirectory(socket_dir)) {
@@ -96,20 +96,20 @@ bool CreateServerUnixDomainSocket(const base::FilePath& socket_path,
}
// Bind the socket.
- if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
+ if (bind(fd.get(), reinterpret_cast<const sockaddr*>(&unix_addr),
unix_addr_len) < 0) {
PLOG(ERROR) << "bind " << socket_path.value();
return false;
}
// Start listening on the socket.
- if (listen(fd, SOMAXCONN) < 0) {
+ if (listen(fd.get(), SOMAXCONN) < 0) {
PLOG(ERROR) << "listen " << socket_path.value();
unlink(socket_name.c_str());
return false;
}
- *server_listen_fd = *scoped_fd.release();
+ *server_listen_fd = fd.release();
return true;
}
@@ -122,18 +122,18 @@ bool CreateClientUnixDomainSocket(const base::FilePath& socket_path,
struct sockaddr_un unix_addr;
size_t unix_addr_len;
- int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len);
- if (fd < 0)
+ base::ScopedFD fd(
+ MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len));
+ if (!fd.is_valid())
return false;
- file_util::ScopedFD scoped_fd(&fd);
- if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&unix_addr),
+ if (HANDLE_EINTR(connect(fd.get(), reinterpret_cast<sockaddr*>(&unix_addr),
unix_addr_len)) < 0) {
PLOG(ERROR) << "connect " << socket_path.value();
return false;
}
- *client_socket = *scoped_fd.release();
+ *client_socket = fd.release();
return true;
}
@@ -184,18 +184,17 @@ bool ServerAcceptConnection(int server_listen_fd, int* server_socket) {
DCHECK(server_socket);
*server_socket = -1;
- int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
- if (accept_fd < 0)
+ base::ScopedFD accept_fd(HANDLE_EINTR(accept(server_listen_fd, NULL, 0)));
+ if (!accept_fd.is_valid())
return IsRecoverableError(errno);
- file_util::ScopedFD scoped_fd(&accept_fd);
- if (HANDLE_EINTR(fcntl(accept_fd, F_SETFL, O_NONBLOCK)) < 0) {
- PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd;
+ if (HANDLE_EINTR(fcntl(accept_fd.get(), F_SETFL, O_NONBLOCK)) < 0) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd.get();
// It's safe to keep listening on |server_listen_fd| even if the attempt to
// set O_NONBLOCK failed on the client fd.
return true;
}
- *server_socket = *scoped_fd.release();
+ *server_socket = accept_fd.release();
return true;
}