summaryrefslogtreecommitdiff
path: root/chromium/ipc
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2014-03-18 13:16:26 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-03-20 15:55:39 +0100
commit3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch)
tree92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/ipc
parente90d7c4b152c56919d963987e2503f9909a666d2 (diff)
downloadqtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies needed on Windows. Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42 Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu> Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/ipc')
-rw-r--r--chromium/ipc/OWNERS2
-rw-r--r--chromium/ipc/file_descriptor_set_posix.cc14
-rw-r--r--chromium/ipc/file_descriptor_set_posix.h3
-rw-r--r--chromium/ipc/file_descriptor_set_posix_unittest.cc4
-rw-r--r--chromium/ipc/ipc.gyp2
-rw-r--r--chromium/ipc/ipc_channel.h23
-rw-r--r--chromium/ipc/ipc_channel_factory.cc2
-rw-r--r--chromium/ipc/ipc_channel_nacl.cc2
-rw-r--r--chromium/ipc/ipc_channel_nacl.h2
-rw-r--r--chromium/ipc/ipc_channel_posix.cc154
-rw-r--r--chromium/ipc/ipc_channel_posix.h12
-rw-r--r--chromium/ipc/ipc_channel_posix_unittest.cc4
-rw-r--r--chromium/ipc/ipc_channel_proxy.cc8
-rw-r--r--chromium/ipc/ipc_channel_proxy.h37
-rw-r--r--chromium/ipc/ipc_channel_reader.cc12
-rw-r--r--chromium/ipc/ipc_channel_reader.h12
-rw-r--r--chromium/ipc/ipc_channel_win.cc3
-rw-r--r--chromium/ipc/ipc_channel_win.h2
-rw-r--r--chromium/ipc/ipc_descriptors.h4
-rw-r--r--chromium/ipc/ipc_message_macros.h11
-rw-r--r--chromium/ipc/ipc_message_start.h2
-rw-r--r--chromium/ipc/ipc_message_utils.cc27
-rw-r--r--chromium/ipc/ipc_message_utils.h12
-rw-r--r--chromium/ipc/ipc_send_fds_test.cc259
-rw-r--r--chromium/ipc/run_all_unittests.cc40
-rw-r--r--chromium/ipc/unix_domain_socket_util.cc2
26 files changed, 487 insertions, 168 deletions
diff --git a/chromium/ipc/OWNERS b/chromium/ipc/OWNERS
index eaf88320e66..37a61fa0463 100644
--- a/chromium/ipc/OWNERS
+++ b/chromium/ipc/OWNERS
@@ -13,8 +13,10 @@ dmichael@chromium.org
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
per-file ipc_message_start.h=jschuh@chromium.org
per-file ipc_message_start.h=palmer@chromium.org
per-file ipc_message_start.h=tsepez@chromium.org
per-file ipc_message_start.h=kenrb@chromium.org
+per-file ipc_message_start.h=nasko@chromium.org
diff --git a/chromium/ipc/file_descriptor_set_posix.cc b/chromium/ipc/file_descriptor_set_posix.cc
index 584efec14ae..1aa86a7f008 100644
--- a/chromium/ipc/file_descriptor_set_posix.cc
+++ b/chromium/ipc/file_descriptor_set_posix.cc
@@ -31,7 +31,7 @@ FileDescriptorSet::~FileDescriptorSet() {
for (unsigned i = consumed_descriptor_highwater_;
i < descriptors_.size(); ++i) {
if (descriptors_[i].auto_close)
- if (HANDLE_EINTR(close(descriptors_[i].fd)) < 0)
+ if (IGNORE_EINTR(close(descriptors_[i].fd)) < 0)
PLOG(ERROR) << "close";
}
}
@@ -119,13 +119,23 @@ void FileDescriptorSet::CommitAll() {
for (std::vector<base::FileDescriptor>::iterator
i = descriptors_.begin(); i != descriptors_.end(); ++i) {
if (i->auto_close)
- if (HANDLE_EINTR(close(i->fd)) < 0)
+ if (IGNORE_EINTR(close(i->fd)) < 0)
PLOG(ERROR) << "close";
}
descriptors_.clear();
consumed_descriptor_highwater_ = 0;
}
+void FileDescriptorSet::ReleaseFDsToClose(std::vector<int>* fds) {
+ for (std::vector<base::FileDescriptor>::iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (i->auto_close)
+ fds->push_back(i->fd);
+ }
+ descriptors_.clear();
+ consumed_descriptor_highwater_ = 0;
+}
+
void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) {
DCHECK(count <= kMaxDescriptorsPerMessage);
DCHECK_EQ(descriptors_.size(), 0u);
diff --git a/chromium/ipc/file_descriptor_set_posix.h b/chromium/ipc/file_descriptor_set_posix.h
index f9c6033c2a6..b413b4a2212 100644
--- a/chromium/ipc/file_descriptor_set_posix.h
+++ b/chromium/ipc/file_descriptor_set_posix.h
@@ -77,6 +77,9 @@ class IPC_EXPORT FileDescriptorSet
// Returns true if any contained file descriptors appear to be handles to a
// directory.
bool ContainsDirectoryDescriptor() const;
+ // Fetch all filedescriptors with the "auto close" property.
+ // Used instead of CommitAll() when closing must be handled manually.
+ void ReleaseFDsToClose(std::vector<int>* fds);
// ---------------------------------------------------------------------------
diff --git a/chromium/ipc/file_descriptor_set_posix_unittest.cc b/chromium/ipc/file_descriptor_set_posix_unittest.cc
index b4a01414a55..d9107f9f881 100644
--- a/chromium/ipc/file_descriptor_set_posix_unittest.cc
+++ b/chromium/ipc/file_descriptor_set_posix_unittest.cc
@@ -24,8 +24,8 @@ int GetSafeFd() {
bool VerifyClosed(int fd) {
const int duped = dup(fd);
if (duped != -1) {
- EXPECT_NE(HANDLE_EINTR(close(duped)), -1);
- EXPECT_NE(HANDLE_EINTR(close(fd)), -1);
+ EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
+ EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
return false;
}
return true;
diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp
index a2476511a84..ace836b3a1b 100644
--- a/chromium/ipc/ipc.gyp
+++ b/chromium/ipc/ipc.gyp
@@ -37,7 +37,6 @@
'test_support_ipc',
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
- '../base/base.gyp:run_all_unittests',
'../base/base.gyp:test_support_base',
'../testing/gtest.gyp:gtest',
],
@@ -57,6 +56,7 @@
'ipc_sync_message_unittest.h',
'ipc_test_base.cc',
'ipc_test_base.h',
+ 'run_all_unittests.cc',
'sync_socket_unittest.cc',
'unix_domain_socket_util_unittest.cc',
],
diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h
index f65a62b9cc9..7e09a806f7a 100644
--- a/chromium/ipc/ipc_channel.h
+++ b/chromium/ipc/ipc_channel.h
@@ -75,15 +75,22 @@ class IPC_EXPORT Channel : public Sender {
#endif
};
- // The Hello message is internal to the Channel class. It is sent
- // by the peer when the channel is connected. The message contains
- // just the process id (pid). The message has a special routing_id
- // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE).
+ // Messages internal to the IPC implementation are defined here.
+ // Uses Maximum value of message type (uint16), to avoid conflicting
+ // with normal message types, which are enumeration constants starting from 0.
enum {
- HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16),
- // to avoid conflicting with normal
- // message types, which are enumeration
- // constants starting from 0.
+ // The Hello message is sent by the peer when the channel is connected.
+ // The message contains just the process id (pid).
+ // The message has a special routing_id (MSG_ROUTING_NONE)
+ // and type (HELLO_MESSAGE_TYPE).
+ HELLO_MESSAGE_TYPE = kuint16max,
+ // The CLOSE_FD_MESSAGE_TYPE is used in the IPC class to
+ // work around a bug in sendmsg() on Mac. When an FD is sent
+ // over the socket, a CLOSE_FD_MESSAGE is sent with hops = 2.
+ // The client will return the message with hops = 1, *after* it
+ // has received the message that contains the FD. When we
+ // receive it again on the sender side, we close the FD.
+ CLOSE_FD_MESSAGE_TYPE = HELLO_MESSAGE_TYPE - 1
};
// The maximum message size in bytes. Attempting to receive a message of this
diff --git a/chromium/ipc/ipc_channel_factory.cc b/chromium/ipc/ipc_channel_factory.cc
index f3ad11a6b4f..5c24284f95d 100644
--- a/chromium/ipc/ipc_channel_factory.cc
+++ b/chromium/ipc/ipc_channel_factory.cc
@@ -76,7 +76,7 @@ void ChannelFactory::OnFileCanWriteWithoutBlocking(int fd) {
void ChannelFactory::Close() {
if (listen_fd_ < 0)
return;
- if (HANDLE_EINTR(close(listen_fd_)) < 0)
+ if (IGNORE_EINTR(close(listen_fd_)) < 0)
PLOG(ERROR) << "close";
listen_fd_ = -1;
if (unlink(path_.value().c_str()) < 0)
diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc
index 860815e91cb..1ecd5718245 100644
--- a/chromium/ipc/ipc_channel_nacl.cc
+++ b/chromium/ipc/ipc_channel_nacl.cc
@@ -344,7 +344,7 @@ bool Channel::ChannelImpl::DidEmptyInputBuffers() {
return input_fds_.empty();
}
-void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) {
+void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
// The trusted side IPC::Channel should handle the "hello" handshake; we
// should not receive the "Hello" message.
NOTREACHED();
diff --git a/chromium/ipc/ipc_channel_nacl.h b/chromium/ipc/ipc_channel_nacl.h
index 7c8960f6d71..a21730eb813 100644
--- a/chromium/ipc/ipc_channel_nacl.h
+++ b/chromium/ipc/ipc_channel_nacl.h
@@ -60,7 +60,7 @@ class Channel::ChannelImpl : public internal::ChannelReader {
int* bytes_read) OVERRIDE;
virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE;
virtual bool DidEmptyInputBuffers() OVERRIDE;
- virtual void HandleHelloMessage(const Message& msg) OVERRIDE;
+ virtual void HandleInternalMessage(const Message& msg) OVERRIDE;
Mode mode_;
bool waiting_connect_;
diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc
index 98a7cd8a9fa..87885329001 100644
--- a/chromium/ipc/ipc_channel_posix.cc
+++ b/chromium/ipc/ipc_channel_posix.cc
@@ -206,9 +206,9 @@ bool SocketPair(int* fd1, int* fd2) {
if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
PLOG(ERROR) << "fcntl(O_NONBLOCK)";
- if (HANDLE_EINTR(close(pipe_fds[0])) < 0)
+ if (IGNORE_EINTR(close(pipe_fds[0])) < 0)
PLOG(ERROR) << "close";
- if (HANDLE_EINTR(close(pipe_fds[1])) < 0)
+ if (IGNORE_EINTR(close(pipe_fds[1])) < 0)
PLOG(ERROR) << "close";
return false;
}
@@ -347,6 +347,27 @@ bool Channel::ChannelImpl::Connect() {
return did_connect;
}
+void Channel::ChannelImpl::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
+ // store the file descriptor in a set and send a message to
+ // the recipient, which is queued AFTER the message that
+ // sent the FD. The recipient will reply to the message,
+ // letting us know that it is now safe to close the file
+ // descriptor. For more information, see:
+ // http://crbug.com/298276
+ std::vector<int> to_close;
+ msg->file_descriptor_set()->ReleaseFDsToClose(&to_close);
+ for (size_t i = 0; i < to_close.size(); i++) {
+ fds_to_close_.insert(to_close[i]);
+ QueueCloseFDMessage(to_close[i], 2);
+ }
+#else
+ msg->file_descriptor_set()->CommitAll();
+#endif
+}
+
bool Channel::ChannelImpl::ProcessOutgoingMessages() {
DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
// no connection?
@@ -419,7 +440,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
msgh.msg_iov = &iov;
msgh.msg_controllen = 0;
if (bytes_written > 0) {
- msg->file_descriptor_set()->CommitAll();
+ CloseFileDescriptors(msg);
}
}
#endif // IPC_USES_READWRITE
@@ -440,7 +461,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
}
}
if (bytes_written > 0)
- msg->file_descriptor_set()->CommitAll();
+ CloseFileDescriptors(msg);
if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
#if defined(OS_MACOSX)
@@ -526,7 +547,7 @@ void Channel::ChannelImpl::CloseClientFileDescriptor() {
base::AutoLock lock(client_pipe_lock_);
if (client_pipe_ != -1) {
PipeMap::GetInstance()->Remove(pipe_name_);
- if (HANDLE_EINTR(close(client_pipe_)) < 0)
+ if (IGNORE_EINTR(close(client_pipe_)) < 0)
PLOG(ERROR) << "close " << pipe_name_;
client_pipe_ = -1;
}
@@ -550,18 +571,18 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
read_watcher_.StopWatchingFileDescriptor();
write_watcher_.StopWatchingFileDescriptor();
if (pipe_ != -1) {
- if (HANDLE_EINTR(close(pipe_)) < 0)
+ if (IGNORE_EINTR(close(pipe_)) < 0)
PLOG(ERROR) << "close pipe_ " << pipe_name_;
pipe_ = -1;
}
#if defined(IPC_USES_READWRITE)
if (fd_pipe_ != -1) {
- if (HANDLE_EINTR(close(fd_pipe_)) < 0)
+ if (IGNORE_EINTR(close(fd_pipe_)) < 0)
PLOG(ERROR) << "close fd_pipe_ " << pipe_name_;
fd_pipe_ = -1;
}
if (remote_fd_pipe_ != -1) {
- if (HANDLE_EINTR(close(remote_fd_pipe_)) < 0)
+ if (IGNORE_EINTR(close(remote_fd_pipe_)) < 0)
PLOG(ERROR) << "close remote_fd_pipe_ " << pipe_name_;
remote_fd_pipe_ = -1;
}
@@ -575,6 +596,17 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
// Close any outstanding, received file descriptors.
ClearInputFDs();
+
+#if defined(OS_MACOSX)
+ // Clear any outstanding, sent file descriptors.
+ for (std::set<int>::iterator i = fds_to_close_.begin();
+ i != fds_to_close_.end();
+ ++i) {
+ if (IGNORE_EINTR(close(*i)) < 0)
+ PLOG(ERROR) << "close";
+ }
+ fds_to_close_.clear();
+#endif
}
// static
@@ -592,7 +624,6 @@ void Channel::ChannelImpl::SetGlobalPid(int pid) {
// Called by libevent when we can read from the pipe without blocking.
void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
- bool send_server_hello_msg = false;
if (fd == server_listen_pipe_) {
int new_pipe = 0;
if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) ||
@@ -606,7 +637,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
// close our new descriptor.
if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0)
DPLOG(ERROR) << "shutdown " << pipe_name_;
- if (HANDLE_EINTR(close(new_pipe)) < 0)
+ if (IGNORE_EINTR(close(new_pipe)) < 0)
DPLOG(ERROR) << "close " << pipe_name_;
listener()->OnChannelDenied();
return;
@@ -631,18 +662,16 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
if (!AcceptConnection()) {
NOTREACHED() << "AcceptConnection should not fail on server";
}
- send_server_hello_msg = true;
waiting_connect_ = false;
} else if (fd == pipe_) {
if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) {
- send_server_hello_msg = true;
waiting_connect_ = false;
}
if (!ProcessIncomingMessages()) {
// ClosePipeOnError may delete this object, so we mustn't call
// ProcessOutgoingMessages.
- send_server_hello_msg = false;
ClosePipeOnError();
+ return;
}
} else {
NOTREACHED() << "Unknown pipe " << fd;
@@ -651,9 +680,11 @@ 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.
- if (send_server_hello_msg) {
- ProcessOutgoingMessages();
+ // is invalid. This also flushes any closefd messagse.
+ if (!is_blocked_on_write_) {
+ if (!ProcessOutgoingMessages()) {
+ ClosePipeOnError();
+ }
}
}
@@ -896,35 +927,86 @@ bool Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr(msghdr* msg) {
void Channel::ChannelImpl::ClearInputFDs() {
for (size_t i = 0; i < input_fds_.size(); ++i) {
- if (HANDLE_EINTR(close(input_fds_[i])) < 0)
+ if (IGNORE_EINTR(close(input_fds_[i])) < 0)
PLOG(ERROR) << "close ";
}
input_fds_.clear();
}
-void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) {
+void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) {
+ switch (hops) {
+ case 1:
+ case 2: {
+ // Create the message
+ scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
+ CLOSE_FD_MESSAGE_TYPE,
+ IPC::Message::PRIORITY_NORMAL));
+ if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) {
+ NOTREACHED() << "Unable to pickle close fd.";
+ }
+ // Send(msg.release());
+ output_queue_.push(msg.release());
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
// The Hello message contains only the process id.
PickleIterator iter(msg);
- int pid;
- if (!msg.ReadInt(&iter, &pid))
- NOTREACHED();
-#if defined(IPC_USES_READWRITE)
- if (mode_ & MODE_SERVER_FLAG) {
- // With IPC_USES_READWRITE, the Hello message from the client to the
- // server also contains the fd_pipe_, which will be used for all
- // subsequent file descriptor passing.
- DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
- base::FileDescriptor descriptor;
- if (!msg.ReadFileDescriptor(&iter, &descriptor)) {
+ switch (msg.type()) {
+ default:
NOTREACHED();
- }
- fd_pipe_ = descriptor.fd;
- CHECK(descriptor.auto_close);
- }
+ break;
+
+ case Channel::HELLO_MESSAGE_TYPE:
+ int pid;
+ if (!msg.ReadInt(&iter, &pid))
+ NOTREACHED();
+
+#if defined(IPC_USES_READWRITE)
+ if (mode_ & MODE_SERVER_FLAG) {
+ // With IPC_USES_READWRITE, the Hello message from the client to the
+ // server also contains the fd_pipe_, which will be used for all
+ // subsequent file descriptor passing.
+ DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
+ base::FileDescriptor descriptor;
+ if (!msg.ReadFileDescriptor(&iter, &descriptor)) {
+ NOTREACHED();
+ }
+ fd_pipe_ = descriptor.fd;
+ CHECK(descriptor.auto_close);
+ }
#endif // IPC_USES_READWRITE
- peer_pid_ = pid;
- listener()->OnChannelConnected(pid);
+ peer_pid_ = pid;
+ listener()->OnChannelConnected(pid);
+ break;
+
+#if defined(OS_MACOSX)
+ case Channel::CLOSE_FD_MESSAGE_TYPE:
+ int fd, hops;
+ if (!msg.ReadInt(&iter, &hops))
+ NOTREACHED();
+ if (!msg.ReadInt(&iter, &fd))
+ NOTREACHED();
+ if (hops == 0) {
+ if (fds_to_close_.erase(fd) > 0) {
+ if (IGNORE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close";
+ } else {
+ NOTREACHED();
+ }
+ } else {
+ QueueCloseFDMessage(fd, hops);
+ }
+ break;
+#endif
+ }
}
void Channel::ChannelImpl::Close() {
@@ -938,7 +1020,7 @@ void Channel::ChannelImpl::Close() {
must_unlink_ = false;
}
if (server_listen_pipe_ != -1) {
- if (HANDLE_EINTR(close(server_listen_pipe_)) < 0)
+ if (IGNORE_EINTR(close(server_listen_pipe_)) < 0)
DPLOG(ERROR) << "close " << server_listen_pipe_;
server_listen_pipe_ = -1;
// Unregister libevent for the listening socket and close it.
diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h
index 645a1303713..1e587c13eb0 100644
--- a/chromium/ipc/ipc_channel_posix.h
+++ b/chromium/ipc/ipc_channel_posix.h
@@ -10,6 +10,7 @@
#include <sys/socket.h> // for CMSG macros
#include <queue>
+#include <set>
#include <string>
#include <vector>
@@ -80,6 +81,8 @@ class Channel::ChannelImpl : public internal::ChannelReader,
void ClosePipeOnError();
int GetHelloMessageProcId();
void QueueHelloMessage();
+ void CloseFileDescriptors(Message* msg);
+ void QueueCloseFDMessage(int fd, int hops);
// ChannelReader implementation.
virtual ReadState ReadData(char* buffer,
@@ -87,7 +90,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
int* bytes_read) OVERRIDE;
virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE;
virtual bool DidEmptyInputBuffers() OVERRIDE;
- virtual void HandleHelloMessage(const Message& msg) OVERRIDE;
+ virtual void HandleInternalMessage(const Message& msg) OVERRIDE;
#if defined(IPC_USES_READWRITE)
// Reads the next message from the fd_pipe_ and appends them to the
@@ -184,6 +187,13 @@ class Channel::ChannelImpl : public internal::ChannelReader,
// implementation!
std::vector<int> input_fds_;
+#if defined(OS_MACOSX)
+ // On OSX, sent FDs must not be closed until we get an ack.
+ // Keep track of sent FDs here to make sure the remote is not
+ // trying to bamboozle us.
+ std::set<int> fds_to_close_;
+#endif
+
// True if we are responsible for unlinking the unix domain socket file.
bool must_unlink_;
diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc
index 66ddeb2b496..dbd854e16c6 100644
--- a/chromium/ipc/ipc_channel_posix_unittest.cc
+++ b/chromium/ipc/ipc_channel_posix_unittest.cc
@@ -159,7 +159,7 @@ void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle,
// Make sure the path we need exists.
base::FilePath path(name);
base::FilePath dir_path = path.DirName();
- ASSERT_TRUE(file_util::CreateDirectory(dir_path));
+ ASSERT_TRUE(base::CreateDirectory(dir_path));
ASSERT_GE(bind(socket_fd,
reinterpret_cast<struct sockaddr *>(&server_address),
server_address_len), 0) << server_address.sun_path
@@ -219,7 +219,7 @@ TEST_F(IPCChannelPosixTest, BasicConnected) {
ASSERT_TRUE(channel.Connect());
ASSERT_FALSE(channel.AcceptsConnections());
channel.Close();
- ASSERT_TRUE(HANDLE_EINTR(close(pipe_fds[1])) == 0);
+ 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.
diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc
index 45512f97e18..18ed3041336 100644
--- a/chromium/ipc/ipc_channel_proxy.cc
+++ b/chromium/ipc/ipc_channel_proxy.cc
@@ -36,10 +36,6 @@ bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) {
return false;
}
-void ChannelProxy::MessageFilter::OnDestruct() const {
- delete this;
-}
-
ChannelProxy::MessageFilter::~MessageFilter() {}
//------------------------------------------------------------------------------
@@ -292,14 +288,12 @@ ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle,
Listener* listener,
base::SingleThreadTaskRunner* ipc_task_runner)
: context_(new Context(listener, ipc_task_runner)),
- outgoing_message_filter_(NULL),
did_init_(false) {
Init(channel_handle, mode, true);
}
ChannelProxy::ChannelProxy(Context* context)
: context_(context),
- outgoing_message_filter_(NULL),
did_init_(false) {
}
@@ -362,8 +356,6 @@ bool ChannelProxy::Send(Message* message) {
// TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are
// tests that call Send() from a wrong thread. See http://crbug.com/163523.
- if (outgoing_message_filter())
- message = outgoing_message_filter()->Rewrite(message);
#ifdef IPC_MESSAGE_LOG_ENABLED
Logging::GetInstance()->OnSendMessage(message, context_->channel_id());
diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h
index 4d5a7d45ec2..1f5ecf450df 100644
--- a/chromium/ipc/ipc_channel_proxy.h
+++ b/chromium/ipc/ipc_channel_proxy.h
@@ -54,12 +54,11 @@ class SendCallbackHelper;
//
class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
public:
- struct MessageFilterTraits;
// 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, MessageFilterTraits> {
+ : public base::RefCountedThreadSafe<MessageFilter> {
public:
MessageFilter();
@@ -89,33 +88,11 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// the message be handled in the default way.
virtual bool OnMessageReceived(const Message& message);
- // Called when the message filter is about to be deleted. This gives
- // derived classes the option of controlling which thread they're deleted
- // on etc.
- virtual void OnDestruct() const;
-
protected:
virtual ~MessageFilter();
private:
- friend class base::RefCountedThreadSafe<MessageFilter,
- MessageFilterTraits>;
- };
-
- struct MessageFilterTraits {
- static void Destruct(const MessageFilter* filter) {
- filter->OnDestruct();
- }
- };
-
-
- // Interface for a filter to be imposed on outgoing messages which can
- // re-write the message. Used mainly for testing.
- class OutgoingMessageFilter {
- public:
- // Returns a re-written message, freeing the original, or simply the
- // original unchanged if no rewrite indicated.
- virtual Message *Rewrite(Message *message) = 0;
+ friend class base::RefCountedThreadSafe<MessageFilter>;
};
// Initializes a channel proxy. The channel_handle and mode parameters are
@@ -166,10 +143,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
void AddFilter(MessageFilter* filter);
void RemoveFilter(MessageFilter* filter);
- void set_outgoing_message_filter(OutgoingMessageFilter* filter) {
- outgoing_message_filter_ = filter;
- }
-
// Called to clear the pointer to the IPC task runner when it's going away.
void ClearIPCTaskRunner();
@@ -270,10 +243,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
Context* context() { return context_.get(); }
- OutgoingMessageFilter* outgoing_message_filter() {
- return outgoing_message_filter_;
- }
-
private:
friend class SendCallbackHelper;
@@ -282,8 +251,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
// that involves this data.
scoped_refptr<Context> context_;
- OutgoingMessageFilter* outgoing_message_filter_;
-
// Whether the channel has been initialized.
bool did_init_;
};
diff --git a/chromium/ipc/ipc_channel_reader.cc b/chromium/ipc/ipc_channel_reader.cc
index 9055deb1775..2ee7449ea8d 100644
--- a/chromium/ipc/ipc_channel_reader.cc
+++ b/chromium/ipc/ipc_channel_reader.cc
@@ -38,9 +38,15 @@ bool ChannelReader::AsyncReadComplete(int bytes_read) {
return DispatchInputData(input_buf_, bytes_read);
}
+bool ChannelReader::IsInternalMessage(const Message& m) const {
+ return m.routing_id() == MSG_ROUTING_NONE &&
+ m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE &&
+ m.type() <= Channel::HELLO_MESSAGE_TYPE;
+}
+
bool ChannelReader::IsHelloMessage(const Message& m) const {
return m.routing_id() == MSG_ROUTING_NONE &&
- m.type() == Channel::HELLO_MESSAGE_TYPE;
+ m.type() == Channel::HELLO_MESSAGE_TYPE;
}
bool ChannelReader::DispatchInputData(const char* input_data,
@@ -84,8 +90,8 @@ bool ChannelReader::DispatchInputData(const char* input_data,
"line", IPC_MESSAGE_ID_LINE(m.type()));
#endif
m.TraceMessageEnd();
- if (IsHelloMessage(m))
- HandleHelloMessage(m);
+ if (IsInternalMessage(m))
+ HandleInternalMessage(m);
else
listener_->OnMessageReceived(m);
p = message_tail;
diff --git a/chromium/ipc/ipc_channel_reader.h b/chromium/ipc/ipc_channel_reader.h
index 9c398bdce35..130384659fc 100644
--- a/chromium/ipc/ipc_channel_reader.h
+++ b/chromium/ipc/ipc_channel_reader.h
@@ -42,8 +42,12 @@ class ChannelReader {
// data. See ReadData for more.
bool AsyncReadComplete(int bytes_read);
- // Returns true if the given message is the "hello" message sent on channel
- // set-up.
+ // Returns true if the given message is internal to the IPC implementation,
+ // like the "hello" message sent on channel set-up.
+ bool IsInternalMessage(const Message& m) const;
+
+ // Returns true if the given message is an Hello message
+ // sent on channel set-up.
bool IsHelloMessage(const Message& m) const;
protected:
@@ -76,8 +80,8 @@ class ChannelReader {
// though there could be more data ready to be read from the OS.
virtual bool DidEmptyInputBuffers() = 0;
- // Handles the first message sent over the pipe which contains setup info.
- virtual void HandleHelloMessage(const Message& msg) = 0;
+ // Handles internal messages, like the hello message sent on channel startup.
+ virtual void HandleInternalMessage(const Message& msg) = 0;
private:
// Takes the given data received from the IPC channel and dispatches any
diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc
index 6d7cfe8d3f4..8c08500355e 100644
--- a/chromium/ipc/ipc_channel_win.cc
+++ b/chromium/ipc/ipc_channel_win.cc
@@ -152,7 +152,8 @@ bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
return true;
}
-void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) {
+void Channel::ChannelImpl::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);
int32 claimed_pid;
diff --git a/chromium/ipc/ipc_channel_win.h b/chromium/ipc/ipc_channel_win.h
index 711f57fde72..a544f8be4bb 100644
--- a/chromium/ipc/ipc_channel_win.h
+++ b/chromium/ipc/ipc_channel_win.h
@@ -41,7 +41,7 @@ class Channel::ChannelImpl : public internal::ChannelReader,
int* bytes_read) OVERRIDE;
virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE;
bool DidEmptyInputBuffers() OVERRIDE;
- virtual void HandleHelloMessage(const Message& msg) OVERRIDE;
+ virtual void HandleInternalMessage(const Message& msg) OVERRIDE;
static const string16 PipeName(const std::string& channel_id,
int32* secret);
diff --git a/chromium/ipc/ipc_descriptors.h b/chromium/ipc/ipc_descriptors.h
index b766bbbe769..9dcff8ceb13 100644
--- a/chromium/ipc/ipc_descriptors.h
+++ b/chromium/ipc/ipc_descriptors.h
@@ -9,6 +9,10 @@
// base::GlobalDescriptors object (see base/posix/global_descriptors.h)
enum {
kPrimaryIPCChannel = 0,
+ kStatsTableSharedMemFd,
+
+ // The first key that can be use to register descriptors.
+ kIPCDescriptorMax
};
#endif // IPC_IPC_DESCRIPTORS_H_
diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h
index cd036802528..c4e250cf9e6 100644
--- a/chromium/ipc/ipc_message_macros.h
+++ b/chromium/ipc/ipc_message_macros.h
@@ -202,7 +202,7 @@
#include "ipc/ipc_message_utils_impl.h"
#endif
-// Convenience macro for defining structs without inheritence. Should not need
+// Convenience macro for defining structs without inheritance. Should not need
// to be subsequently redefined.
#define IPC_STRUCT_BEGIN(struct_name) \
IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, IPC::NoParams)
@@ -996,8 +996,8 @@
ipc_message__.type())
#define IPC_END_MESSAGE_MAP() \
- DCHECK(msg_is_ok__); \
} \
+ DCHECK(msg_is_ok__); \
}
#define IPC_END_MESSAGE_MAP_EX() \
@@ -1010,7 +1010,14 @@
#endif // IPC_IPC_MESSAGE_MACROS_H_
+// The following #ifdef cannot be removed. Although the code is semantically
+// equivalent without the #ifdef, VS2013 contains a bug where it is
+// over-aggressive in optimizing out #includes. Putting the #ifdef is a
+// workaround for this bug. See http://goo.gl/eGt2Fb for more details.
+// This can be removed once VS2013 is fixed.
+#ifdef IPC_MESSAGE_START
// Clean up IPC_MESSAGE_START in this unguarded section so that the
// XXX_messages.h files need not do so themselves. This makes the
// XXX_messages.h files easier to write.
#undef IPC_MESSAGE_START
+#endif
diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h
index 314ed0e4689..3016f5d3461 100644
--- a/chromium/ipc/ipc_message_start.h
+++ b/chromium/ipc/ipc_message_start.h
@@ -11,6 +11,7 @@
enum IPCMessageStart {
AutomationMsgStart = 0,
QtMsgStart,
+ FrameMsgStart,
ViewMsgStart,
InputMsgStart,
PluginMsgStart,
@@ -91,6 +92,7 @@ enum IPCMessageStart {
PowerMonitorMsgStart,
EncryptedMediaMsgStart,
ServiceWorkerMsgStart,
+ MessagePortMsgStart,
LastIPCMsgStart // Must come last.
};
diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc
index 2acddceb51c..0390648f457 100644
--- a/chromium/ipc/ipc_message_utils.cc
+++ b/chromium/ipc/ipc_message_utils.cc
@@ -311,37 +311,18 @@ void ParamTraits<unsigned long long>::Log(const param_type& p, std::string* l) {
l->append(base::Uint64ToString(p));
}
-void ParamTraits<float>::Write(Message* m, const param_type& p) {
- m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
-}
-
-bool ParamTraits<float>::Read(const Message* m, PickleIterator* iter,
- param_type* r) {
- const char *data;
- int data_size;
- if (!m->ReadData(iter, &data, &data_size) ||
- data_size != sizeof(param_type)) {
- NOTREACHED();
- return false;
- }
- memcpy(r, data, sizeof(param_type));
- return true;
-}
-
void ParamTraits<float>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("%e", p));
}
void ParamTraits<double>::Write(Message* m, const param_type& p) {
- m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
+ m->WriteBytes(reinterpret_cast<const char*>(&p), sizeof(param_type));
}
bool ParamTraits<double>::Read(const Message* m, PickleIterator* iter,
param_type* r) {
const char *data;
- int data_size;
- if (!m->ReadData(iter, &data, &data_size) ||
- data_size != sizeof(param_type)) {
+ if (!m->ReadBytes(iter, &data, sizeof(*r))) {
NOTREACHED();
return false;
}
@@ -363,7 +344,7 @@ void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) {
}
#if !defined(WCHAR_T_IS_UTF16)
-void ParamTraits<string16>::Log(const param_type& p, std::string* l) {
+void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) {
l->append(UTF16ToUTF8(p));
}
#endif
@@ -555,7 +536,7 @@ void ParamTraits<base::NullableString16>::Write(Message* m,
bool ParamTraits<base::NullableString16>::Read(const Message* m,
PickleIterator* iter,
param_type* r) {
- string16 string;
+ base::string16 string;
if (!ReadParam(m, iter, &string))
return false;
bool is_null;
diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h
index 7121c19e304..24b38af68ee 100644
--- a/chromium/ipc/ipc_message_utils.h
+++ b/chromium/ipc/ipc_message_utils.h
@@ -216,8 +216,12 @@ struct ParamTraits<unsigned long long> {
template <>
struct IPC_EXPORT ParamTraits<float> {
typedef float param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Write(Message* m, const param_type& p) {
+ m->WriteFloat(p);
+ }
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
+ return m->ReadFloat(iter, r);
+ }
static void Log(const param_type& p, std::string* l);
};
@@ -261,8 +265,8 @@ struct ParamTraits<std::wstring> {
// need this trait.
#if !defined(WCHAR_T_IS_UTF16)
template <>
-struct ParamTraits<string16> {
- typedef string16 param_type;
+struct ParamTraits<base::string16> {
+ typedef base::string16 param_type;
static void Write(Message* m, const param_type& p) {
m->WriteString16(p);
}
diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc
index 4cddc1c2274..aeec8907a4f 100644
--- a/chromium/ipc/ipc_send_fds_test.cc
+++ b/chromium/ipc/ipc_send_fds_test.cc
@@ -11,13 +11,18 @@ extern "C" {
}
#endif
#include <fcntl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <queue>
+
+#include "base/callback.h"
#include "base/file_descriptor_posix.h"
#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/waitable_event.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_test_base.h"
@@ -26,57 +31,67 @@ namespace {
const unsigned kNumFDsToSend = 20;
const char* kDevZeroPath = "/dev/zero";
-static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
- // Check that we can read from the FD.
- char buf;
- ssize_t amt_read = read(fd, &buf, 1);
- ASSERT_EQ(amt_read, 1);
- ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes.
-
- struct stat st;
- ASSERT_EQ(fstat(fd, &st), 0);
-
- ASSERT_EQ(close(fd), 0);
-
- // Compare inode numbers to check that the file sent over the wire is actually
- // the one expected.
- ASSERT_EQ(inode_num, st.st_ino);
-}
-
-class MyChannelDescriptorListener : public IPC::Listener {
+class MyChannelDescriptorListenerBase : public IPC::Listener {
public:
- explicit MyChannelDescriptorListener(ino_t expected_inode_num)
- : expected_inode_num_(expected_inode_num),
- num_fds_received_(0) {}
-
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
PickleIterator iter(message);
- ++num_fds_received_;
base::FileDescriptor descriptor;
IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor);
- VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
- if (num_fds_received_ == kNumFDsToSend)
- base::MessageLoop::current()->Quit();
-
+ HandleFD(descriptor.fd);
return true;
}
- virtual void OnChannelError() OVERRIDE {
- base::MessageLoop::current()->Quit();
+ protected:
+ virtual void HandleFD(int fd) = 0;
+};
+
+class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
+ public:
+ explicit MyChannelDescriptorListener(ino_t expected_inode_num)
+ : MyChannelDescriptorListenerBase(),
+ expected_inode_num_(expected_inode_num),
+ num_fds_received_(0) {
}
bool GotExpectedNumberOfDescriptors() const {
return num_fds_received_ == kNumFDsToSend;
}
+ virtual void OnChannelError() OVERRIDE {
+ base::MessageLoop::current()->Quit();
+ }
+
+ protected:
+ virtual void HandleFD(int fd) OVERRIDE {
+ // Check that we can read from the FD.
+ char buf;
+ ssize_t amt_read = read(fd, &buf, 1);
+ ASSERT_EQ(amt_read, 1);
+ ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes.
+
+ struct stat st;
+ ASSERT_EQ(fstat(fd, &st), 0);
+
+ ASSERT_EQ(close(fd), 0);
+
+ // Compare inode numbers to check that the file sent over the wire is
+ // actually the one expected.
+ ASSERT_EQ(expected_inode_num_, st.st_ino);
+
+ ++num_fds_received_;
+ if (num_fds_received_ == kNumFDsToSend)
+ base::MessageLoop::current()->Quit();
+ }
+
private:
ino_t expected_inode_num_;
unsigned num_fds_received_;
};
+
class IPCSendFdsTest : public IPCTestBase {
protected:
void RunServer() {
@@ -138,7 +153,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient) {
struct stat st;
int fd = open(kDevZeroPath, O_RDONLY);
fstat(fd, &st);
- EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
+ EXPECT_GE(IGNORE_EINTR(close(fd)), 0);
return SendFdsClientCommon("SendFdsClient", st.st_ino);
}
@@ -154,7 +169,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) {
struct stat st;
const int fd = open(kDevZeroPath, O_RDONLY);
fstat(fd, &st);
- if (HANDLE_EINTR(close(fd)) < 0)
+ if (IGNORE_EINTR(close(fd)) < 0)
return -1;
// Enable the sandbox.
@@ -178,6 +193,188 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) {
}
#endif // defined(OS_MACOSX)
+
+class MyCBListener : public MyChannelDescriptorListenerBase {
+ public:
+ MyCBListener(base::Callback<void(int)> cb, int fds_to_send)
+ : MyChannelDescriptorListenerBase(),
+ cb_(cb) {
+ }
+
+ protected:
+ virtual void HandleFD(int fd) OVERRIDE {
+ cb_.Run(fd);
+ }
+ private:
+ base::Callback<void(int)> cb_;
+};
+
+std::pair<int, int> make_socket_pair() {
+ int pipe_fds[2];
+ CHECK_EQ(0, HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds)));
+ return std::pair<int, int>(pipe_fds[0], pipe_fds[1]);
+}
+
+static void null_cb(int unused_fd) {
+ NOTREACHED();
+}
+
+class PipeChannelHelper {
+ public:
+ PipeChannelHelper(base::Thread* in_thread,
+ base::Thread* out_thread,
+ base::Callback<void(int)> cb,
+ int fds_to_send) :
+ in_thread_(in_thread),
+ out_thread_(out_thread),
+ cb_listener_(cb, fds_to_send),
+ null_listener_(base::Bind(&null_cb), 0) {
+ }
+
+ 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);
+ IPC::ChannelHandle out_handle("OUT", out_fd);
+ out.reset(new IPC::Channel(out_handle,
+ IPC::Channel::MODE_CLIENT,
+ &cb_listener_));
+ // PostTask the connect calls to make sure the callbacks happens
+ // on the right threads.
+ in_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PipeChannelHelper::Connect, in.get()));
+ out_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PipeChannelHelper::Connect, out.get()));
+ }
+
+ static void DestroyChannel(scoped_ptr<IPC::Channel> *c,
+ base::WaitableEvent *event) {
+ c->reset(0);
+ event->Signal();
+ }
+
+ ~PipeChannelHelper() {
+ base::WaitableEvent a(true, false);
+ base::WaitableEvent b(true, false);
+ in_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a));
+ out_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b));
+ a.Wait();
+ b.Wait();
+ }
+
+ static void Connect(IPC::Channel *channel) {
+ EXPECT_TRUE(channel->Connect());
+ }
+
+ void Send(int fd) {
+ CHECK_EQ(base::MessageLoop::current(), in_thread_->message_loop());
+
+ ASSERT_GE(fd, 0);
+ base::FileDescriptor descriptor(fd, true);
+
+ IPC::Message* message =
+ new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
+ IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
+ ASSERT_TRUE(in->Send(message));
+ }
+
+ private:
+ scoped_ptr<IPC::Channel> in, out;
+ base::Thread* in_thread_;
+ base::Thread* out_thread_;
+ MyCBListener cb_listener_;
+ MyCBListener null_listener_;
+};
+
+// This test is meant to provoke a kernel bug on OSX, and to prove
+// that the workaround for it is working. It sets up two pipes and three
+// threads, the producer thread creates socketpairs and sends one of the fds
+// over pipe1 to the middleman thread. The middleman thread simply takes the fd
+// sends it over pipe2 to the consumer thread. The consumer thread writes a byte
+// to each fd it receives and then closes the pipe. The producer thread reads
+// the bytes back from each pair of pipes and make sure that everything worked.
+// This feedback mechanism makes sure that not too many file descriptors are
+// in flight at the same time. For more info on the bug, see:
+// http://crbug.com/298276
+class IPCMultiSendingFdsTest : public testing::Test {
+ public:
+ IPCMultiSendingFdsTest() : received_(true, false) {}
+
+ void Producer(PipeChannelHelper* dest,
+ base::Thread* t,
+ int pipes_to_send) {
+ for (int i = 0; i < pipes_to_send; i++) {
+ received_.Reset();
+ std::pair<int, int> pipe_fds = make_socket_pair();
+ t->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PipeChannelHelper::Send,
+ base::Unretained(dest),
+ pipe_fds.second));
+ char tmp = 'x';
+ CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds.first, &tmp, 1)));
+ CHECK_EQ(0, IGNORE_EINTR(close(pipe_fds.first)));
+ received_.Wait();
+ }
+ }
+
+ void ConsumerHandleFD(int fd) {
+ char tmp = 'y';
+ CHECK_EQ(1, HANDLE_EINTR(read(fd, &tmp, 1)));
+ CHECK_EQ(tmp, 'x');
+ CHECK_EQ(0, IGNORE_EINTR(close(fd)));
+ received_.Signal();
+ }
+
+ base::Thread* CreateThread(const char* name) {
+ base::Thread* ret = new base::Thread(name);
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ ret->StartWithOptions(options);
+ return ret;
+ }
+
+ void Run() {
+ // On my mac, this test fails roughly 35 times per
+ // million sends with low load, but much more with high load.
+ // Unless the workaround is in place. With 10000 sends, we
+ // should see at least a 3% failure rate.
+ const int pipes_to_send = 20000;
+ scoped_ptr<base::Thread> producer(CreateThread("producer"));
+ scoped_ptr<base::Thread> middleman(CreateThread("middleman"));
+ scoped_ptr<base::Thread> consumer(CreateThread("consumer"));
+ PipeChannelHelper pipe1(
+ middleman.get(),
+ consumer.get(),
+ base::Bind(&IPCMultiSendingFdsTest::ConsumerHandleFD,
+ base::Unretained(this)),
+ pipes_to_send);
+ PipeChannelHelper pipe2(
+ producer.get(),
+ middleman.get(),
+ base::Bind(&PipeChannelHelper::Send, base::Unretained(&pipe1)),
+ pipes_to_send);
+ pipe1.Init();
+ pipe2.Init();
+ Producer(&pipe2, producer.get(), pipes_to_send);
+ }
+
+ private:
+ base::WaitableEvent received_;
+};
+
+TEST_F(IPCMultiSendingFdsTest, StressTest) {
+ Run();
+}
+
} // namespace
#endif // defined(OS_POSIX)
diff --git a/chromium/ipc/run_all_unittests.cc b/chromium/ipc/run_all_unittests.cc
new file mode 100644
index 00000000000..d36f8712210
--- /dev/null
+++ b/chromium/ipc/run_all_unittests.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 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 "base/at_exit.h"
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "base/test/test_file_util.h"
+#endif
+
+namespace {
+
+class NoAtExitBaseTestSuite : public base::TestSuite {
+ public:
+ NoAtExitBaseTestSuite(int argc, char** argv)
+ : base::TestSuite(argc, argv, false) {
+ }
+};
+
+int RunTestSuite(int argc, char** argv) {
+ return NoAtExitBaseTestSuite(argc, argv).Run();
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+#if defined(OS_ANDROID)
+ JNIEnv* env = base::android::AttachCurrentThread();
+ file_util::RegisterContentUriTestUtils(env);
+#else
+ base::AtExitManager at_exit;
+#endif
+ return base::LaunchUnitTestsSerially(argc,
+ argv,
+ base::Bind(&RunTestSuite, argc, argv));
+}
diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc
index 7f513a3ab48..10df9b21441 100644
--- a/chromium/ipc/unix_domain_socket_util.cc
+++ b/chromium/ipc/unix_domain_socket_util.cc
@@ -84,7 +84,7 @@ bool CreateServerUnixDomainSocket(const base::FilePath& socket_path,
file_util::ScopedFD scoped_fd(&fd);
// Make sure the path we need exists.
- if (!file_util::CreateDirectory(socket_dir)) {
+ if (!base::CreateDirectory(socket_dir)) {
LOG(ERROR) << "Couldn't create directory: " << socket_dir.value();
return false;
}