diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 20:50:09 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 20:50:09 +0000 |
commit | 255a9f6c6f6db2a95fec78c6c2f2c504c655e733 (patch) | |
tree | 471d21ae7e41cc2e33a491a5309b3ea77430ebca /chrome/common/ipc_channel_posix.cc | |
parent | 04b74d13d927794495a1a3a1b89d67f85a104e12 (diff) | |
download | chromium_src-255a9f6c6f6db2a95fec78c6c2f2c504c655e733.zip chromium_src-255a9f6c6f6db2a95fec78c6c2f2c504c655e733.tar.gz chromium_src-255a9f6c6f6db2a95fec78c6c2f2c504c655e733.tar.bz2 |
posix: two related changes to make plugin IPC work on POSIX.
* use a new ChannelHandle type when passing IPC channels over IPC
The current POSIX code assumes that one end of a channel is always a new
child process (a renderer). For plugins we need to be able to construct
channels between each of the browser, plugin, and renderer.
This change augments the messages related to creating channels to allow
passing in a base::FileDescriptor containing the socket. The intent is
that the browser process, as the initial interchange between plugin and
renderer, creates the socketpair() on their behalf and hands each their
respective end of the connection.
* register channel endpoint names in the global pipe map
The plugin code assumes it can map from a string to a channel endpoint
at basically any time. So whenever we get a channel endpoint over IPC,
we install it in a global map of channel endpoints.
Review URL: http://codereview.chromium.org/113157
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18850 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/ipc_channel_posix.cc')
-rw-r--r-- | chrome/common/ipc_channel_posix.cc | 87 |
1 files changed, 58 insertions, 29 deletions
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; } |