diff options
Diffstat (limited to 'ipc')
35 files changed, 0 insertions, 9396 deletions
diff --git a/ipc/file_descriptor_set_posix.cc b/ipc/file_descriptor_set_posix.cc deleted file mode 100644 index 3b04553..0000000 --- a/ipc/file_descriptor_set_posix.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/file_descriptor_set_posix.h" - -#include "base/logging.h" - -FileDescriptorSet::FileDescriptorSet() - : consumed_descriptor_highwater_(0) { -} - -FileDescriptorSet::~FileDescriptorSet() { - if (consumed_descriptor_highwater_ == descriptors_.size()) - return; - - LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors"; - // We close all the descriptors where the close flag is set. If this - // message should have been transmitted, then closing those with close - // flags set mirrors the expected behaviour. - // - // If this message was received with more descriptors than expected - // (which could a DOS against the browser by a rogue renderer) then all - // the descriptors have their close flag set and we free all the extra - // kernel resources. - for (unsigned i = consumed_descriptor_highwater_; - i < descriptors_.size(); ++i) { - if (descriptors_[i].auto_close) - close(descriptors_[i].fd); - } -} - -bool FileDescriptorSet::Add(int fd) { - if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) - return false; - - struct base::FileDescriptor sd; - sd.fd = fd; - sd.auto_close = false; - descriptors_.push_back(sd); - return true; -} - -bool FileDescriptorSet::AddAndAutoClose(int fd) { - if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE) - return false; - - struct base::FileDescriptor sd; - sd.fd = fd; - sd.auto_close = true; - descriptors_.push_back(sd); - DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE); - return true; -} - -int FileDescriptorSet::GetDescriptorAt(unsigned index) const { - if (index >= descriptors_.size()) - return -1; - - // We should always walk the descriptors in order, so it's reasonable to - // enforce this. Consider the case where a compromised renderer sends us - // the following message: - // - // ExampleMsg: - // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m} - // - // Here the renderer sent us a message which should have a descriptor, but - // actually sent two in an attempt to fill our fd table and kill us. By - // setting the index of the descriptor in the message to 1 (it should be - // 0), we would record a highwater of 1 and then consider all the - // descriptors to have been used. - // - // So we can either track of the use of each descriptor in a bitset, or we - // can enforce that we walk the indexes strictly in order. - // - // There's one more wrinkle: When logging messages, we may reparse them. So - // we have an exception: When the consumed_descriptor_highwater_ is at the - // end of the array and index 0 is requested, we reset the highwater value. - if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size()) - consumed_descriptor_highwater_ = 0; - - if (index != consumed_descriptor_highwater_) - return -1; - - consumed_descriptor_highwater_ = index + 1; - return descriptors_[index].fd; -} - -void FileDescriptorSet::GetDescriptors(int* buffer) const { - for (std::vector<base::FileDescriptor>::const_iterator - i = descriptors_.begin(); i != descriptors_.end(); ++i) { - *(buffer++) = i->fd; - } -} - -void FileDescriptorSet::CommitAll() { - for (std::vector<base::FileDescriptor>::iterator - i = descriptors_.begin(); i != descriptors_.end(); ++i) { - if (i->auto_close) - close(i->fd); - } - descriptors_.clear(); - consumed_descriptor_highwater_ = 0; -} - -void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) { - DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE); - DCHECK_EQ(descriptors_.size(), 0u); - DCHECK_EQ(consumed_descriptor_highwater_, 0u); - - descriptors_.reserve(count); - for (unsigned i = 0; i < count; ++i) { - struct base::FileDescriptor sd; - sd.fd = buffer[i]; - sd.auto_close = true; - descriptors_.push_back(sd); - } -} diff --git a/ipc/file_descriptor_set_posix.h b/ipc/file_descriptor_set_posix.h deleted file mode 100644 index c3d26ba8..0000000 --- a/ipc/file_descriptor_set_posix.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_FILE_DESCRIPTOR_SET_POSIX_H_ -#define IPC_FILE_DESCRIPTOR_SET_POSIX_H_ - -#include <vector> - -#include "base/basictypes.h" -#include "base/file_descriptor_posix.h" -#include "base/ref_counted.h" - -// ----------------------------------------------------------------------------- -// A FileDescriptorSet is an ordered set of POSIX file descriptors. These are -// associated with IPC messages so that descriptors can be transmitted over a -// UNIX domain socket. -// ----------------------------------------------------------------------------- -class FileDescriptorSet : public base::RefCountedThreadSafe<FileDescriptorSet> { - public: - FileDescriptorSet(); - ~FileDescriptorSet(); - - // This is the maximum number of descriptors per message. We need to know this - // because the control message kernel interface has to be given a buffer which - // is large enough to store all the descriptor numbers. Otherwise the kernel - // tells us that it truncated the control data and the extra descriptors are - // lost. - // - // In debugging mode, it's a fatal error to try and add more than this number - // of descriptors to a FileDescriptorSet. - enum { - MAX_DESCRIPTORS_PER_MESSAGE = 4, - }; - - // --------------------------------------------------------------------------- - // Interfaces for building during message serialisation... - - // Add a descriptor to the end of the set. Returns false iff the set is full. - bool Add(int fd); - // Add a descriptor to the end of the set and automatically close it after - // transmission. Returns false iff the set is full. - bool AddAndAutoClose(int fd); - - // --------------------------------------------------------------------------- - - - // --------------------------------------------------------------------------- - // Interfaces for accessing during message deserialisation... - - // Return the number of descriptors - unsigned size() const { return descriptors_.size(); } - // Return true if no unconsumed descriptors remain - bool empty() const { return descriptors_.empty(); } - // Fetch the nth descriptor from the beginning of the set. Code using this - // /must/ access the descriptors in order, except that it may wrap from the - // end to index 0 again. - // - // This interface is designed for the deserialising code as it doesn't - // support close flags. - // returns: file descriptor, or -1 on error - int GetDescriptorAt(unsigned n) const; - - // --------------------------------------------------------------------------- - - - // --------------------------------------------------------------------------- - // Interfaces for transmission... - - // Fill an array with file descriptors without 'consuming' them. CommitAll - // must be called after these descriptors have been transmitted. - // buffer: (output) a buffer of, at least, size() integers. - void GetDescriptors(int* buffer) const; - // This must be called after transmitting the descriptors returned by - // GetDescriptors. It marks all the descriptors as consumed and closes those - // which are auto-close. - void CommitAll(); - - // --------------------------------------------------------------------------- - - - // --------------------------------------------------------------------------- - // Interfaces for receiving... - - // Set the contents of the set from the given buffer. This set must be empty - // before calling. The auto-close flag is set on all the descriptors so that - // unconsumed descriptors are closed on destruction. - void SetDescriptors(const int* buffer, unsigned count); - - // --------------------------------------------------------------------------- - - private: - // A vector of descriptors and close flags. If this message is sent, then - // these descriptors are sent as control data. After sending, any descriptors - // with a true flag are closed. If this message has been received, then these - // are the descriptors which were received and all close flags are true. - std::vector<base::FileDescriptor> descriptors_; - - // This contains the index of the next descriptor which should be consumed. - // It's used in a couple of ways. Firstly, at destruction we can check that - // all the descriptors have been read (with GetNthDescriptor). Secondly, we - // can check that they are read in order. - mutable unsigned consumed_descriptor_highwater_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorSet); -}; - -#endif // IPC_FILE_DESCRIPTOR_SET_POSIX_H_ diff --git a/ipc/file_descriptor_set_unittest.cc b/ipc/file_descriptor_set_unittest.cc deleted file mode 100644 index 0d158b2..0000000 --- a/ipc/file_descriptor_set_unittest.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This test is POSIX only. - -#include <unistd.h> -#include <fcntl.h> - -#include "base/basictypes.h" -#include "ipc/file_descriptor_set_posix.h" -#include "testing/gtest/include/gtest/gtest.h" - -// The FileDescriptorSet will try and close some of the descriptor numbers -// which we given it. This is the base descriptor value. It's great enough such -// that no real descriptor will accidently be closed. -static const int kFDBase = 50000; - -TEST(FileDescriptorSet, BasicAdd) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_EQ(set->size(), 0u); - ASSERT_TRUE(set->empty()); - ASSERT_TRUE(set->Add(kFDBase)); - ASSERT_EQ(set->size(), 1u); - ASSERT_TRUE(!set->empty()); - - // Empties the set and stops a warning about deleting a set with unconsumed - // descriptors - set->CommitAll(); -} - -TEST(FileDescriptorSet, BasicAddAndClose) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_EQ(set->size(), 0u); - ASSERT_TRUE(set->empty()); - ASSERT_TRUE(set->AddAndAutoClose(kFDBase)); - ASSERT_EQ(set->size(), 1u); - ASSERT_TRUE(!set->empty()); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, MaxSize) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - for (unsigned i = 0; - i < FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; ++i) { - ASSERT_TRUE(set->Add(kFDBase + 1 + i)); - } - - ASSERT_TRUE(!set->Add(kFDBase)); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, SetDescriptors) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_TRUE(set->empty()); - set->SetDescriptors(NULL, 0); - ASSERT_TRUE(set->empty()); - - static const int fds[] = {kFDBase}; - set->SetDescriptors(fds, 1); - ASSERT_TRUE(!set->empty()); - ASSERT_EQ(set->size(), 1u); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, GetDescriptors) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - set->GetDescriptors(NULL); - ASSERT_TRUE(set->Add(kFDBase)); - - int fds[1]; - fds[0] = 0; - set->GetDescriptors(fds); - ASSERT_EQ(fds[0], kFDBase); - set->CommitAll(); - ASSERT_TRUE(set->empty()); -} - -TEST(FileDescriptorSet, WalkInOrder) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_TRUE(set->Add(kFDBase)); - ASSERT_TRUE(set->Add(kFDBase + 1)); - ASSERT_TRUE(set->Add(kFDBase + 2)); - - ASSERT_EQ(set->GetDescriptorAt(0), kFDBase); - ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1); - ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, WalkWrongOrder) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_TRUE(set->Add(kFDBase)); - ASSERT_TRUE(set->Add(kFDBase + 1)); - ASSERT_TRUE(set->Add(kFDBase + 2)); - - ASSERT_EQ(set->GetDescriptorAt(0), kFDBase); - ASSERT_EQ(set->GetDescriptorAt(2), -1); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, WalkCycle) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - ASSERT_TRUE(set->Add(kFDBase)); - ASSERT_TRUE(set->Add(kFDBase + 1)); - ASSERT_TRUE(set->Add(kFDBase + 2)); - - ASSERT_EQ(set->GetDescriptorAt(0), kFDBase); - ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1); - ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2); - ASSERT_EQ(set->GetDescriptorAt(0), kFDBase); - ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1); - ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2); - ASSERT_EQ(set->GetDescriptorAt(0), kFDBase); - ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1); - ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2); - - set->CommitAll(); -} - -TEST(FileDescriptorSet, DontClose) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - const int fd = open("/dev/null", O_RDONLY); - ASSERT_TRUE(set->Add(fd)); - set->CommitAll(); - - const int duped = dup(fd); - ASSERT_GE(duped, 0); - close(duped); - close(fd); -} - -TEST(FileDescriptorSet, DoClose) { - scoped_refptr<FileDescriptorSet> set = new FileDescriptorSet; - - const int fd = open("/dev/null", O_RDONLY); - ASSERT_TRUE(set->AddAndAutoClose(fd)); - set->CommitAll(); - - const int duped = dup(fd); - ASSERT_EQ(duped, -1); - close(fd); -} diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp deleted file mode 100644 index a2c1adc..0000000 --- a/ipc/ipc.gyp +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2009 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'chromium_code': 1, - }, - 'includes': [ - '../build/common.gypi', - ], - - 'targets': [ - { - 'target_name': 'ipc', - 'type': 'static_library', - 'dependencies': [ - '../base/base.gyp:base', - '../base/base.gyp:base_gfx', - ], - 'sources': [ - 'ipc_channel.h', - 'ipc_channel_proxy.cc', - 'ipc_channel_proxy.h', - 'ipc_counters.cc', - 'ipc_logging.cc', - 'ipc_logging.h', - 'ipc_message.cc', - 'ipc_message.h', - 'ipc_message_macros.h', - 'ipc_message_utils.cc', - 'ipc_message_utils.h', - 'ipc_sync_channel.cc', - 'ipc_sync_channel.h', - 'ipc_sync_message.cc', - 'ipc_sync_message.h', - 'ipc_switches.cc', - ], - - 'conditions': [ - ['OS=="linux"', {'sources': [ - 'ipc_channel_posix.cc', - 'ipc_channel_posix.h', - 'file_descriptor_set_posix.cc', - ]}], - ['OS=="mac"', {'sources': [ - 'ipc_channel_posix.cc', - 'ipc_channel_posix.h', - ]}], - ['OS=="win"', {'sources': [ - 'ipc_channel_win.cc', - 'ipc_channel_win.h', - ]}], - ], - }, - { - 'target_name': 'ipc_tests', - 'type': 'executable', - 'dependencies': [ - 'ipc', - '../base/base.gyp:base', - '../testing/gtest.gyp:gtest', - ], - 'sources': [ - 'ipc_fuzzing_tests.cc', - 'ipc_sync_channel_unittest.cc', - 'ipc_sync_message_unittest.cc', - 'ipc_sync_message_unittest.h', - 'ipc_tests.cc', - 'ipc_tests.h', - ], - 'conditions': [ - ['OS=="linux"', {'sources': [ - 'ipc_send_fds_test.cc', - ]}], - ['OS=="mac"', {'sources': [ - 'ipc_send_fds_test.cc', - ]}], - ], - }, - ], -} diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h deleted file mode 100644 index 1ecffdf..0000000 --- a/ipc/ipc_channel.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_CHANNEL_H_ -#define IPC_IPC_CHANNEL_H_ - -#include "ipc/ipc_message.h" - -namespace IPC { - -//------------------------------------------------------------------------------ - -class Channel : public Message::Sender { - // Security tests need access to the pipe handle. - friend class ChannelTest; - - public: - // Implemented by consumers of a Channel to receive messages. - class Listener { - public: - virtual ~Listener() {} - - // Called when a message is received. - virtual void OnMessageReceived(const Message& message) = 0; - - // Called when the channel is connected and we have received the internal - // Hello message from the peer. - virtual void OnChannelConnected(int32 peer_pid) {} - - // Called when an error is detected that causes the channel to close. - // This method is not called when a channel is closed normally. - virtual void OnChannelError() {} - }; - - enum Mode { - MODE_SERVER, - MODE_CLIENT - }; - - enum { - // The maximum message size in bytes. Attempting to receive a - // message of this size or bigger results in a channel error. - kMaximumMessageSize = 256 * 1024 * 1024, - - // Ammount of data to read at once from the pipe. - kReadBufferSize = 4 * 1024 - }; - - // Initialize a Channel. - // - // |channel_id| identifies the communication Channel. - // |mode| specifies whether this Channel is to operate in server mode or - // client mode. In server mode, the Channel is responsible for setting up the - // IPC object, whereas in client mode, the Channel merely connects to the - // already established IPC object. - // |listener| receives a callback on the current thread for each newly - // received message. - // - Channel(const std::wstring& channel_id, Mode mode, Listener* listener); - - ~Channel(); - - // Connect the pipe. On the server side, this will initiate - // waiting for connections. On the client, it attempts to - // connect to a pre-existing pipe. Note, calling Connect() - // will not block the calling thread and may complete - // asynchronously. - bool Connect(); - - // Close this Channel explicitly. May be called multiple times. - void Close(); - - // Modify the Channel's listener. - void set_listener(Listener* listener); - - // Send a message over the Channel to the listener on the other end. - // - // |message| must be allocated using operator new. This object will be - // deleted once the contents of the Message have been sent. - // - // FIXME bug 551500: the channel does not notice failures, so if the - // renderer crashes, it will silently succeed, leaking the parameter. - // At least the leak will be fixed by... - // - virtual bool Send(Message* message); - -#if defined(OS_POSIX) - // On POSIX an IPC::Channel wraps a socketpair(), this method returns the - // FD # for the client end of the socket and the equivalent FD# to use for - // mapping it into the Child process. - // This method may only be called on the server side of a channel. - // - // If the kTestingChannelID flag is specified on the command line then - // a named FIFO is used as the channel transport mechanism rather than a - // socketpair() in which case this method returns -1 for both parameters. - void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd); - - // Call this method on the server side of the IPC Channel once a client is - // connected in order to close the client side of the socketpair(). - void OnClientConnected(); -#endif // defined(OS_POSIX) - - private: - // PIMPL to which all channel calls are delegated. - class ChannelImpl; - ChannelImpl *channel_impl_; - - // 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). - 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. - }; -}; - -} // namespace IPC - -#endif // IPC_IPC_CHANNEL_H_ diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc deleted file mode 100644 index 96209a0..0000000 --- a/ipc/ipc_channel_posix.cc +++ /dev/null @@ -1,803 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_channel_posix.h" - -#include <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> - -#include <string> -#include <map> - -#include "base/command_line.h" -#include "base/lock.h" -#include "base/logging.h" -#include "base/process_util.h" -#include "base/scoped_ptr.h" -#include "base/string_util.h" -#include "base/singleton.h" -#include "ipc/ipc_counters.h" -#include "ipc/ipc_switches.h" -#include "ipc/file_descriptor_set_posix.h" -#include "ipc/ipc_logging.h" -#include "ipc/ipc_message_utils.h" - -namespace IPC { - -//------------------------------------------------------------------------------ -namespace { - -// When running as a browser, we install the client socket in a specific file -// descriptor number (@kClientChannelFd). However, we also have to support the -// case where we are running unittests in the same process. -// -// We do not support forking without execing. -// -// Case 1: normal running -// The IPC server object will install a mapping in PipeMap from the -// name which it was given to the client pipe. When forking the client, the -// GetClientFileDescriptorMapping will ensure that the socket is installed in -// the magic slot (@kClientChannelFd). The client will search for the -// mapping, but it won't find any since we are in a new process. Thus the -// magic fd number is returned. Once the client connects, the server will -// close it's copy of the client socket and remove the mapping. -// -// Case 2: unittests - client and server in the same process -// The IPC server will install a mapping as before. The client will search -// for a mapping and find out. It duplicates the file descriptor and -// connects. Once the client connects, the server will close the original -// copy of the client socket and remove the mapping. Thus, when the client -// object closes, it will close the only remaining copy of the client socket -// in the fd table and the server will see EOF on its side. -// -// TODO(port): a client process cannot connect to multiple IPC channels with -// this scheme. - -class PipeMap { - public: - // Lookup a given channel id. Return -1 if not found. - int Lookup(const std::string& channel_id) { - AutoLock locked(lock_); - - ChannelToFDMap::const_iterator i = map_.find(channel_id); - if (i == map_.end()) - return -1; - return i->second; - } - - // Remove the mapping for the given channel id. No error is signaled if the - // channel_id doesn't exist - void Remove(const std::string& channel_id) { - AutoLock locked(lock_); - - ChannelToFDMap::iterator i = map_.find(channel_id); - if (i != map_.end()) - map_.erase(i); - } - - // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a - // mapping if one already exists for the given channel_id - void Insert(const std::string& channel_id, int fd) { - AutoLock locked(lock_); - DCHECK(fd != -1); - - ChannelToFDMap::const_iterator i = map_.find(channel_id); - CHECK(i == map_.end()) << "Creating second IPC server for '" - << channel_id - << "' while first still exists"; - map_[channel_id] = fd; - } - - private: - Lock lock_; - typedef std::map<std::string, int> ChannelToFDMap; - ChannelToFDMap map_; -}; - -// This is the file descriptor number that a client process expects to find its -// IPC socket. -static const int kClientChannelFd = 3; - -// Used to map a channel name to the equivalent FD # in the client process. -int ChannelNameToClientFD(const std::string& channel_id) { - // See the large block comment above PipeMap for the reasoning here. - const int fd = Singleton<PipeMap>()->Lookup(channel_id); - if (fd != -1) - return dup(fd); - - // If we don't find an entry, we assume that the correct value has been - // inserted in the magic slot. - return kClientChannelFd; -} - -//------------------------------------------------------------------------------ -sockaddr_un sizecheck; -const size_t kMaxPipeNameLength = sizeof(sizecheck.sun_path); - -// Creates a Fifo with the specified name ready to listen on. -bool CreateServerFifo(const std::string &pipe_name, int* server_listen_fd) { - DCHECK(server_listen_fd); - DCHECK_GT(pipe_name.length(), 0u); - DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); - - if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) { - return false; - } - - // Create socket. - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - return false; - } - - // Make socket non-blocking - if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - close(fd); - return false; - } - - // Delete any old FS instances. - unlink(pipe_name.c_str()); - - // Create unix_addr structure - struct sockaddr_un unix_addr; - memset(&unix_addr, 0, sizeof(unix_addr)); - unix_addr.sun_family = AF_UNIX; - snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str()); - size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(unix_addr.sun_path) + 1; - - // Bind the socket. - if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr), - unix_addr_len) != 0) { - close(fd); - return false; - } - - // Start listening on the socket. - const int listen_queue_length = 1; - if (listen(fd, listen_queue_length) != 0) { - close(fd); - return false; - } - - *server_listen_fd = fd; - return true; -} - -// Accept a connection on a fifo. -bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) { - DCHECK(server_socket); - - int accept_fd = accept(server_listen_fd, NULL, 0); - if (accept_fd < 0) - return false; - if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) { - close(accept_fd); - return false; - } - - *server_socket = accept_fd; - return true; -} - -bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) { - DCHECK(client_socket); - DCHECK_LT(pipe_name.length(), kMaxPipeNameLength); - - // Create socket. - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - LOG(ERROR) << "fd is invalid"; - return false; - } - - // Make socket non-blocking - if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - LOG(ERROR) << "fcntl failed"; - close(fd); - return false; - } - - // Create server side of socket. - struct sockaddr_un server_unix_addr; - memset(&server_unix_addr, 0, sizeof(server_unix_addr)); - server_unix_addr.sun_family = AF_UNIX; - snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s", - pipe_name.c_str()); - size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) + - strlen(server_unix_addr.sun_path) + 1; - - int ret_val = -1; - do { - ret_val = connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr), - server_unix_addr_len); - } while (ret_val == -1 && errno == EINTR); - if (ret_val != 0) { - close(fd); - return false; - } - - *client_socket = fd; - return true; -} - -} // namespace -//------------------------------------------------------------------------------ - -Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode, - Listener* listener) - : mode_(mode), - is_blocked_on_write_(false), - message_send_bytes_written_(0), - uses_fifo_(CommandLine::ForCurrentProcess()->HasSwitch( - switches::kIPCUseFIFO)), - server_listen_pipe_(-1), - pipe_(-1), - client_pipe_(-1), - listener_(listener), - waiting_connect_(true), - processing_incoming_(false), - factory_(this) { - if (!CreatePipe(channel_id, mode)) { - // The pipe may have been closed already. - LOG(WARNING) << "Unable to create pipe named \"" << channel_id << - "\" in " << (mode == MODE_SERVER ? "server" : "client") << - " mode error(" << strerror(errno) << ")."; - } -} - -const std::wstring Channel::ChannelImpl::PipeName( - const std::wstring& channel_id) const { - // TODO(playmobil): This should live in the Chrome user data directory. - // TODO(playmobil): Cleanup any stale fifos. - return L"/var/tmp/chrome_" + channel_id; -} - -bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, - Mode mode) { - DCHECK(server_listen_pipe_ == -1 && pipe_ == -1); - pipe_name_ = WideToUTF8(PipeName(channel_id)); - - if (uses_fifo_) { - // TODO(playmobil): Should we just change pipe_name to be a normal string - // everywhere? - - if (mode == MODE_SERVER) { - if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) { - return false; - } - } else { - if (!ClientConnectToFifo(pipe_name_, &pipe_)) { - return false; - } - waiting_connect_ = false; - } - } else { - // socketpair() - if (mode == MODE_SERVER) { - int pipe_fds[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) { - return false; - } - // Set both ends to be non-blocking. - if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || - fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { - close(pipe_fds[0]); - close(pipe_fds[1]); - return false; - } - pipe_ = pipe_fds[0]; - client_pipe_ = pipe_fds[1]; - - Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_); - } else { - pipe_ = ChannelNameToClientFD(pipe_name_); - DCHECK(pipe_ > 0); - waiting_connect_ = false; - } - } - - // Create the Hello message to be sent when Connect is called - scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE, - HELLO_MESSAGE_TYPE, - IPC::Message::PRIORITY_NORMAL)); - if (!msg->WriteInt(base::GetCurrentProcId())) { - Close(); - return false; - } - - output_queue_.push(msg.release()); - return true; -} - -bool Channel::ChannelImpl::Connect() { - if (mode_ == MODE_SERVER && uses_fifo_) { - if (server_listen_pipe_ == -1) { - return false; - } - MessageLoopForIO::current()->WatchFileDescriptor( - server_listen_pipe_, - true, - MessageLoopForIO::WATCH_READ, - &server_listen_connection_watcher_, - this); - } else { - if (pipe_ == -1) { - return false; - } - MessageLoopForIO::current()->WatchFileDescriptor( - pipe_, - true, - MessageLoopForIO::WATCH_READ, - &read_watcher_, - this); - waiting_connect_ = false; - } - - if (!waiting_connect_) - return ProcessOutgoingMessages(); - return true; -} - -bool Channel::ChannelImpl::ProcessIncomingMessages() { - ssize_t bytes_read = 0; - - struct msghdr msg = {0}; - struct iovec iov = {input_buf_, Channel::kReadBufferSize}; - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = input_cmsg_buf_; - - for (;;) { - msg.msg_controllen = sizeof(input_cmsg_buf_); - - if (bytes_read == 0) { - if (pipe_ == -1) - return false; - - // Read from pipe. - // recvmsg() returns 0 if the connection has closed or EAGAIN if no data - // is waiting on the pipe. - do { - bytes_read = recvmsg(pipe_, &msg, MSG_DONTWAIT); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read < 0) { - if (errno == EAGAIN) { - return true; - } else { - LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno); - return false; - } - } else if (bytes_read == 0) { - // The pipe has closed... - Close(); - return false; - } - } - DCHECK(bytes_read); - - if (client_pipe_ != -1) { - Singleton<PipeMap>()->Remove(pipe_name_); - close(client_pipe_); - client_pipe_ = -1; - } - - // a pointer to an array of |num_wire_fds| file descriptors from the read - const int* wire_fds = NULL; - unsigned num_wire_fds = 0; - - // walk the list of control messages and, if we find an array of file - // descriptors, save a pointer to the array - - // This next if statement is to work around an OSX issue where - // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0. - // Here's a test case: - // - // int main() { - // struct msghdr msg; - // msg.msg_control = &msg; - // msg.msg_controllen = 0; - // if (CMSG_FIRSTHDR(&msg)) - // printf("Bug found!\n"); - // } - if (msg.msg_controllen > 0) { - // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0 - // and will return a pointer into nowhere. - for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); - DCHECK(payload_len % sizeof(int) == 0); - wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); - num_wire_fds = payload_len / 4; - - if (msg.msg_flags & MSG_CTRUNC) { - LOG(ERROR) << "SCM_RIGHTS message was truncated" - << " cmsg_len:" << cmsg->cmsg_len - << " fd:" << pipe_; - for (unsigned i = 0; i < num_wire_fds; ++i) - close(wire_fds[i]); - return false; - } - break; - } - } - } - - // Process messages from input buffer. - const char *p; - const char *end; - if (input_overflow_buf_.empty()) { - p = input_buf_; - end = p + bytes_read; - } else { - if (input_overflow_buf_.size() > - static_cast<size_t>(kMaximumMessageSize - bytes_read)) { - input_overflow_buf_.clear(); - LOG(ERROR) << "IPC message is too big"; - return false; - } - input_overflow_buf_.append(input_buf_, bytes_read); - p = input_overflow_buf_.data(); - end = p + input_overflow_buf_.size(); - } - - // A pointer to an array of |num_fds| file descriptors which includes any - // fds that have spilled over from a previous read. - const int* fds; - unsigned num_fds; - unsigned fds_i = 0; // the index of the first unused descriptor - - if (input_overflow_fds_.empty()) { - fds = wire_fds; - num_fds = num_wire_fds; - } else { - const size_t prev_size = input_overflow_fds_.size(); - input_overflow_fds_.resize(prev_size + num_wire_fds); - memcpy(&input_overflow_fds_[prev_size], wire_fds, - num_wire_fds * sizeof(int)); - fds = &input_overflow_fds_[0]; - num_fds = input_overflow_fds_.size(); - } - - while (p < end) { - const char* message_tail = Message::FindNext(p, end); - if (message_tail) { - int len = static_cast<int>(message_tail - p); - Message m(p, len); - if (m.header()->num_fds) { - // the message has file descriptors - const char* error = NULL; - if (m.header()->num_fds > num_fds - fds_i) { - // the message has been completely received, but we didn't get - // enough file descriptors. - error = "Message needs unreceived descriptors"; - } - - if (m.header()->num_fds > - FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) { - // There are too many descriptors in this message - error = "Message requires an excessive number of descriptors"; - } - - if (error) { - LOG(WARNING) << error - << " channel:" << this - << " message-type:" << m.type() - << " header()->num_fds:" << m.header()->num_fds - << " num_fds:" << num_fds - << " fds_i:" << fds_i; - // close the existing file descriptors so that we don't leak them - for (unsigned i = fds_i; i < num_fds; ++i) - close(fds[i]); - input_overflow_fds_.clear(); - // abort the connection - return false; - } - - m.file_descriptor_set()->SetDescriptors( - &fds[fds_i], m.header()->num_fds); - fds_i += m.header()->num_fds; - } -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "received message on channel @" << this << - " with type " << m.type(); -#endif - if (m.routing_id() == MSG_ROUTING_NONE && - m.type() == HELLO_MESSAGE_TYPE) { - // The Hello message contains only the process id. - listener_->OnChannelConnected(MessageIterator(m).NextInt()); - } else { - listener_->OnMessageReceived(m); - } - p = message_tail; - } else { - // Last message is partial. - break; - } - } - input_overflow_buf_.assign(p, end - p); - input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); - - // When the input data buffer is empty, the overflow fds should be too. If - // this is not the case, we probably have a rogue renderer which is trying - // to fill our descriptor table. - if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) { - // We close these descriptors in Close() - return false; - } - - bytes_read = 0; // Get more data. - } - - return true; -} - -bool Channel::ChannelImpl::ProcessOutgoingMessages() { - DCHECK(!waiting_connect_); // Why are we trying to send messages if there's - // no connection? - is_blocked_on_write_ = false; - - if (output_queue_.empty()) - return true; - - if (pipe_ == -1) - return false; - - // Write out all the messages we can till the write blocks or there are no - // more outgoing messages. - while (!output_queue_.empty()) { - Message* msg = output_queue_.front(); - - size_t amt_to_write = msg->size() - message_send_bytes_written_; - DCHECK(amt_to_write != 0); - const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + - message_send_bytes_written_; - ssize_t bytes_written = -1; - do { - struct msghdr msgh = {0}; - struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write}; - msgh.msg_iov = &iov; - msgh.msg_iovlen = 1; - char buf[CMSG_SPACE( - sizeof(int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))]; - - if (message_send_bytes_written_ == 0 && - !msg->file_descriptor_set()->empty()) { - // This is the first chunk of a message which has descriptors to send - struct cmsghdr *cmsg; - const unsigned num_fds = msg->file_descriptor_set()->size(); - - DCHECK_LE(num_fds, FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE); - - msgh.msg_control = buf; - msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); - cmsg = CMSG_FIRSTHDR(&msgh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); - msg->file_descriptor_set()->GetDescriptors( - reinterpret_cast<int*>(CMSG_DATA(cmsg))); - msgh.msg_controllen = cmsg->cmsg_len; - - msg->header()->num_fds = num_fds; - } - - bytes_written = sendmsg(pipe_, &msgh, MSG_DONTWAIT); - if (bytes_written > 0) - msg->file_descriptor_set()->CommitAll(); - } while (bytes_written == -1 && errno == EINTR); - - if (bytes_written < 0 && errno != EAGAIN) { - LOG(ERROR) << "pipe error: " << strerror(errno); - return false; - } - - if (static_cast<size_t>(bytes_written) != amt_to_write) { - if (bytes_written > 0) { - // If write() fails with EAGAIN then bytes_written will be -1. - message_send_bytes_written_ += bytes_written; - } - - // Tell libevent to call us back once things are unblocked. - is_blocked_on_write_ = true; - MessageLoopForIO::current()->WatchFileDescriptor( - pipe_, - false, // One shot - MessageLoopForIO::WATCH_WRITE, - &write_watcher_, - this); - return true; - } else { - message_send_bytes_written_ = 0; - - // Message sent OK! -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "sent message @" << msg << " on channel @" << this << - " with type " << msg->type(); -#endif - output_queue_.pop(); - delete msg; - } - } - return true; -} - -bool Channel::ChannelImpl::Send(Message* message) { - Counters::ipc_send_counter().Increment(); -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "sending message @" << message << " on channel @" << this - << " with type " << message->type() - << " (" << output_queue_.size() << " in queue)"; -#endif - -#ifdef IPC_MESSAGE_LOG_ENABLED - Logging::current()->OnSendMessage(message, L""); -#endif - - output_queue_.push(message); - if (!waiting_connect_) { - if (!is_blocked_on_write_) { - if (!ProcessOutgoingMessages()) - return false; - } - } - - return true; -} - -void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd, - int *dest_fd) { - DCHECK(mode_ == MODE_SERVER); - *src_fd = client_pipe_; - *dest_fd = kClientChannelFd; -} - -void Channel::ChannelImpl::OnClientConnected() { - // WARNING: this isn't actually called when a client connects. - DCHECK(mode_ == MODE_SERVER); -} - -// Called by libevent when we can read from th pipe without blocking. -void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { - bool send_server_hello_msg = false; - if (waiting_connect_ && mode_ == MODE_SERVER) { - // In the case of a socketpair() the server starts listening on its end - // of the pipe in Connect(). - DCHECK(uses_fifo_); - - if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) { - Close(); - } - - // No need to watch the listening socket any longer since only one client - // can connect. So unregister with libevent. - server_listen_connection_watcher_.StopWatchingFileDescriptor(); - - // Start watching our end of the socket. - MessageLoopForIO::current()->WatchFileDescriptor( - pipe_, - true, - MessageLoopForIO::WATCH_READ, - &read_watcher_, - this); - - waiting_connect_ = false; - send_server_hello_msg = true; - } - - if (!waiting_connect_ && fd == pipe_) { - if (!ProcessIncomingMessages()) { - Close(); - listener_->OnChannelError(); - } - } - - // 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) { - // This should be our first write so there's no chance we can block here... - DCHECK(is_blocked_on_write_ == false); - ProcessOutgoingMessages(); - } -} - -// Called by libevent when we can write to the pipe without blocking. -void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { - if (!ProcessOutgoingMessages()) { - Close(); - listener_->OnChannelError(); - } -} - -void Channel::ChannelImpl::Close() { - // Close can be called multiple time, so we need to make sure we're - // idempotent. - - // Unregister libevent for the listening socket and close it. - server_listen_connection_watcher_.StopWatchingFileDescriptor(); - - if (server_listen_pipe_ != -1) { - close(server_listen_pipe_); - server_listen_pipe_ = -1; - } - - // Unregister libevent for the FIFO and close it. - read_watcher_.StopWatchingFileDescriptor(); - write_watcher_.StopWatchingFileDescriptor(); - if (pipe_ != -1) { - close(pipe_); - pipe_ = -1; - } - if (client_pipe_ != -1) { - Singleton<PipeMap>()->Remove(pipe_name_); - close(client_pipe_); - client_pipe_ = -1; - } - - // Unlink the FIFO - unlink(pipe_name_.c_str()); - - while (!output_queue_.empty()) { - Message* m = output_queue_.front(); - output_queue_.pop(); - delete m; - } - - // Close any outstanding, received file descriptors - for (std::vector<int>::iterator - i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) { - close(*i); - } - input_overflow_fds_.clear(); -} - -//------------------------------------------------------------------------------ -// Channel's methods simply call through to ChannelImpl. -Channel::Channel(const std::wstring& channel_id, Mode mode, - Listener* listener) - : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { -} - -Channel::~Channel() { - delete channel_impl_; -} - -bool Channel::Connect() { - return channel_impl_->Connect(); -} - -void Channel::Close() { - channel_impl_->Close(); -} - -void Channel::set_listener(Listener* listener) { - channel_impl_->set_listener(listener); -} - -bool Channel::Send(Message* message) { - return channel_impl_->Send(message); -} - -void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) { - return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd); -} - -void Channel::OnClientConnected() { - return channel_impl_->OnClientConnected(); -} - - -} // namespace IPC diff --git a/ipc/ipc_channel_posix.h b/ipc/ipc_channel_posix.h deleted file mode 100644 index 53fba1b9..0000000 --- a/ipc/ipc_channel_posix.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_CHANNEL_POSIX_H_ -#define IPC_IPC_CHANNEL_POSIX_H_ - -#include "ipc/ipc_channel.h" - -#include <sys/socket.h> // for CMSG macros - -#include <queue> -#include <string> -#include <vector> - -#include "base/message_loop.h" -#include "ipc/file_descriptor_set_posix.h" - -namespace IPC { - -class Channel::ChannelImpl : public MessageLoopForIO::Watcher { - public: - // Mirror methods of Channel, see ipc_channel.h for description. - ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener); - ~ChannelImpl() { Close(); } - bool Connect(); - void Close(); - void set_listener(Listener* listener) { listener_ = listener; } - bool Send(Message* message); - void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd); - void OnClientConnected(); - - private: - const std::wstring PipeName(const std::wstring& channel_id) const; - bool CreatePipe(const std::wstring& channel_id, Mode mode); - - bool ProcessIncomingMessages(); - bool ProcessOutgoingMessages(); - - void OnFileCanReadWithoutBlocking(int fd); - void OnFileCanWriteWithoutBlocking(int fd); - - Mode mode_; - - // After accepting one client connection on our server socket we want to - // stop listening. - MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_; - MessageLoopForIO::FileDescriptorWatcher read_watcher_; - MessageLoopForIO::FileDescriptorWatcher write_watcher_; - - // Indicates whether we're currently blocked waiting for a write to complete. - bool is_blocked_on_write_; - - // If sending a message blocks then we use this variable - // to keep track of where we are. - size_t message_send_bytes_written_; - - // If the kTestingChannelID flag is specified, we use a FIFO instead of - // a socketpair(). - bool uses_fifo_; - - int server_listen_pipe_; - int pipe_; - int client_pipe_; // The client end of our socketpair(). - std::string pipe_name_; - - Listener* listener_; - - // Messages to be sent are queued here. - std::queue<Message*> output_queue_; - - // We read from the pipe into this buffer - char input_buf_[Channel::kReadBufferSize]; - - enum { - // We assume a worst case: kReadBufferSize bytes of messages, where each - // message has no payload and a full complement of descriptors. - MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) * - FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE, - }; - - // This is a control message buffer large enough to hold kMaxReadFDs -#if defined(OS_MACOSX) - // TODO(agl): OSX appears to have non-constant CMSG macros! - char input_cmsg_buf_[1024]; -#else - char input_cmsg_buf_[CMSG_SPACE(sizeof(int) * MAX_READ_FDS)]; -#endif - - // Large messages that span multiple pipe buffers, get built-up using - // this buffer. - std::string input_overflow_buf_; - std::vector<int> input_overflow_fds_; - - // In server-mode, we have to wait for the client to connect before we - // can begin reading. We make use of the input_state_ when performing - // the connect operation in overlapped mode. - bool waiting_connect_; - - // This flag is set when processing incoming messages. It is used to - // avoid recursing through ProcessIncomingMessages, which could cause - // problems. TODO(darin): make this unnecessary - bool processing_incoming_; - - ScopedRunnableMethodFactory<ChannelImpl> factory_; - - DISALLOW_COPY_AND_ASSIGN(ChannelImpl); -}; - -} // namespace IPC - -#endif // IPC_IPC_CHANNEL_POSIX_H_ diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc deleted file mode 100644 index a07c677..0000000 --- a/ipc/ipc_channel_proxy.cc +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop.h" -#include "base/thread.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_logging.h" -#include "ipc/ipc_message_utils.h" - -namespace IPC { - -//----------------------------------------------------------------------------- - -ChannelProxy::Context::Context(Channel::Listener* listener, - MessageFilter* filter, - MessageLoop* ipc_message_loop) - : listener_message_loop_(MessageLoop::current()), - listener_(listener), - ipc_message_loop_(ipc_message_loop), - channel_(NULL), - peer_pid_(0), - channel_connected_called_(false) { - if (filter) - filters_.push_back(filter); -} - -void ChannelProxy::Context::CreateChannel(const std::wstring& id, - const Channel::Mode& mode) { - DCHECK(channel_ == NULL); - channel_id_ = id; - channel_ = new Channel(id, mode, this); -} - -bool ChannelProxy::Context::TryFilters(const Message& message) { -#ifdef IPC_MESSAGE_LOG_ENABLED - Logging* logger = Logging::current(); - if (logger->Enabled()) - logger->OnPreDispatchMessage(message); -#endif - - for (size_t i = 0; i < filters_.size(); ++i) { - if (filters_[i]->OnMessageReceived(message)) { -#ifdef IPC_MESSAGE_LOG_ENABLED - if (logger->Enabled()) - logger->OnPostDispatchMessage(message, channel_id_); -#endif - return true; - } - } - return false; -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnMessageReceived(const Message& message) { - // First give a chance to the filters to process this message. - if (!TryFilters(message)) - OnMessageReceivedNoFilter(message); -} - -// Called on the IPC::Channel thread -void 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_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &Context::OnDispatchMessage, message)); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { - peer_pid_ = peer_pid; - for (size_t i = 0; i < filters_.size(); ++i) - filters_[i]->OnChannelConnected(peer_pid); - - // See above comment about using listener_message_loop_ here. - listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &Context::OnDispatchConnected)); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnChannelError() { - // See above comment about using listener_message_loop_ here. - listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &Context::OnDispatchError)); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnChannelOpened() { - DCHECK(channel_ != NULL); - - // Assume a reference to ourselves on behalf of this thread. This reference - // will be released when we are closed. - AddRef(); - - if (!channel_->Connect()) { - OnChannelError(); - return; - } - - for (size_t i = 0; i < filters_.size(); ++i) - filters_[i]->OnFilterAdded(channel_); -} - -// Called on the IPC::Channel thread -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_) - return; - - for (size_t i = 0; i < filters_.size(); ++i) { - filters_[i]->OnChannelClosing(); - filters_[i]->OnFilterRemoved(); - } - - // We don't need the filters anymore. - filters_.clear(); - - delete channel_; - channel_ = NULL; - - // Balance with the reference taken during startup. This may result in - // self-destruction. - Release(); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnSendMessage(Message* message) { - if (!channel_->Send(message)) - OnChannelError(); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) { - filters_.push_back(filter); - - // 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_) - filter->OnFilterAdded(channel_); - - // Balances the AddRef in ChannelProxy::AddFilter. - filter->Release(); -} - -// Called on the IPC::Channel thread -void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { - for (size_t i = 0; i < filters_.size(); ++i) { - if (filters_[i].get() == filter) { - filter->OnFilterRemoved(); - filters_.erase(filters_.begin() + i); - return; - } - } - - NOTREACHED() << "filter to be removed not found"; -} - -// Called on the listener's thread -void ChannelProxy::Context::OnDispatchMessage(const Message& message) { - if (!listener_) - return; - - OnDispatchConnected(); - -#ifdef IPC_MESSAGE_LOG_ENABLED - Logging* logger = Logging::current(); - if (message.type() == IPC_LOGGING_ID) { - logger->OnReceivedLoggingMessage(message); - return; - } - - if (logger->Enabled()) - logger->OnPreDispatchMessage(message); -#endif - - listener_->OnMessageReceived(message); - -#ifdef IPC_MESSAGE_LOG_ENABLED - if (logger->Enabled()) - logger->OnPostDispatchMessage(message, channel_id_); -#endif -} - -// Called on the listener's thread -void ChannelProxy::Context::OnDispatchConnected() { - if (channel_connected_called_) - return; - - channel_connected_called_ = true; - if (listener_) - listener_->OnChannelConnected(peer_pid_); -} - -// Called on the listener's thread -void ChannelProxy::Context::OnDispatchError() { - if (listener_) - listener_->OnChannelError(); -} - -//----------------------------------------------------------------------------- - -ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, - Channel::Listener* listener, MessageFilter* filter, - MessageLoop* ipc_thread) - : context_(new Context(listener, filter, ipc_thread)) { - Init(channel_id, mode, ipc_thread, true); -} - -ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, - MessageLoop* ipc_thread, Context* context, - bool create_pipe_now) - : context_(context) { - Init(channel_id, mode, ipc_thread, create_pipe_now); -} - -void ChannelProxy::Init(const std::wstring& channel_id, Channel::Mode mode, - MessageLoop* ipc_thread_loop, bool create_pipe_now) { - if (create_pipe_now) { - // Create the channel immediately. This effectively sets up the - // low-level pipe so that the client can connect. Without creating - // the pipe immediately, it is possible for a listener to attempt - // to connect and get an error since the pipe doesn't exist yet. - context_->CreateChannel(channel_id, mode); - } else { -#if defined(OS_POSIX) - // TODO(playmobil): On POSIX, IPC::Channel uses a socketpair(), one side of - // which needs to be mapped into the child process' address space. - // To know the value of the client side FD we need to have already - // created a socketpair which currently occurs in IPC::Channel's - // constructor. - // If we lazilly construct the IPC::Channel then the caller has no way - // of knowing the FD #. - // - // We can solve this either by having the Channel's creation launch the - // subprocess itself or by creating the socketpair() externally. - NOTIMPLEMENTED(); -#endif // defined(OS_POSIX) - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::CreateChannel, channel_id, mode)); - } - - // complete initialization on the background thread - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::OnChannelOpened)); -} - -void ChannelProxy::Close() { - // Clear the backpointer to the listener so that any pending calls to - // Context::OnDispatchMessage or OnDispatchError will be ignored. It is - // possible that the channel could be closed while it is receiving messages! - context_->Clear(); - - if (context_->ipc_message_loop()) { - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::OnChannelClosed)); - } -} - -bool ChannelProxy::Send(Message* message) { -#ifdef IPC_MESSAGE_LOG_ENABLED - Logging::current()->OnSendMessage(message, context_->channel_id()); -#endif - - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::OnSendMessage, message)); - return true; -} - -void ChannelProxy::AddFilter(MessageFilter* filter) { - // We want to addref the filter to prevent it from - // being destroyed before the OnAddFilter call is invoked. - filter->AddRef(); - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::OnAddFilter, filter)); -} - -void ChannelProxy::RemoveFilter(MessageFilter* filter) { - context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - context_.get(), &Context::OnRemoveFilter, filter)); -} - -#if defined(OS_POSIX) -// See the TODO regarding lazy initialization of the channel in -// ChannelProxy::Init(). -// We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe. -void ChannelProxy::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) { - Channel *channel = context_.get()->channel_; - DCHECK(channel); // Channel must have been created first. - channel->GetClientFileDescriptorMapping(src_fd, dest_fd); -} - -// We assume that IP::Channel::OnClientConnected() is thread-safe. -void ChannelProxy::OnClientConnected() { - Channel *channel = context_.get()->channel_; - DCHECK(channel); // Channel must have been created first. - channel->OnClientConnected(); -} -#endif - -//----------------------------------------------------------------------------- - -} // namespace IPC diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h deleted file mode 100644 index 7f78a7e..0000000 --- a/ipc/ipc_channel_proxy.h +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_CHANNEL_PROXY_H__ -#define IPC_IPC_CHANNEL_PROXY_H__ - -#include <vector> -#include "base/lock.h" -#include "base/ref_counted.h" -#include "ipc/ipc_channel.h" - -class MessageLoop; - -namespace IPC { - -//----------------------------------------------------------------------------- -// IPC::ChannelProxy -// -// This class is a helper class that is useful when you wish to run an IPC -// channel on a background thread. It provides you with the option of either -// handling IPC messages on that background thread or having them dispatched to -// your main thread (the thread on which the IPC::ChannelProxy is created). -// -// The API for an IPC::ChannelProxy is very similar to that of an IPC::Channel. -// When you send a message to an IPC::ChannelProxy, the message is routed to -// the background thread, where it is then passed to the IPC::Channel's Send -// method. This means that you can send a message from your thread and your -// message will be sent over the IPC channel when possible instead of being -// delayed until your thread returns to its message loop. (Often IPC messages -// will queue up on the IPC::Channel when there is a lot of traffic, and the -// channel will not get cycles to flush its message queue until the thread, on -// which it is running, returns to its message loop.) -// -// An IPC::ChannelProxy can have a MessageFilter associated with it, which will -// be notified of incoming messages on the IPC::Channel's thread. This gives -// the consumer of IPC::ChannelProxy the ability to respond to incoming -// messages on this background thread instead of on their own thread, which may -// be bogged down with other processing. The result can be greatly improved -// latency for messages that can be handled on a background thread. -// -// The consumer of IPC::ChannelProxy is responsible for allocating the Thread -// instance where the IPC::Channel will be created and operated. -// -class ChannelProxy : public Message::Sender { - 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 MessageFilter : public base::RefCountedThreadSafe<MessageFilter> { - public: - virtual ~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 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) { - return false; - } - }; - - // Initializes a channel proxy. The channel_id 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 - // method is called on the thread where the IPC::Channel is running. The - // filter may be null if the consumer is not interested in handling messages - // on the background thread. Any message not handled by the filter will be - // dispatched to the listener. The given message loop indicates where the - // IPC::Channel should be created. - ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, - Channel::Listener* listener, MessageFilter* filter, - MessageLoop* ipc_thread_loop); - - ~ChannelProxy() { - Close(); - } - - // Close the IPC::Channel. This operation completes asynchronously, once the - // 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 - // 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. - void Close(); - - // Send a message asynchronously. The message is routed to the background - // thread where it is passed to the IPC::Channel's Send method. - virtual bool Send(Message* message); - - // Used to intercept messages as they are received on the background thread. - // - // Ordinarily, messages sent to the ChannelProxy are routed to the matching - // listener on the worker thread. This API allows code to intercept messages - // before they are sent to the worker thread. - void AddFilter(MessageFilter* filter); - void RemoveFilter(MessageFilter* filter); - -#if defined(OS_POSIX) - // Calls through to the underlying channel's methods. - // TODO(playmobil): For now this is only implemented in the case of - // create_pipe_now = true, we need to figure this out for the latter case. - void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd); - void OnClientConnected(); -#endif // defined(OS_POSIX) - - protected: - class Context; - // A subclass uses this constructor if it needs to add more information - // to the internal state. If create_pipe_now is true, the pipe is created - // immediately. Otherwise it's created on the IO thread. - ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, - MessageLoop* ipc_thread_loop, Context* context, - bool create_pipe_now); - - // Used internally to hold state that is referenced on the IPC thread. - class Context : public base::RefCountedThreadSafe<Context>, - public Channel::Listener { - public: - Context(Channel::Listener* listener, MessageFilter* filter, - MessageLoop* ipc_thread); - virtual ~Context() { } - MessageLoop* ipc_message_loop() const { return ipc_message_loop_; } - const std::wstring& channel_id() const { return channel_id_; } - - // Dispatches a message on the listener thread. - void OnDispatchMessage(const Message& message); - - protected: - // IPC::Channel::Listener methods: - virtual void OnMessageReceived(const Message& message); - virtual void OnChannelConnected(int32 peer_pid); - virtual void OnChannelError(); - - // Like OnMessageReceived but doesn't try the filters. - void OnMessageReceivedNoFilter(const Message& message); - - // Gives the filters a chance at processing |message|. - // Returns true if the message was processed, false otherwise. - bool TryFilters(const Message& message); - - // Like Open and Close, but called on the IPC thread. - virtual void OnChannelOpened(); - virtual void OnChannelClosed(); - - // Called on the consumers thread when the ChannelProxy is closed. At that - // point the consumer is telling us that they don't want to receive any - // more messages, so we honor that wish by forgetting them! - virtual void Clear() { listener_ = NULL; } - - private: - friend class ChannelProxy; - // Create the Channel - void CreateChannel(const std::wstring& id, const Channel::Mode& mode); - - // Methods called via InvokeLater: - void OnSendMessage(Message* message_ptr); - void OnAddFilter(MessageFilter* filter); - void OnRemoveFilter(MessageFilter* filter); - void OnDispatchConnected(); - void OnDispatchError(); - - MessageLoop* listener_message_loop_; - Channel::Listener* listener_; - - // List of filters. This is only accessed on the IPC thread. - std::vector<scoped_refptr<MessageFilter> > filters_; - MessageLoop* ipc_message_loop_; - Channel* channel_; - std::wstring channel_id_; - int peer_pid_; - bool channel_connected_called_; - }; - - Context* context() { return context_; } - - private: - void Init(const std::wstring& channel_id, Channel::Mode mode, - MessageLoop* ipc_thread_loop, bool create_pipe_now); - - // By maintaining this indirection (ref-counted) to our internal state, we - // can safely be destroyed while the background thread continues to do stuff - // that involves this data. - scoped_refptr<Context> context_; -}; - -} // namespace IPC - -#endif // IPC_IPC_CHANNEL_PROXY_H__ diff --git a/ipc/ipc_channel_win.cc b/ipc/ipc_channel_win.cc deleted file mode 100644 index 950b140..0000000 --- a/ipc/ipc_channel_win.cc +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_channel_win.h" - -#include <windows.h> -#include <sstream> - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/non_thread_safe.h" -#include "base/win_util.h" -#include "ipc/ipc_counters.h" -#include "ipc/ipc_logging.h" -#include "ipc/ipc_message_utils.h" - -namespace IPC { -//------------------------------------------------------------------------------ - -Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) { - memset(&context.overlapped, 0, sizeof(context.overlapped)); - context.handler = channel; -} - -Channel::ChannelImpl::State::~State() { - COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), - starts_with_io_context); -} - -//------------------------------------------------------------------------------ - -Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode, - Listener* listener) - : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), - pipe_(INVALID_HANDLE_VALUE), - listener_(listener), - waiting_connect_(mode == MODE_SERVER), - processing_incoming_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) { - if (!CreatePipe(channel_id, mode)) { - // The pipe may have been closed already. - LOG(WARNING) << "Unable to create pipe named \"" << channel_id << - "\" in " << (mode == 0 ? "server" : "client") << " mode."; - } -} - -void Channel::ChannelImpl::Close() { - if (thread_check_.get()) { - DCHECK(thread_check_->CalledOnValidThread()); - } - - bool waited = false; - if (input_state_.is_pending || output_state_.is_pending) { - CancelIo(pipe_); - waited = true; - } - - // Closing the handle at this point prevents us from issuing more requests - // form OnIOCompleted(). - if (pipe_ != INVALID_HANDLE_VALUE) { - CloseHandle(pipe_); - pipe_ = INVALID_HANDLE_VALUE; - } - - // Make sure all IO has completed. - base::Time start = base::Time::Now(); - while (input_state_.is_pending || output_state_.is_pending) { - MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); - } - if (waited) { - // We want to see if we block the message loop for too long. - UMA_HISTOGRAM_TIMES("AsyncIO.IPCChannelClose", base::Time::Now() - start); - } - - while (!output_queue_.empty()) { - Message* m = output_queue_.front(); - output_queue_.pop(); - delete m; - } -} - -bool Channel::ChannelImpl::Send(Message* message) { - DCHECK(thread_check_->CalledOnValidThread()); - Counters::ipc_send_counter().Increment(); -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "sending message @" << message << " on channel @" << this - << " with type " << message->type() - << " (" << output_queue_.size() << " in queue)"; -#endif - -#ifdef IPC_MESSAGE_LOG_ENABLED - Logging::current()->OnSendMessage(message, L""); -#endif - - output_queue_.push(message); - // ensure waiting to write - if (!waiting_connect_) { - if (!output_state_.is_pending) { - if (!ProcessOutgoingMessages(NULL, 0)) - return false; - } - } - - return true; -} - -const std::wstring Channel::ChannelImpl::PipeName( - const std::wstring& channel_id) const { - std::wostringstream ss; - // XXX(darin): get application name from somewhere else - ss << L"\\\\.\\pipe\\chrome." << channel_id; - return ss.str(); -} - -bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, - Mode mode) { - DCHECK(pipe_ == INVALID_HANDLE_VALUE); - const std::wstring pipe_name = PipeName(channel_id); - if (mode == MODE_SERVER) { - SECURITY_ATTRIBUTES security_attributes = {0}; - security_attributes.bInheritHandle = FALSE; - security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); - if (!win_util::GetLogonSessionOnlyDACL( - reinterpret_cast<SECURITY_DESCRIPTOR**>( - &security_attributes.lpSecurityDescriptor))) { - NOTREACHED(); - } - - pipe_ = CreateNamedPipeW(pipe_name.c_str(), - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, - 1, // number of pipe instances - // output buffer size (XXX tune) - Channel::kReadBufferSize, - // input buffer size (XXX tune) - Channel::kReadBufferSize, - 5000, // timeout in milliseconds (XXX tune) - &security_attributes); - LocalFree(security_attributes.lpSecurityDescriptor); - } else { - pipe_ = CreateFileW(pipe_name.c_str(), - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION | - FILE_FLAG_OVERLAPPED, - NULL); - } - if (pipe_ == INVALID_HANDLE_VALUE) { - // If this process is being closed, the pipe may be gone already. - LOG(WARNING) << "failed to create pipe: " << GetLastError(); - return false; - } - - // Create the Hello message to be sent when Connect is called - scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE, - HELLO_MESSAGE_TYPE, - IPC::Message::PRIORITY_NORMAL)); - if (!m->WriteInt(GetCurrentProcessId())) { - CloseHandle(pipe_); - pipe_ = INVALID_HANDLE_VALUE; - return false; - } - - output_queue_.push(m.release()); - return true; -} - -bool Channel::ChannelImpl::Connect() { - DLOG(WARNING) << "Connect called twice"; - - if (!thread_check_.get()) - thread_check_.reset(new NonThreadSafe()); - - if (pipe_ == INVALID_HANDLE_VALUE) - return false; - - MessageLoopForIO::current()->RegisterIOHandler(pipe_, this); - - // Check to see if there is a client connected to our pipe... - if (waiting_connect_) - ProcessConnection(); - - if (!input_state_.is_pending) { - // Complete setup asynchronously. By not setting input_state_.is_pending - // to true, we indicate to OnIOCompleted that this is the special - // initialization signal. - MessageLoopForIO::current()->PostTask(FROM_HERE, factory_.NewRunnableMethod( - &Channel::ChannelImpl::OnIOCompleted, &input_state_.context, 0, 0)); - } - - if (!waiting_connect_) - ProcessOutgoingMessages(NULL, 0); - return true; -} - -bool Channel::ChannelImpl::ProcessConnection() { - DCHECK(thread_check_->CalledOnValidThread()); - if (input_state_.is_pending) - input_state_.is_pending = false; - - // Do we have a client connected to our pipe? - if (INVALID_HANDLE_VALUE == pipe_) - return false; - - BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped); - - DWORD err = GetLastError(); - if (ok) { - // Uhm, the API documentation says that this function should never - // return success when used in overlapped mode. - NOTREACHED(); - return false; - } - - switch (err) { - case ERROR_IO_PENDING: - input_state_.is_pending = true; - break; - case ERROR_PIPE_CONNECTED: - waiting_connect_ = false; - break; - default: - NOTREACHED(); - return false; - } - - return true; -} - -bool Channel::ChannelImpl::ProcessIncomingMessages( - MessageLoopForIO::IOContext* context, - DWORD bytes_read) { - DCHECK(thread_check_->CalledOnValidThread()); - if (input_state_.is_pending) { - input_state_.is_pending = false; - DCHECK(context); - - if (!context || !bytes_read) - return false; - } else { - // This happens at channel initialization. - DCHECK(!bytes_read && context == &input_state_.context); - } - - for (;;) { - if (bytes_read == 0) { - if (INVALID_HANDLE_VALUE == pipe_) - return false; - - // Read from pipe... - BOOL ok = ReadFile(pipe_, - input_buf_, - Channel::kReadBufferSize, - &bytes_read, - &input_state_.context.overlapped); - if (!ok) { - DWORD err = GetLastError(); - if (err == ERROR_IO_PENDING) { - input_state_.is_pending = true; - return true; - } - LOG(ERROR) << "pipe error: " << err; - return false; - } - input_state_.is_pending = true; - return true; - } - DCHECK(bytes_read); - - // Process messages from input buffer. - - const char* p, *end; - if (input_overflow_buf_.empty()) { - p = input_buf_; - end = p + bytes_read; - } else { - if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) { - input_overflow_buf_.clear(); - LOG(ERROR) << "IPC message is too big"; - return false; - } - input_overflow_buf_.append(input_buf_, bytes_read); - p = input_overflow_buf_.data(); - end = p + input_overflow_buf_.size(); - } - - while (p < end) { - const char* message_tail = Message::FindNext(p, end); - if (message_tail) { - int len = static_cast<int>(message_tail - p); - const Message m(p, len); -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "received message on channel @" << this << - " with type " << m.type(); -#endif - if (m.routing_id() == MSG_ROUTING_NONE && - m.type() == HELLO_MESSAGE_TYPE) { - // The Hello message contains only the process id. - listener_->OnChannelConnected(MessageIterator(m).NextInt()); - } else { - listener_->OnMessageReceived(m); - } - p = message_tail; - } else { - // Last message is partial. - break; - } - } - input_overflow_buf_.assign(p, end - p); - - bytes_read = 0; // Get more data. - } - - return true; -} - -bool Channel::ChannelImpl::ProcessOutgoingMessages( - MessageLoopForIO::IOContext* context, - DWORD bytes_written) { - DCHECK(!waiting_connect_); // Why are we trying to send messages if there's - // no connection? - DCHECK(thread_check_->CalledOnValidThread()); - - if (output_state_.is_pending) { - DCHECK(context); - output_state_.is_pending = false; - if (!context || bytes_written == 0) { - DWORD err = GetLastError(); - LOG(ERROR) << "pipe error: " << err; - return false; - } - // Message was sent. - DCHECK(!output_queue_.empty()); - Message* m = output_queue_.front(); - output_queue_.pop(); - delete m; - } - - if (output_queue_.empty()) - return true; - - if (INVALID_HANDLE_VALUE == pipe_) - return false; - - // Write to pipe... - Message* m = output_queue_.front(); - BOOL ok = WriteFile(pipe_, - m->data(), - m->size(), - &bytes_written, - &output_state_.context.overlapped); - if (!ok) { - DWORD err = GetLastError(); - if (err == ERROR_IO_PENDING) { - output_state_.is_pending = true; - -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "sent pending message @" << m << " on channel @" << - this << " with type " << m->type(); -#endif - - return true; - } - LOG(ERROR) << "pipe error: " << err; - return false; - } - -#ifdef IPC_MESSAGE_DEBUG_EXTRA - DLOG(INFO) << "sent message @" << m << " on channel @" << this << - " with type " << m->type(); -#endif - - output_state_.is_pending = true; - return true; -} - -void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context, - DWORD bytes_transfered, DWORD error) { - bool ok; - DCHECK(thread_check_->CalledOnValidThread()); - if (context == &input_state_.context) { - if (waiting_connect_) { - if (!ProcessConnection()) - return; - // We may have some messages queued up to send... - if (!output_queue_.empty() && !output_state_.is_pending) - ProcessOutgoingMessages(NULL, 0); - if (input_state_.is_pending) - return; - // else, fall-through and look for incoming messages... - } - // we don't support recursion through OnMessageReceived yet! - DCHECK(!processing_incoming_); - processing_incoming_ = true; - ok = ProcessIncomingMessages(context, bytes_transfered); - processing_incoming_ = false; - } else { - DCHECK(context == &output_state_.context); - ok = ProcessOutgoingMessages(context, bytes_transfered); - } - if (!ok && INVALID_HANDLE_VALUE != pipe_) { - // We don't want to re-enter Close(). - Close(); - listener_->OnChannelError(); - } -} - -//------------------------------------------------------------------------------ -// Channel's methods simply call through to ChannelImpl. -Channel::Channel(const std::wstring& channel_id, Mode mode, - Listener* listener) - : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { -} - -Channel::~Channel() { - delete channel_impl_; -} - -bool Channel::Connect() { - return channel_impl_->Connect(); -} - -void Channel::Close() { - channel_impl_->Close(); -} - -void Channel::set_listener(Listener* listener) { - channel_impl_->set_listener(listener); -} - -bool Channel::Send(Message* message) { - return channel_impl_->Send(message); -} - -} // namespace IPC diff --git a/ipc/ipc_channel_win.h b/ipc/ipc_channel_win.h deleted file mode 100644 index 998b7f8..0000000 --- a/ipc/ipc_channel_win.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_CHANNEL_WIN_H_ -#define IPC_IPC_CHANNEL_WIN_H_ - -#include "ipc/ipc_channel.h" - -#include <queue> -#include <string> - -#include "base/message_loop.h" - -class NonThreadSafe; - -namespace IPC { - -class Channel::ChannelImpl : public MessageLoopForIO::IOHandler { - public: - // Mirror methods of Channel, see ipc_channel.h for description. - ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener); - ~ChannelImpl() { Close(); } - bool Connect(); - void Close(); - void set_listener(Listener* listener) { listener_ = listener; } - bool Send(Message* message); - private: - const std::wstring PipeName(const std::wstring& channel_id) const; - bool CreatePipe(const std::wstring& channel_id, Mode mode); - - bool ProcessConnection(); - bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context, - DWORD bytes_read); - bool ProcessOutgoingMessages(MessageLoopForIO::IOContext* context, - DWORD bytes_written); - - // MessageLoop::IOHandler implementation. - virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, - DWORD bytes_transfered, DWORD error); - private: - struct State { - explicit State(ChannelImpl* channel); - ~State(); - MessageLoopForIO::IOContext context; - bool is_pending; - }; - - State input_state_; - State output_state_; - - HANDLE pipe_; - - Listener* listener_; - - // Messages to be sent are queued here. - std::queue<Message*> output_queue_; - - // We read from the pipe into this buffer - char input_buf_[Channel::kReadBufferSize]; - - // Large messages that span multiple pipe buffers, get built-up using - // this buffer. - std::string input_overflow_buf_; - - // In server-mode, we have to wait for the client to connect before we - // can begin reading. We make use of the input_state_ when performing - // the connect operation in overlapped mode. - bool waiting_connect_; - - // This flag is set when processing incoming messages. It is used to - // avoid recursing through ProcessIncomingMessages, which could cause - // problems. TODO(darin): make this unnecessary - bool processing_incoming_; - - ScopedRunnableMethodFactory<ChannelImpl> factory_; - - scoped_ptr<NonThreadSafe> thread_check_; - - DISALLOW_COPY_AND_ASSIGN(ChannelImpl); -}; - -} // namespace IPC - -#endif // IPC_IPC_CHANNEL_WIN_H_ diff --git a/ipc/ipc_counters.cc b/ipc/ipc_counters.cc deleted file mode 100644 index 29bf3b5..0000000 --- a/ipc/ipc_counters.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_counters.h" - -#include "base/stats_counters.h" - -namespace IPC { - -// Note: We use the construct-on-first-use pattern here, because we don't -// want to fight with any static initializer ordering problems later. -// The downside of this is that the objects don't ever get cleaned up. -// But they are small and this is okay. - -// Note: Because these are constructed on-first-use, there is a slight -// race condition - two threads could initialize the same counter. -// If this happened, the stats table would still work just fine; -// we'd leak the extraneous StatsCounter object once, and that -// would be it. But these are small objects, so this is ok. - -StatsCounter& Counters::ipc_send_counter() { - static StatsCounter* ctr = new StatsCounter("IPC.SendMsgCount"); - return *ctr; -} - -} // namespace IPC diff --git a/ipc/ipc_counters.h b/ipc/ipc_counters.h deleted file mode 100644 index 647632a..0000000 --- a/ipc/ipc_counters.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Counters used within the browser. - -#ifndef IPC_COMMON_IPC_COUNTERS_H_ -#define IPC_COMMON_IPC_COUNTERS_H_ - -class StatsCounter; - -namespace IPC { - -class Counters { - public: - // The number of messages sent on IPC channels. - static StatsCounter& ipc_send_counter(); -}; - -} // namespace IPC - -#endif // IPC_COMMON_IPC_COUNTERS_H_ diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc deleted file mode 100644 index 6b4f899..0000000 --- a/ipc/ipc_fuzzing_tests.cc +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stdio.h> -#include <iostream> -#include <string> -#include <sstream> - -#include "base/message_loop.h" -#include "base/platform_thread.h" -#include "base/process_util.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_tests.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -TEST(IPCMessageIntegrity, ReadBeyondBufferStr) { - //This was BUG 984408. - uint32 v1 = kuint32max - 1; - int v2 = 666; - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(v1)); - EXPECT_TRUE(m.WriteInt(v2)); - - void* iter = NULL; - std::string vs; - EXPECT_FALSE(m.ReadString(&iter, &vs)); -} - -TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) { - //This was BUG 984408. - uint32 v1 = kuint32max - 1; - int v2 = 777; - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(v1)); - EXPECT_TRUE(m.WriteInt(v2)); - - void* iter = NULL; - std::wstring vs; - EXPECT_FALSE(m.ReadWString(&iter, &vs)); -} - -TEST(IPCMessageIntegrity, ReadBytesBadIterator) { - // This was BUG 1035467. - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(1)); - EXPECT_TRUE(m.WriteInt(2)); - - void* iter = NULL; - const char* data = NULL; - EXPECT_FALSE(m.ReadBytes(&iter, &data, sizeof(int))); -} - -TEST(IPCMessageIntegrity, ReadVectorNegativeSize) { - // A slight variation of BUG 984408. Note that the pickling of vector<char> - // has a specialized template which is not vulnerable to this bug. So here - // try to hit the non-specialized case vector<P>. - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(-1)); // This is the count of elements. - EXPECT_TRUE(m.WriteInt(1)); - EXPECT_TRUE(m.WriteInt(2)); - EXPECT_TRUE(m.WriteInt(3)); - - std::vector<double> vec; - void* iter = 0; - EXPECT_FALSE(ReadParam(&m, &iter, &vec)); -} - -TEST(IPCMessageIntegrity, ReadVectorTooLarge1) { - // This was BUG 1006367. This is the large but positive length case. Again - // we try to hit the non-specialized case vector<P>. - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(0x21000003)); // This is the count of elements. - EXPECT_TRUE(m.WriteInt64(1)); - EXPECT_TRUE(m.WriteInt64(2)); - - std::vector<int64> vec; - void* iter = 0; - EXPECT_FALSE(ReadParam(&m, &iter, &vec)); -} - -TEST(IPCMessageIntegrity, ReadVectorTooLarge2) { - // This was BUG 1006367. This is the large but positive with an additional - // integer overflow when computing the actual byte size. Again we try to hit - // the non-specialized case vector<P>. - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(0x71000000)); // This is the count of elements. - EXPECT_TRUE(m.WriteInt64(1)); - EXPECT_TRUE(m.WriteInt64(2)); - - std::vector<int64> vec; - void* iter = 0; - EXPECT_FALSE(ReadParam(&m, &iter, &vec)); -} - -// We don't actually use the messages defined in this file, but we do this -// to get to the IPC macros. -#if 0 -// This for tools which parse #include lines, but cannot process when we -// include via a macro name. -#include "ipc/ipc_sync_message_unittest.h" -#endif -#define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h" -#include "ipc/ipc_message_macros.h" - -enum IPCMessageIds { - UNUSED_IPC_TYPE, - SERVER_FIRST_IPC_TYPE, // 1st Test message tag. - SERVER_SECOND_IPC_TYPE, // 2nd Test message tag. - SERVER_THIRD_IPC_TYPE, // 3rd Test message tag. - CLIENT_MALFORMED_IPC, // Sent to client if server detects bad message. - CLIENT_UNHANDLED_IPC // Sent to client if server detects unhanded IPC. -}; - -// Generic message class that is an int followed by a wstring. -class MsgClassIS : public IPC::MessageWithTuple< Tuple2<int, std::wstring> > { - public: - enum { ID = SERVER_FIRST_IPC_TYPE }; - MsgClassIS(const int& arg1, const std::wstring& arg2) - : IPC::MessageWithTuple< Tuple2<int, std::wstring> >( - MSG_ROUTING_CONTROL, ID, MakeTuple(arg1, arg2)) {} -}; - -// Generic message class that is a wstring followed by an int. -class MsgClassSI : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > { - public: - enum { ID = SERVER_SECOND_IPC_TYPE }; - MsgClassSI(const std::wstring& arg1, const int& arg2) - : IPC::MessageWithTuple< Tuple2<std::wstring, int> >( - MSG_ROUTING_CONTROL, ID, MakeTuple(arg1, arg2)) {} -}; - -// Message to create a mutex in the IPC server, using the received name. -class MsgDoMutex : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > { - public: - enum { ID = SERVER_THIRD_IPC_TYPE }; - MsgDoMutex(const std::wstring& mutex_name, const int& unused) - : IPC::MessageWithTuple< Tuple2<std::wstring, int> >( - MSG_ROUTING_CONTROL, ID, MakeTuple(mutex_name, unused)) {} -}; - -class SimpleListener : public IPC::Channel::Listener { - public: - SimpleListener() : other_(NULL) { - } - void Init(IPC::Message::Sender* s) { - other_ = s; - } - protected: - IPC::Message::Sender* other_; -}; - -enum { - FUZZER_ROUTING_ID = 5 -}; - -// The fuzzer server class. It runs in a child process and expects -// only two IPC calls; after that it exits the message loop which -// terminates the child process. -class FuzzerServerListener : public SimpleListener { - public: - FuzzerServerListener() : message_count_(2), pending_messages_(0) { - } - virtual void OnMessageReceived(const IPC::Message& msg) { - if (msg.routing_id() == MSG_ROUTING_CONTROL) { - ++pending_messages_; - IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg) - IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage) - IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage) - IPC_END_MESSAGE_MAP() - if (pending_messages_) { - // Probably a problem de-serializing the message. - ReplyMsgNotHandled(msg.type()); - } - } - } - - private: - void OnMsgClassISMessage(int value, const std::wstring& text) { - UseData(MsgClassIS::ID, value, text); - RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value); - Cleanup(); - } - - void OnMsgClassSIMessage(const std::wstring& text, int value) { - UseData(MsgClassSI::ID, value, text); - RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value); - Cleanup(); - } - - bool RoundtripAckReply(int routing, int type_id, int reply) { - IPC::Message* message = new IPC::Message(routing, type_id, - IPC::Message::PRIORITY_NORMAL); - message->WriteInt(reply + 1); - message->WriteInt(reply); - return other_->Send(message); - } - - void Cleanup() { - --message_count_; - --pending_messages_; - if (0 == message_count_) - MessageLoop::current()->Quit(); - } - - void ReplyMsgNotHandled(int type_id) { - RoundtripAckReply(FUZZER_ROUTING_ID, CLIENT_UNHANDLED_IPC, type_id); - Cleanup(); - } - - void UseData(int caller, int value, const std::wstring& text) { - std::wostringstream wos; - wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n"; - std::wstring output = wos.str(); - LOG(WARNING) << output.c_str(); - }; - - int message_count_; - int pending_messages_; -}; - -class FuzzerClientListener : public SimpleListener { - public: - FuzzerClientListener() : last_msg_(NULL) { - } - - virtual void OnMessageReceived(const IPC::Message& msg) { - last_msg_ = new IPC::Message(msg); - MessageLoop::current()->Quit(); - } - - bool ExpectMessage(int value, int type_id) { - if (!MsgHandlerInternal(type_id)) - return false; - int msg_value1 = 0; - int msg_value2 = 0; - void* iter = NULL; - if (!last_msg_->ReadInt(&iter, &msg_value1)) - return false; - if (!last_msg_->ReadInt(&iter, &msg_value2)) - return false; - if ((msg_value2 + 1) != msg_value1) - return false; - if (msg_value2 != value) - return false; - - delete last_msg_; - last_msg_ = NULL; - return true; - } - - bool ExpectMsgNotHandled(int type_id) { - return ExpectMessage(type_id, CLIENT_UNHANDLED_IPC); - } - - private: - bool MsgHandlerInternal(int type_id) { - MessageLoop::current()->Run(); - if (NULL == last_msg_) - return false; - if (FUZZER_ROUTING_ID != last_msg_->routing_id()) - return false; - return (type_id == last_msg_->type()); - }; - - IPC::Message* last_msg_; -}; - -// Runs the fuzzing server child mode. Returns when the preset number -// of messages have been received. -MULTIPROCESS_TEST_MAIN(RunFuzzServer) { - MessageLoopForIO main_message_loop; - FuzzerServerListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, &listener); - chan.Connect(); - listener.Init(&chan); - MessageLoop::current()->Run(); - return 0; -} - -class IPCFuzzingTest : public IPCChannelTest { -}; - -// This test makes sure that the FuzzerClientListener and FuzzerServerListener -// are working properly by generating two well formed IPC calls. -TEST_F(IPCFuzzingTest, SanityTest) { - FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - PlatformThread::Sleep(1000); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); - - IPC::Message* msg = NULL; - int value = 43; - msg = new MsgClassIS(value, L"expect 43"); - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID)); - - msg = new MsgClassSI(L"expect 44", ++value); - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID)); - - EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); - base::CloseProcessHandle(server_process); -} - -// This test uses a payload that is smaller than expected. -// This generates an error while unpacking the IPC buffer which in -// In debug this triggers an assertion and in release it is ignored(!!). Right -// after we generate another valid IPC to make sure framing is working -// properly. -#ifdef NDEBUG -TEST_F(IPCFuzzingTest, MsgBadPayloadShort) { - FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - PlatformThread::Sleep(1000); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); - - IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID, - IPC::Message::PRIORITY_NORMAL); - msg->WriteInt(666); - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID)); - - msg = new MsgClassSI(L"expect one", 1); - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID)); - - EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); - base::CloseProcessHandle(server_process); -} -#endif // NDEBUG - -// This test uses a payload that has too many arguments, but so the payload -// size is big enough so the unpacking routine does not generate an error as -// in the case of MsgBadPayloadShort test. -// This test does not pinpoint a flaw (per se) as by design we don't carry -// type information on the IPC message. -TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) { - FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - PlatformThread::Sleep(1000); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); - - IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID, - IPC::Message::PRIORITY_NORMAL); - msg->WriteWString(L"d"); - msg->WriteInt(0); - msg->WriteInt(0x65); // Extra argument. - - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID)); - - // Now send a well formed message to make sure the receiver wasn't - // thrown out of sync by the extra argument. - msg = new MsgClassIS(3, L"expect three"); - chan.Send(msg); - EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID)); - - EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); - base::CloseProcessHandle(server_process); -} - -// This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros. -class ServerMacroExTest { - public: - ServerMacroExTest() : unhandled_msgs_(0) { - } - 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_; -}; - -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; - -#ifdef NDEBUG - // 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 -} diff --git a/ipc/ipc_logging.cc b/ipc/ipc_logging.cc deleted file mode 100644 index baa9cc30f..0000000 --- a/ipc/ipc_logging.cc +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_logging.h" - -#include "base/command_line.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/string_util.h" -#include "base/thread.h" -#include "base/time.h" -#include "base/waitable_event.h" -#include "base/waitable_event_watcher.h" -#include "ipc/ipc_sync_message.h" -#include "ipc/ipc_switches.h" -#include "ipc/ipc_message_utils.h" - -#if defined(OS_POSIX) -#include "base/string_util.h" -#include <unistd.h> -#endif - -#ifdef IPC_MESSAGE_LOG_ENABLED - -using base::Time; - -// IPC::Logging is allocated as a singleton, so we don't need any kind of -// special retention program. -template <> -struct RunnableMethodTraits<IPC::Logging> { - static void RetainCallee(IPC::Logging*) {} - static void ReleaseCallee(IPC::Logging*) {} -}; - -namespace IPC { - -const wchar_t kLoggingEventName[] = L"ChromeIPCLog.%d"; -const int kLogSendDelayMs = 100; - -// We use a pointer to the function table to avoid any linker dependencies on -// all the traits used as IPC message parameters. -Logging::LogFunction *Logging::log_function_mapping_; - -Logging::Logging() - : logging_event_on_(NULL), - logging_event_off_(NULL), - enabled_(false), - queue_invoke_later_pending_(false), - sender_(NULL), - main_thread_(MessageLoop::current()), - consumer_(NULL) { - // Create an event for this browser instance that's set when logging is - // enabled, so child processes can know when logging is enabled. - -#if defined(OS_WIN) - // On Windows we have a couple of named events which switch logging on and - // off. - int browser_pid; - const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); - std::wstring process_type = - parsed_command_line.GetSwitchValue(switches::kProcessType); - if (process_type.empty()) { - browser_pid = GetCurrentProcessId(); - } else { - std::wstring channel_name = - parsed_command_line.GetSwitchValue(switches::kProcessChannelID); - - browser_pid = _wtoi(channel_name.c_str()); - DCHECK(browser_pid != 0); - } - - std::wstring event_name = GetEventName(browser_pid, true); - logging_event_on_.reset(new base::WaitableEvent( - CreateEvent(NULL, TRUE, FALSE, event_name.c_str()))); - - event_name = GetEventName(browser_pid, false); - logging_event_off_.reset(new base::WaitableEvent( - CreateEvent(NULL, TRUE, FALSE, event_name.c_str()))); - - RegisterWaitForEvent(true); -#elif defined(OS_POSIX) - if (getenv("CHROME_IPC_LOGGING")) - enabled_ = true; -#endif - - MessageLoop::current()->AddDestructionObserver(this); -} - -Logging::~Logging() { -} - -Logging* Logging::current() { - return Singleton<Logging>::get(); -} - -void Logging::RegisterWaitForEvent(bool enabled) { - watcher_.StopWatching(); - watcher_.StartWatching( - enabled ? logging_event_on_.get() : logging_event_off_.get(), this); -} - -void Logging::OnWaitableEventSignaled(base::WaitableEvent* event) { - enabled_ = event == logging_event_on_.get(); - RegisterWaitForEvent(!enabled_); -} - -void Logging::WillDestroyCurrentMessageLoop() { - watcher_.StopWatching(); -} - -// static -void Logging::SetLoggerFunctions(LogFunction *functions) { - log_function_mapping_ = functions; -} - -#if defined(OS_WIN) -std::wstring Logging::GetEventName(bool enabled) { - return current()->GetEventName(GetCurrentProcessId(), enabled); -} -#endif - -std::wstring Logging::GetEventName(int browser_pid, bool enabled) { - std::wstring result = StringPrintf(kLoggingEventName, browser_pid); - result += enabled ? L"on" : L"off"; - return result; -} - -void Logging::SetConsumer(Consumer* consumer) { - consumer_ = consumer; -} - -void Logging::Enable() { - logging_event_off_->Reset(); - logging_event_on_->Signal(); -} - -void Logging::Disable() { - logging_event_on_->Reset(); - logging_event_off_->Signal(); -} - -void Logging::OnSendLogs() { - queue_invoke_later_pending_ = false; - if (!sender_) - return; - - Message* msg = new Message( - MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL); - WriteParam(msg, queued_logs_); - queued_logs_.clear(); - sender_->Send(msg); -} - -void Logging::SetIPCSender(IPC::Message::Sender* sender) { - sender_ = sender; -} - -void Logging::OnReceivedLoggingMessage(const Message& message) { - std::vector<LogData> data; - void* iter = NULL; - if (!ReadParam(&message, &iter, &data)) - return; - - for (size_t i = 0; i < data.size(); ++i) { - Log(data[i]); - } -} - -void Logging::OnSendMessage(Message* message, const std::wstring& channel_id) { - if (!Enabled()) - return; - - if (message->is_reply()) { - LogData* data = message->sync_log_data(); - if (!data) - return; - - // This is actually the delayed reply to a sync message. Create a string - // of the output parameters, add it to the LogData that was earlier stashed - // with the reply, and log the result. - data->channel = channel_id; - GenerateLogData(L"", *message, data); - Log(*data); - delete data; - message->set_sync_log_data(NULL); - } else { - // If the time has already been set (i.e. by ChannelProxy), keep that time - // instead as it's more accurate. - if (!message->sent_time()) - message->set_sent_time(Time::Now().ToInternalValue()); - } -} - -void Logging::OnPreDispatchMessage(const Message& message) { - message.set_received_time(Time::Now().ToInternalValue()); -} - -void Logging::OnPostDispatchMessage(const Message& message, - const std::wstring& channel_id) { - if (!Enabled() || -#if defined(OS_WIN) - !message.sent_time() || -#endif - message.dont_log()) - return; - - LogData data; - GenerateLogData(channel_id, message, &data); - - if (MessageLoop::current() == main_thread_) { - Log(data); - } else { - main_thread_->PostTask(FROM_HERE, NewRunnableMethod( - this, &Logging::Log, data)); - } -} - -void Logging::GetMessageText(uint16 type, std::wstring* name, - const Message* message, - std::wstring* params) { - if (!log_function_mapping_) - return; - - int message_class = type >> 12; - if (log_function_mapping_[message_class] != NULL) { - log_function_mapping_[message_class](type, name, message, params); - } else { - DLOG(INFO) << "No logger function associated with message class " << - message_class; - } -} - -void Logging::Log(const LogData& data) { -#if defined(OS_WIN) - if (consumer_) { - // We're in the browser process. - consumer_->Log(data); - } else { - // We're in the renderer or plugin processes. - if (sender_) { - queued_logs_.push_back(data); - if (!queue_invoke_later_pending_) { - queue_invoke_later_pending_ = true; - MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( - this, &Logging::OnSendLogs), kLogSendDelayMs); - } - } - } -#elif defined(OS_POSIX) - // On POSIX, for now, we just dump the log to stderr - fprintf(stderr, "ipc %s %d %s %s %s\n", - WideToUTF8(data.channel).c_str(), - data.type, - WideToUTF8(data.flags).c_str(), - WideToUTF8(data.message_name).c_str(), - WideToUTF8(data.params).c_str()); -#endif -} - -void GenerateLogData(const std::wstring& channel, const Message& message, - LogData* data) { - if (message.is_reply()) { - // "data" should already be filled in. - std::wstring params; - Logging::GetMessageText(data->type, NULL, &message, ¶ms); - - if (!data->params.empty() && !params.empty()) - data->params += L", "; - - data->flags += L" DR"; - - data->params += params; - } else { - std::wstring flags; - if (message.is_sync()) - flags = L"S"; - - if (message.is_reply()) - flags += L"R"; - - if (message.is_reply_error()) - flags += L"E"; - - std::wstring params, message_name; - Logging::GetMessageText(message.type(), &message_name, &message, ¶ms); - - data->channel = channel; - data->type = message.type(); - data->flags = flags; - data->sent = message.sent_time(); - data->receive = message.received_time(); - data->dispatch = Time::Now().ToInternalValue(); - data->params = params; - data->message_name = message_name; - } -} - -} // namespace IPC - -#endif // IPC_MESSAGE_LOG_ENABLED diff --git a/ipc/ipc_logging.h b/ipc/ipc_logging.h deleted file mode 100644 index 4d8f81d4d..0000000 --- a/ipc/ipc_logging.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_LOGGING_H_ -#define IPC_IPC_LOGGING_H_ - -#include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. - -#ifdef IPC_MESSAGE_LOG_ENABLED - -#include "base/lock.h" -#include "base/message_loop.h" -#include "base/singleton.h" -#include "base/waitable_event_watcher.h" -#include "ipc/ipc_message_utils.h" - -class MessageLoop; - -namespace IPC { - -class Message; - -// One instance per process. Needs to be created on the main thread (the UI -// thread in the browser) but OnPreDispatchMessage/OnPostDispatchMessage -// can be called on other threads. -class Logging : public base::WaitableEventWatcher::Delegate, - public MessageLoop::DestructionObserver { - public: - // Implemented by consumers of log messages. - class Consumer { - public: - virtual void Log(const LogData& data) = 0; - }; - - void SetConsumer(Consumer* consumer); - - ~Logging(); - static Logging* current(); - - void Enable(); - void Disable(); - bool Enabled() const { return enabled_; } - - // Called by child processes to give the logger object the channel to send - // logging data to the browser process. - void SetIPCSender(Message::Sender* sender); - - // Called in the browser process when logging data from a child process is - // received. - void OnReceivedLoggingMessage(const Message& message); - - void OnSendMessage(Message* message, const std::wstring& channel_id); - void OnPreDispatchMessage(const Message& message); - void OnPostDispatchMessage(const Message& message, - const std::wstring& channel_id); - - // Returns the name of the logging enabled/disabled events so that the - // sandbox can add them to to the policy. If true, gets the name of the - // enabled event, if false, gets the name of the disabled event. - static std::wstring GetEventName(bool enabled); - - // Like the *MsgLog functions declared for each message class, except this - // calls the correct one based on the message type automatically. Defined in - // ipc_logging.cc. - static void GetMessageText(uint16 type, std::wstring* name, - const Message* message, std::wstring* params); - - // WaitableEventWatcher::Delegate implementation - void OnWaitableEventSignaled(base::WaitableEvent* event); - - // MessageLoop::DestructionObserver implementation - void WillDestroyCurrentMessageLoop(); - - typedef void (*LogFunction)(uint16 type, - std::wstring* name, - const Message* msg, - std::wstring* params); - - static void SetLoggerFunctions(LogFunction *functions); - - private: - friend struct DefaultSingletonTraits<Logging>; - Logging(); - - std::wstring GetEventName(int browser_pid, bool enabled); - void OnSendLogs(); - void Log(const LogData& data); - - void RegisterWaitForEvent(bool enabled); - - base::WaitableEventWatcher watcher_; - - scoped_ptr<base::WaitableEvent> logging_event_on_; - scoped_ptr<base::WaitableEvent> logging_event_off_; - bool enabled_; - - std::vector<LogData> queued_logs_; - bool queue_invoke_later_pending_; - - Message::Sender* sender_; - MessageLoop* main_thread_; - - Consumer* consumer_; - - static LogFunction *log_function_mapping_; -}; - -} // namespace IPC - -#endif // IPC_MESSAGE_LOG_ENABLED - -#endif // IPC_IPC_LOGGING_H_ diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc deleted file mode 100644 index 7a2b5cd..0000000 --- a/ipc/ipc_message.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_message.h" - -#include "base/logging.h" -#include "build/build_config.h" - -#if defined(OS_POSIX) -#include "ipc/file_descriptor_set_posix.h" -#endif - -namespace IPC { - -//------------------------------------------------------------------------------ - -Message::~Message() { -} - -Message::Message() - : Pickle(sizeof(Header)) { - header()->routing = header()->type = header()->flags = 0; -#if defined(OS_POSIX) - header()->num_fds = 0; -#endif - InitLoggingVariables(); -} - -Message::Message(int32 routing_id, uint16 type, PriorityValue priority) - : Pickle(sizeof(Header)) { - header()->routing = routing_id; - header()->type = type; - header()->flags = priority; -#if defined(OS_POSIX) - header()->num_fds = 0; -#endif - InitLoggingVariables(); -} - -Message::Message(const char* data, int data_len) : Pickle(data, data_len) { - InitLoggingVariables(); -} - -Message::Message(const Message& other) : Pickle(other) { - InitLoggingVariables(); -#if defined(OS_POSIX) - file_descriptor_set_ = other.file_descriptor_set_; -#endif -} - -void Message::InitLoggingVariables() { -#ifdef IPC_MESSAGE_LOG_ENABLED - received_time_ = 0; - dont_log_ = false; - log_data_ = NULL; -#endif -} - -Message& Message::operator=(const Message& other) { - *static_cast<Pickle*>(this) = other; -#if defined(OS_POSIX) - file_descriptor_set_ = other.file_descriptor_set_; -#endif - return *this; -} - -#ifdef IPC_MESSAGE_LOG_ENABLED -void Message::set_sent_time(int64 time) { - DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0); - header()->flags |= HAS_SENT_TIME_BIT; - WriteInt64(time); -} - -int64 Message::sent_time() const { - if ((header()->flags & HAS_SENT_TIME_BIT) == 0) - return 0; - - const char* data = end_of_payload(); - data -= sizeof(int64); - return *(reinterpret_cast<const int64*>(data)); -} - -void Message::set_received_time(int64 time) const { - received_time_ = time; -} -#endif - -#if defined(OS_POSIX) -bool Message::WriteFileDescriptor(const base::FileDescriptor& descriptor) { - // We write the index of the descriptor so that we don't have to - // keep the current descriptor as extra decoding state when deserialising. - WriteInt(file_descriptor_set()->size()); - if (descriptor.auto_close) { - return file_descriptor_set()->AddAndAutoClose(descriptor.fd); - } else { - return file_descriptor_set()->Add(descriptor.fd); - } -} - -bool Message::ReadFileDescriptor(void** iter, - base::FileDescriptor* descriptor) const { - int descriptor_index; - if (!ReadInt(iter, &descriptor_index)) - return false; - - FileDescriptorSet* file_descriptor_set = file_descriptor_set_.get(); - if (!file_descriptor_set) - return false; - - descriptor->fd = file_descriptor_set->GetDescriptorAt(descriptor_index); - descriptor->auto_close = false; - - return descriptor->fd >= 0; -} - -void Message::EnsureFileDescriptorSet() { - if (file_descriptor_set_.get() == NULL) - file_descriptor_set_ = new FileDescriptorSet; -} - -#endif - -} // namespace IPC diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h deleted file mode 100644 index 6357c0b..0000000 --- a/ipc/ipc_message.h +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_MESSAGE_H__ -#define IPC_IPC_MESSAGE_H__ - -#include <string> - -#include "base/basictypes.h" -#include "base/pickle.h" - -#ifndef NDEBUG -#define IPC_MESSAGE_LOG_ENABLED -#endif - -#if defined(OS_POSIX) -#include "base/ref_counted.h" -#endif - -namespace base { -class FileDescriptor; -} - -class FileDescriptorSet; - -namespace IPC { - -//------------------------------------------------------------------------------ - -class Channel; -class Message; -struct LogData; - -class Message : public Pickle { - public: - // Implemented by objects that can send IPC messages across a channel. - class Sender { - public: - virtual ~Sender() {} - - // Sends the given IPC message. The implementor takes ownership of the - // given Message regardless of whether or not this method succeeds. This - // is done to make this method easier to use. Returns true on success and - // false otherwise. - virtual bool Send(Message* msg) = 0; - }; - - enum PriorityValue { - PRIORITY_LOW = 1, - PRIORITY_NORMAL, - PRIORITY_HIGH - }; - - virtual ~Message(); - - Message(); - - // Initialize a message with a user-defined type, priority value, and - // destination WebView ID. - Message(int32 routing_id, uint16 type, PriorityValue priority); - - // Initializes a message from a const block of data. The data is not copied; - // instead the data is merely referenced by this message. Only const methods - // should be used on the message when initialized this way. - Message(const char* data, int data_len); - - Message(const Message& other); - Message& operator=(const Message& other); - - PriorityValue priority() const { - return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK); - } - - // True if this is a synchronous message. - bool is_sync() const { - return (header()->flags & SYNC_BIT) != 0; - } - - // Set this on a reply to a synchronous message. - void set_reply() { - header()->flags |= REPLY_BIT; - } - - bool is_reply() const { - return (header()->flags & REPLY_BIT) != 0; - } - - // Set this on a reply to a synchronous message to indicate that no receiver - // was found. - void set_reply_error() { - header()->flags |= REPLY_ERROR_BIT; - } - - bool is_reply_error() const { - return (header()->flags & REPLY_ERROR_BIT) != 0; - } - - // Normally when a receiver gets a message and they're blocked on a - // synchronous message Send, they buffer a message. Setting this flag causes - // the receiver to be unblocked and the message to be dispatched immediately. - void set_unblock(bool unblock) { - if (unblock) { - header()->flags |= UNBLOCK_BIT; - } else { - header()->flags &= ~UNBLOCK_BIT; - } - } - - bool should_unblock() const { - return (header()->flags & UNBLOCK_BIT) != 0; - } - - // Tells the receiver that the caller is pumping messages while waiting - // for the result. - bool is_caller_pumping_messages() const { - return (header()->flags & PUMPING_MSGS_BIT) != 0; - } - - uint16 type() const { - return header()->type; - } - - int32 routing_id() const { - return header()->routing; - } - - void set_routing_id(int32 new_id) { - header()->routing = new_id; - } - - template<class T> - static bool Dispatch(const Message* msg, T* obj, void (T::*func)()) { - (obj->*func)(); - return true; - } - - template<class T> - static bool Dispatch(const Message* msg, T* obj, void (T::*func)() const) { - (obj->*func)(); - return true; - } - - template<class T> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&)) { - (obj->*func)(*msg); - return true; - } - - template<class T> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&) const) { - (obj->*func)(*msg); - return true; - } - - // Used for async messages with no parameters. - static void Log(const Message* msg, std::wstring* l) { - } - - // Find the end of the message data that starts at range_start. Returns NULL - // if the entire message is not found in the given data range. - static const char* FindNext(const char* range_start, const char* range_end) { - return Pickle::FindNext(sizeof(Header), range_start, range_end); - } - -#if defined(OS_POSIX) - // On POSIX, a message supports reading / writing FileDescriptor objects. - // This is used to pass a file descriptor to the peer of an IPC channel. - - // Add a descriptor to the end of the set. Returns false iff the set is full. - bool WriteFileDescriptor(const base::FileDescriptor& descriptor); - // Get a file descriptor from the message. Returns false on error. - // iter: a Pickle iterator to the current location in the message. - bool ReadFileDescriptor(void** iter, base::FileDescriptor* descriptor) const; -#endif - -#ifdef IPC_MESSAGE_LOG_ENABLED - // Adds the outgoing time from Time::Now() at the end of the message and sets - // a bit to indicate that it's been added. - void set_sent_time(int64 time); - int64 sent_time() const; - - void set_received_time(int64 time) const; - int64 received_time() const { return received_time_; } - void set_output_params(const std::wstring& op) const { output_params_ = op; } - const std::wstring& output_params() const { return output_params_; } - // The following four functions are needed so we can log sync messages with - // delayed replies. We stick the log data from the sent message into the - // reply message, so that when it's sent and we have the output parameters - // we can log it. As such, we set a flag on the sent message to not log it. - void set_sync_log_data(LogData* data) const { log_data_ = data; } - LogData* sync_log_data() const { return log_data_; } - void set_dont_log() const { dont_log_ = true; } - bool dont_log() const { return dont_log_; } -#endif - - protected: - friend class Channel; - friend class MessageReplyDeserializer; - friend class SyncMessage; - - void set_sync() { - header()->flags |= SYNC_BIT; - } - - // flags - enum { - PRIORITY_MASK = 0x0003, - SYNC_BIT = 0x0004, - REPLY_BIT = 0x0008, - REPLY_ERROR_BIT = 0x0010, - UNBLOCK_BIT = 0x0020, - PUMPING_MSGS_BIT= 0x0040, - HAS_SENT_TIME_BIT = 0x0080, - }; - -#pragma pack(push, 2) - struct Header : Pickle::Header { - int32 routing; // ID of the view that this message is destined for - uint16 type; // specifies the user-defined message type - uint16 flags; // specifies control flags for the message -#if defined(OS_POSIX) - uint32 num_fds; // the number of descriptors included with this message -#endif - }; -#pragma pack(pop) - - Header* header() { - return headerT<Header>(); - } - const Header* header() const { - return headerT<Header>(); - } - - void InitLoggingVariables(); - -#if defined(OS_POSIX) - // The set of file descriptors associated with this message. - scoped_refptr<FileDescriptorSet> file_descriptor_set_; - - // Ensure that a FileDescriptorSet is allocated - void EnsureFileDescriptorSet(); - - FileDescriptorSet* file_descriptor_set() { - EnsureFileDescriptorSet(); - return file_descriptor_set_.get(); - } - const FileDescriptorSet* file_descriptor_set() const { - return file_descriptor_set_.get(); - } -#endif - -#ifdef IPC_MESSAGE_LOG_ENABLED - // Used for logging. - mutable int64 received_time_; - mutable std::wstring output_params_; - mutable LogData* log_data_; - mutable bool dont_log_; -#endif -}; - -//------------------------------------------------------------------------------ - -} // namespace IPC - -enum SpecialRoutingIDs { - // indicates that we don't have a routing ID yet. - MSG_ROUTING_NONE = -2, - - // indicates a general message not sent to a particular tab. - MSG_ROUTING_CONTROL = kint32max, -}; - -#define IPC_REPLY_ID 0xFFF0 // Special message id for replies -#define IPC_LOGGING_ID 0xFFF1 // Special message id for logging - -#endif // IPC_IPC_MESSAGE_H__ diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h deleted file mode 100644 index 8bddb7f..0000000 --- a/ipc/ipc_message_macros.h +++ /dev/null @@ -1,1140 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This header is meant to be included in multiple passes, hence no traditional -// header guard. -// -// In the first pass, IPC_MESSAGE_MACROS_ENUMS should be defined, which will -// create enums for each of the messages defined with the IPC_MESSAGE_* macros. -// -// In the second pass, either IPC_MESSAGE_MACROS_DEBUGSTRINGS or -// IPC_MESSAGE_MACROS_CLASSES should be defined (if both, DEBUGSTRINGS takes -// precedence). Only one .cc file should have DEBUGSTRINGS defined, as this -// will create helper functions mapping message types to strings. Having -// CLASSES defined will create classes for each of the messages defined with -// the IPC_MESSAGE_* macros. -// -// "Sync" messages are just synchronous calls, the Send() call doesn't return -// until a reply comes back. Input parameters are first (const TYPE&), and -// To declare a sync message, use the IPC_SYNC_ macros. The numbers at the -// end show how many input/output parameters there are (i.e. 1_2 is 1 in, 2 -// out). The caller does a Send([route id, ], in1, &out1, &out2). -// The receiver's handler function will be -// void OnSyncMessageName(const type1& in1, type2* out1, type3* out2) -// -// -// A caller can also send a synchronous message, while the receiver can respond -// at a later time. This is transparent from the sender's size. The receiver -// needs to use a different handler that takes in a IPC::Message* as the output -// type, stash the message, and when it has the data it can Send the message. -// -// Use the IPC_MESSAGE_HANDLER_DELAY_REPLY macro instead of IPC_MESSAGE_HANDLER -// IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncMessageName, -// OnSyncMessageName) -// -// The handler function will look like: -// void OnSyncMessageName(const type1& in1, IPC::Message* reply_msg); -// -// Receiver stashes the IPC::Message* pointer, and when it's ready, it does: -// ViewHostMsg_SyncMessageName::WriteReplyParams(reply_msg, out1, out2); -// Send(reply_msg); - -#include "ipc/ipc_message_utils.h" - -#ifndef MESSAGES_INTERNAL_FILE -#error This file should only be included by X_messages.h, which needs to define MESSAGES_INTERNAL_FILE first. -#endif - -#ifndef IPC_MESSAGE_MACROS_INCLUDE_BLOCK -#define IPC_MESSAGE_MACROS_INCLUDE_BLOCK - -// Multi-pass include of X_messages_internal.h. Preprocessor magic allows -// us to use 1 header to define the enums and classes for our render messages. -#define IPC_MESSAGE_MACROS_ENUMS -#include MESSAGES_INTERNAL_FILE - -#define IPC_MESSAGE_MACROS_CLASSES -#include MESSAGES_INTERNAL_FILE - -#ifdef IPC_MESSAGE_MACROS_LOG_ENABLED -#define IPC_MESSAGE_MACROS_LOG -#include MESSAGES_INTERNAL_FILE -#endif - -#undef MESSAGES_INTERNAL_FILE -#undef IPC_MESSAGE_MACROS_INCLUDE_BLOCK - -#endif - - -// Undefine the macros from the previous pass (if any). -#undef IPC_BEGIN_MESSAGES -#undef IPC_END_MESSAGES -#undef IPC_MESSAGE_CONTROL0 -#undef IPC_MESSAGE_CONTROL1 -#undef IPC_MESSAGE_CONTROL2 -#undef IPC_MESSAGE_CONTROL3 -#undef IPC_MESSAGE_CONTROL4 -#undef IPC_MESSAGE_CONTROL5 -#undef IPC_MESSAGE_ROUTED0 -#undef IPC_MESSAGE_ROUTED1 -#undef IPC_MESSAGE_ROUTED2 -#undef IPC_MESSAGE_ROUTED3 -#undef IPC_MESSAGE_ROUTED4 -#undef IPC_MESSAGE_ROUTED5 -#undef IPC_MESSAGE_ROUTED6 -#undef IPC_SYNC_MESSAGE_CONTROL0_0 -#undef IPC_SYNC_MESSAGE_CONTROL0_1 -#undef IPC_SYNC_MESSAGE_CONTROL0_2 -#undef IPC_SYNC_MESSAGE_CONTROL0_3 -#undef IPC_SYNC_MESSAGE_CONTROL1_0 -#undef IPC_SYNC_MESSAGE_CONTROL1_1 -#undef IPC_SYNC_MESSAGE_CONTROL1_2 -#undef IPC_SYNC_MESSAGE_CONTROL1_3 -#undef IPC_SYNC_MESSAGE_CONTROL2_0 -#undef IPC_SYNC_MESSAGE_CONTROL2_1 -#undef IPC_SYNC_MESSAGE_CONTROL2_2 -#undef IPC_SYNC_MESSAGE_CONTROL2_3 -#undef IPC_SYNC_MESSAGE_CONTROL3_1 -#undef IPC_SYNC_MESSAGE_CONTROL3_2 -#undef IPC_SYNC_MESSAGE_CONTROL3_3 -#undef IPC_SYNC_MESSAGE_CONTROL4_1 -#undef IPC_SYNC_MESSAGE_CONTROL4_2 -#undef IPC_SYNC_MESSAGE_ROUTED0_0 -#undef IPC_SYNC_MESSAGE_ROUTED0_1 -#undef IPC_SYNC_MESSAGE_ROUTED0_2 -#undef IPC_SYNC_MESSAGE_ROUTED0_3 -#undef IPC_SYNC_MESSAGE_ROUTED1_0 -#undef IPC_SYNC_MESSAGE_ROUTED1_1 -#undef IPC_SYNC_MESSAGE_ROUTED1_2 -#undef IPC_SYNC_MESSAGE_ROUTED1_3 -#undef IPC_SYNC_MESSAGE_ROUTED1_4 -#undef IPC_SYNC_MESSAGE_ROUTED2_0 -#undef IPC_SYNC_MESSAGE_ROUTED2_1 -#undef IPC_SYNC_MESSAGE_ROUTED2_2 -#undef IPC_SYNC_MESSAGE_ROUTED2_3 -#undef IPC_SYNC_MESSAGE_ROUTED3_0 -#undef IPC_SYNC_MESSAGE_ROUTED3_1 -#undef IPC_SYNC_MESSAGE_ROUTED3_2 -#undef IPC_SYNC_MESSAGE_ROUTED3_3 -#undef IPC_SYNC_MESSAGE_ROUTED4_0 -#undef IPC_SYNC_MESSAGE_ROUTED4_1 -#undef IPC_SYNC_MESSAGE_ROUTED4_2 - -#if defined(IPC_MESSAGE_MACROS_ENUMS) -#undef IPC_MESSAGE_MACROS_ENUMS - -// TODO(jabdelmalek): we're using the lowest 12 bits of type for the message -// id, and the highest 4 bits for the channel type. This constrains us to -// 16 channel types (currently using 8) and 4K messages per type. Should -// really make type be 32 bits, but then we break automation with older Chrome -// builds.. -// Do label##PreStart so that automation messages keep the same id as before. -#define IPC_BEGIN_MESSAGES(label) \ - enum label##MsgType { \ - label##Start = label##MsgStart << 12, \ - label##PreStart = (label##MsgStart << 12) - 1, - -#define IPC_END_MESSAGES(label) \ - label##End \ - }; - -#define IPC_MESSAGE_CONTROL0(msg_class) \ - msg_class##__ID, - -#define IPC_MESSAGE_CONTROL1(msg_class, type1) \ - msg_class##__ID, - -#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \ - msg_class##__ID, - -#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \ - msg_class##__ID, - -#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \ - msg_class##__ID, - -#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED0(msg_class) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED1(msg_class, type1) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \ - msg_class##__ID, - -#define IPC_MESSAGE_ROUTED6(msg_class, type1, type2, type3, type4, type5, type6) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - msg_class##__ID, - -#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - msg_class##__ID, - -// 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: -// -// void MyClass::OnMessageReceived(const IPC::Message& msg) { -// bool msg_is_good = false; -// IPC_BEGIN_MESSAGE_MAP_EX(MyClass, msg, msg_is_good) -// IPC_MESSAGE_HANDLER(MsgClassOne, OnMsgClassOne) -// ...more handlers here ... -// IPC_MESSAGE_HANDLER(MsgClassTen, OnMsgClassTen) -// IPC_END_MESSAGE_MAP_EX() -// if (!msg_is_good) { -// // Signal error here or terminate offending process. -// } -// } - -#define IPC_DEFINE_MESSAGE_MAP(class_name) \ -void class_name::OnMessageReceived(const IPC::Message& msg) \ - IPC_BEGIN_MESSAGE_MAP(class_name, msg) - -#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; \ - const IPC::Message& ipc_message__ = msg; \ - bool msg_is_ok__ = true; \ - switch (ipc_message__.type()) { \ - -#define IPC_MESSAGE_FORWARD(msg_class, obj, member_func) \ - case msg_class::ID: \ - msg_is_ok__ = msg_class::Dispatch(&ipc_message__, obj, &member_func); \ - break; - -#define IPC_MESSAGE_HANDLER(msg_class, member_func) \ - IPC_MESSAGE_FORWARD(msg_class, this, _IpcMessageHandlerClass::member_func) - -#define IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, obj, member_func) \ - case msg_class::ID: \ - msg_class::DispatchDelayReply(&ipc_message__, obj, &member_func); \ - break; - -#define IPC_MESSAGE_HANDLER_DELAY_REPLY(msg_class, member_func) \ - IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, this, _IpcMessageHandlerClass::member_func) - -#define IPC_MESSAGE_HANDLER_GENERIC(msg_class, code) \ - case msg_class::ID: \ - code; \ - break; - -#define IPC_REPLY_HANDLER(func) \ - case IPC_REPLY_ID: \ - func(ipc_message__); \ - break; - - -#define IPC_MESSAGE_UNHANDLED(code) \ - default: \ - code; \ - break; - -#define IPC_MESSAGE_UNHANDLED_ERROR() \ - IPC_MESSAGE_UNHANDLED(NOTREACHED() << \ - "Invalid message with type = " << \ - ipc_message__.type()) - -#define IPC_END_MESSAGE_MAP() \ - DCHECK(msg_is_ok__); \ - } \ -} - -#define IPC_END_MESSAGE_MAP_EX() \ - } \ -} - -#elif defined(IPC_MESSAGE_MACROS_LOG) -#undef IPC_MESSAGE_MACROS_LOG - -#ifndef IPC_LOG_TABLE_CREATED -#define IPC_LOG_TABLE_CREATED -typedef void (*LogFunction)(uint16 type, - std::wstring* name, - const IPC::Message* msg, - std::wstring* params); - -LogFunction g_log_function_mapping[LastMsgIndex]; -#endif - - -#define IPC_BEGIN_MESSAGES(label) \ - void label##MsgLog(uint16 type, std::wstring* name, const IPC::Message* msg, std::wstring* params) { \ - switch (type) { - -#define IPC_END_MESSAGES(label) \ - default: \ - if (name) \ - *name = L"[UNKNOWN " L ## #label L" MSG"; \ - } \ - } \ - class LoggerRegisterHelper##label { \ - public: \ - LoggerRegisterHelper##label() { \ - g_log_function_mapping[label##MsgStart] = label##MsgLog; \ - } \ - }; \ - LoggerRegisterHelper##label g_LoggerRegisterHelper##label; - -#define IPC_MESSAGE_LOG(msg_class) \ - case msg_class##__ID: \ - if (name) \ - *name = L ## #msg_class; \ - if (msg && params) \ - msg_class::Log(msg, params); \ - break; - -#define IPC_MESSAGE_CONTROL0(msg_class) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_CONTROL1(msg_class, type1) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED0(msg_class) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED1(msg_class, type1) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_MESSAGE_ROUTED6(msg_class, type1, type2, type3, type4, type5, type6) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - IPC_MESSAGE_LOG(msg_class) - -#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - IPC_MESSAGE_LOG(msg_class) - -#elif defined(IPC_MESSAGE_MACROS_CLASSES) -#undef IPC_MESSAGE_MACROS_CLASSES - -#define IPC_BEGIN_MESSAGES(label) -#define IPC_END_MESSAGES(label) - -#define IPC_MESSAGE_CONTROL0(msg_class) \ - class msg_class : public IPC::Message { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class() \ - : IPC::Message(MSG_ROUTING_CONTROL, \ - ID, \ - PRIORITY_NORMAL) {} \ - }; - -#define IPC_MESSAGE_CONTROL1(msg_class, type1) \ - class msg_class : public IPC::MessageWithTuple<type1> { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1& arg1) \ - : IPC::MessageWithTuple<type1>(MSG_ROUTING_CONTROL, \ - ID, \ - arg1) {} \ - }; - -#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \ - class msg_class : public IPC::MessageWithTuple< Tuple2<type1, type2> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1& arg1, const type2& arg2) \ - : IPC::MessageWithTuple< Tuple2<type1, type2> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2)) {} \ - }; - -#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple3<type1, type2, type3> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1& arg1, const type2& arg2, const type3& arg3) \ - : IPC::MessageWithTuple< Tuple3<type1, type2, type3> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2, arg3)) {} \ - }; - -#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple4<type1, type2, type3, type4> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1& arg1, const type2& arg2, const type3& arg3, \ - const type4& arg4) \ - : IPC::MessageWithTuple< Tuple4<type1, type2, type3, type4> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2, arg3, arg4)) {} \ - }; - -#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple5<type1, type2, type3, type4, type5> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1& arg1, const type2& arg2, \ - const type3& arg3, const type4& arg4, const type5& arg5) \ - : IPC::MessageWithTuple< Tuple5<type1, type2, type3, type4, type5> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2, arg3, arg4, arg5)) {} \ - }; - -#define IPC_MESSAGE_ROUTED0(msg_class) \ - class msg_class : public IPC::Message { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id) \ - : IPC::Message(routing_id, ID, PRIORITY_NORMAL) {} \ - }; - -#define IPC_MESSAGE_ROUTED1(msg_class, type1) \ - class msg_class : public IPC::MessageWithTuple<type1> { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1) \ - : IPC::MessageWithTuple<type1>(routing_id, ID, arg1) {} \ - }; - -#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \ - class msg_class : public IPC::MessageWithTuple< Tuple2<type1, type2> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1, const type2& arg2) \ - : IPC::MessageWithTuple< Tuple2<type1, type2> >( \ - routing_id, ID, MakeTuple(arg1, arg2)) {} \ - }; - -#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple3<type1, type2, type3> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1, const type2& arg2, \ - const type3& arg3) \ - : IPC::MessageWithTuple< Tuple3<type1, type2, type3> >( \ - routing_id, ID, MakeTuple(arg1, arg2, arg3)) {} \ - }; - -#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple4<type1, type2, type3, type4> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1, const type2& arg2, \ - const type3& arg3, const type4& arg4) \ - : IPC::MessageWithTuple< Tuple4<type1, type2, type3, type4> >( \ - routing_id, ID, MakeTuple(arg1, arg2, arg3, arg4)) {} \ - }; - -#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple5<type1, type2, type3, type4, type5> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1, const type2& arg2, \ - const type3& arg3, const type4& arg4, const type5& arg5) \ - : IPC::MessageWithTuple< Tuple5<type1, type2, type3, type4, type5> >( \ - routing_id, ID, MakeTuple(arg1, arg2, arg3, arg4, arg5)) {} \ - }; - -#define IPC_MESSAGE_ROUTED6(msg_class, type1, type2, type3, type4, type5, \ - type6) \ - class msg_class : \ - public IPC::MessageWithTuple< Tuple6<type1, type2, type3, type4, type5, \ - type6> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int32 routing_id, const type1& arg1, const type2& arg2, \ - const type3& arg3, const type4& arg4, const type5& arg5, \ - const type6& arg6) \ - : IPC::MessageWithTuple< Tuple6<type1, type2, type3, type4, type5, \ - type6> >( \ - routing_id, ID, MakeTuple(arg1, arg2, arg3, arg4, arg5, arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \ - class msg_class : public IPC::MessageWithReply<Tuple0, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class() \ - : IPC::MessageWithReply<Tuple0, Tuple0 >( \ - MSG_ROUTING_CONTROL, ID, \ - MakeTuple(), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \ - class msg_class : public IPC::MessageWithReply<Tuple0, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(type1_out* arg1) \ - : IPC::MessageWithReply<Tuple0, Tuple1<type1_out&> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(), MakeRefTuple(*arg1)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple0, Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(type1_out* arg1, type2_out* arg2) \ - : IPC::MessageWithReply<Tuple0, Tuple2<type1_out&, type2_out&> >( \ - MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(), MakeRefTuple(*arg1, *arg2)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple0, \ - Tuple3<type1_out&, type2_out&, type3_out&> >{ \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(type1_out* arg1, type2_out* arg2, type3_out* arg3) \ - : IPC::MessageWithReply<Tuple0, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(), MakeRefTuple(*arg1, *arg2, *arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1) \ - : IPC::MessageWithReply<type1_in, Tuple0 >( \ - MSG_ROUTING_CONTROL, ID, \ - arg1, MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, type1_out* arg2) \ - : IPC::MessageWithReply<type1_in, Tuple1<type1_out&> >( \ - MSG_ROUTING_CONTROL, ID, \ - arg1, MakeRefTuple(*arg2)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, type1_out* arg2, type2_out* arg3) \ - : IPC::MessageWithReply<type1_in, Tuple2<type1_out&, type2_out&> >( \ - MSG_ROUTING_CONTROL, ID, \ - arg1, MakeRefTuple(*arg2, *arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, \ - Tuple3<type1_out&, type2_out&, type3_out&> >{ \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, type1_out* arg2, type2_out* arg3, type3_out* arg4) \ - : IPC::MessageWithReply<type1_in, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(MSG_ROUTING_CONTROL, \ - ID, \ - arg1, MakeRefTuple(*arg2, *arg3, *arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple0 >( \ - MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, type1_out* arg3) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple1<type1_out&> >( \ - MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, type1_out* arg3, type2_out* arg4) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple2<type1_out&, type2_out&> >(MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3, *arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, type1_out* arg3, type2_out* arg4, type3_out* arg5) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3, *arg4, *arg5)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple1<type1_out&> >(MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4, type2_out* arg5) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple2<type1_out&, type2_out&> >(MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4, *arg5)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4, type2_out* arg5, type3_out* arg6) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(MSG_ROUTING_CONTROL, \ - ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4, *arg5, *arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, const type4_in& arg4, type1_out* arg6) \ - : IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple1<type1_out&> >(MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2, arg3, arg4), MakeRefTuple(*arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, const type4_in& arg4, type1_out* arg5, type2_out* arg6) \ - : IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple2<type1_out&, type2_out&> >(MSG_ROUTING_CONTROL, ID, \ - MakeTuple(arg1, arg2, arg3, arg4), MakeRefTuple(*arg5, *arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \ - class msg_class : public IPC::MessageWithReply<Tuple0, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, type1_out* arg1) \ - : IPC::MessageWithReply<Tuple0, Tuple1<type1_out&> >( \ - routing_id, ID, \ - MakeTuple(), MakeRefTuple(*arg1)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \ - class msg_class : public IPC::MessageWithReply<Tuple0, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id) \ - : IPC::MessageWithReply<Tuple0, Tuple0 >( \ - routing_id, ID, \ - MakeTuple(), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple0, Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, type1_out* arg1, type2_out* arg2) \ - : IPC::MessageWithReply<Tuple0, Tuple2<type1_out&, type2_out&> >( \ - routing_id, ID, \ - MakeTuple(), MakeRefTuple(*arg1, *arg2)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple0, \ - Tuple3<type1_out&, type2_out&, type3_out&> >{ \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, type1_out* arg1, type2_out* arg2, type3_out* arg3) \ - : IPC::MessageWithReply<Tuple0, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(routing_id, ID, \ - MakeTuple(), MakeRefTuple(*arg1, *arg2, *arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1) \ - : IPC::MessageWithReply<type1_in, Tuple0 >( \ - routing_id, ID, \ - arg1, MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, type1_out* arg2) \ - : IPC::MessageWithReply<type1_in, Tuple1<type1_out&> >( \ - routing_id, ID, \ - arg1, MakeRefTuple(*arg2)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, type1_out* arg2, type2_out* arg3) \ - : IPC::MessageWithReply<type1_in, Tuple2<type1_out&, type2_out&> >( \ - routing_id, ID, \ - arg1, MakeRefTuple(*arg2, *arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, \ - Tuple3<type1_out&, type2_out&, type3_out&> >{ \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, type1_out* arg2, type2_out* arg3, type3_out* arg4) \ - : IPC::MessageWithReply<type1_in, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(routing_id, ID, \ - arg1, MakeRefTuple(*arg2, *arg3, *arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \ - class msg_class : \ - public IPC::MessageWithReply<type1_in, \ - Tuple4<type1_out&, type2_out&, type3_out&, type4_out&> >{ \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, type1_out* arg2, type2_out* arg3, type3_out* arg4, type4_out* arg5) \ - : IPC::MessageWithReply<type1_in, \ - Tuple4<type1_out&, type2_out&, type3_out&, type4_out&> >(routing_id, ID, \ - arg1, MakeRefTuple(*arg2, *arg3, *arg4, *arg5)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple0 >( \ - routing_id, ID, \ - MakeTuple(arg1, arg2), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, type1_out* arg3) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, Tuple1<type1_out&> >( \ - routing_id, ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, type1_out* arg3, type2_out* arg4) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple2<type1_out&, type2_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3, *arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, type1_out* arg3, type2_out* arg4, type3_out* arg5) \ - : IPC::MessageWithReply<Tuple2<type1_in, type2_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2), MakeRefTuple(*arg3, *arg4, *arg5)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, Tuple0>( \ - routing_id, ID, \ - MakeTuple(arg1, arg2, arg3), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple1<type1_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4, type2_out* arg5) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple2<type1_out&, type2_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4, *arg5)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, type1_out* arg4, type2_out* arg5, type3_out* arg6) \ - : IPC::MessageWithReply<Tuple3<type1_in, type2_in, type3_in>, \ - Tuple3<type1_out&, type2_out&, type3_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3), MakeRefTuple(*arg4, *arg5, *arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple0 > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, const type4_in& arg4) \ - : IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple0 >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3, arg4), MakeTuple()) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple1<type1_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, const type4_in& arg4, type1_out* arg6) \ - : IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple1<type1_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3, arg4), MakeRefTuple(*arg6)) {} \ - }; - -#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \ - class msg_class : \ - public IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple2<type1_out&, type2_out&> > { \ - public: \ - enum { ID = msg_class##__ID }; \ - msg_class(int routing_id, const type1_in& arg1, const type2_in& arg2, const type3_in& arg3, const type4_in& arg4, type1_out* arg5, type2_out* arg6) \ - : IPC::MessageWithReply<Tuple4<type1_in, type2_in, type3_in, type4_in>, \ - Tuple2<type1_out&, type2_out&> >(routing_id, ID, \ - MakeTuple(arg1, arg2, arg3, arg4), MakeRefTuple(*arg5, *arg6)) {} \ - }; - -#endif // #if defined() diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc deleted file mode 100644 index 2ee7025..0000000 --- a/ipc/ipc_message_utils.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_message_utils.h" - -#include "base/gfx/rect.h" - -namespace IPC { - -void ParamTraits<gfx::Point>::Write(Message* m, const gfx::Point& p) { - m->WriteInt(p.x()); - m->WriteInt(p.y()); -} - -bool ParamTraits<gfx::Point>::Read(const Message* m, void** iter, - gfx::Point* r) { - int x, y; - if (!m->ReadInt(iter, &x) || - !m->ReadInt(iter, &y)) - return false; - r->set_x(x); - r->set_y(y); - return true; -} - -void ParamTraits<gfx::Point>::Log(const gfx::Point& p, std::wstring* l) { - l->append(StringPrintf(L"(%d, %d)", p.x(), p.y())); -} - -void ParamTraits<gfx::Rect>::Write(Message* m, const gfx::Rect& p) { - m->WriteInt(p.x()); - m->WriteInt(p.y()); - m->WriteInt(p.width()); - m->WriteInt(p.height()); -} - -bool ParamTraits<gfx::Rect>::Read(const Message* m, void** iter, gfx::Rect* r) { - int x, y, w, h; - if (!m->ReadInt(iter, &x) || - !m->ReadInt(iter, &y) || - !m->ReadInt(iter, &w) || - !m->ReadInt(iter, &h)) - return false; - r->set_x(x); - r->set_y(y); - r->set_width(w); - r->set_height(h); - return true; -} - -void ParamTraits<gfx::Rect>::Log(const gfx::Rect& p, std::wstring* l) { - l->append(StringPrintf(L"(%d, %d, %d, %d)", p.x(), p.y(), - p.width(), p.height())); -} - -void ParamTraits<gfx::Size>::Write(Message* m, const gfx::Size& p) { - m->WriteInt(p.width()); - m->WriteInt(p.height()); -} - -bool ParamTraits<gfx::Size>::Read(const Message* m, void** iter, gfx::Size* r) { - int w, h; - if (!m->ReadInt(iter, &w) || - !m->ReadInt(iter, &h)) - return false; - r->set_width(w); - r->set_height(h); - return true; -} - -void ParamTraits<gfx::Size>::Log(const gfx::Size& p, std::wstring* l) { - l->append(StringPrintf(L"(%d, %d)", p.width(), p.height())); -} - -} // namespace IPC diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h deleted file mode 100644 index 582b491..0000000 --- a/ipc/ipc_message_utils.h +++ /dev/null @@ -1,1258 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_MESSAGE_UTILS_H_ -#define IPC_IPC_MESSAGE_UTILS_H_ - -#include <string> -#include <vector> -#include <map> - -#include "base/file_path.h" -#include "base/string_util.h" -#include "base/string16.h" -#include "base/time.h" -#include "base/tuple.h" -#if defined(OS_POSIX) -#include "ipc/file_descriptor_set_posix.h" -#endif -#include "ipc/ipc_sync_message.h" - -// Forward declarations. -namespace gfx { -class Point; -class Rect; -class Size; -} // namespace gfx - -// Used by IPC_BEGIN_MESSAGES so that each message class starts from a unique -// base. Messages have unique IDs across channels in order for the IPC logging -// code to figure out the message class from its ID. -enum IPCMessageStart { - // By using a start value of 0 for automation messages, we keep backward - // compatibility with old builds. - AutomationMsgStart = 0, - ViewMsgStart, - ViewHostMsgStart, - PluginProcessMsgStart, - PluginProcessHostMsgStart, - PluginMsgStart, - PluginHostMsgStart, - NPObjectMsgStart, - TestMsgStart, - DevToolsAgentMsgStart, - DevToolsClientMsgStart, - WorkerProcessMsgStart, - WorkerProcessHostMsgStart, - WorkerMsgStart, - WorkerHostMsgStart, - // NOTE: When you add a new message class, also update - // IPCStatusView::IPCStatusView to ensure logging works. - // NOTE: this enum is used by IPC_MESSAGE_MACRO to generate a unique message - // id. Only 4 bits are used for the message type, so if this enum needs more - // than 16 entries, that code needs to be updated. - LastMsgIndex -}; - -COMPILE_ASSERT(LastMsgIndex <= 16, need_to_update_IPC_MESSAGE_MACRO); - -namespace IPC { - -//----------------------------------------------------------------------------- -// An iterator class for reading the fields contained within a Message. - -class MessageIterator { - public: - explicit MessageIterator(const Message& m) : msg_(m), iter_(NULL) { - } - int NextInt() const { - int val; - if (!msg_.ReadInt(&iter_, &val)) - NOTREACHED(); - return val; - } - intptr_t NextIntPtr() const { - intptr_t val; - if (!msg_.ReadIntPtr(&iter_, &val)) - NOTREACHED(); - return val; - } - const std::string NextString() const { - std::string val; - if (!msg_.ReadString(&iter_, &val)) - NOTREACHED(); - return val; - } - const std::wstring NextWString() const { - std::wstring val; - if (!msg_.ReadWString(&iter_, &val)) - NOTREACHED(); - return val; - } - const void NextData(const char** data, int* length) const { - if (!msg_.ReadData(&iter_, data, length)) { - NOTREACHED(); - } - } - private: - const Message& msg_; - mutable void* iter_; -}; - -//----------------------------------------------------------------------------- -// ParamTraits specializations, etc. - -template <class P> struct ParamTraits {}; - -template <class P> -static inline void WriteParam(Message* m, const P& p) { - ParamTraits<P>::Write(m, p); -} - -template <class P> -static inline bool ReadParam(const Message* m, void** iter, P* p) { - return ParamTraits<P>::Read(m, iter, p); -} - -template <class P> -static inline void LogParam(const P& p, std::wstring* l) { - ParamTraits<P>::Log(p, l); -} - -template <> -struct ParamTraits<bool> { - typedef bool param_type; - static void Write(Message* m, const param_type& p) { - m->WriteBool(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadBool(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(p ? L"true" : L"false"); - } -}; - -template <> -struct ParamTraits<int> { - typedef int param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadInt(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%d", p)); - } -}; - -template <> -struct ParamTraits<long> { - typedef long param_type; - static void Write(Message* m, const param_type& p) { - m->WriteLong(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadLong(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%l", p)); - } -}; - -template <> -struct ParamTraits<size_t> { - typedef size_t param_type; - static void Write(Message* m, const param_type& p) { - m->WriteSize(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadSize(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%u", p)); - } -}; - -#if defined(OS_MACOSX) -// On Linux size_t & uint32 can be the same type. -// TODO(playmobil): Fix compilation if this is not the case. -template <> -struct ParamTraits<uint32> { - typedef uint32 param_type; - static void Write(Message* m, const param_type& p) { - m->WriteUInt32(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadUInt32(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%u", p)); - } -}; -#endif // defined(OS_MACOSX) - -template <> -struct ParamTraits<int64> { - typedef int64 param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt64(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadInt64(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%I64d", p)); - } -}; - -template <> -struct ParamTraits<uint64> { - typedef uint64 param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt64(static_cast<int64>(p)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadInt64(iter, reinterpret_cast<int64*>(r)); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%I64u", p)); - } -}; - -template <> -struct ParamTraits<double> { - typedef double param_type; - static void Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - bool result = m->ReadData(iter, &data, &data_size); - if (result && data_size == sizeof(param_type)) { - memcpy(r, data, sizeof(param_type)); - } else { - result = false; - NOTREACHED(); - } - - return result; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"e", p)); - } -}; - -template <> -struct ParamTraits<wchar_t> { - typedef wchar_t param_type; - static void Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - bool result = m->ReadData(iter, &data, &data_size); - if (result && data_size == sizeof(param_type)) { - memcpy(r, data, sizeof(param_type)); - } else { - result = false; - NOTREACHED(); - } - - return result; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"%lc", p)); - } -}; - -template <> -struct ParamTraits<base::Time> { - typedef base::Time param_type; - static void Write(Message* m, const param_type& p) { - ParamTraits<int64>::Write(m, p.ToInternalValue()); - } - static bool Read(const Message* m, void** iter, param_type* r) { - int64 value; - if (!ParamTraits<int64>::Read(m, iter, &value)) - return false; - *r = base::Time::FromInternalValue(value); - return true; - } - static void Log(const param_type& p, std::wstring* l) { - ParamTraits<int64>::Log(p.ToInternalValue(), l); - } -}; - -#if defined(OS_WIN) -template <> -struct ParamTraits<LOGFONT> { - typedef LOGFONT param_type; - static void Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - bool result = m->ReadData(iter, &data, &data_size); - if (result && data_size == sizeof(LOGFONT)) { - memcpy(r, data, sizeof(LOGFONT)); - } else { - result = false; - NOTREACHED(); - } - - return result; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"<LOGFONT>")); - } -}; - -template <> -struct ParamTraits<MSG> { - typedef MSG param_type; - static void Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - bool result = m->ReadData(iter, &data, &data_size); - if (result && data_size == sizeof(MSG)) { - memcpy(r, data, sizeof(MSG)); - } else { - result = false; - NOTREACHED(); - } - - return result; - } -}; -#endif // defined(OS_WIN) - -template <> -struct ParamTraits<std::string> { - typedef std::string param_type; - static void Write(Message* m, const param_type& p) { - m->WriteString(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadString(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(UTF8ToWide(p)); - } -}; - -template <> -struct ParamTraits<std::vector<unsigned char> > { - typedef std::vector<unsigned char> param_type; - static void Write(Message* m, const param_type& p) { - if (p.size() == 0) { - m->WriteData(NULL, 0); - } else { - m->WriteData(reinterpret_cast<const char*>(&p.front()), - static_cast<int>(p.size())); - } - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - if (!m->ReadData(iter, &data, &data_size) || data_size < 0) - return false; - r->resize(data_size); - if (data_size) - memcpy(&r->front(), data, data_size); - return true; - } - static void Log(const param_type& p, std::wstring* l) { - for (size_t i = 0; i < p.size(); ++i) - l->push_back(p[i]); - } -}; - -template <> -struct ParamTraits<std::vector<char> > { - typedef std::vector<char> param_type; - static void Write(Message* m, const param_type& p) { - if (p.size() == 0) { - m->WriteData(NULL, 0); - } else { - m->WriteData(&p.front(), static_cast<int>(p.size())); - } - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - if (!m->ReadData(iter, &data, &data_size) || data_size < 0) - return false; - r->resize(data_size); - if (data_size) - memcpy(&r->front(), data, data_size); - return true; - } - static void Log(const param_type& p, std::wstring* l) { - for (size_t i = 0; i < p.size(); ++i) - l->push_back(p[i]); - } -}; - -template <class P> -struct ParamTraits<std::vector<P> > { - typedef std::vector<P> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, static_cast<int>(p.size())); - for (size_t i = 0; i < p.size(); i++) - WriteParam(m, p[i]); - } - static bool Read(const Message* m, void** iter, param_type* r) { - int size; - if (!m->ReadLength(iter, &size)) - return false; - // Resizing beforehand is not safe, see BUG 1006367 for details. - if (m->IteratorHasRoomFor(*iter, size * sizeof(P))) { - r->resize(size); - for (int i = 0; i < size; i++) { - if (!ReadParam(m, iter, &(*r)[i])) - return false; - } - } else { - for (int i = 0; i < size; i++) { - P element; - if (!ReadParam(m, iter, &element)) - return false; - r->push_back(element); - } - } - return true; - } - static void Log(const param_type& p, std::wstring* l) { - for (size_t i = 0; i < p.size(); ++i) { - if (i != 0) - l->append(L" "); - - LogParam((p[i]), l); - } - } -}; - -template <class K, class V> -struct ParamTraits<std::map<K, V> > { - typedef std::map<K, V> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, static_cast<int>(p.size())); - typename param_type::const_iterator iter; - for (iter = p.begin(); iter != p.end(); ++iter) { - WriteParam(m, iter->first); - WriteParam(m, iter->second); - } - } - static bool Read(const Message* m, void** iter, param_type* r) { - int size; - if (!ReadParam(m, iter, &size) || size < 0) - return false; - for (int i = 0; i < size; ++i) { - K k; - if (!ReadParam(m, iter, &k)) - return false; - V& value = (*r)[k]; - if (!ReadParam(m, iter, &value)) - return false; - } - return true; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(L"<std::map>"); - } -}; - - -template <> -struct ParamTraits<std::wstring> { - typedef std::wstring param_type; - static void Write(Message* m, const param_type& p) { - m->WriteWString(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadWString(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(p); - } -}; - -// If WCHAR_T_IS_UTF16 is defined, then string16 is a std::wstring so we don't -// need this trait. -#if !defined(WCHAR_T_IS_UTF16) -template <> -struct ParamTraits<string16> { - typedef string16 param_type; - static void Write(Message* m, const param_type& p) { - m->WriteString16(p); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return m->ReadString16(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(UTF16ToWide(p)); - } -}; -#endif - -// and, a few more useful types... -#if defined(OS_WIN) -template <> -struct ParamTraits<HANDLE> { - typedef HANDLE param_type; - static void Write(Message* m, const param_type& p) { - m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); - return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"0x%X", p)); - } -}; - -template <> -struct ParamTraits<HCURSOR> { - typedef HCURSOR param_type; - static void Write(Message* m, const param_type& p) { - m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); - return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"0x%X", p)); - } -}; - -template <> -struct ParamTraits<HWND> { - typedef HWND param_type; - static void Write(Message* m, const param_type& p) { - m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); - return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"0x%X", p)); - } -}; - -template <> -struct ParamTraits<HRGN> { - typedef HRGN param_type; - static void Write(Message* m, const param_type& p) { - int data_size = GetRegionData(p, 0, NULL); - if (data_size) { - char* bytes = new char[data_size]; - GetRegionData(p, data_size, reinterpret_cast<LPRGNDATA>(bytes)); - m->WriteData(reinterpret_cast<const char*>(bytes), data_size); - delete [] bytes; - } else { - m->WriteData(NULL, 0); - } - } - static bool Read(const Message* m, void** iter, param_type* r) { - bool res = FALSE; - const char *data; - int data_size = 0; - res = m->ReadData(iter, &data, &data_size); - if (data_size) { - *r = ExtCreateRegion(NULL, data_size, - reinterpret_cast<CONST RGNDATA*>(data)); - } else { - res = TRUE; - *r = CreateRectRgn(0, 0, 0, 0); - } - return res; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"0x%X", p)); - } -}; - -template <> -struct ParamTraits<HACCEL> { - typedef HACCEL param_type; - static void Write(Message* m, const param_type& p) { - m->WriteIntPtr(reinterpret_cast<intptr_t>(p)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - DCHECK_EQ(sizeof(param_type), sizeof(intptr_t)); - return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r)); - } -}; - -template <> -struct ParamTraits<POINT> { - typedef POINT param_type; - static void Write(Message* m, const param_type& p) { - m->WriteInt(p.x); - m->WriteInt(p.y); - } - static bool Read(const Message* m, void** iter, param_type* r) { - int x, y; - if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y)) - return false; - r->x = x; - r->y = y; - return true; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(StringPrintf(L"(%d, %d)", p.x, p.y)); - } -}; -#endif // defined(OS_WIN) - -template <> -struct ParamTraits<FilePath> { - typedef FilePath param_type; - static void Write(Message* m, const param_type& p) { - ParamTraits<FilePath::StringType>::Write(m, p.value()); - } - static bool Read(const Message* m, void** iter, param_type* r) { - FilePath::StringType value; - if (!ParamTraits<FilePath::StringType>::Read(m, iter, &value)) - return false; - *r = FilePath(value); - return true; - } - static void Log(const param_type& p, std::wstring* l) { - ParamTraits<FilePath::StringType>::Log(p.value(), l); - } -}; - -template <> -struct ParamTraits<gfx::Point> { - typedef gfx::Point param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, void** iter, param_type* r); - static void Log(const param_type& p, std::wstring* l); -}; - -template <> -struct ParamTraits<gfx::Rect> { - typedef gfx::Rect param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, void** iter, param_type* r); - static void Log(const param_type& p, std::wstring* l); -}; - -template <> -struct ParamTraits<gfx::Size> { - typedef gfx::Size param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, void** iter, param_type* r); - static void Log(const param_type& p, std::wstring* l); -}; - -#if defined(OS_POSIX) -// FileDescriptors may be serialised over IPC channels on POSIX. On the -// receiving side, the FileDescriptor is a valid duplicate of the file -// descriptor which was transmitted: *it is not just a copy of the integer like -// HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In -// this case, the receiving end will see a value of -1. *Zero is a valid file -// descriptor*. -// -// The received file descriptor will have the |auto_close| flag set to true. The -// code which handles the message is responsible for taking ownership of it. -// File descriptors are OS resources and must be closed when no longer needed. -// -// When sending a file descriptor, the file descriptor must be valid at the time -// of transmission. Since transmission is not synchronous, one should consider -// dup()ing any file descriptors to be transmitted and setting the |auto_close| -// flag, which causes the file descriptor to be closed after writing. -template<> -struct ParamTraits<base::FileDescriptor> { - typedef base::FileDescriptor param_type; - static void Write(Message* m, const param_type& p) { - const bool valid = p.fd >= 0; - WriteParam(m, valid); - - if (valid) { - if (!m->WriteFileDescriptor(p)) - NOTREACHED(); - } - } - static bool Read(const Message* m, void** iter, param_type* r) { - bool valid; - if (!ReadParam(m, iter, &valid)) - return false; - - if (!valid) { - r->fd = -1; - r->auto_close = false; - return true; - } - - return m->ReadFileDescriptor(iter, r); - } - static void Log(const param_type& p, std::wstring* l) { - if (p.auto_close) { - l->append(StringPrintf(L"FD(%d auto-close)", p.fd)); - } else { - l->append(StringPrintf(L"FD(%d)", p.fd)); - } - } -}; -#endif // defined(OS_POSIX) - -#if defined(OS_WIN) -template <> -struct ParamTraits<XFORM> { - typedef XFORM param_type; - static void Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(XFORM)); - } - static bool Read(const Message* m, void** iter, param_type* r) { - const char *data; - int data_size = 0; - bool result = m->ReadData(iter, &data, &data_size); - if (result && data_size == sizeof(XFORM)) { - memcpy(r, data, sizeof(XFORM)); - } else { - result = false; - NOTREACHED(); - } - - return result; - } - static void Log(const param_type& p, std::wstring* l) { - l->append(L"<XFORM>"); - } -}; -#endif // defined(OS_WIN) - -struct LogData { - std::wstring channel; - uint16 type; - std::wstring flags; - int64 sent; // Time that the message was sent (i.e. at Send()). - int64 receive; // Time before it was dispatched (i.e. before calling - // OnMessageReceived). - int64 dispatch; // Time after it was dispatched (i.e. after calling - // OnMessageReceived). - std::wstring message_name; - std::wstring params; -}; - -template <> -struct ParamTraits<LogData> { - typedef LogData param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.channel); - WriteParam(m, static_cast<int>(p.type)); - WriteParam(m, p.flags); - WriteParam(m, p.sent); - WriteParam(m, p.receive); - WriteParam(m, p.dispatch); - WriteParam(m, p.params); - } - static bool Read(const Message* m, void** iter, param_type* r) { - int type; - bool result = - ReadParam(m, iter, &r->channel) && - ReadParam(m, iter, &type) && - ReadParam(m, iter, &r->flags) && - ReadParam(m, iter, &r->sent) && - ReadParam(m, iter, &r->receive) && - ReadParam(m, iter, &r->dispatch) && - ReadParam(m, iter, &r->params); - r->type = static_cast<uint16>(type); - return result; - } - static void Log(const param_type& p, std::wstring* l) { - // Doesn't make sense to implement this! - } -}; - - -template <> -struct ParamTraits<Message> { - static void Write(Message* m, const Message& p) { - m->WriteInt(p.size()); - m->WriteData(reinterpret_cast<const char*>(p.data()), p.size()); - } - static bool Read(const Message* m, void** iter, Message* r) { - int size; - if (!m->ReadInt(iter, &size)) - return false; - const char* data; - if (!m->ReadData(iter, &data, &size)) - return false; - *r = Message(data, size); - return true; - } - static void Log(const Message& p, std::wstring* l) { - l->append(L"<IPC::Message>"); - } -}; - -template <> -struct ParamTraits<Tuple0> { - typedef Tuple0 param_type; - static void Write(Message* m, const param_type& p) { - } - static bool Read(const Message* m, void** iter, param_type* r) { - return true; - } - static void Log(const param_type& p, std::wstring* l) { - } -}; - -template <class A> -struct ParamTraits< Tuple1<A> > { - typedef Tuple1<A> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return ReadParam(m, iter, &r->a); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - } -}; - -template <class A, class B> -struct ParamTraits< Tuple2<A, B> > { - typedef Tuple2<A, B> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - WriteParam(m, p.b); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return (ReadParam(m, iter, &r->a) && - ReadParam(m, iter, &r->b)); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - l->append(L", "); - LogParam(p.b, l); - } -}; - -template <class A, class B, class C> -struct ParamTraits< Tuple3<A, B, C> > { - typedef Tuple3<A, B, C> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - WriteParam(m, p.b); - WriteParam(m, p.c); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return (ReadParam(m, iter, &r->a) && - ReadParam(m, iter, &r->b) && - ReadParam(m, iter, &r->c)); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - l->append(L", "); - LogParam(p.b, l); - l->append(L", "); - LogParam(p.c, l); - } -}; - -template <class A, class B, class C, class D> -struct ParamTraits< Tuple4<A, B, C, D> > { - typedef Tuple4<A, B, C, D> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - WriteParam(m, p.b); - WriteParam(m, p.c); - WriteParam(m, p.d); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return (ReadParam(m, iter, &r->a) && - ReadParam(m, iter, &r->b) && - ReadParam(m, iter, &r->c) && - ReadParam(m, iter, &r->d)); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - l->append(L", "); - LogParam(p.b, l); - l->append(L", "); - LogParam(p.c, l); - l->append(L", "); - LogParam(p.d, l); - } -}; - -template <class A, class B, class C, class D, class E> -struct ParamTraits< Tuple5<A, B, C, D, E> > { - typedef Tuple5<A, B, C, D, E> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - WriteParam(m, p.b); - WriteParam(m, p.c); - WriteParam(m, p.d); - WriteParam(m, p.e); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return (ReadParam(m, iter, &r->a) && - ReadParam(m, iter, &r->b) && - ReadParam(m, iter, &r->c) && - ReadParam(m, iter, &r->d) && - ReadParam(m, iter, &r->e)); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - l->append(L", "); - LogParam(p.b, l); - l->append(L", "); - LogParam(p.c, l); - l->append(L", "); - LogParam(p.d, l); - l->append(L", "); - LogParam(p.e, l); - } -}; - -template <class A, class B, class C, class D, class E, class F> -struct ParamTraits< Tuple6<A, B, C, D, E, F> > { - typedef Tuple6<A, B, C, D, E, F> param_type; - static void Write(Message* m, const param_type& p) { - WriteParam(m, p.a); - WriteParam(m, p.b); - WriteParam(m, p.c); - WriteParam(m, p.d); - WriteParam(m, p.e); - WriteParam(m, p.f); - } - static bool Read(const Message* m, void** iter, param_type* r) { - return (ReadParam(m, iter, &r->a) && - ReadParam(m, iter, &r->b) && - ReadParam(m, iter, &r->c) && - ReadParam(m, iter, &r->d) && - ReadParam(m, iter, &r->e) && - ReadParam(m, iter, &r->f)); - } - static void Log(const param_type& p, std::wstring* l) { - LogParam(p.a, l); - l->append(L", "); - LogParam(p.b, l); - l->append(L", "); - LogParam(p.c, l); - l->append(L", "); - LogParam(p.d, l); - l->append(L", "); - LogParam(p.e, l); - l->append(L", "); - LogParam(p.f, l); - } -}; - - - -//----------------------------------------------------------------------------- -// Generic message subclasses - -// Used for asynchronous messages. -template <class ParamType> -class MessageWithTuple : public Message { - public: - typedef ParamType Param; - - MessageWithTuple(int32 routing_id, uint16 type, const Param& p) - : Message(routing_id, type, PRIORITY_NORMAL) { - WriteParam(this, p); - } - - static bool Read(const Message* msg, Param* p) { - void* iter = NULL; - bool rv = ReadParam(msg, &iter, p); - DCHECK(rv) << "Error deserializing message " << msg->type(); - return rv; - } - - // Generic dispatcher. Should cover most cases. - template<class T, class Method> - static bool Dispatch(const Message* msg, T* obj, Method func) { - Param p; - if (Read(msg, &p)) { - DispatchToMethod(obj, func, p); - return true; - } - return false; - } - - // The following dispatchers exist for the case where the callback function - // needs the message as well. They assume that "Param" is a type of Tuple - // (except the one arg case, as there is no Tuple1). - template<class T, typename TA> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&, TA)) { - Param p; - if (Read(msg, &p)) { - (obj->*func)(*msg, p); - return true; - } - return false; - } - - template<class T, typename TA, typename TB> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&, TA, TB)) { - Param p; - if (Read(msg, &p)) { - (obj->*func)(*msg, p.a, p.b); - return true; - } - return false; - } - - template<class T, typename TA, typename TB, typename TC> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&, TA, TB, TC)) { - Param p; - if (Read(msg, &p)) { - (obj->*func)(*msg, p.a, p.b, p.c); - return true; - } - return false; - } - - template<class T, typename TA, typename TB, typename TC, typename TD> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&, TA, TB, TC, TD)) { - Param p; - if (Read(msg, &p)) { - (obj->*func)(*msg, p.a, p.b, p.c, p.d); - return true; - } - return false; - } - - template<class T, typename TA, typename TB, typename TC, typename TD, - typename TE> - static bool Dispatch(const Message* msg, T* obj, - void (T::*func)(const Message&, TA, TB, TC, TD, TE)) { - Param p; - if (Read(msg, &p)) { - (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e); - return true; - } - return false; - } - - static void Log(const Message* msg, std::wstring* l) { - Param p; - if (Read(msg, &p)) - LogParam(p, l); - } - - // Functions used to do manual unpacking. Only used by the automation code, - // these should go away once that code uses SyncChannel. - template<typename TA, typename TB> - static bool Read(const IPC::Message* msg, TA* a, TB* b) { - ParamType params; - if (!Read(msg, ¶ms)) - return false; - *a = params.a; - *b = params.b; - return true; - } - - template<typename TA, typename TB, typename TC> - static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) { - ParamType params; - if (!Read(msg, ¶ms)) - return false; - *a = params.a; - *b = params.b; - *c = params.c; - return true; - } - - template<typename TA, typename TB, typename TC, typename TD> - static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) { - ParamType params; - if (!Read(msg, ¶ms)) - return false; - *a = params.a; - *b = params.b; - *c = params.c; - *d = params.d; - return true; - } - - 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) { - ParamType params; - if (!Read(msg, ¶ms)) - return false; - *a = params.a; - *b = params.b; - *c = params.c; - *d = params.d; - *e = params.e; - return true; - } -}; - -// This class assumes that its template argument is a RefTuple (a Tuple with -// reference elements). -template <class RefTuple> -class ParamDeserializer : public MessageReplyDeserializer { - public: - explicit ParamDeserializer(const RefTuple& out) : out_(out) { } - - bool SerializeOutputParameters(const IPC::Message& msg, void* iter) { - return ReadParam(&msg, &iter, &out_); - } - - RefTuple out_; -}; - -// defined in ipc_logging.cc -void GenerateLogData(const std::wstring& channel, const Message& message, - LogData* data); - -// Used for synchronous messages. -template <class SendParamType, class ReplyParamType> -class MessageWithReply : public SyncMessage { - public: - typedef SendParamType SendParam; - typedef ReplyParamType ReplyParam; - - MessageWithReply(int32 routing_id, uint16 type, - const SendParam& send, const ReplyParam& reply) - : SyncMessage(routing_id, type, PRIORITY_NORMAL, - new ParamDeserializer<ReplyParam>(reply)) { - WriteParam(this, send); - } - - static void Log(const Message* msg, std::wstring* l) { - if (msg->is_sync()) { - SendParam p; - void* iter = SyncMessage::GetDataIterator(msg); - ReadParam(msg, &iter, &p); - LogParam(p, l); - -#if defined(IPC_MESSAGE_LOG_ENABLED) - const std::wstring& output_params = msg->output_params(); - if (!l->empty() && !output_params.empty()) - l->append(L", "); - - l->append(output_params); -#endif - } else { - // This is an outgoing reply. Now that we have the output parameters, we - // can finally log the message. - typename ReplyParam::ValueTuple p; - void* iter = SyncMessage::GetDataIterator(msg); - ReadParam(msg, &iter, &p); - LogParam(p, l); - } - } - - template<class T, class Method> - static bool Dispatch(const Message* msg, T* obj, Method func) { - SendParam send_params; - void* iter = GetDataIterator(msg); - Message* reply = GenerateReply(msg); - bool error; - if (ReadParam(msg, &iter, &send_params)) { - typename ReplyParam::ValueTuple reply_params; - DispatchToMethod(obj, func, send_params, &reply_params); - WriteParam(reply, reply_params); - error = false; -#ifdef IPC_MESSAGE_LOG_ENABLED - if (msg->received_time() != 0) { - std::wstring output_params; - LogParam(reply_params, &output_params); - msg->set_output_params(output_params); - } -#endif - } else { - NOTREACHED() << "Error deserializing message " << msg->type(); - reply->set_reply_error(); - error = true; - } - - obj->Send(reply); - return !error; - } - - template<class T, class Method> - static bool DispatchDelayReply(const Message* msg, T* obj, Method func) { - SendParam send_params; - void* iter = GetDataIterator(msg); - Message* reply = GenerateReply(msg); - bool error; - if (ReadParam(msg, &iter, &send_params)) { - Tuple1<Message&> t = MakeRefTuple(*reply); - -#ifdef IPC_MESSAGE_LOG_ENABLED - if (msg->sent_time()) { - // Don't log the sync message after dispatch, as we don't have the - // output parameters at that point. Instead, save its data and log it - // with the outgoing reply message when it's sent. - LogData* data = new LogData; - GenerateLogData(L"", *msg, data); - msg->set_dont_log(); - reply->set_sync_log_data(data); - } -#endif - DispatchToMethod(obj, func, send_params, &t); - error = false; - } else { - NOTREACHED() << "Error deserializing message " << msg->type(); - reply->set_reply_error(); - obj->Send(reply); - error = true; - } - return !error; - } - - template<typename TA> - static void WriteReplyParams(Message* reply, TA a) { - ReplyParam p(a); - WriteParam(reply, p); - } - - template<typename TA, typename TB> - static void WriteReplyParams(Message* reply, TA a, TB b) { - ReplyParam p(a, b); - WriteParam(reply, p); - } - - template<typename TA, typename TB, typename TC> - static void WriteReplyParams(Message* reply, TA a, TB b, TC c) { - ReplyParam p(a, b, c); - WriteParam(reply, p); - } - - template<typename TA, typename TB, typename TC, typename TD> - static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) { - ReplyParam p(a, b, c, d); - WriteParam(reply, p); - } - - template<typename TA, typename TB, typename TC, typename TD, typename TE> - static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) { - ReplyParam p(a, b, c, d, e); - WriteParam(reply, p); - } -}; - -//----------------------------------------------------------------------------- - -} // namespace IPC - -#endif // IPC_IPC_MESSAGE_UTILS_H_ diff --git a/ipc/ipc_send_fds_test.cc b/ipc/ipc_send_fds_test.cc deleted file mode 100644 index ff32afc..0000000 --- a/ipc/ipc_send_fds_test.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#include "ipc/ipc_tests.h" - -#if defined(OS_MACOSX) -extern "C" { -#include <sandbox.h> -} -#endif -#include <fcntl.h> -#include <sys/stat.h> - -#include "base/message_loop.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_message_utils.h" - -#if defined(OS_POSIX) - -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 NUL bytes. - - struct stat st; - ASSERT_EQ(fstat(fd, &st), 0); - - ASSERT_EQ(close(fd), 0); - - // We compare iNode numbers to check that the file sent over the wire - // was actually the same physical file as the one we were expecting. - ASSERT_EQ(inode_num, st.st_ino); -} - -class MyChannelDescriptorListener : public IPC::Channel::Listener { - public: - MyChannelDescriptorListener(ino_t expected_inode_num) - : expected_inode_num_(expected_inode_num), - num_fds_received_(0) {} - - virtual void OnMessageReceived(const IPC::Message& message) { - void* iter = NULL; - - ++num_fds_received_; - base::FileDescriptor descriptor; - - ASSERT_TRUE( - IPC::ParamTraits<base::FileDescriptor>::Read( - &message, &iter, &descriptor)); - - VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_); - if (num_fds_received_ == kNumFDsToSend) { - MessageLoop::current()->Quit(); - } - } - - virtual void OnChannelError() { - MessageLoop::current()->Quit(); - } - private: - ino_t expected_inode_num_; - unsigned num_fds_received_; -}; - -void TestDescriptorServer(IPC::Channel &chan, - base::ProcessHandle process_handle) { - ASSERT_TRUE(process_handle); - - for (unsigned i = 0; i < kNumFDsToSend; ++i) { - base::FileDescriptor descriptor; - const int fd = open(kDevZeroPath, O_RDONLY); - ASSERT_GE(fd, 0); - descriptor.auto_close = true; - descriptor.fd = fd; - - IPC::Message* message = new IPC::Message(0, // routing_id - 3, // message type - IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); - chan.Send(message); - } - - // Run message loop. - MessageLoop::current()->Run(); - - // Close Channel so client gets its OnChannelError() callback fired. - chan.Close(); - - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000)); -} - -int TestDescriptorClient(ino_t expected_inode_num) { - MessageLoopForIO main_message_loop; - MyChannelDescriptorListener listener(expected_inode_num); - - // Setup IPC channel. - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, - &listener); - chan.Connect(); - MessageLoop::current()->Run(); - - return 0; -} - -} // namespace - -// --------------------------------------------------------------------------- -#if defined(OS_MACOSX) -// TODO(port): Make this test cross-platform. -MULTIPROCESS_TEST_MAIN(RunTestDescriptorClientSandboxed) { - struct stat st; - const int fd = open(kDevZeroPath, O_RDONLY); - fstat(fd, &st); - close(fd); - - // Enable the Sandbox. - char* error_buff = NULL; - int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, - &error_buff); - bool success = (error == 0 && error_buff == NULL); - if (!success) { - return -1; - } - - sandbox_free_error(error_buff); - - // Make sure Sandbox is really enabled. - if (open(kDevZeroPath, O_RDONLY) != -1) { - LOG(ERROR) << "Sandbox wasn't properly enabled"; - return -1; - } - - // See if we can receive a file descriptor. - return TestDescriptorClient(st.st_ino); -} - -// Test that FDs are correctly sent to a sandboxed process. -TEST_F(IPCChannelTest, DescriptorTestSandboxed) { - // Setup IPC channel. - MyChannelDescriptorListener listener(-1); - - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &listener); - chan.Connect(); - - base::ProcessHandle process_handle = SpawnChild( - TEST_DESCRIPTOR_CLIENT_SANDBOXED, - &chan); - TestDescriptorServer(chan, process_handle); -} -#endif // defined(OS_MACOSX) - -MULTIPROCESS_TEST_MAIN(RunTestDescriptorClient) { - struct stat st; - const int fd = open(kDevZeroPath, O_RDONLY); - fstat(fd, &st); - close(fd); - - return TestDescriptorClient(st.st_ino); -} - -TEST_F(IPCChannelTest, DescriptorTest) { - // Setup IPC channel. - MyChannelDescriptorListener listener(-1); - - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &listener); - chan.Connect(); - - base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT, - &chan); - TestDescriptorServer(chan, process_handle); -} - -#endif // defined(OS_POSIX) diff --git a/ipc/ipc_switches.cc b/ipc/ipc_switches.cc deleted file mode 100644 index 9d45f7b..0000000 --- a/ipc/ipc_switches.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_switches.h" - -namespace switches { - -// On POSIX only: use FIFO for IPC channels so that "unrelated" process -// can connect to a channel, provided it knows its name. For debugging purposes. -const wchar_t kIPCUseFIFO[] = L"ipc-use-fifo"; - -// The value of this switch tells the child process which -// IPC channel the browser expects to use to communicate with it. -const wchar_t kProcessChannelID[] = L"channel"; - -} // namespace switches diff --git a/ipc/ipc_switches.h b/ipc/ipc_switches.h deleted file mode 100644 index 7dbc746..0000000 --- a/ipc/ipc_switches.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines command line switches used by the IPC system - -#ifndef IPC_IPC_SWITCHES_H__ -#define IPC_IPC_SWITCHES_H__ - -#include "base/base_switches.h" - -namespace switches { - -extern const wchar_t kIPCUseFIFO[]; -extern const wchar_t kProcessChannelID[]; - -} // namespace switches - -#endif // IPC_IPC_SWITCHES_H__ diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc deleted file mode 100644 index 137d9fa..0000000 --- a/ipc/ipc_sync_channel.cc +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_sync_channel.h" - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/thread_local.h" -#include "base/message_loop.h" -#include "base/waitable_event.h" -#include "base/waitable_event_watcher.h" -#include "ipc/ipc_sync_message.h" - -using base::TimeDelta; -using base::TimeTicks; -using base::WaitableEvent; - -namespace IPC { -// When we're blocked in a Send(), we need to process incoming synchronous -// messages right away because it could be blocking our reply (either -// directly from the same object we're calling, or indirectly through one or -// more other channels). That means that in SyncContext's OnMessageReceived, -// we need to process sync message right away if we're blocked. However a -// simple check isn't sufficient, because the listener thread can be in the -// process of calling Send. -// To work around this, when SyncChannel filters a sync message, it sets -// an event that the listener thread waits on during its Send() call. This -// allows us to dispatch incoming sync messages when blocked. The race -// condition is handled because if Send is in the process of being called, it -// will check the event. In case the listener thread isn't sending a message, -// we queue a task on the listener thread to dispatch the received messages. -// The messages are stored in this queue object that's shared among all -// SyncChannel objects on the same thread (since one object can receive a -// sync message while another one is blocked). - -class SyncChannel::ReceivedSyncMsgQueue : - public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> { - public: - // Returns the ReceivedSyncMsgQueue instance for this thread, creating one - // if necessary. Call RemoveContext on the same thread when done. - static ReceivedSyncMsgQueue* AddContext() { - // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple - // SyncChannel objects can block the same thread). - ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get(); - if (!rv) { - rv = new ReceivedSyncMsgQueue(); - ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv); - } - rv->listener_count_++; - return rv; - } - - ~ReceivedSyncMsgQueue() { - } - - // Called on IPC thread when a synchronous message or reply arrives. - void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) { - bool was_task_pending; - { - AutoLock auto_lock(message_lock_); - - was_task_pending = task_pending_; - task_pending_ = true; - - // We set the event in case the listener thread is blocked (or is about - // to). In case it's not, the PostTask dispatches the messages. - message_queue_.push_back(QueuedMessage(new Message(msg), context)); - } - - dispatch_event_.Signal(); - if (!was_task_pending) { - listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( - this, &ReceivedSyncMsgQueue::DispatchMessagesTask)); - } - } - - void QueueReply(const Message &msg, SyncChannel::SyncContext* context) { - received_replies_.push_back(QueuedMessage(new Message(msg), context)); - } - - // Called on the listener's thread to process any queues synchronous - // messages. - void DispatchMessagesTask() { - { - AutoLock auto_lock(message_lock_); - task_pending_ = false; - } - DispatchMessages(); - } - - void DispatchMessages() { - while (true) { - Message* message; - scoped_refptr<SyncChannel::SyncContext> context; - { - AutoLock auto_lock(message_lock_); - if (message_queue_.empty()) - break; - - message = message_queue_.front().message; - context = message_queue_.front().context; - message_queue_.pop_front(); - } - - context->OnDispatchMessage(*message); - delete message; - } - } - - // SyncChannel calls this in its destructor. - void RemoveContext(SyncContext* context) { - AutoLock auto_lock(message_lock_); - - SyncMessageQueue::iterator iter = message_queue_.begin(); - while (iter != message_queue_.end()) { - if (iter->context == context) { - delete iter->message; - iter = message_queue_.erase(iter); - } else { - iter++; - } - } - - if (--listener_count_ == 0) { - DCHECK(lazy_tls_ptr_.Pointer()->Get()); - lazy_tls_ptr_.Pointer()->Set(NULL); - } - } - - WaitableEvent* dispatch_event() { return &dispatch_event_; } - MessageLoop* listener_message_loop() { return listener_message_loop_; } - - // Holds a pointer to the per-thread ReceivedSyncMsgQueue object. - static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue> > - lazy_tls_ptr_; - - // Called on the ipc thread to check if we can unblock any current Send() - // calls based on a queued reply. - void DispatchReplies() { - for (size_t i = 0; i < received_replies_.size(); ++i) { - Message* message = received_replies_[i].message; - if (received_replies_[i].context->TryToUnblockListener(message)) { - delete message; - received_replies_.erase(received_replies_.begin() + i); - return; - } - } - } - - private: - // See the comment in SyncChannel::SyncChannel for why this event is created - // as manual reset. - ReceivedSyncMsgQueue() : - dispatch_event_(true, false), - listener_message_loop_(MessageLoop::current()), - task_pending_(false), - listener_count_(0) { - } - - // Holds information about a queued synchronous message or reply. - struct QueuedMessage { - QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { } - Message* message; - scoped_refptr<SyncChannel::SyncContext> context; - }; - - typedef std::deque<QueuedMessage> SyncMessageQueue; - SyncMessageQueue message_queue_; - - std::vector<QueuedMessage> received_replies_; - - // Set when we got a synchronous message that we must respond to as the - // sender needs its reply before it can reply to our original synchronous - // message. - WaitableEvent dispatch_event_; - MessageLoop* listener_message_loop_; - Lock message_lock_; - bool task_pending_; - int listener_count_; -}; - -base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> > - SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED); - -SyncChannel::SyncContext::SyncContext( - Channel::Listener* listener, - MessageFilter* filter, - MessageLoop* ipc_thread, - WaitableEvent* shutdown_event) - : ChannelProxy::Context(listener, filter, ipc_thread), - received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()), - shutdown_event_(shutdown_event) { -} - -SyncChannel::SyncContext::~SyncContext() { - while (!deserializers_.empty()) - Pop(); -} - -// Adds information about an outgoing sync message to the context so that -// we know how to deserialize the reply. Returns a handle that's set when -// the reply has arrived. -void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) { - // The event is created as manual reset because in between Signal and - // OnObjectSignalled, another Send can happen which would stop the watcher - // from being called. The event would get watched later, when the nested - // Send completes, so the event will need to remain set. - PendingSyncMsg pending(SyncMessage::GetMessageId(*sync_msg), - sync_msg->GetReplyDeserializer(), - new WaitableEvent(true, false)); - AutoLock auto_lock(deserializers_lock_); - deserializers_.push_back(pending); -} - -bool SyncChannel::SyncContext::Pop() { - bool result; - { - AutoLock auto_lock(deserializers_lock_); - PendingSyncMsg msg = deserializers_.back(); - delete msg.deserializer; - delete msg.done_event; - msg.done_event = NULL; - deserializers_.pop_back(); - result = msg.send_result; - } - - // We got a reply to a synchronous Send() call that's blocking the listener - // thread. However, further down the call stack there could be another - // blocking Send() call, whose reply we received after we made this last - // Send() call. So check if we have any queued replies available that - // can now unblock the listener thread. - ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - received_sync_msgs_.get(), &ReceivedSyncMsgQueue::DispatchReplies)); - - return result; -} - -WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() { - AutoLock auto_lock(deserializers_lock_); - return deserializers_.back().done_event; -} - -WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() { - return received_sync_msgs_->dispatch_event(); -} - -void SyncChannel::SyncContext::DispatchMessages() { - received_sync_msgs_->DispatchMessages(); -} - -bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) { - AutoLock auto_lock(deserializers_lock_); - if (deserializers_.empty() || - !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) { - return false; - } - - if (!msg->is_reply_error()) { - deserializers_.back().send_result = deserializers_.back().deserializer-> - SerializeOutputParameters(*msg); - } - deserializers_.back().done_event->Signal(); - - return true; -} - -void SyncChannel::SyncContext::Clear() { - CancelPendingSends(); - received_sync_msgs_->RemoveContext(this); - - Context::Clear(); -} - -void SyncChannel::SyncContext::OnMessageReceived(const Message& msg) { - // Give the filters a chance at processing this message. - if (TryFilters(msg)) - return; - - if (TryToUnblockListener(&msg)) - return; - - if (msg.should_unblock()) { - received_sync_msgs_->QueueMessage(msg, this); - return; - } - - if (msg.is_reply()) { - received_sync_msgs_->QueueReply(msg, this); - return; - } - - return Context::OnMessageReceivedNoFilter(msg); -} - -void SyncChannel::SyncContext::OnChannelError() { - CancelPendingSends(); - shutdown_watcher_.StopWatching(); - Context::OnChannelError(); -} - -void SyncChannel::SyncContext::OnChannelOpened() { - shutdown_watcher_.StartWatching(shutdown_event_, this); - Context::OnChannelOpened(); -} - -void SyncChannel::SyncContext::OnChannelClosed() { - shutdown_watcher_.StopWatching(); - Context::OnChannelClosed(); -} - -void SyncChannel::SyncContext::OnSendTimeout(int message_id) { - AutoLock auto_lock(deserializers_lock_); - PendingSyncMessageQueue::iterator iter; - for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) { - if (iter->id == message_id) { - iter->done_event->Signal(); - break; - } - } -} - -void SyncChannel::SyncContext::CancelPendingSends() { - AutoLock auto_lock(deserializers_lock_); - PendingSyncMessageQueue::iterator iter; - for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) - iter->done_event->Signal(); -} - -void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) { - DCHECK(event == shutdown_event_); - // Process shut down before we can get a reply to a synchronous message. - // Cancel pending Send calls, which will end up setting the send done event. - CancelPendingSends(); -} - - -SyncChannel::SyncChannel( - const std::wstring& channel_id, Channel::Mode mode, - Channel::Listener* listener, MessageFilter* filter, - MessageLoop* ipc_message_loop, bool create_pipe_now, - WaitableEvent* shutdown_event) - : ChannelProxy( - channel_id, mode, ipc_message_loop, - new SyncContext(listener, filter, ipc_message_loop, shutdown_event), - create_pipe_now), - sync_messages_with_no_timeout_allowed_(true) { - // Ideally we only want to watch this object when running a nested message - // loop. However, we don't know when it exits if there's another nested - // message loop running under it or not, so we wouldn't know whether to - // stop or keep watching. So we always watch it, and create the event as - // manual reset since the object watcher might otherwise reset the event - // when we're doing a WaitMany. - dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this); -} - -SyncChannel::~SyncChannel() { -} - -bool SyncChannel::Send(Message* message) { - return SendWithTimeout(message, base::kNoTimeout); -} - -bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) { - if (!message->is_sync()) { - ChannelProxy::Send(message); - return true; - } - - // *this* might get deleted in WaitForReply. - scoped_refptr<SyncContext> context(sync_context()); - if (context->shutdown_event()->IsSignaled()) { - delete message; - 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_message_loop()->PostDelayedTask(FROM_HERE, - NewRunnableMethod(context.get(), - &SyncContext::OnSendTimeout, message_id), timeout_ms); - } - - // Wait for reply, or for any other incoming synchronous messages. - WaitForReply(pump_messages_event); - - return context->Pop(); -} - -void SyncChannel::WaitForReply(WaitableEvent* pump_messages_event) { - while (true) { - WaitableEvent* objects[] = { - sync_context()->GetDispatchEvent(), - sync_context()->GetSendDoneEvent(), - pump_messages_event - }; - - unsigned count = pump_messages_event ? 3: 2; - unsigned result = WaitableEvent::WaitMany(objects, count); - if (result == 0 /* dispatch event */) { - // We're waiting for a reply, but we received a blocking synchronous - // call. We must process it or otherwise a deadlock might occur. - sync_context()->GetDispatchEvent()->Reset(); - sync_context()->DispatchMessages(); - continue; - } - - if (result == 2 /* pump_messages_event */) - WaitForReplyWithNestedMessageLoop(); // Start a nested message loop. - - break; - } -} - -void SyncChannel::WaitForReplyWithNestedMessageLoop() { - WaitableEvent* old_done_event = send_done_watcher_.GetWatchedEvent(); - send_done_watcher_.StopWatching(); - send_done_watcher_.StartWatching(sync_context()->GetSendDoneEvent(), this); - bool old_state = MessageLoop::current()->NestableTasksAllowed(); - MessageLoop::current()->SetNestableTasksAllowed(true); - MessageLoop::current()->Run(); - MessageLoop::current()->SetNestableTasksAllowed(old_state); - if (old_done_event) - send_done_watcher_.StartWatching(old_done_event, this); -} - -void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) { - WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent(); - if (event == dispatch_event) { - // The call to DispatchMessages might delete this object, so reregister - // the object watcher first. - dispatch_event->Reset(); - dispatch_watcher_.StartWatching(dispatch_event, this); - sync_context()->DispatchMessages(); - } else { - // We got the reply, timed out or the process shutdown. - DCHECK(event == sync_context()->GetSendDoneEvent()); - MessageLoop::current()->Quit(); - } -} - -} // namespace IPC diff --git a/ipc/ipc_sync_channel.h b/ipc/ipc_sync_channel.h deleted file mode 100644 index d802d91..0000000 --- a/ipc/ipc_sync_channel.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMMON_IPC_SYNC_SENDER_H__ -#define COMMON_IPC_SYNC_SENDER_H__ - -#include <string> -#include <deque> -#include "base/basictypes.h" -#include "base/lock.h" -#include "base/ref_counted.h" -#include "base/scoped_handle.h" -#include "base/waitable_event.h" -#include "base/waitable_event_watcher.h" -#include "ipc/ipc_channel_proxy.h" - -namespace IPC { - -class SyncMessage; -class MessageReplyDeserializer; - -// This is similar to IPC::ChannelProxy, with the added feature of supporting -// sending synchronous messages. -// Note that care must be taken that the lifetime of the ipc_thread argument -// is more than this object. If the message loop goes away while this object -// is running and it's used to send a message, then it will use the invalid -// message loop pointer to proxy it to the ipc thread. -class SyncChannel : public ChannelProxy, - public base::WaitableEventWatcher::Delegate { - public: - SyncChannel(const std::wstring& channel_id, Channel::Mode mode, - Channel::Listener* listener, MessageFilter* filter, - MessageLoop* ipc_message_loop, bool create_pipe_now, - base::WaitableEvent* shutdown_event); - ~SyncChannel(); - - virtual bool Send(Message* message); - 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; - } - - protected: - class ReceivedSyncMsgQueue; - friend class ReceivedSyncMsgQueue; - - // SyncContext holds the per object data for SyncChannel, so that SyncChannel - // can be deleted while it's being used in a different thread. See - // ChannelProxy::Context for more information. - class SyncContext : public Context, - public base::WaitableEventWatcher::Delegate { - public: - SyncContext(Channel::Listener* listener, - MessageFilter* filter, - MessageLoop* ipc_thread, - base::WaitableEvent* shutdown_event); - - ~SyncContext(); - - // Adds information about an outgoing sync message to the context so that - // we know how to deserialize the reply. - void Push(IPC::SyncMessage* sync_msg); - - // Cleanly remove the top deserializer (and throw it away). Returns the - // result of the Send call for that message. - bool Pop(); - - // Returns an event that's set when the send is complete, timed out or the - // process shut down. - base::WaitableEvent* GetSendDoneEvent(); - - // Returns an event that's set when an incoming message that's not the reply - // needs to get dispatched (by calling SyncContext::DispatchMessages). - base::WaitableEvent* GetDispatchEvent(); - - void DispatchMessages(); - - // Checks if the given message is blocking the listener thread because of a - // synchronous send. If it is, the thread is unblocked and true is - // returned. Otherwise the function returns false. - bool TryToUnblockListener(const Message* msg); - - // Called on the IPC thread when a sync send that runs a nested message loop - // times out. - void OnSendTimeout(int message_id); - - base::WaitableEvent* shutdown_event() { return shutdown_event_; } - - private: - // IPC::ChannelProxy methods that we override. - - // Called on the listener thread. - virtual void Clear(); - - // Called on the IPC thread. - virtual void OnMessageReceived(const Message& msg); - virtual void OnChannelError(); - virtual void OnChannelOpened(); - virtual void OnChannelClosed(); - - // Cancels all pending Send calls. - void CancelPendingSends(); - - // WaitableEventWatcher::Delegate implementation. - virtual void OnWaitableEventSignaled(base::WaitableEvent* arg); - - // When sending a synchronous message, this structure contains an object - // that knows how to deserialize the response. - struct PendingSyncMsg { - PendingSyncMsg(int id, IPC::MessageReplyDeserializer* d, - base::WaitableEvent* e) : - id(id), deserializer(d), done_event(e), send_result(false) { } - int id; - IPC::MessageReplyDeserializer* deserializer; - base::WaitableEvent* done_event; - bool send_result; - }; - - typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue; - PendingSyncMessageQueue deserializers_; - Lock deserializers_lock_; - - scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_; - - base::WaitableEvent* shutdown_event_; - base::WaitableEventWatcher shutdown_watcher_; - }; - - private: - // WaitableEventWatcher::Delegate implementation. - virtual void OnWaitableEventSignaled(base::WaitableEvent* arg); - - SyncContext* sync_context() { - return reinterpret_cast<SyncContext*>(context()); - } - - // Both these functions wait for a reply, timeout or process shutdown. The - // latter one also runs a nested message loop in the meantime. - void WaitForReply(base::WaitableEvent* pump_messages_event); - - // Runs a nested message loop until a reply arrives, times out, or the process - // shuts down. - void WaitForReplyWithNestedMessageLoop(); - - bool sync_messages_with_no_timeout_allowed_; - - // Used to signal events between the IPC and listener threads. - base::WaitableEventWatcher send_done_watcher_; - base::WaitableEventWatcher dispatch_watcher_; - - DISALLOW_EVIL_CONSTRUCTORS(SyncChannel); -}; - -} // namespace IPC - -#endif // COMMON_IPC_SYNC_SENDER_H__ diff --git a/ipc/ipc_sync_channel_unittest.cc b/ipc/ipc_sync_channel_unittest.cc deleted file mode 100644 index 056a084..0000000 --- a/ipc/ipc_sync_channel_unittest.cc +++ /dev/null @@ -1,1013 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit test for SyncChannel. - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/platform_thread.h" -#include "base/string_util.h" -#include "base/thread.h" -#include "base/waitable_event.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_sync_channel.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if 0 -// This for tools which parse #include lines, but cannot process when we -// include via a macro name. -#include "ipc/ipc_sync_message_unittest.h" -#endif -#define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h" -#include "ipc/ipc_message_macros.h" - -using namespace IPC; -using base::WaitableEvent; - -namespace { - -// Base class for a "process" with listener and IPC threads. -class Worker : public Channel::Listener, public Message::Sender { - public: - // Will create a channel without a name. - Worker(Channel::Mode mode, const std::string& thread_name) - : done_(new WaitableEvent(false, false)), - channel_created_(new WaitableEvent(false, false)), - mode_(mode), - ipc_thread_((thread_name + "_ipc").c_str()), - listener_thread_((thread_name + "_listener").c_str()), - overrided_thread_(NULL), - shutdown_event_(true, false) { } - - // Will create a named channel and use this name for the threads' name. - Worker(const std::wstring& channel_name, Channel::Mode mode) - : done_(new WaitableEvent(false, false)), - channel_created_(new WaitableEvent(false, false)), - channel_name_(channel_name), - mode_(mode), - ipc_thread_((WideToUTF8(channel_name) + "_ipc").c_str()), - listener_thread_((WideToUTF8(channel_name) + "_listener").c_str()), - overrided_thread_(NULL), - shutdown_event_(true, false) { } - - // The IPC thread needs to outlive SyncChannel, so force the correct order of - // destruction. - virtual ~Worker() { - WaitableEvent listener_done(false, false), ipc_done(false, false); - ListenerThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &Worker::OnListenerThreadShutdown1, &listener_done, - &ipc_done)); - listener_done.Wait(); - ipc_done.Wait(); - ipc_thread_.Stop(); - listener_thread_.Stop(); - } - void AddRef() { } - void Release() { } - bool Send(Message* msg) { 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(MessageLoop::current() == ListenerThread()->message_loop()); - channel_->Close(); - } - void Start() { - StartThread(&listener_thread_, MessageLoop::TYPE_DEFAULT); - ListenerThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &Worker::OnStart)); - } - void OverrideThread(base::Thread* overrided_thread) { - DCHECK(overrided_thread_ == NULL); - overrided_thread_ = overrided_thread; - } - bool SendAnswerToLife(bool pump, int timeout, bool succeed) { - int answer = 0; - SyncMessage* msg = new SyncChannelTestMsg_AnswerToLife(&answer); - if (pump) - msg->EnableMessagePumping(); - bool result = SendWithTimeout(msg, timeout); - DCHECK(result == succeed); - DCHECK(answer == (succeed ? 42 : 0)); - return result; - } - bool SendDouble(bool pump, bool succeed) { - int answer = 0; - SyncMessage* msg = new SyncChannelTestMsg_Double(5, &answer); - if (pump) - msg->EnableMessagePumping(); - bool result = Send(msg); - DCHECK(result == succeed); - DCHECK(answer == (succeed ? 10 : 0)); - return result; - } - Channel::Mode mode() { return mode_; } - WaitableEvent* done_event() { return done_.get(); } - - protected: - // Derived classes need to call this when they've completed their part of - // the test. - void Done() { done_->Signal(); } - // Functions for dervied classes to implement if they wish. - virtual void Run() { } - virtual void OnAnswer(int* answer) { NOTREACHED(); } - virtual void OnAnswerDelay(Message* reply_msg) { - // The message handler map below can only take one entry for - // SyncChannelTestMsg_AnswerToLife, so since some classes want - // the normal version while other want the delayed reply, we - // call the normal version if the derived class didn't override - // this function. - int answer; - OnAnswer(&answer); - SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, answer); - Send(reply_msg); - } - virtual void OnDouble(int in, int* out) { NOTREACHED(); } - virtual void OnDoubleDelay(int in, Message* reply_msg) { - int result; - OnDouble(in, &result); - SyncChannelTestMsg_Double::WriteReplyParams(reply_msg, result); - Send(reply_msg); - } - - private: - base::Thread* ListenerThread() { - return overrided_thread_ ? overrided_thread_ : &listener_thread_; - } - // Called on the listener thread to create the sync channel. - void OnStart() { - // Link ipc_thread_, listener_thread_ and channel_ altogether. - StartThread(&ipc_thread_, MessageLoop::TYPE_IO); - channel_.reset(new SyncChannel( - channel_name_, mode_, this, NULL, ipc_thread_.message_loop(), true, - &shutdown_event_)); - channel_created_->Signal(); - Run(); - } - - void OnListenerThreadShutdown1(WaitableEvent* listener_event, - WaitableEvent* ipc_event) { - // SyncChannel needs to be destructed on the thread that it was created on. - channel_.reset(); - - MessageLoop::current()->RunAllPending(); - - ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &Worker::OnIPCThreadShutdown, listener_event, ipc_event)); - } - - void OnIPCThreadShutdown(WaitableEvent* listener_event, - WaitableEvent* ipc_event) { - MessageLoop::current()->RunAllPending(); - ipc_event->Signal(); - - listener_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &Worker::OnListenerThreadShutdown2, listener_event)); - } - - void OnListenerThreadShutdown2(WaitableEvent* listener_event) { - MessageLoop::current()->RunAllPending(); - listener_event->Signal(); - } - - void OnMessageReceived(const Message& message) { - IPC_BEGIN_MESSAGE_MAP(Worker, message) - IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_Double, OnDoubleDelay) - IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_AnswerToLife, - OnAnswerDelay) - IPC_END_MESSAGE_MAP() - } - - void StartThread(base::Thread* thread, MessageLoop::Type type) { - base::Thread::Options options; - options.message_loop_type = type; - thread->StartWithOptions(options); - } - - scoped_ptr<WaitableEvent> done_; - scoped_ptr<WaitableEvent> channel_created_; - std::wstring channel_name_; - Channel::Mode mode_; - scoped_ptr<SyncChannel> channel_; - base::Thread ipc_thread_; - base::Thread listener_thread_; - base::Thread* overrided_thread_; - - base::WaitableEvent shutdown_event_; - - DISALLOW_EVIL_CONSTRUCTORS(Worker); -}; - - -// Starts the test with the given workers. This function deletes the workers -// when it's done. -void RunTest(std::vector<Worker*> workers) { - // First we create the workers that are channel servers, or else the other - // workers' channel initialization might fail because the pipe isn't created.. - for (size_t i = 0; i < workers.size(); ++i) { - if (workers[i]->mode() == Channel::MODE_SERVER) { - workers[i]->Start(); - workers[i]->WaitForChannelCreation(); - } - } - - // now create the clients - for (size_t i = 0; i < workers.size(); ++i) { - if (workers[i]->mode() == Channel::MODE_CLIENT) - workers[i]->Start(); - } - - // wait for all the workers to finish - for (size_t i = 0; i < workers.size(); ++i) - workers[i]->done_event()->Wait(); - - for (size_t i = 0; i < workers.size(); ++i) - delete workers[i]; -} - -} // namespace - -class IPCSyncChannelTest : public testing::Test { - private: - MessageLoop message_loop_; -}; - -//----------------------------------------------------------------------------- - -namespace { - -class SimpleServer : public Worker { - public: - SimpleServer(bool pump_during_send) - : Worker(Channel::MODE_SERVER, "simpler_server"), - pump_during_send_(pump_during_send) { } - void Run() { - SendAnswerToLife(pump_during_send_, base::kNoTimeout, true); - Done(); - } - - bool pump_during_send_; -}; - -class SimpleClient : public Worker { - public: - SimpleClient() : Worker(Channel::MODE_CLIENT, "simple_client") { } - - void OnAnswer(int* answer) { - *answer = 42; - Done(); - } -}; - -void Simple(bool pump_during_send) { - std::vector<Worker*> workers; - workers.push_back(new SimpleServer(pump_during_send)); - workers.push_back(new SimpleClient()); - RunTest(workers); -} - -} // namespace - -// Tests basic synchronous call -TEST_F(IPCSyncChannelTest, Simple) { - Simple(false); - Simple(true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class DelayClient : public Worker { - public: - DelayClient() : Worker(Channel::MODE_CLIENT, "delay_client") { } - - void OnAnswerDelay(Message* reply_msg) { - SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42); - Send(reply_msg); - Done(); - } -}; - -void DelayReply(bool pump_during_send) { - std::vector<Worker*> workers; - workers.push_back(new SimpleServer(pump_during_send)); - workers.push_back(new DelayClient()); - RunTest(workers); -} - -} // namespace - -// Tests that asynchronous replies work -TEST_F(IPCSyncChannelTest, DelayReply) { - DelayReply(false); - DelayReply(true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class NoHangServer : public Worker { - public: - explicit NoHangServer(WaitableEvent* got_first_reply, bool pump_during_send) - : Worker(Channel::MODE_SERVER, "no_hang_server"), - got_first_reply_(got_first_reply), - pump_during_send_(pump_during_send) { } - void Run() { - SendAnswerToLife(pump_during_send_, base::kNoTimeout, true); - got_first_reply_->Signal(); - - SendAnswerToLife(pump_during_send_, base::kNoTimeout, false); - Done(); - } - - WaitableEvent* got_first_reply_; - bool pump_during_send_; -}; - -class NoHangClient : public Worker { - public: - explicit NoHangClient(WaitableEvent* got_first_reply) - : Worker(Channel::MODE_CLIENT, "no_hang_client"), - got_first_reply_(got_first_reply) { } - - virtual void OnAnswerDelay(Message* reply_msg) { - // Use the DELAY_REPLY macro so that we can force the reply to be sent - // before this function returns (when the channel will be reset). - SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42); - Send(reply_msg); - got_first_reply_->Wait(); - CloseChannel(); - Done(); - } - - WaitableEvent* got_first_reply_; -}; - -void NoHang(bool pump_during_send) { - WaitableEvent got_first_reply(false, false); - std::vector<Worker*> workers; - workers.push_back(new NoHangServer(&got_first_reply, pump_during_send)); - workers.push_back(new NoHangClient(&got_first_reply)); - RunTest(workers); -} - -} // namespace - -// Tests that caller doesn't hang if receiver dies -TEST_F(IPCSyncChannelTest, NoHang) { - NoHang(false); - NoHang(true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class UnblockServer : public Worker { - public: - UnblockServer(bool pump_during_send) - : Worker(Channel::MODE_SERVER, "unblock_server"), - pump_during_send_(pump_during_send) { } - void Run() { - SendAnswerToLife(pump_during_send_, base::kNoTimeout, true); - Done(); - } - - void OnDouble(int in, int* out) { - *out = in * 2; - } - - bool pump_during_send_; -}; - -class UnblockClient : public Worker { - public: - UnblockClient(bool pump_during_send) - : Worker(Channel::MODE_CLIENT, "unblock_client"), - pump_during_send_(pump_during_send) { } - - void OnAnswer(int* answer) { - SendDouble(pump_during_send_, true); - *answer = 42; - Done(); - } - - bool pump_during_send_; -}; - -void Unblock(bool server_pump, bool client_pump) { - std::vector<Worker*> workers; - workers.push_back(new UnblockServer(server_pump)); - workers.push_back(new UnblockClient(client_pump)); - RunTest(workers); -} - -} // namespace - -// Tests that the caller unblocks to answer a sync message from the receiver. -TEST_F(IPCSyncChannelTest, Unblock) { - Unblock(false, false); - Unblock(false, true); - Unblock(true, false); - Unblock(true, true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class RecursiveServer : public Worker { - public: - explicit RecursiveServer( - bool expected_send_result, bool pump_first, bool pump_second) - : Worker(Channel::MODE_SERVER, "recursive_server"), - expected_send_result_(expected_send_result), - pump_first_(pump_first), pump_second_(pump_second) { } - void Run() { - SendDouble(pump_first_, expected_send_result_); - Done(); - } - - void OnDouble(int in, int* out) { - *out = in * 2; - SendAnswerToLife(pump_second_, base::kNoTimeout, expected_send_result_); - } - - bool expected_send_result_, pump_first_, pump_second_; -}; - -class RecursiveClient : public Worker { - public: - explicit RecursiveClient(bool pump_during_send, bool close_channel) - : Worker(Channel::MODE_CLIENT, "recursive_client"), - pump_during_send_(pump_during_send), close_channel_(close_channel) { } - - void OnDoubleDelay(int in, Message* reply_msg) { - SendDouble(pump_during_send_, !close_channel_); - if (close_channel_) { - delete reply_msg; - } else { - SyncChannelTestMsg_Double::WriteReplyParams(reply_msg, in * 2); - Send(reply_msg); - } - Done(); - } - - void OnAnswerDelay(Message* reply_msg) { - if (close_channel_) { - delete reply_msg; - CloseChannel(); - } else { - SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42); - Send(reply_msg); - } - } - - bool pump_during_send_, close_channel_; -}; - -void Recursive( - bool server_pump_first, bool server_pump_second, bool client_pump) { - std::vector<Worker*> workers; - workers.push_back( - new RecursiveServer(true, server_pump_first, server_pump_second)); - workers.push_back(new RecursiveClient(client_pump, false)); - RunTest(workers); -} - -} // namespace - -// Tests a server calling Send while another Send is pending. -TEST_F(IPCSyncChannelTest, Recursive) { - Recursive(false, false, false); - Recursive(false, false, true); - Recursive(false, true, false); - Recursive(false, true, true); - Recursive(true, false, false); - Recursive(true, false, true); - Recursive(true, true, false); - Recursive(true, true, true); -} - -//----------------------------------------------------------------------------- - -namespace { - -void RecursiveNoHang( - bool server_pump_first, bool server_pump_second, bool client_pump) { - std::vector<Worker*> workers; - workers.push_back( - new RecursiveServer(false, server_pump_first, server_pump_second)); - workers.push_back(new RecursiveClient(client_pump, true)); - RunTest(workers); -} - -} // namespace - -// Tests that if a caller makes a sync call during an existing sync call and -// the receiver dies, neither of the Send() calls hang. -TEST_F(IPCSyncChannelTest, RecursiveNoHang) { - RecursiveNoHang(false, false, false); - RecursiveNoHang(false, false, true); - RecursiveNoHang(false, true, false); - RecursiveNoHang(false, true, true); - RecursiveNoHang(true, false, false); - RecursiveNoHang(true, false, true); - RecursiveNoHang(true, true, false); - RecursiveNoHang(true, true, true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class MultipleServer1 : public Worker { - public: - MultipleServer1(bool pump_during_send) - : Worker(L"test_channel1", Channel::MODE_SERVER), - pump_during_send_(pump_during_send) { } - - void Run() { - SendDouble(pump_during_send_, true); - Done(); - } - - bool pump_during_send_; -}; - -class MultipleClient1 : public Worker { - public: - MultipleClient1(WaitableEvent* client1_msg_received, - WaitableEvent* client1_can_reply) : - Worker(L"test_channel1", Channel::MODE_CLIENT), - client1_msg_received_(client1_msg_received), - client1_can_reply_(client1_can_reply) { } - - void OnDouble(int in, int* out) { - client1_msg_received_->Signal(); - *out = in * 2; - client1_can_reply_->Wait(); - Done(); - } - - private: - WaitableEvent *client1_msg_received_, *client1_can_reply_; -}; - -class MultipleServer2 : public Worker { - public: - MultipleServer2() : Worker(L"test_channel2", Channel::MODE_SERVER) { } - - void OnAnswer(int* result) { - *result = 42; - Done(); - } -}; - -class MultipleClient2 : public Worker { - public: - MultipleClient2( - WaitableEvent* client1_msg_received, WaitableEvent* client1_can_reply, - bool pump_during_send) - : Worker(L"test_channel2", Channel::MODE_CLIENT), - client1_msg_received_(client1_msg_received), - client1_can_reply_(client1_can_reply), - pump_during_send_(pump_during_send) { } - - void Run() { - client1_msg_received_->Wait(); - SendAnswerToLife(pump_during_send_, base::kNoTimeout, true); - client1_can_reply_->Signal(); - Done(); - } - - private: - WaitableEvent *client1_msg_received_, *client1_can_reply_; - bool pump_during_send_; -}; - -void Multiple(bool server_pump, bool client_pump) { - std::vector<Worker*> workers; - - // A shared worker thread so that server1 and server2 run on one thread. - base::Thread worker_thread("Multiple"); - worker_thread.Start(); - - // Server1 sends a sync msg to client1, which blocks the reply until - // server2 (which runs on the same worker thread as server1) responds - // to a sync msg from client2. - WaitableEvent client1_msg_received(false, false); - WaitableEvent client1_can_reply(false, false); - - Worker* worker; - - worker = new MultipleServer2(); - worker->OverrideThread(&worker_thread); - workers.push_back(worker); - - worker = new MultipleClient2( - &client1_msg_received, &client1_can_reply, client_pump); - workers.push_back(worker); - - worker = new MultipleServer1(server_pump); - worker->OverrideThread(&worker_thread); - workers.push_back(worker); - - worker = new MultipleClient1( - &client1_msg_received, &client1_can_reply); - workers.push_back(worker); - - RunTest(workers); -} - -} // namespace - -// Tests that multiple SyncObjects on the same listener thread can unblock each -// other. -TEST_F(IPCSyncChannelTest, Multiple) { - Multiple(false, false); - Multiple(false, true); - Multiple(true, false); - Multiple(true, true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class QueuedReplyServer1 : public Worker { - public: - QueuedReplyServer1(bool pump_during_send) - : Worker(L"test_channel1", Channel::MODE_SERVER), - pump_during_send_(pump_during_send) { } - void Run() { - SendDouble(pump_during_send_, true); - Done(); - } - - bool pump_during_send_; -}; - -class QueuedReplyClient1 : public Worker { - public: - QueuedReplyClient1(WaitableEvent* client1_msg_received, - WaitableEvent* server2_can_reply) : - Worker(L"test_channel1", Channel::MODE_CLIENT), - client1_msg_received_(client1_msg_received), - server2_can_reply_(server2_can_reply) { } - - void OnDouble(int in, int* out) { - client1_msg_received_->Signal(); - *out = in * 2; - server2_can_reply_->Wait(); - Done(); - } - - private: - WaitableEvent *client1_msg_received_, *server2_can_reply_; -}; - -class QueuedReplyServer2 : public Worker { - public: - explicit QueuedReplyServer2(WaitableEvent* server2_can_reply) : - Worker(L"test_channel2", Channel::MODE_SERVER), - server2_can_reply_(server2_can_reply) { } - - void OnAnswer(int* result) { - server2_can_reply_->Signal(); - - // give client1's reply time to reach the server listener thread - PlatformThread::Sleep(200); - - *result = 42; - Done(); - } - - WaitableEvent *server2_can_reply_; -}; - -class QueuedReplyClient2 : public Worker { - public: - explicit QueuedReplyClient2( - WaitableEvent* client1_msg_received, bool pump_during_send) - : Worker(L"test_channel2", Channel::MODE_CLIENT), - client1_msg_received_(client1_msg_received), - pump_during_send_(pump_during_send){ } - - void Run() { - client1_msg_received_->Wait(); - SendAnswerToLife(pump_during_send_, base::kNoTimeout, true); - Done(); - } - - WaitableEvent *client1_msg_received_; - bool pump_during_send_; -}; - -void QueuedReply(bool server_pump, bool client_pump) { - std::vector<Worker*> workers; - - // A shared worker thread so that server1 and server2 run on one thread. - base::Thread worker_thread("QueuedReply"); - worker_thread.Start(); - - WaitableEvent client1_msg_received(false, false); - WaitableEvent server2_can_reply(false, false); - - Worker* worker; - - worker = new QueuedReplyServer2(&server2_can_reply); - worker->OverrideThread(&worker_thread); - workers.push_back(worker); - - worker = new QueuedReplyClient2(&client1_msg_received, client_pump); - workers.push_back(worker); - - worker = new QueuedReplyServer1(server_pump); - worker->OverrideThread(&worker_thread); - workers.push_back(worker); - - worker = new QueuedReplyClient1( - &client1_msg_received, &server2_can_reply); - workers.push_back(worker); - - RunTest(workers); -} - -} // namespace - -// While a blocking send is in progress, the listener thread might answer other -// synchronous messages. This tests that if during the response to another -// message the reply to the original messages comes, it is queued up correctly -// and the original Send is unblocked later. -TEST_F(IPCSyncChannelTest, QueuedReply) { - QueuedReply(false, false); - QueuedReply(false, true); - QueuedReply(true, false); - QueuedReply(true, true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class BadServer : public Worker { - public: - BadServer(bool pump_during_send) - : Worker(Channel::MODE_SERVER, "simpler_server"), - pump_during_send_(pump_during_send) { } - void Run() { - int answer = 0; - - SyncMessage* msg = new SyncMessage( - MSG_ROUTING_CONTROL, SyncChannelTestMsg_Double::ID, - Message::PRIORITY_NORMAL, NULL); - if (pump_during_send_) - msg->EnableMessagePumping(); - - // Temporarily set the minimum logging very high so that the assertion - // in ipc_message_utils doesn't fire. - int log_level = logging::GetMinLogLevel(); - logging::SetMinLogLevel(kint32max); - bool result = Send(msg); - logging::SetMinLogLevel(log_level); - DCHECK(!result); - - // Need to send another message to get the client to call Done(). - result = Send(new SyncChannelTestMsg_AnswerToLife(&answer)); - DCHECK(result); - DCHECK(answer == 42); - - Done(); - } - - bool pump_during_send_; -}; - -void BadMessage(bool pump_during_send) { - std::vector<Worker*> workers; - workers.push_back(new BadServer(pump_during_send)); - workers.push_back(new SimpleClient()); - RunTest(workers); -} - -} // namespace - -// Tests that if a message is not serialized correctly, the Send() will fail. -TEST_F(IPCSyncChannelTest, BadMessage) { - BadMessage(false); - BadMessage(true); -} - -//----------------------------------------------------------------------------- - -namespace { - -class ChattyClient : public Worker { - public: - ChattyClient() : - Worker(Channel::MODE_CLIENT, "chatty_client") { } - - void OnAnswer(int* answer) { - // The PostMessage limit is 10k. Send 20% more than that. - const int kMessageLimit = 10000; - const int kMessagesToSend = kMessageLimit * 120 / 100; - for (int i = 0; i < kMessagesToSend; ++i) { - if (!SendDouble(false, true)) - break; - } - *answer = 42; - Done(); - } -}; - -void ChattyServer(bool pump_during_send) { - std::vector<Worker*> workers; - workers.push_back(new UnblockServer(pump_during_send)); - workers.push_back(new ChattyClient()); - RunTest(workers); -} - -} // namespace - -// Tests http://b/1093251 - that sending lots of sync messages while -// the receiver is waiting for a sync reply does not overflow the PostMessage -// queue. -TEST_F(IPCSyncChannelTest, ChattyServer) { - ChattyServer(false); - ChattyServer(true); -} - -//------------------------------------------------------------------------------ - -namespace { - -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) { - } - - void Run() { - 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: - UnresponsiveClient(std::vector<bool> timeout_seq) - : Worker(Channel::MODE_CLIENT, "unresponsive_client"), - timeout_seq_(timeout_seq) { - } - - void OnAnswerDelay(Message* reply_msg) { - 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); -} - -} // namespace - -// 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); -} - -//------------------------------------------------------------------------------ - -namespace { - -class NestedTask : public Task { - public: - NestedTask(Worker* server) : server_(server) { } - void Run() { - // Sleep a bit so that we wake up after the reply has been received. - PlatformThread::Sleep(250); - server_->SendAnswerToLife(true, base::kNoTimeout, true); - } - - Worker* server_; -}; - -static bool timeout_occured = false; - -class TimeoutTask : public Task { - public: - void Run() { - timeout_occured = true; - } -}; - -class DoneEventRaceServer : public Worker { - public: - DoneEventRaceServer() - : Worker(Channel::MODE_SERVER, "done_event_race_server") { } - - void Run() { - MessageLoop::current()->PostTask(FROM_HERE, new NestedTask(this)); - MessageLoop::current()->PostDelayedTask(FROM_HERE, new TimeoutTask(), 9000); - // Even though we have a timeout on the Send, it will succeed since for this - // 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); - DCHECK(!timeout_occured); - Done(); - } -}; - -} // namespace - -// Tests http://b/1474092 - that if after the done_event is set but before -// OnObjectSignaled is called another message is sent out, then after its -// reply comes back OnObjectSignaled will be called for the first message. -TEST_F(IPCSyncChannelTest, DoneEventRace) { - std::vector<Worker*> workers; - workers.push_back(new DoneEventRaceServer()); - workers.push_back(new SimpleClient()); - RunTest(workers); -} diff --git a/ipc/ipc_sync_message.cc b/ipc/ipc_sync_message.cc deleted file mode 100644 index 519adb1..0000000 --- a/ipc/ipc_sync_message.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include <windows.h> -#endif -#include <stack> - -#include "base/logging.h" -#include "base/waitable_event.h" -#include "ipc/ipc_sync_message.h" - -namespace IPC { - -uint32 SyncMessage::next_id_ = 0; -#define kSyncMessageHeaderSize 4 - -base::WaitableEvent* dummy_event = new base::WaitableEvent(true, true); - -SyncMessage::SyncMessage( - int32 routing_id, - uint16 type, - PriorityValue priority, - MessageReplyDeserializer* deserializer) - : Message(routing_id, type, priority), - deserializer_(deserializer), - pump_messages_event_(NULL) - { - set_sync(); - set_unblock(true); - - // Add synchronous message data before the message payload. - SyncHeader header; - header.message_id = ++next_id_; - WriteSyncHeader(this, header); -} - -MessageReplyDeserializer* SyncMessage::GetReplyDeserializer() { - MessageReplyDeserializer* rv = deserializer_; - DCHECK(rv); - deserializer_ = NULL; - return rv; -} - -void SyncMessage::EnableMessagePumping() { - DCHECK(!pump_messages_event_); - set_pump_messages_event(dummy_event); -} - -bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) { - if (!msg.is_reply()) - return false; - - return GetMessageId(msg) == request_id; -} - -void* SyncMessage::GetDataIterator(const Message* msg) { - void* iter = const_cast<char*>(msg->payload()); - UpdateIter(&iter, kSyncMessageHeaderSize); - return iter; -} - -int SyncMessage::GetMessageId(const Message& msg) { - if (!msg.is_sync() && !msg.is_reply()) - return 0; - - SyncHeader header; - if (!ReadSyncHeader(msg, &header)) - return 0; - - return header.message_id; -} - -Message* SyncMessage::GenerateReply(const Message* msg) { - DCHECK(msg->is_sync()); - - Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID, - msg->priority()); - reply->set_reply(); - - SyncHeader header; - - // use the same message id, but this time reply bit is set - header.message_id = GetMessageId(*msg); - WriteSyncHeader(reply, header); - - return reply; -} - -bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) { - DCHECK(msg.is_sync() || msg.is_reply()); - - void* iter = NULL; - bool result = msg.ReadInt(&iter, &header->message_id); - if (!result) { - NOTREACHED(); - return false; - } - - return true; -} - -bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) { - DCHECK(msg->is_sync() || msg->is_reply()); - DCHECK(msg->payload_size() == 0); - bool result = msg->WriteInt(header.message_id); - if (!result) { - NOTREACHED(); - return false; - } - - // Note: if you add anything here, you need to update kSyncMessageHeaderSize. - DCHECK(kSyncMessageHeaderSize == msg->payload_size()); - - return true; -} - - -bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) { - return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg)); -} - -} // namespace IPC diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h deleted file mode 100644 index 3006736..0000000 --- a/ipc/ipc_sync_message.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMMON_IPC_SYNC_MESSAGE_H__ -#define COMMON_IPC_SYNC_MESSAGE_H__ - -#if defined(OS_WIN) -#include <windows.h> -#endif -#include <string> -#include "base/basictypes.h" -#include "ipc/ipc_message.h" - -namespace base { -class WaitableEvent; -} - -namespace IPC { - -class MessageReplyDeserializer; - -class SyncMessage : public Message { - public: - SyncMessage(int32 routing_id, uint16 type, PriorityValue priority, - MessageReplyDeserializer* deserializer); - - // Call this to get a deserializer for the output parameters. - // Note that this can only be called once, and the caller is responsible - // for deleting the deserializer when they're done. - MessageReplyDeserializer* GetReplyDeserializer(); - - // If this message can cause the receiver to block while waiting for user - // input (i.e. by calling MessageBox), then the caller needs to pump window - // messages and dispatch asynchronous messages while waiting for the reply. - // If this event is passed in, then window messages will start being pumped - // when it's set. Note that this behavior will continue even if the event is - // later reset. The event must be valid until after the Send call returns. - void set_pump_messages_event(base::WaitableEvent* event) { - pump_messages_event_ = event; - if (event) { - header()->flags |= PUMPING_MSGS_BIT; - } else { - header()->flags &= ~PUMPING_MSGS_BIT; - } - } - - // Call this if you always want to pump messages. You can call this method - // or set_pump_messages_event but not both. - void EnableMessagePumping(); - - base::WaitableEvent* pump_messages_event() const { - return pump_messages_event_; - } - - // Returns true if the message is a reply to the given request id. - static bool IsMessageReplyTo(const Message& msg, int request_id); - - // Given a reply message, returns an iterator to the beginning of the data - // (i.e. skips over the synchronous specific data). - static void* GetDataIterator(const Message* msg); - - // Given a synchronous message (or its reply), returns its id. - static int GetMessageId(const Message& msg); - - // Generates a reply message to the given message. - static Message* GenerateReply(const Message* msg); - - private: - struct SyncHeader { - // unique ID (unique per sender) - int message_id; - }; - - static bool ReadSyncHeader(const Message& msg, SyncHeader* header); - static bool WriteSyncHeader(Message* msg, const SyncHeader& header); - - MessageReplyDeserializer* deserializer_; - base::WaitableEvent* pump_messages_event_; - - static uint32 next_id_; // for generation of unique ids -}; - -// Used to deserialize parameters from a reply to a synchronous message -class MessageReplyDeserializer { - public: - bool SerializeOutputParameters(const Message& msg); - private: - // Derived classes need to implement this, using the given iterator (which - // is skipped past the header for synchronous messages). - virtual bool SerializeOutputParameters(const Message& msg, void* iter) = 0; -}; - -} // namespace IPC - -#endif // COMMON_IPC_SYNC_MESSAGE_H__ diff --git a/ipc/ipc_sync_message_unittest.cc b/ipc/ipc_sync_message_unittest.cc deleted file mode 100644 index 9e3de1f..0000000 --- a/ipc/ipc_sync_message_unittest.cc +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit test to make sure that the serialization of synchronous IPC messages -// works. This ensures that the macros and templates were defined correctly. -// Doesn't test the IPC channel mechanism. - -#include <string.h> - -#include "base/basictypes.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_message_utils.h" -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if 0 -// This for tools which parse #include lines, but cannot process when we -// include via a macro name. -#include "ipc/ipc_sync_message_unittest.h" -#endif -#define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h" -#include "ipc/ipc_message_macros.h" - -static IPC::Message* g_reply; - -class TestMessageReceiver { - public: - - void On_0_1(bool* out1) { - *out1 = false; - } - - void On_0_2(bool* out1, int* out2) { - *out1 = true; - *out2 = 2; - } - - void On_0_3(bool* out1, int* out2, std::string* out3) { - *out1 = false; - *out2 = 3; - *out3 = "0_3"; - } - - void On_1_1(int in1, bool* out1) { - DCHECK(in1 == 1); - *out1 = true; - } - - void On_1_2(bool in1, bool* out1, int* out2) { - DCHECK(!in1); - *out1 = true; - *out2 = 12; - } - - void On_1_3(int in1, std::string* out1, int* out2, bool* out3) { - DCHECK(in1 == 3); - *out1 = "1_3"; - *out2 = 13; - *out3 = false; - } - - void On_2_1(int in1, bool in2, bool* out1) { - DCHECK(in1 == 1 && !in2); - *out1 = true; - } - - void On_2_2(bool in1, int in2, bool* out1, int* out2) { - DCHECK(!in1 && in2 == 2); - *out1 = true; - *out2 = 22; - } - - void On_2_3(int in1, bool in2, std::string* out1, int* out2, bool* out3) { - DCHECK(in1 == 3 && in2); - *out1 = "2_3"; - *out2 = 23; - *out3 = false; - } - - void On_3_1(int in1, bool in2, std::string in3, bool* out1) { - DCHECK(in1 == 1 && !in2 && in3 == "3_1"); - *out1 = true; - } - - void On_3_2(std::string in1, bool in2, int in3, bool* out1, int* out2) { - DCHECK(in1 == "3_2" && !in2 && in3 == 2); - *out1 = true; - *out2 = 32; - } - - void On_3_3(int in1, std::string in2, bool in3, std::string* out1, int* out2, - bool* out3) { - DCHECK(in1 == 3 && in2 == "3_3" && in3); - *out1 = "3_3"; - *out2 = 33; - *out3 = false; - } - - bool Send(IPC::Message* message) { - // gets the reply message, stash in global - DCHECK(g_reply == NULL); - g_reply = message; - return true; - } - - void OnMessageReceived(const IPC::Message& msg) { - IPC_BEGIN_MESSAGE_MAP(TestMessageReceiver, msg) - IPC_MESSAGE_HANDLER(Msg_C_0_1, On_0_1) - IPC_MESSAGE_HANDLER(Msg_C_0_2, On_0_2) - IPC_MESSAGE_HANDLER(Msg_C_0_3, On_0_3) - IPC_MESSAGE_HANDLER(Msg_C_1_1, On_1_1) - IPC_MESSAGE_HANDLER(Msg_C_1_2, On_1_2) - IPC_MESSAGE_HANDLER(Msg_C_1_3, On_1_3) - IPC_MESSAGE_HANDLER(Msg_C_2_1, On_2_1) - IPC_MESSAGE_HANDLER(Msg_C_2_2, On_2_2) - IPC_MESSAGE_HANDLER(Msg_C_2_3, On_2_3) - IPC_MESSAGE_HANDLER(Msg_C_3_1, On_3_1) - IPC_MESSAGE_HANDLER(Msg_C_3_2, On_3_2) - IPC_MESSAGE_HANDLER(Msg_C_3_3, On_3_3) - IPC_MESSAGE_HANDLER(Msg_R_0_1, On_0_1) - IPC_MESSAGE_HANDLER(Msg_R_0_2, On_0_2) - IPC_MESSAGE_HANDLER(Msg_R_0_3, On_0_3) - IPC_MESSAGE_HANDLER(Msg_R_1_1, On_1_1) - IPC_MESSAGE_HANDLER(Msg_R_1_2, On_1_2) - IPC_MESSAGE_HANDLER(Msg_R_1_3, On_1_3) - IPC_MESSAGE_HANDLER(Msg_R_2_1, On_2_1) - IPC_MESSAGE_HANDLER(Msg_R_2_2, On_2_2) - IPC_MESSAGE_HANDLER(Msg_R_2_3, On_2_3) - IPC_MESSAGE_HANDLER(Msg_R_3_1, On_3_1) - IPC_MESSAGE_HANDLER(Msg_R_3_2, On_3_2) - IPC_MESSAGE_HANDLER(Msg_R_3_3, On_3_3) - IPC_END_MESSAGE_MAP() - } - -}; - -void Send(IPC::SyncMessage* msg) { - static TestMessageReceiver receiver; - - IPC::MessageReplyDeserializer* reply_serializer = msg->GetReplyDeserializer(); - DCHECK(reply_serializer != NULL); - - // "send" the message - receiver.OnMessageReceived(*msg); - delete msg; - - // get the reply message from the global, and deserialize the output - // parameters into the output pointers. - DCHECK(g_reply != NULL); - bool result = reply_serializer->SerializeOutputParameters(*g_reply); - DCHECK(result); - delete g_reply; - g_reply = NULL; - delete reply_serializer; -} - -TEST(IPCSyncMessageTest, Main) { - bool bool1 = true; - int int1 = 0; - std::string string1; - - Send(new Msg_C_0_1(&bool1)); - DCHECK(!bool1); - - Send(new Msg_C_0_2(&bool1, &int1)); - DCHECK(bool1 && int1 == 2); - - Send(new Msg_C_0_3(&bool1, &int1, &string1)); - DCHECK(!bool1 && int1 == 3 && string1 == "0_3"); - - bool1 = false; - Send(new Msg_C_1_1(1, &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_C_1_2(false, &bool1, &int1)); - DCHECK(bool1 && int1 == 12); - - bool1 = true; - Send(new Msg_C_1_3(3, &string1, &int1, &bool1)); - DCHECK(string1 == "1_3" && int1 == 13 && !bool1); - - bool1 = false; - Send(new Msg_C_2_1(1, false, &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_C_2_2(false, 2, &bool1, &int1)); - DCHECK(bool1 && int1 == 22); - - bool1 = true; - Send(new Msg_C_2_3(3, true, &string1, &int1, &bool1)); - DCHECK(string1 == "2_3" && int1 == 23 && !bool1); - - bool1 = false; - Send(new Msg_C_3_1(1, false, "3_1", &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_C_3_2("3_2", false, 2, &bool1, &int1)); - DCHECK(bool1 && int1 == 32); - - bool1 = true; - Send(new Msg_C_3_3(3, "3_3", true, &string1, &int1, &bool1)); - DCHECK(string1 == "3_3" && int1 == 33 && !bool1); - - // Routed messages, just a copy of the above but with extra routing paramater - Send(new Msg_R_0_1(0, &bool1)); - DCHECK(!bool1); - - Send(new Msg_R_0_2(0, &bool1, &int1)); - DCHECK(bool1 && int1 == 2); - - Send(new Msg_R_0_3(0, &bool1, &int1, &string1)); - DCHECK(!bool1 && int1 == 3 && string1 == "0_3"); - - bool1 = false; - Send(new Msg_R_1_1(0, 1, &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_R_1_2(0, false, &bool1, &int1)); - DCHECK(bool1 && int1 == 12); - - bool1 = true; - Send(new Msg_R_1_3(0, 3, &string1, &int1, &bool1)); - DCHECK(string1 == "1_3" && int1 == 13 && !bool1); - - bool1 = false; - Send(new Msg_R_2_1(0, 1, false, &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_R_2_2(0, false, 2, &bool1, &int1)); - DCHECK(bool1 && int1 == 22); - - bool1 = true; - Send(new Msg_R_2_3(0, 3, true, &string1, &int1, &bool1)); - DCHECK(string1 == "2_3" && int1 == 23 && !bool1); - - bool1 = false; - Send(new Msg_R_3_1(0, 1, false, "3_1", &bool1)); - DCHECK(bool1); - - bool1 = false; - Send(new Msg_R_3_2(0, "3_2", false, 2, &bool1, &int1)); - DCHECK(bool1 && int1 == 32); - - bool1 = true; - Send(new Msg_R_3_3(0, 3, "3_3", true, &string1, &int1, &bool1)); - DCHECK(string1 == "3_3" && int1 == 33 && !bool1); -} diff --git a/ipc/ipc_sync_message_unittest.h b/ipc/ipc_sync_message_unittest.h deleted file mode 100644 index 7b252b5..0000000 --- a/ipc/ipc_sync_message_unittest.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_message_macros.h" - -IPC_BEGIN_MESSAGES(Test) - IPC_SYNC_MESSAGE_CONTROL0_0(SyncChannelTestMsg_NoArgs) - - IPC_SYNC_MESSAGE_CONTROL0_1(SyncChannelTestMsg_AnswerToLife, - int /* answer */) - - IPC_SYNC_MESSAGE_CONTROL1_1(SyncChannelTestMsg_Double, - int /* in */, - int /* out */) - - // out1 is false - IPC_SYNC_MESSAGE_CONTROL0_1(Msg_C_0_1, bool) - - // out1 is true, out2 is 2 - IPC_SYNC_MESSAGE_CONTROL0_2(Msg_C_0_2, bool, int) - - // out1 is false, out2 is 3, out3 is "0_3" - IPC_SYNC_MESSAGE_CONTROL0_3(Msg_C_0_3, bool, int, std::string) - - // in1 must be 1, out1 is true - IPC_SYNC_MESSAGE_CONTROL1_1(Msg_C_1_1, int, bool) - - // in1 must be false, out1 is true, out2 is 12 - IPC_SYNC_MESSAGE_CONTROL1_2(Msg_C_1_2, bool, bool, int) - - // in1 must be 3, out1 is "1_3", out2 is 13, out3 is false - IPC_SYNC_MESSAGE_CONTROL1_3(Msg_C_1_3, int, std::string, int, bool) - - // in1 must be 1, in2 must be false, out1 is true - IPC_SYNC_MESSAGE_CONTROL2_1(Msg_C_2_1, int, bool, bool) - - // in1 must be false, in2 must be 2, out1 is true, out2 is 22 - IPC_SYNC_MESSAGE_CONTROL2_2(Msg_C_2_2, bool, int, bool, int) - - // in1 must be 3, in2 must be true, out1 is "2_3", out2 is 23, out3 is false - IPC_SYNC_MESSAGE_CONTROL2_3(Msg_C_2_3, int, bool, std::string, int, bool) - - // in1 must be 1, in2 must be false, in3 must be "3_1", out1 is true - IPC_SYNC_MESSAGE_CONTROL3_1(Msg_C_3_1, int, bool, std::string, bool) - - // in1 must be "3_3", in2 must be false, in3 must be 2, out1 is true, out2 is - // 32 - IPC_SYNC_MESSAGE_CONTROL3_2(Msg_C_3_2, std::string, bool, int, bool, int) - - // in1 must be 3, in2 must be "3_3", in3 must be true, out1 is "3_3", out2 is - // 33, out3 is false - IPC_SYNC_MESSAGE_CONTROL3_3(Msg_C_3_3, int, std::string, bool, std::string, - int, bool) - - - // NOTE: routed messages are just a copy of the above... - - // out1 is false - IPC_SYNC_MESSAGE_ROUTED0_1(Msg_R_0_1, bool) - - // out1 is true, out2 is 2 - IPC_SYNC_MESSAGE_ROUTED0_2(Msg_R_0_2, bool, int) - - // out1 is false, out2 is 3, out3 is "0_3" - IPC_SYNC_MESSAGE_ROUTED0_3(Msg_R_0_3, bool, int, std::string) - - // in1 must be 1, out1 is true - IPC_SYNC_MESSAGE_ROUTED1_1(Msg_R_1_1, int, bool) - - // in1 must be false, out1 is true, out2 is 12 - IPC_SYNC_MESSAGE_ROUTED1_2(Msg_R_1_2, bool, bool, int) - - // in1 must be 3, out1 is "1_3", out2 is 13, out3 is false - IPC_SYNC_MESSAGE_ROUTED1_3(Msg_R_1_3, int, std::string, int, bool) - - // in1 must be 1, in2 must be false, out1 is true - IPC_SYNC_MESSAGE_ROUTED2_1(Msg_R_2_1, int, bool, bool) - - // in1 must be false, in2 must be 2, out1 is true, out2 is 22 - IPC_SYNC_MESSAGE_ROUTED2_2(Msg_R_2_2, bool, int, bool, int) - - // in1 must be 3, in2 must be true, out1 is "2_3", out2 is 23, out3 is false - IPC_SYNC_MESSAGE_ROUTED2_3(Msg_R_2_3, int, bool, std::string, int, bool) - - // in1 must be 1, in2 must be false, in3 must be "3_1", out1 is true - IPC_SYNC_MESSAGE_ROUTED3_1(Msg_R_3_1, int, bool, std::string, bool) - - // in1 must be "3_3", in2 must be false, in3 must be 2, out1 is true, out2 - // is 32 - IPC_SYNC_MESSAGE_ROUTED3_2(Msg_R_3_2, std::string, bool, int, bool, int) - - // in1 must be 3, in2 must be "3_3", in3 must be true, out1 is "3_3", out2 is - // 33, out3 is false - IPC_SYNC_MESSAGE_ROUTED3_3(Msg_R_3_3, int, std::string, bool, std::string, - int, bool) - -IPC_END_MESSAGES(TestMsg) diff --git a/ipc/ipc_test_sink.cc b/ipc/ipc_test_sink.cc deleted file mode 100644 index 1f1ce3f..0000000 --- a/ipc/ipc_test_sink.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_test_sink.h" - -namespace IPC { - -TestSink::TestSink() { -} - -TestSink::~TestSink() { -} - -void TestSink::OnMessageReceived(const Message& msg) { - messages_.push_back(Message(msg)); -} - -void TestSink::ClearMessages() { - messages_.clear(); -} - -const Message* TestSink::GetMessageAt(size_t index) const { - if (index >= messages_.size()) - return NULL; - return &messages_[index]; -} - -const Message* TestSink::GetFirstMessageMatching(uint16 id) const { - for (size_t i = 0; i < messages_.size(); i++) { - if (messages_[i].type() == id) - return &messages_[i]; - } - return NULL; -} - -const Message* TestSink::GetUniqueMessageMatching(uint16 id) const { - size_t found_index = 0; - size_t found_count = 0; - for (size_t i = 0; i < messages_.size(); i++) { - if (messages_[i].type() == id) { - found_count++; - found_index = i; - } - } - if (found_count != 1) - return NULL; // Didn't find a unique one. - return &messages_[found_index]; -} - -} // namespace IPC diff --git a/ipc/ipc_test_sink.h b/ipc/ipc_test_sink.h deleted file mode 100644 index 851ed8e..0000000 --- a/ipc/ipc_test_sink.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMMON_IPC_TEST_SINK_H_ -#define COMMON_IPC_TEST_SINK_H_ - -#include <utility> -#include <vector> - -#include "base/basictypes.h" -#include "ipc/ipc_message.h" - -namespace IPC { - -// This test sink provides a "sink" for IPC messages that are sent. It allows -// the caller to query messages received in various different ways. It is -// designed for tests for objects that use the IPC system. -// -// Typical usage: -// -// test_sink.ClearMessages(); -// do_something(); -// -// // We should have gotten exactly one update state message. -// EXPECT_TRUE(test_sink.GetUniqeMessageMatching(ViewHostMsg_Update::ID)); -// // ...and no start load messages. -// EXPECT_FALSE(test_sink.GetFirstMessageMatching(ViewHostMsg_Start::ID)); -// -// // Now inspect a message. This assumes a message that was declared like -// // this: IPC_MESSAGE_ROUTED2(ViewMsg_Foo, bool, int) -// IPC::Message* msg = test_sink.GetFirstMessageMatching(ViewMsg_Foo::ID)); -// ASSERT_TRUE(msg); -// bool first_param; -// int second_param; -// ViewMsg_Foo::Read(msg, &first_param, &second_param); -// -// // Go on to the next phase of the test. -// test_sink.ClearMessages(); -// -// To hook up the sink, all you need to do is call OnMessageReceived when a -// message is recieved. -class TestSink { - public: - TestSink(); - ~TestSink(); - - // 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. - void OnMessageReceived(const Message& msg); - - // Returns the number of messages in the queue. - size_t message_count() const { return messages_.size(); } - - // Clears the message queue of saved messages. - void ClearMessages(); - - // Returns the message at the given index in the queue. The index may be out - // of range, in which case the return value is NULL. The returned pointer will - // only be valid until another message is received or the list is cleared. - const Message* GetMessageAt(size_t index) const; - - // Returns the first message with the given ID in the queue. If there is no - // message with the given ID, returns NULL. The returned pointer will only be - // valid until another message is received or the list is cleared. - const Message* GetFirstMessageMatching(uint16 id) const; - - // Returns the message with the given ID in the queue. If there is no such - // message or there is more than one of that message, this will return NULL - // (with the expectation that you'll do an ASSERT_TRUE() on the result). - // The returned pointer will only be valid until another message is received - // or the list is cleared. - const Message* GetUniqueMessageMatching(uint16 id) const; - - private: - // The actual list of received messages. - std::vector<Message> messages_; - - DISALLOW_COPY_AND_ASSIGN(TestSink); -}; - -} // namespace IPC - -#endif // COMMON_IPC_TEST_SINK_H_ diff --git a/ipc/ipc_tests.cc b/ipc/ipc_tests.cc deleted file mode 100644 index 506b888..0000000 --- a/ipc/ipc_tests.cc +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include <windows.h> -#elif defined(OS_POSIX) -#include <sys/types.h> -#include <unistd.h> -#endif - -#include <stdio.h> -#include <iostream> -#include <string> - -#include "ipc/ipc_tests.h" - -#include "base/at_exit.h" -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/debug_on_start.h" -#include "base/perftimer.h" -#include "base/perf_test_suite.h" -#include "base/test_suite.h" -#include "base/thread.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message_utils.h" -#include "testing/multiprocess_func_list.h" - -// Define to enable IPC performance testing instead of the regular unit tests -// #define PERFORMANCE_TEST - -const wchar_t kTestClientChannel[] = L"T1"; -const wchar_t kReflectorChannel[] = L"T2"; -const wchar_t kFuzzerChannel[] = L"F3"; - -const size_t kLongMessageStringNumBytes = 50000; - -#ifndef PERFORMANCE_TEST - -void IPCChannelTest::SetUp() { - MultiProcessTest::SetUp(); - - // Construct a fresh IO Message loop for the duration of each test. - message_loop_ = new MessageLoopForIO(); -} - -void IPCChannelTest::TearDown() { - delete message_loop_; - message_loop_ = NULL; - - MultiProcessTest::TearDown(); -} - -#if defined(OS_WIN) -base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type, - IPC::Channel *channel) { - // kDebugChildren support. - bool debug_on_start = - CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren); - - switch (child_type) { - case TEST_CLIENT: - return MultiProcessTest::SpawnChild(L"RunTestClient", debug_on_start); - break; - case TEST_REFLECTOR: - return MultiProcessTest::SpawnChild(L"RunReflector", debug_on_start); - break; - case FUZZER_SERVER: - return MultiProcessTest::SpawnChild(L"RunFuzzServer", debug_on_start); - break; - default: - return NULL; - break; - } -} -#elif defined(OS_POSIX) -base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type, - IPC::Channel *channel) { - // kDebugChildren support. - bool debug_on_start = - CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren); - - base::file_handle_mapping_vector fds_to_map; - int src_fd; - int dest_fd; - channel->GetClientFileDescriptorMapping(&src_fd, &dest_fd); - if (src_fd > -1) { - fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd)); - } - - base::ProcessHandle ret = NULL; - switch (child_type) { - case TEST_CLIENT: - ret = MultiProcessTest::SpawnChild(L"RunTestClient", - fds_to_map, - debug_on_start); - channel->OnClientConnected(); - break; - case TEST_DESCRIPTOR_CLIENT: - ret = MultiProcessTest::SpawnChild(L"RunTestDescriptorClient", - fds_to_map, - debug_on_start); - channel->OnClientConnected(); - break; - case TEST_DESCRIPTOR_CLIENT_SANDBOXED: - ret = MultiProcessTest::SpawnChild(L"RunTestDescriptorClientSandboxed", - fds_to_map, - debug_on_start); - channel->OnClientConnected(); - break; - case TEST_REFLECTOR: - ret = MultiProcessTest::SpawnChild(L"RunReflector", - fds_to_map, - debug_on_start); - channel->OnClientConnected(); - break; - case FUZZER_SERVER: - ret = MultiProcessTest::SpawnChild(L"RunFuzzServer", - fds_to_map, - debug_on_start); - channel->OnClientConnected(); - break; - default: - return NULL; - break; - } - return ret; -} -#endif // defined(OS_POSIX) - -TEST_F(IPCChannelTest, BasicMessageTest) { - int v1 = 10; - std::string v2("foobar"); - std::wstring v3(L"hello world"); - - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(v1)); - EXPECT_TRUE(m.WriteString(v2)); - EXPECT_TRUE(m.WriteWString(v3)); - - void* iter = NULL; - - int vi; - std::string vs; - std::wstring vw; - - EXPECT_TRUE(m.ReadInt(&iter, &vi)); - EXPECT_EQ(v1, vi); - - EXPECT_TRUE(m.ReadString(&iter, &vs)); - EXPECT_EQ(v2, vs); - - EXPECT_TRUE(m.ReadWString(&iter, &vw)); - EXPECT_EQ(v3, vw); - - // should fail - EXPECT_FALSE(m.ReadInt(&iter, &vi)); - EXPECT_FALSE(m.ReadString(&iter, &vs)); - EXPECT_FALSE(m.ReadWString(&iter, &vw)); -} - -static void Send(IPC::Message::Sender* sender, const char* text) { - static int message_index = 0; - - IPC::Message* message = new IPC::Message(0, - 2, - IPC::Message::PRIORITY_NORMAL); - message->WriteInt(message_index++); - message->WriteString(std::string(text)); - - // Make sure we can handle large messages. - char junk[kLongMessageStringNumBytes]; - memset(junk, 'a', sizeof(junk)-1); - junk[sizeof(junk)-1] = 0; - message->WriteString(std::string(junk)); - - // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text); - sender->Send(message); -} - -class MyChannelListener : public IPC::Channel::Listener { - public: - virtual void OnMessageReceived(const IPC::Message& message) { - IPC::MessageIterator iter(message); - - iter.NextInt(); - const std::string data = iter.NextString(); - const std::string big_string = iter.NextString(); - EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length()); - - - if (--messages_left_ == 0) { - MessageLoop::current()->Quit(); - } else { - Send(sender_, "Foo"); - } - } - - virtual void OnChannelError() { - // There is a race when closing the channel so the last message may be lost. - EXPECT_LE(messages_left_, 1); - MessageLoop::current()->Quit(); - } - - void Init(IPC::Message::Sender* s) { - sender_ = s; - messages_left_ = 50; - } - - private: - IPC::Message::Sender* sender_; - int messages_left_; -}; - -TEST_F(IPCChannelTest, ChannelTest) { - MyChannelListener channel_listener; - // Setup IPC channel. - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &channel_listener); - chan.Connect(); - - channel_listener.Init(&chan); - - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan); - ASSERT_TRUE(process_handle); - - Send(&chan, "hello from parent"); - - // Run message loop. - MessageLoop::current()->Run(); - - // Close Channel so client gets its OnChannelError() callback fired. - chan.Close(); - - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000)); - base::CloseProcessHandle(process_handle); -} - -TEST_F(IPCChannelTest, ChannelProxyTest) { - MyChannelListener channel_listener; - - // The thread needs to out-live the ChannelProxy. - base::Thread thread("ChannelProxyTestServer"); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - thread.StartWithOptions(options); - { - // setup IPC channel proxy - IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &channel_listener, NULL, thread.message_loop()); - - channel_listener.Init(&chan); - -#if defined(OS_WIN) - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL); -#elif defined(OS_POSIX) - bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDebugChildren); - base::file_handle_mapping_vector fds_to_map; - int src_fd; - int dest_fd; - chan.GetClientFileDescriptorMapping(&src_fd, &dest_fd); - if (src_fd > -1) { - fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd)); - } - - base::ProcessHandle process_handle = MultiProcessTest::SpawnChild( - L"RunTestClient", - fds_to_map, - debug_on_start); - chan.OnClientConnected(); -#endif // defined(OS_POXIX) - - ASSERT_TRUE(process_handle); - - Send(&chan, "hello from parent"); - - // run message loop - MessageLoop::current()->Run(); - - // cleanup child process - EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000)); - base::CloseProcessHandle(process_handle); - } - thread.Stop(); -} - -MULTIPROCESS_TEST_MAIN(RunTestClient) { - MessageLoopForIO main_message_loop; - MyChannelListener channel_listener; - - // setup IPC channel - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, - &channel_listener); - chan.Connect(); - channel_listener.Init(&chan); - Send(&chan, "hello from child"); - // run message loop - MessageLoop::current()->Run(); - // return true; - return NULL; -} - -#endif // !PERFORMANCE_TEST - -#ifdef PERFORMANCE_TEST - -//----------------------------------------------------------------------------- -// Manually performance test -// -// This test times the roundtrip IPC message cycle. It is enabled with a -// special preprocessor define to enable it instead of the standard IPC -// unit tests. This works around some funny termination conditions in the -// regular unit tests. -// -// This test is not automated. To test, you will want to vary the message -// count and message size in TEST to get the numbers you want. -// -// FIXME(brettw): Automate this test and have it run by default. - -// This channel listener just replies to all messages with the exact same -// message. It assumes each message has one string parameter. When the string -// "quit" is sent, it will exit. -class ChannelReflectorListener : public IPC::Channel::Listener { - public: - explicit ChannelReflectorListener(IPC::Channel *channel) : - channel_(channel), - count_messages_(0), - latency_messages_(0) { - std::cout << "Reflector up" << std::endl; - } - - ~ChannelReflectorListener() { - std::cout << "Client Messages: " << count_messages_ << std::endl; - std::cout << "Client Latency: " << latency_messages_ << std::endl; - } - - virtual void OnMessageReceived(const IPC::Message& message) { - count_messages_++; - IPC::MessageIterator iter(message); - int time = iter.NextInt(); - int msgid = iter.NextInt(); - std::string payload = iter.NextString(); - latency_messages_ += GetTickCount() - time; - - // cout << "reflector msg received: " << msgid << endl; - if (payload == "quit") - MessageLoop::current()->Quit(); - - IPC::Message* msg = new IPC::Message(0, - 2, - IPC::Message::PRIORITY_NORMAL); - msg->WriteInt(GetTickCount()); - msg->WriteInt(msgid); - msg->WriteString(payload); - channel_->Send(msg); - } - private: - IPC::Channel *channel_; - int count_messages_; - int latency_messages_; -}; - -class ChannelPerfListener : public IPC::Channel::Listener { - public: - ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) : - count_down_(msg_count), - channel_(channel), - count_messages_(0), - latency_messages_(0) { - payload_.resize(msg_size); - for (int i = 0; i < static_cast<int>(payload_.size()); i++) - payload_[i] = 'a'; - std::cout << "perflistener up" << std::endl; - } - - ~ChannelPerfListener() { - std::cout << "Server Messages: " << count_messages_ << std::endl; - std::cout << "Server Latency: " << latency_messages_ << std::endl; - } - - virtual void OnMessageReceived(const IPC::Message& message) { - count_messages_++; - // decode the string so this gets counted in the total time - IPC::MessageIterator iter(message); - int time = iter.NextInt(); - int msgid = iter.NextInt(); - std::string cur = iter.NextString(); - latency_messages_ += GetTickCount() - time; - - // cout << "perflistener got message" << endl; - - count_down_--; - if (count_down_ == 0) { - IPC::Message* msg = new IPC::Message(0, - 2, - IPC::Message::PRIORITY_NORMAL); - msg->WriteInt(GetTickCount()); - msg->WriteInt(count_down_); - msg->WriteString("quit"); - channel_->Send(msg); - SetTimer(NULL, 1, 250, (TIMERPROC) PostQuitMessage); - return; - } - - IPC::Message* msg = new IPC::Message(0, - 2, - IPC::Message::PRIORITY_NORMAL); - msg->WriteInt(GetTickCount()); - msg->WriteInt(count_down_); - msg->WriteString(payload_); - channel_->Send(msg); - } - - private: - int count_down_; - std::string payload_; - IPC::Channel *channel_; - int count_messages_; - int latency_messages_; -}; - -TEST_F(IPCChannelTest, Performance) { - // setup IPC channel - IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL); - ChannelPerfListener perf_listener(&chan, 10000, 100000); - chan.set_listener(&perf_listener); - chan.Connect(); - - HANDLE process = SpawnChild(TEST_REFLECTOR, &chan); - ASSERT_TRUE(process); - - Sleep(1000); - - PerfTimeLogger logger("IPC_Perf"); - - // this initial message will kick-start the ping-pong of messages - IPC::Message* message = new IPC::Message(0, - 2, - IPC::Message::PRIORITY_NORMAL); - message->WriteInt(GetTickCount()); - message->WriteInt(-1); - message->WriteString("Hello"); - chan.Send(message); - - // run message loop - MessageLoop::current()->Run(); - - // cleanup child process - WaitForSingleObject(process, 5000); - CloseHandle(process); -} - -// This message loop bounces all messages back to the sender -MULTIPROCESS_TEST_MAIN(RunReflector) { - MessageLoopForIO main_message_loop; - IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL); - ChannelReflectorListener channel_reflector_listener(&chan); - chan.set_listener(&channel_reflector_listener); - chan.Connect(); - - MessageLoop::current()->Run(); - return true; -} - -#endif // PERFORMANCE_TEST - -int main(int argc, char** argv) { -#ifdef PERFORMANCE_TEST - int retval = PerfTestSuite(argc, argv).Run(); -#else - int retval = TestSuite(argc, argv).Run(); -#endif - return retval; -} diff --git a/ipc/ipc_tests.h b/ipc/ipc_tests.h deleted file mode 100644 index 5005eb3..0000000 --- a/ipc/ipc_tests.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMMON_IPC_TESTS_H__ -#define COMMON_IPC_TESTS_H__ - -#include "base/multiprocess_test.h" -#include "base/process.h" - -// This unit test uses 3 types of child processes, a regular pipe client, -// a client reflector and a IPC server used for fuzzing tests. -enum ChildType { - TEST_CLIENT, - TEST_DESCRIPTOR_CLIENT, - TEST_DESCRIPTOR_CLIENT_SANDBOXED, - TEST_REFLECTOR, - FUZZER_SERVER -}; - -// The different channel names for the child processes. -extern const wchar_t kTestClientChannel[]; -extern const wchar_t kReflectorChannel[]; -extern const wchar_t kFuzzerChannel[]; - -class MessageLoopForIO; -namespace IPC { -class Channel; -} // namespace IPC - -//Base class to facilitate Spawning IPC Client processes. -class IPCChannelTest : public MultiProcessTest { - protected: - - // Create a new MessageLoopForIO For each test. - virtual void SetUp(); - virtual void TearDown(); - - // Spawns a child process of the specified type - base::ProcessHandle SpawnChild(ChildType child_type, - IPC::Channel *channel); - - // Created around each test instantiation. - MessageLoopForIO *message_loop_; -}; - -#endif // COMMON_IPC_TESTS_H__ |