summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/ipc_channel_handle.h45
-rw-r--r--chrome/common/ipc_channel_posix.cc87
-rw-r--r--chrome/common/ipc_channel_posix.h18
-rw-r--r--chrome/common/ipc_message_utils.h29
-rw-r--r--chrome/common/plugin_messages_internal.h15
-rw-r--r--chrome/common/render_messages_internal.h11
6 files changed, 170 insertions, 35 deletions
diff --git a/chrome/common/ipc_channel_handle.h b/chrome/common/ipc_channel_handle.h
new file mode 100644
index 0000000..2bb6380
--- /dev/null
+++ b/chrome/common/ipc_channel_handle.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IPC_CHANNEL_HANDLE_H_
+#define CHROME_COMMON_IPC_CHANNEL_HANDLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+// On Windows, any process can create an IPC channel and others can fetch
+// it by name. We pass around the channel names over IPC.
+// On POSIX, we instead pass around handles to channel endpoints via IPC.
+// When it's time to IPC a new channel endpoint around, we send both the
+// channel name as well as a base::FileDescriptor, which is itself a special
+// type that knows how to copy a socket endpoint over IPC.
+//
+// In sum, when passing a handle to a channel over IPC, use this data structure
+// to work on both Windows and POSIX.
+
+namespace IPC {
+
+struct ChannelHandle {
+ // Note that serialization for this object is defined in the ParamTraits
+ // template specialization in ipc_message_utils.h.
+ std::string name;
+#if defined(OS_POSIX)
+ base::FileDescriptor socket;
+#endif
+
+ ChannelHandle() {}
+#if defined(OS_POSIX)
+ ChannelHandle(const std::string& n, const base::FileDescriptor& s)
+ : name(n), socket(s) {}
+#else
+ ChannelHandle(const std::string& n) : name(n) {}
+#endif
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_IPC_CHANNEL_HANDLE_H_
diff --git a/chrome/common/ipc_channel_posix.cc b/chrome/common/ipc_channel_posix.cc
index babc16c..63f2703 100644
--- a/chrome/common/ipc_channel_posix.cc
+++ b/chrome/common/ipc_channel_posix.cc
@@ -104,9 +104,9 @@ class PipeMap {
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";
+ CHECK(i == map_.end()) << "Creating second IPC server (fd " << fd << ") "
+ << "for '" << channel_id << "' while first "
+ << "(fd " << i->second << ") still exists";
map_[channel_id] = fd;
}
@@ -116,16 +116,20 @@ class PipeMap {
ChannelToFDMap map_;
};
-// Used to map a channel name to the equivalent FD # in the client process.
-int ChannelNameToClientFD(const std::string& channel_id) {
+// Used to map a channel name to the equivalent FD # in the current process.
+// Returns -1 if the channel is unknown.
+int ChannelNameToFD(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 Singleton<base::GlobalDescriptors>()->Get(kPrimaryIPCChannel);
+ if (fd != -1) {
+ int dup_fd = dup(fd);
+ if (dup_fd < 0)
+ LOG(FATAL) << "dup(" << fd << "): " << strerror(errno);
+ return dup_fd;
+ }
+
+ return fd;
}
//------------------------------------------------------------------------------
@@ -261,6 +265,34 @@ Channel::ChannelImpl::ChannelImpl(const std::string& channel_id, Mode mode,
}
}
+// static
+void AddChannelSocket(const std::string& name, int socket) {
+ Singleton<PipeMap>()->Insert(name, socket);
+}
+
+// static
+bool SocketPair(int* fd1, int* fd2) {
+ int pipe_fds[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
+ LOG(ERROR) << "socketpair(): " << strerror(errno);
+ return false;
+ }
+
+ // Set both ends to be non-blocking.
+ if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
+ fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
+ LOG(ERROR) << "fcntl(O_NONBLOCK): " << strerror(errno);
+ HANDLE_EINTR(close(pipe_fds[0]));
+ HANDLE_EINTR(close(pipe_fds[1]));
+ return false;
+ }
+
+ *fd1 = pipe_fds[0];
+ *fd2 = pipe_fds[1];
+
+ return true;
+}
+
bool Channel::ChannelImpl::CreatePipe(const std::string& channel_id,
Mode mode) {
DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
@@ -282,27 +314,24 @@ bool Channel::ChannelImpl::CreatePipe(const std::string& channel_id,
waiting_connect_ = false;
}
} else {
- // socketpair()
+ // This is the normal (non-unit-test) case, where we're using sockets.
+ // Three possible cases:
+ // 1) It's for a channel we already have a pipe for; reuse it.
+ // 2) It's the initial IPC channel:
+ // 2a) Server side: create the pipe.
+ // 2b) Client side: Pull the pipe out of the GlobalDescriptors set.
pipe_name_ = channel_id;
- 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) {
- HANDLE_EINTR(close(pipe_fds[0]));
- HANDLE_EINTR(close(pipe_fds[1]));
- return false;
+ pipe_ = ChannelNameToFD(pipe_name_);
+ if (pipe_ < 0) {
+ // Initial IPC channel.
+ if (mode == MODE_SERVER) {
+ if (!SocketPair(&pipe_, &client_pipe_))
+ return false;
+ AddChannelSocket(pipe_name_, client_pipe_);
+ } else {
+ pipe_ = Singleton<base::GlobalDescriptors>()->Get(kPrimaryIPCChannel);
}
- 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;
}
}
@@ -612,7 +641,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
return false;
}
#endif // OS_MACOSX
- LOG(ERROR) << "pipe error: " << strerror(errno);
+ LOG(ERROR) << "pipe error on " << pipe_ << ": " << strerror(errno);
return false;
}
diff --git a/chrome/common/ipc_channel_posix.h b/chrome/common/ipc_channel_posix.h
index ed3d727..5e8d977 100644
--- a/chrome/common/ipc_channel_posix.h
+++ b/chrome/common/ipc_channel_posix.h
@@ -18,6 +18,15 @@
namespace IPC {
+// Store that channel name |name| is available via socket |socket|.
+// Used when the channel has been precreated by another process on
+// our behalf and they've just shipped us the socket.
+void AddChannelSocket(const std::string& name, int socket);
+
+// Construct a socket pair appropriate for IPC: UNIX domain, nonblocking.
+// Returns false on error.
+bool SocketPair(int* fd1, int* fd2);
+
// An implementation of ChannelImpl for POSIX systems that works via
// socketpairs. See the .cc file for an overview of the implementation.
class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
@@ -60,9 +69,16 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
// a socketpair().
bool uses_fifo_;
+ // File descriptor we're listening on for new connections in the FIFO case;
+ // unused otherwise.
int server_listen_pipe_;
+
+ // The pipe used for communication.
int pipe_;
- int client_pipe_; // The client end of our socketpair().
+
+ // For a server, the client end of our socketpair() -- the other end of our
+ // pipe_ that is passed to the client.
+ int client_pipe_;
// The "name" of our pipe. On Windows this is the global identifier for
// the pipe. On POSIX it's used as a key in a local map of file descriptors.
diff --git a/chrome/common/ipc_message_utils.h b/chrome/common/ipc_message_utils.h
index 3f0f7b2..2ae2ab5 100644
--- a/chrome/common/ipc_message_utils.h
+++ b/chrome/common/ipc_message_utils.h
@@ -16,6 +16,7 @@
#if defined(OS_POSIX)
#include "chrome/common/file_descriptor_set_posix.h"
#endif
+#include "chrome/common/ipc_channel_handle.h"
#include "chrome/common/ipc_sync_message.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/common/transport_dib.h"
@@ -726,6 +727,34 @@ struct ParamTraits<base::FileDescriptor> {
};
#endif // defined(OS_POSIX)
+// A ChannelHandle is basically a platform-inspecific wrapper around the
+// fact that IPC endpoints are handled specially on POSIX. See above comments
+// on FileDescriptor for more background.
+template<>
+struct ParamTraits<IPC::ChannelHandle> {
+ typedef ChannelHandle param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.name);
+#if defined(OS_POSIX)
+ WriteParam(m, p.socket);
+#endif
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return ReadParam(m, iter, &r->name)
+#if defined(OS_POSIX)
+ && ReadParam(m, iter, &r->socket)
+#endif
+ ;
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"ChannelHandle(%s", p.name.c_str()));
+#if defined(OS_POSIX)
+ ParamTraits<base::FileDescriptor>::Log(p.socket, l);
+#endif
+ l->append(L")");
+ }
+};
+
template<>
struct ParamTraits<ThumbnailScore> {
typedef ThumbnailScore param_type;
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index b2805fc..500bd93 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -3,9 +3,14 @@
// found in the LICENSE file.
#include "base/shared_memory.h"
+#include "build/build_config.h"
#include "chrome/common/ipc_message_macros.h"
#include "webkit/glue/webcursor.h"
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
//-----------------------------------------------------------------------------
// PluginProcess messages
// These are messages sent from the browser to the plugin process.
@@ -15,9 +20,19 @@ IPC_BEGIN_MESSAGES(PluginProcess)
// PluginProcessHostMsg_ChannelCreated message. The renderer's process_id is
// passed so that the plugin process reuses an existing channel to that
// process if it exists.
+ // It would be nice to use #ifdefs inside the parameter list to not need to
+ // duplicate this across POSIX/Windows but the Visual Studio compiler doesn't
+ // like that.
+#if defined(OS_WIN)
IPC_MESSAGE_CONTROL2(PluginProcessMsg_CreateChannel,
int /* process_id */,
bool /* off_the_record */)
+#elif defined(OS_POSIX)
+ IPC_MESSAGE_CONTROL3(PluginProcessMsg_CreateChannel,
+ base::FileDescriptor /* socket for new channel */,
+ int /* process_id */,
+ bool /* off_the_record */)
+#endif
// Allows a chrome plugin loaded in the browser process to send arbitrary
// data to an instance of the same plugin loaded in a plugin process.
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index d96220d..5debd5f 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -17,6 +17,7 @@
#include "base/gfx/native_widget_types.h"
#include "base/shared_memory.h"
#include "base/values.h"
+#include "chrome/common/ipc_channel_handle.h"
#include "chrome/common/ipc_message_macros.h"
#include "chrome/common/transport_dib.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -924,16 +925,16 @@ IPC_BEGIN_MESSAGES(ViewHost)
std::string /* origin */,
std::string /* target */)
- // A renderer sends this to the browser process when it wants to create a
- // plugin. The browser will create the plugin process if necessary, and
- // will return the channel name on success. On error an empty string is
- // returned.
+ // A renderer sends this to the browser process when it wants to
+ // create a plugin. The browser will create the plugin process if
+ // necessary, and will return a handle to the channel on success.
+ // On error an empty string is returned.
IPC_SYNC_MESSAGE_CONTROL4_2(ViewHostMsg_OpenChannelToPlugin,
GURL /* url */,
std::string /* mime_type */,
std::string /* clsid */,
std::wstring /* locale */,
- std::string /* channel_name */,
+ IPC::ChannelHandle /* handle to channel */,
FilePath /* plugin_path */)
// Clipboard IPC messages