ipc/chromium/src/chrome/common/ipc_channel_posix.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1020 @@
     1.4 +// Copyright (c) 2008 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#include "chrome/common/ipc_channel_posix.h"
     1.9 +
    1.10 +#include <errno.h>
    1.11 +#include <fcntl.h>
    1.12 +#include <stddef.h>
    1.13 +#include <unistd.h>
    1.14 +#include <sys/types.h>
    1.15 +#include <sys/socket.h>
    1.16 +#include <sys/stat.h>
    1.17 +#include <sys/un.h>
    1.18 +#include <sys/uio.h>
    1.19 +
    1.20 +#include <string>
    1.21 +#include <map>
    1.22 +
    1.23 +#include "base/command_line.h"
    1.24 +#include "base/eintr_wrapper.h"
    1.25 +#include "base/lock.h"
    1.26 +#include "base/logging.h"
    1.27 +#include "base/process_util.h"
    1.28 +#include "base/scoped_ptr.h"
    1.29 +#include "base/string_util.h"
    1.30 +#include "base/singleton.h"
    1.31 +#include "base/stats_counters.h"
    1.32 +#include "chrome/common/chrome_switches.h"
    1.33 +#include "chrome/common/file_descriptor_set_posix.h"
    1.34 +#include "chrome/common/ipc_logging.h"
    1.35 +#include "chrome/common/ipc_message_utils.h"
    1.36 +#include "mozilla/ipc/ProtocolUtils.h"
    1.37 +
    1.38 +#ifdef MOZ_TASK_TRACER
    1.39 +#include "GeckoTaskTracerImpl.h"
    1.40 +using namespace mozilla::tasktracer;
    1.41 +#endif
    1.42 +
    1.43 +namespace IPC {
    1.44 +
    1.45 +// IPC channels on Windows use named pipes (CreateNamedPipe()) with
    1.46 +// channel ids as the pipe names.  Channels on POSIX use anonymous
    1.47 +// Unix domain sockets created via socketpair() as pipes.  These don't
    1.48 +// quite line up.
    1.49 +//
    1.50 +// When creating a child subprocess, the parent side of the fork
    1.51 +// arranges it such that the initial control channel ends up on the
    1.52 +// magic file descriptor kClientChannelFd in the child.  Future
    1.53 +// connections (file descriptors) can then be passed via that
    1.54 +// connection via sendmsg().
    1.55 +
    1.56 +//------------------------------------------------------------------------------
    1.57 +namespace {
    1.58 +
    1.59 +// The PipeMap class works around this quirk related to unit tests:
    1.60 +//
    1.61 +// When running as a server, we install the client socket in a
    1.62 +// specific file descriptor number (@kClientChannelFd). However, we
    1.63 +// also have to support the case where we are running unittests in the
    1.64 +// same process.  (We do not support forking without execing.)
    1.65 +//
    1.66 +// Case 1: normal running
    1.67 +//   The IPC server object will install a mapping in PipeMap from the
    1.68 +//   name which it was given to the client pipe. When forking the client, the
    1.69 +//   GetClientFileDescriptorMapping will ensure that the socket is installed in
    1.70 +//   the magic slot (@kClientChannelFd). The client will search for the
    1.71 +//   mapping, but it won't find any since we are in a new process. Thus the
    1.72 +//   magic fd number is returned. Once the client connects, the server will
    1.73 +//   close its copy of the client socket and remove the mapping.
    1.74 +//
    1.75 +// Case 2: unittests - client and server in the same process
    1.76 +//   The IPC server will install a mapping as before. The client will search
    1.77 +//   for a mapping and find out. It duplicates the file descriptor and
    1.78 +//   connects. Once the client connects, the server will close the original
    1.79 +//   copy of the client socket and remove the mapping. Thus, when the client
    1.80 +//   object closes, it will close the only remaining copy of the client socket
    1.81 +//   in the fd table and the server will see EOF on its side.
    1.82 +//
    1.83 +// TODO(port): a client process cannot connect to multiple IPC channels with
    1.84 +// this scheme.
    1.85 +
    1.86 +class PipeMap {
    1.87 + public:
    1.88 +  // Lookup a given channel id. Return -1 if not found.
    1.89 +  int Lookup(const std::string& channel_id) {
    1.90 +    AutoLock locked(lock_);
    1.91 +
    1.92 +    ChannelToFDMap::const_iterator i = map_.find(channel_id);
    1.93 +    if (i == map_.end())
    1.94 +      return -1;
    1.95 +    return i->second;
    1.96 +  }
    1.97 +
    1.98 +  // Remove the mapping for the given channel id. No error is signaled if the
    1.99 +  // channel_id doesn't exist
   1.100 +  void Remove(const std::string& channel_id) {
   1.101 +    AutoLock locked(lock_);
   1.102 +
   1.103 +    ChannelToFDMap::iterator i = map_.find(channel_id);
   1.104 +    if (i != map_.end())
   1.105 +      map_.erase(i);
   1.106 +  }
   1.107 +
   1.108 +  // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
   1.109 +  // mapping if one already exists for the given channel_id
   1.110 +  void Insert(const std::string& channel_id, int fd) {
   1.111 +    AutoLock locked(lock_);
   1.112 +    DCHECK(fd != -1);
   1.113 +
   1.114 +    ChannelToFDMap::const_iterator i = map_.find(channel_id);
   1.115 +    CHECK(i == map_.end()) << "Creating second IPC server for '"
   1.116 +                           << channel_id
   1.117 +                           << "' while first still exists";
   1.118 +    map_[channel_id] = fd;
   1.119 +  }
   1.120 +
   1.121 + private:
   1.122 +  Lock lock_;
   1.123 +  typedef std::map<std::string, int> ChannelToFDMap;
   1.124 +  ChannelToFDMap map_;
   1.125 +};
   1.126 +
   1.127 +// This is the file descriptor number that a client process expects to find its
   1.128 +// IPC socket.
   1.129 +static const int kClientChannelFd = 3;
   1.130 +
   1.131 +// Used to map a channel name to the equivalent FD # in the client process.
   1.132 +int ChannelNameToClientFD(const std::string& channel_id) {
   1.133 +  // See the large block comment above PipeMap for the reasoning here.
   1.134 +  const int fd = Singleton<PipeMap>()->Lookup(channel_id);
   1.135 +  if (fd != -1)
   1.136 +    return dup(fd);
   1.137 +
   1.138 +  // If we don't find an entry, we assume that the correct value has been
   1.139 +  // inserted in the magic slot.
   1.140 +  return kClientChannelFd;
   1.141 +}
   1.142 +
   1.143 +//------------------------------------------------------------------------------
   1.144 +const size_t kMaxPipeNameLength = sizeof(((sockaddr_un*)0)->sun_path);
   1.145 +
   1.146 +// Creates a Fifo with the specified name ready to listen on.
   1.147 +bool CreateServerFifo(const std::string& pipe_name, int* server_listen_fd) {
   1.148 +  DCHECK(server_listen_fd);
   1.149 +  DCHECK_GT(pipe_name.length(), 0u);
   1.150 +  DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
   1.151 +
   1.152 +  if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
   1.153 +    return false;
   1.154 +  }
   1.155 +
   1.156 +  // Create socket.
   1.157 +  int fd = socket(AF_UNIX, SOCK_STREAM, 0);
   1.158 +  if (fd < 0) {
   1.159 +    return false;
   1.160 +  }
   1.161 +
   1.162 +  // Make socket non-blocking
   1.163 +  if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
   1.164 +    HANDLE_EINTR(close(fd));
   1.165 +    return false;
   1.166 +  }
   1.167 +
   1.168 +  // Delete any old FS instances.
   1.169 +  unlink(pipe_name.c_str());
   1.170 +
   1.171 +  // Create unix_addr structure
   1.172 +  struct sockaddr_un unix_addr;
   1.173 +  memset(&unix_addr, 0, sizeof(unix_addr));
   1.174 +  unix_addr.sun_family = AF_UNIX;
   1.175 +  snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str());
   1.176 +  size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
   1.177 +      strlen(unix_addr.sun_path) + 1;
   1.178 +
   1.179 +  // Bind the socket.
   1.180 +  if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
   1.181 +           unix_addr_len) != 0) {
   1.182 +    HANDLE_EINTR(close(fd));
   1.183 +    return false;
   1.184 +  }
   1.185 +
   1.186 +  // Start listening on the socket.
   1.187 +  const int listen_queue_length = 1;
   1.188 +  if (listen(fd, listen_queue_length) != 0) {
   1.189 +    HANDLE_EINTR(close(fd));
   1.190 +    return false;
   1.191 +  }
   1.192 +
   1.193 +  *server_listen_fd = fd;
   1.194 +  return true;
   1.195 +}
   1.196 +
   1.197 +// Accept a connection on a fifo.
   1.198 +bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) {
   1.199 +  DCHECK(server_socket);
   1.200 +
   1.201 +  int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
   1.202 +  if (accept_fd < 0)
   1.203 +    return false;
   1.204 +  if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
   1.205 +    HANDLE_EINTR(close(accept_fd));
   1.206 +    return false;
   1.207 +  }
   1.208 +
   1.209 +  *server_socket = accept_fd;
   1.210 +  return true;
   1.211 +}
   1.212 +
   1.213 +bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) {
   1.214 +  DCHECK(client_socket);
   1.215 +  DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
   1.216 +
   1.217 +  // Create socket.
   1.218 +  int fd = socket(AF_UNIX, SOCK_STREAM, 0);
   1.219 +  if (fd < 0) {
   1.220 +    CHROMIUM_LOG(ERROR) << "fd is invalid";
   1.221 +    return false;
   1.222 +  }
   1.223 +
   1.224 +  // Make socket non-blocking
   1.225 +  if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
   1.226 +    CHROMIUM_LOG(ERROR) << "fcntl failed";
   1.227 +    HANDLE_EINTR(close(fd));
   1.228 +    return false;
   1.229 +  }
   1.230 +
   1.231 +  // Create server side of socket.
   1.232 +  struct sockaddr_un  server_unix_addr;
   1.233 +  memset(&server_unix_addr, 0, sizeof(server_unix_addr));
   1.234 +  server_unix_addr.sun_family = AF_UNIX;
   1.235 +  snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s",
   1.236 +           pipe_name.c_str());
   1.237 +  size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
   1.238 +      strlen(server_unix_addr.sun_path) + 1;
   1.239 +
   1.240 +  if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
   1.241 +                           server_unix_addr_len)) != 0) {
   1.242 +    HANDLE_EINTR(close(fd));
   1.243 +    return false;
   1.244 +  }
   1.245 +
   1.246 +  *client_socket = fd;
   1.247 +  return true;
   1.248 +}
   1.249 +
   1.250 +bool SetCloseOnExec(int fd) {
   1.251 +  int flags = fcntl(fd, F_GETFD);
   1.252 +  if (flags == -1)
   1.253 +    return false;
   1.254 +
   1.255 +  flags |= FD_CLOEXEC;
   1.256 +  if (fcntl(fd, F_SETFD, flags) == -1)
   1.257 +    return false;
   1.258 +
   1.259 +  return true;
   1.260 +}
   1.261 +
   1.262 +}  // namespace
   1.263 +//------------------------------------------------------------------------------
   1.264 +
   1.265 +Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
   1.266 +                                  Listener* listener)
   1.267 +    : factory_(this) {
   1.268 +  Init(mode, listener);
   1.269 +  uses_fifo_ = CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO);
   1.270 +
   1.271 +  if (!CreatePipe(channel_id, mode)) {
   1.272 +    // The pipe may have been closed already.
   1.273 +    CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
   1.274 +                             "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
   1.275 +                             " mode error(" << strerror(errno) << ").";
   1.276 +  }
   1.277 +}
   1.278 +
   1.279 +Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
   1.280 +    : factory_(this) {
   1.281 +  Init(mode, listener);
   1.282 +  pipe_ = fd;
   1.283 +  waiting_connect_ = (MODE_SERVER == mode);
   1.284 +
   1.285 +  EnqueueHelloMessage();
   1.286 +}
   1.287 +
   1.288 +void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
   1.289 +  mode_ = mode;
   1.290 +  is_blocked_on_write_ = false;
   1.291 +  message_send_bytes_written_ = 0;
   1.292 +  uses_fifo_ = false;
   1.293 +  server_listen_pipe_ = -1;
   1.294 +  pipe_ = -1;
   1.295 +  client_pipe_ = -1;
   1.296 +  listener_ = listener;
   1.297 +  waiting_connect_ = true;
   1.298 +  processing_incoming_ = false;
   1.299 +  closed_ = false;
   1.300 +#if defined(OS_MACOSX)
   1.301 +  last_pending_fd_id_ = 0;
   1.302 +#endif
   1.303 +  output_queue_length_ = 0;
   1.304 +}
   1.305 +
   1.306 +bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
   1.307 +                                      Mode mode) {
   1.308 +  DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
   1.309 +
   1.310 +  if (uses_fifo_) {
   1.311 +    // This only happens in unit tests; see the comment above PipeMap.
   1.312 +    // TODO(playmobil): We shouldn't need to create fifos on disk.
   1.313 +    // TODO(playmobil): If we do, they should be in the user data directory.
   1.314 +    // TODO(playmobil): Cleanup any stale fifos.
   1.315 +    pipe_name_ = "/var/tmp/chrome_" + WideToASCII(channel_id);
   1.316 +    if (mode == MODE_SERVER) {
   1.317 +      if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) {
   1.318 +        return false;
   1.319 +      }
   1.320 +    } else {
   1.321 +      if (!ClientConnectToFifo(pipe_name_, &pipe_)) {
   1.322 +        return false;
   1.323 +      }
   1.324 +      waiting_connect_ = false;
   1.325 +    }
   1.326 +  } else {
   1.327 +    // socketpair()
   1.328 +    pipe_name_ = WideToASCII(channel_id);
   1.329 +    if (mode == MODE_SERVER) {
   1.330 +      int pipe_fds[2];
   1.331 +      if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
   1.332 +        return false;
   1.333 +      }
   1.334 +      // Set both ends to be non-blocking.
   1.335 +      if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
   1.336 +          fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
   1.337 +        HANDLE_EINTR(close(pipe_fds[0]));
   1.338 +        HANDLE_EINTR(close(pipe_fds[1]));
   1.339 +        return false;
   1.340 +      }
   1.341 +
   1.342 +      if (!SetCloseOnExec(pipe_fds[0]) ||
   1.343 +          !SetCloseOnExec(pipe_fds[1])) {
   1.344 +        HANDLE_EINTR(close(pipe_fds[0]));
   1.345 +        HANDLE_EINTR(close(pipe_fds[1]));
   1.346 +        return false;
   1.347 +      }
   1.348 +
   1.349 +      pipe_ = pipe_fds[0];
   1.350 +      client_pipe_ = pipe_fds[1];
   1.351 +
   1.352 +      if (pipe_name_.length()) {
   1.353 +        Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
   1.354 +      }
   1.355 +    } else {
   1.356 +      pipe_ = ChannelNameToClientFD(pipe_name_);
   1.357 +      DCHECK(pipe_ > 0);
   1.358 +      waiting_connect_ = false;
   1.359 +    }
   1.360 +  }
   1.361 +
   1.362 +  // Create the Hello message to be sent when Connect is called
   1.363 +  return EnqueueHelloMessage();
   1.364 +}
   1.365 +
   1.366 +/**
   1.367 + * Reset the file descriptor for communication with the peer.
   1.368 + */
   1.369 +void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
   1.370 +  NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
   1.371 +
   1.372 +  EnqueueHelloMessage();
   1.373 +}
   1.374 +
   1.375 +bool Channel::ChannelImpl::EnqueueHelloMessage() {
   1.376 +  scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
   1.377 +                                      HELLO_MESSAGE_TYPE,
   1.378 +                                      IPC::Message::PRIORITY_NORMAL));
   1.379 +  if (!msg->WriteInt(base::GetCurrentProcId())) {
   1.380 +    Close();
   1.381 +    return false;
   1.382 +  }
   1.383 +
   1.384 +  OutputQueuePush(msg.release());
   1.385 +  return true;
   1.386 +}
   1.387 +
   1.388 +static void
   1.389 +ClearAndShrink(std::string& s, size_t capacity)
   1.390 +{
   1.391 +  // This swap trick is the closest thing C++ has to a guaranteed way to
   1.392 +  // shrink the capacity of a string.
   1.393 +  std::string tmp;
   1.394 +  tmp.reserve(capacity);
   1.395 +  s.swap(tmp);
   1.396 +}
   1.397 +
   1.398 +bool Channel::ChannelImpl::Connect() {
   1.399 +  if (mode_ == MODE_SERVER && uses_fifo_) {
   1.400 +    if (server_listen_pipe_ == -1) {
   1.401 +      return false;
   1.402 +    }
   1.403 +    MessageLoopForIO::current()->WatchFileDescriptor(
   1.404 +        server_listen_pipe_,
   1.405 +        true,
   1.406 +        MessageLoopForIO::WATCH_READ,
   1.407 +        &server_listen_connection_watcher_,
   1.408 +        this);
   1.409 +  } else {
   1.410 +    if (pipe_ == -1) {
   1.411 +      return false;
   1.412 +    }
   1.413 +    MessageLoopForIO::current()->WatchFileDescriptor(
   1.414 +        pipe_,
   1.415 +        true,
   1.416 +        MessageLoopForIO::WATCH_READ,
   1.417 +        &read_watcher_,
   1.418 +        this);
   1.419 +    waiting_connect_ = false;
   1.420 +  }
   1.421 +
   1.422 +  if (!waiting_connect_)
   1.423 +    return ProcessOutgoingMessages();
   1.424 +  return true;
   1.425 +}
   1.426 +
   1.427 +bool Channel::ChannelImpl::ProcessIncomingMessages() {
   1.428 +  ssize_t bytes_read = 0;
   1.429 +
   1.430 +  struct msghdr msg = {0};
   1.431 +  struct iovec iov = {input_buf_, Channel::kReadBufferSize};
   1.432 +
   1.433 +  msg.msg_iov = &iov;
   1.434 +  msg.msg_iovlen = 1;
   1.435 +  msg.msg_control = input_cmsg_buf_;
   1.436 +
   1.437 +  for (;;) {
   1.438 +    msg.msg_controllen = sizeof(input_cmsg_buf_);
   1.439 +
   1.440 +    if (bytes_read == 0) {
   1.441 +      if (pipe_ == -1)
   1.442 +        return false;
   1.443 +
   1.444 +      // Read from pipe.
   1.445 +      // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
   1.446 +      // is waiting on the pipe.
   1.447 +      bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
   1.448 +
   1.449 +      if (bytes_read < 0) {
   1.450 +        if (errno == EAGAIN) {
   1.451 +          return true;
   1.452 +        } else {
   1.453 +          CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
   1.454 +          return false;
   1.455 +        }
   1.456 +      } else if (bytes_read == 0) {
   1.457 +        // The pipe has closed...
   1.458 +        Close();
   1.459 +        return false;
   1.460 +      }
   1.461 +    }
   1.462 +    DCHECK(bytes_read);
   1.463 +
   1.464 +    if (client_pipe_ != -1) {
   1.465 +      Singleton<PipeMap>()->Remove(pipe_name_);
   1.466 +      HANDLE_EINTR(close(client_pipe_));
   1.467 +      client_pipe_ = -1;
   1.468 +    }
   1.469 +
   1.470 +    // a pointer to an array of |num_wire_fds| file descriptors from the read
   1.471 +    const int* wire_fds = NULL;
   1.472 +    unsigned num_wire_fds = 0;
   1.473 +
   1.474 +    // walk the list of control messages and, if we find an array of file
   1.475 +    // descriptors, save a pointer to the array
   1.476 +
   1.477 +    // This next if statement is to work around an OSX issue where
   1.478 +    // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
   1.479 +    // Here's a test case:
   1.480 +    //
   1.481 +    // int main() {
   1.482 +    // struct msghdr msg;
   1.483 +    //   msg.msg_control = &msg;
   1.484 +    //   msg.msg_controllen = 0;
   1.485 +    //   if (CMSG_FIRSTHDR(&msg))
   1.486 +    //     printf("Bug found!\n");
   1.487 +    // }
   1.488 +    if (msg.msg_controllen > 0) {
   1.489 +      // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
   1.490 +      // and will return a pointer into nowhere.
   1.491 +      for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
   1.492 +           cmsg = CMSG_NXTHDR(&msg, cmsg)) {
   1.493 +        if (cmsg->cmsg_level == SOL_SOCKET &&
   1.494 +            cmsg->cmsg_type == SCM_RIGHTS) {
   1.495 +          const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
   1.496 +          DCHECK(payload_len % sizeof(int) == 0);
   1.497 +          wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
   1.498 +          num_wire_fds = payload_len / 4;
   1.499 +
   1.500 +          if (msg.msg_flags & MSG_CTRUNC) {
   1.501 +            CHROMIUM_LOG(ERROR) << "SCM_RIGHTS message was truncated"
   1.502 +                                << " cmsg_len:" << cmsg->cmsg_len
   1.503 +                                << " fd:" << pipe_;
   1.504 +            for (unsigned i = 0; i < num_wire_fds; ++i)
   1.505 +              HANDLE_EINTR(close(wire_fds[i]));
   1.506 +            return false;
   1.507 +          }
   1.508 +          break;
   1.509 +        }
   1.510 +      }
   1.511 +    }
   1.512 +
   1.513 +    // Process messages from input buffer.
   1.514 +    const char *p;
   1.515 +    const char *overflowp;
   1.516 +    const char *end;
   1.517 +    if (input_overflow_buf_.empty()) {
   1.518 +      overflowp = NULL;
   1.519 +      p = input_buf_;
   1.520 +      end = p + bytes_read;
   1.521 +    } else {
   1.522 +      if (input_overflow_buf_.size() >
   1.523 +         static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
   1.524 +        ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize);
   1.525 +        CHROMIUM_LOG(ERROR) << "IPC message is too big";
   1.526 +        return false;
   1.527 +      }
   1.528 +      input_overflow_buf_.append(input_buf_, bytes_read);
   1.529 +      overflowp = p = input_overflow_buf_.data();
   1.530 +      end = p + input_overflow_buf_.size();
   1.531 +    }
   1.532 +
   1.533 +    // A pointer to an array of |num_fds| file descriptors which includes any
   1.534 +    // fds that have spilled over from a previous read.
   1.535 +    const int* fds;
   1.536 +    unsigned num_fds;
   1.537 +    unsigned fds_i = 0;  // the index of the first unused descriptor
   1.538 +
   1.539 +    if (input_overflow_fds_.empty()) {
   1.540 +      fds = wire_fds;
   1.541 +      num_fds = num_wire_fds;
   1.542 +    } else {
   1.543 +      const size_t prev_size = input_overflow_fds_.size();
   1.544 +      input_overflow_fds_.resize(prev_size + num_wire_fds);
   1.545 +      memcpy(&input_overflow_fds_[prev_size], wire_fds,
   1.546 +             num_wire_fds * sizeof(int));
   1.547 +      fds = &input_overflow_fds_[0];
   1.548 +      num_fds = input_overflow_fds_.size();
   1.549 +    }
   1.550 +
   1.551 +    while (p < end) {
   1.552 +      const char* message_tail = Message::FindNext(p, end);
   1.553 +      if (message_tail) {
   1.554 +        int len = static_cast<int>(message_tail - p);
   1.555 +        Message m(p, len);
   1.556 +        if (m.header()->num_fds) {
   1.557 +          // the message has file descriptors
   1.558 +          const char* error = NULL;
   1.559 +          if (m.header()->num_fds > num_fds - fds_i) {
   1.560 +            // the message has been completely received, but we didn't get
   1.561 +            // enough file descriptors.
   1.562 +            error = "Message needs unreceived descriptors";
   1.563 +          }
   1.564 +
   1.565 +          if (m.header()->num_fds >
   1.566 +              FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
   1.567 +            // There are too many descriptors in this message
   1.568 +            error = "Message requires an excessive number of descriptors";
   1.569 +          }
   1.570 +
   1.571 +          if (error) {
   1.572 +            CHROMIUM_LOG(WARNING) << error
   1.573 +                                  << " channel:" << this
   1.574 +                                  << " message-type:" << m.type()
   1.575 +                                  << " header()->num_fds:" << m.header()->num_fds
   1.576 +                                  << " num_fds:" << num_fds
   1.577 +                                  << " fds_i:" << fds_i;
   1.578 +            // close the existing file descriptors so that we don't leak them
   1.579 +            for (unsigned i = fds_i; i < num_fds; ++i)
   1.580 +              HANDLE_EINTR(close(fds[i]));
   1.581 +            input_overflow_fds_.clear();
   1.582 +            // abort the connection
   1.583 +            return false;
   1.584 +          }
   1.585 +
   1.586 +#if defined(OS_MACOSX)
   1.587 +          // Send a message to the other side, indicating that we are now
   1.588 +          // responsible for closing the descriptor.
   1.589 +          Message *fdAck = new Message(MSG_ROUTING_NONE,
   1.590 +                                       RECEIVED_FDS_MESSAGE_TYPE,
   1.591 +                                       IPC::Message::PRIORITY_NORMAL);
   1.592 +          DCHECK(m.fd_cookie() != 0);
   1.593 +          fdAck->set_fd_cookie(m.fd_cookie());
   1.594 +          OutputQueuePush(fdAck);
   1.595 +#endif
   1.596 +
   1.597 +          m.file_descriptor_set()->SetDescriptors(
   1.598 +              &fds[fds_i], m.header()->num_fds);
   1.599 +          fds_i += m.header()->num_fds;
   1.600 +        }
   1.601 +#ifdef IPC_MESSAGE_DEBUG_EXTRA
   1.602 +        DLOG(INFO) << "received message on channel @" << this <<
   1.603 +                      " with type " << m.type();
   1.604 +#endif
   1.605 +
   1.606 +#ifdef MOZ_TASK_TRACER
   1.607 +        AutoSaveCurTraceInfo saveCurTraceInfo;
   1.608 +        SetCurTraceInfo(m.header()->source_event_id,
   1.609 +                        m.header()->parent_task_id,
   1.610 +                        m.header()->source_event_type);
   1.611 +#endif
   1.612 +
   1.613 +        if (m.routing_id() == MSG_ROUTING_NONE &&
   1.614 +            m.type() == HELLO_MESSAGE_TYPE) {
   1.615 +          // The Hello message contains only the process id.
   1.616 +          listener_->OnChannelConnected(MessageIterator(m).NextInt());
   1.617 +#if defined(OS_MACOSX)
   1.618 +        } else if (m.routing_id() == MSG_ROUTING_NONE &&
   1.619 +                   m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
   1.620 +          DCHECK(m.fd_cookie() != 0);
   1.621 +          CloseDescriptors(m.fd_cookie());
   1.622 +#endif
   1.623 +        } else {
   1.624 +          listener_->OnMessageReceived(m);
   1.625 +        }
   1.626 +        p = message_tail;
   1.627 +      } else {
   1.628 +        // Last message is partial.
   1.629 +        break;
   1.630 +      }
   1.631 +    }
   1.632 +    if (end == p) {
   1.633 +      ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize);
   1.634 +    } else if (!overflowp) {
   1.635 +      // p is from input_buf_
   1.636 +      input_overflow_buf_.assign(p, end - p);
   1.637 +    } else if (p > overflowp) {
   1.638 +      // p is from input_overflow_buf_
   1.639 +      input_overflow_buf_.erase(0, p - overflowp);
   1.640 +    }
   1.641 +    input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
   1.642 +
   1.643 +    // When the input data buffer is empty, the overflow fds should be too. If
   1.644 +    // this is not the case, we probably have a rogue renderer which is trying
   1.645 +    // to fill our descriptor table.
   1.646 +    if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
   1.647 +      // We close these descriptors in Close()
   1.648 +      return false;
   1.649 +    }
   1.650 +
   1.651 +    bytes_read = 0;  // Get more data.
   1.652 +  }
   1.653 +
   1.654 +  return true;
   1.655 +}
   1.656 +
   1.657 +bool Channel::ChannelImpl::ProcessOutgoingMessages() {
   1.658 +  DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
   1.659 +                              // no connection?
   1.660 +  is_blocked_on_write_ = false;
   1.661 +
   1.662 +  if (output_queue_.empty())
   1.663 +    return true;
   1.664 +
   1.665 +  if (pipe_ == -1)
   1.666 +    return false;
   1.667 +
   1.668 +  // Write out all the messages we can till the write blocks or there are no
   1.669 +  // more outgoing messages.
   1.670 +  while (!output_queue_.empty()) {
   1.671 +    Message* msg = output_queue_.front();
   1.672 +
   1.673 +    struct msghdr msgh = {0};
   1.674 +
   1.675 +    static const int tmp = CMSG_SPACE(sizeof(
   1.676 +        int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
   1.677 +    char buf[tmp];
   1.678 +
   1.679 +    if (message_send_bytes_written_ == 0 &&
   1.680 +        !msg->file_descriptor_set()->empty()) {
   1.681 +      // This is the first chunk of a message which has descriptors to send
   1.682 +      struct cmsghdr *cmsg;
   1.683 +      const unsigned num_fds = msg->file_descriptor_set()->size();
   1.684 +
   1.685 +      if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
   1.686 +        CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
   1.687 +        // This should not be reached.
   1.688 +        return false;
   1.689 +      }
   1.690 +
   1.691 +      msgh.msg_control = buf;
   1.692 +      msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
   1.693 +      cmsg = CMSG_FIRSTHDR(&msgh);
   1.694 +      cmsg->cmsg_level = SOL_SOCKET;
   1.695 +      cmsg->cmsg_type = SCM_RIGHTS;
   1.696 +      cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
   1.697 +      msg->file_descriptor_set()->GetDescriptors(
   1.698 +          reinterpret_cast<int*>(CMSG_DATA(cmsg)));
   1.699 +      msgh.msg_controllen = cmsg->cmsg_len;
   1.700 +
   1.701 +      msg->header()->num_fds = num_fds;
   1.702 +#if defined(OS_MACOSX)
   1.703 +      msg->set_fd_cookie(++last_pending_fd_id_);
   1.704 +#endif
   1.705 +    }
   1.706 +#ifdef MOZ_TASK_TRACER
   1.707 +    GetCurTraceInfo(&msg->header()->source_event_id,
   1.708 +                    &msg->header()->parent_task_id,
   1.709 +                    &msg->header()->source_event_type);
   1.710 +#endif
   1.711 +
   1.712 +    size_t amt_to_write = msg->size() - message_send_bytes_written_;
   1.713 +    DCHECK(amt_to_write != 0);
   1.714 +    const char *out_bytes = reinterpret_cast<const char*>(msg->data()) +
   1.715 +        message_send_bytes_written_;
   1.716 +
   1.717 +    struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
   1.718 +    msgh.msg_iov = &iov;
   1.719 +    msgh.msg_iovlen = 1;
   1.720 +
   1.721 +    ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
   1.722 +#if !defined(OS_MACOSX)
   1.723 +    // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
   1.724 +    // message.
   1.725 +    if (bytes_written > 0)
   1.726 +      msg->file_descriptor_set()->CommitAll();
   1.727 +#endif
   1.728 +
   1.729 +    if (bytes_written < 0 && errno != EAGAIN) {
   1.730 +      CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
   1.731 +      return false;
   1.732 +    }
   1.733 +
   1.734 +    if (static_cast<size_t>(bytes_written) != amt_to_write) {
   1.735 +      if (bytes_written > 0) {
   1.736 +        // If write() fails with EAGAIN then bytes_written will be -1.
   1.737 +        message_send_bytes_written_ += bytes_written;
   1.738 +      }
   1.739 +
   1.740 +      // Tell libevent to call us back once things are unblocked.
   1.741 +      is_blocked_on_write_ = true;
   1.742 +      MessageLoopForIO::current()->WatchFileDescriptor(
   1.743 +          pipe_,
   1.744 +          false,  // One shot
   1.745 +          MessageLoopForIO::WATCH_WRITE,
   1.746 +          &write_watcher_,
   1.747 +          this);
   1.748 +      return true;
   1.749 +    } else {
   1.750 +      message_send_bytes_written_ = 0;
   1.751 +
   1.752 +#if defined(OS_MACOSX)
   1.753 +      if (!msg->file_descriptor_set()->empty())
   1.754 +        pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(),
   1.755 +                                                  msg->file_descriptor_set()));
   1.756 +#endif
   1.757 +
   1.758 +      // Message sent OK!
   1.759 +#ifdef IPC_MESSAGE_DEBUG_EXTRA
   1.760 +      DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
   1.761 +                    " with type " << msg->type();
   1.762 +#endif
   1.763 +      OutputQueuePop();
   1.764 +      delete msg;
   1.765 +    }
   1.766 +  }
   1.767 +  return true;
   1.768 +}
   1.769 +
   1.770 +bool Channel::ChannelImpl::Send(Message* message) {
   1.771 +#ifdef IPC_MESSAGE_DEBUG_EXTRA
   1.772 +  DLOG(INFO) << "sending message @" << message << " on channel @" << this
   1.773 +             << " with type " << message->type()
   1.774 +             << " (" << output_queue_.size() << " in queue)";
   1.775 +#endif
   1.776 +
   1.777 +#ifdef IPC_MESSAGE_LOG_ENABLED
   1.778 +  Logging::current()->OnSendMessage(message, L"");
   1.779 +#endif
   1.780 +
   1.781 +  // If the channel has been closed, ProcessOutgoingMessages() is never going
   1.782 +  // to pop anything off output_queue; output_queue will only get emptied when
   1.783 +  // the channel is destructed.  We might as well delete message now, instead
   1.784 +  // of waiting for the channel to be destructed.
   1.785 +  if (closed_) {
   1.786 +    if (mozilla::ipc::LoggingEnabled()) {
   1.787 +      fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
   1.788 +              message->name());
   1.789 +    }
   1.790 +    delete message;
   1.791 +    return false;
   1.792 +  }
   1.793 +
   1.794 +  OutputQueuePush(message);
   1.795 +  if (!waiting_connect_) {
   1.796 +    if (!is_blocked_on_write_) {
   1.797 +      if (!ProcessOutgoingMessages())
   1.798 +        return false;
   1.799 +    }
   1.800 +  }
   1.801 +
   1.802 +  return true;
   1.803 +}
   1.804 +
   1.805 +void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
   1.806 +                                                          int *dest_fd) const {
   1.807 +  DCHECK(mode_ == MODE_SERVER);
   1.808 +  *src_fd = client_pipe_;
   1.809 +  *dest_fd = kClientChannelFd;
   1.810 +}
   1.811 +
   1.812 +void Channel::ChannelImpl::CloseClientFileDescriptor() {
   1.813 +  if (client_pipe_ != -1) {
   1.814 +    Singleton<PipeMap>()->Remove(pipe_name_);
   1.815 +    HANDLE_EINTR(close(client_pipe_));
   1.816 +    client_pipe_ = -1;
   1.817 +  }
   1.818 +}
   1.819 +
   1.820 +// Called by libevent when we can read from th pipe without blocking.
   1.821 +void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
   1.822 +  bool send_server_hello_msg = false;
   1.823 +  if (waiting_connect_ && mode_ == MODE_SERVER) {
   1.824 +    // In the case of a socketpair() the server starts listening on its end
   1.825 +    // of the pipe in Connect().
   1.826 +    DCHECK(uses_fifo_);
   1.827 +
   1.828 +    if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) {
   1.829 +      Close();
   1.830 +    }
   1.831 +
   1.832 +    // No need to watch the listening socket any longer since only one client
   1.833 +    // can connect.  So unregister with libevent.
   1.834 +    server_listen_connection_watcher_.StopWatchingFileDescriptor();
   1.835 +
   1.836 +    // Start watching our end of the socket.
   1.837 +    MessageLoopForIO::current()->WatchFileDescriptor(
   1.838 +        pipe_,
   1.839 +        true,
   1.840 +        MessageLoopForIO::WATCH_READ,
   1.841 +        &read_watcher_,
   1.842 +        this);
   1.843 +
   1.844 +    waiting_connect_ = false;
   1.845 +    send_server_hello_msg = true;
   1.846 +  }
   1.847 +
   1.848 +  if (!waiting_connect_ && fd == pipe_) {
   1.849 +    if (!ProcessIncomingMessages()) {
   1.850 +      Close();
   1.851 +      listener_->OnChannelError();
   1.852 +    }
   1.853 +  }
   1.854 +
   1.855 +  // If we're a server and handshaking, then we want to make sure that we
   1.856 +  // only send our handshake message after we've processed the client's.
   1.857 +  // This gives us a chance to kill the client if the incoming handshake
   1.858 +  // is invalid.
   1.859 +  if (send_server_hello_msg) {
   1.860 +    // This should be our first write so there's no chance we can block here...
   1.861 +    DCHECK(is_blocked_on_write_ == false);
   1.862 +    ProcessOutgoingMessages();
   1.863 +  }
   1.864 +}
   1.865 +
   1.866 +#if defined(OS_MACOSX)
   1.867 +void Channel::ChannelImpl::CloseDescriptors(uint32_t pending_fd_id)
   1.868 +{
   1.869 +  DCHECK(pending_fd_id != 0);
   1.870 +  for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
   1.871 +       i != pending_fds_.end();
   1.872 +       i++) {
   1.873 +    if ((*i).id == pending_fd_id) {
   1.874 +      (*i).fds->CommitAll();
   1.875 +      pending_fds_.erase(i);
   1.876 +      return;
   1.877 +    }
   1.878 +  }
   1.879 +  DCHECK(false) << "pending_fd_id not in our list!";
   1.880 +}
   1.881 +#endif
   1.882 +
   1.883 +void Channel::ChannelImpl::OutputQueuePush(Message* msg)
   1.884 +{
   1.885 +  output_queue_.push(msg);
   1.886 +  output_queue_length_++;
   1.887 +}
   1.888 +
   1.889 +void Channel::ChannelImpl::OutputQueuePop()
   1.890 +{
   1.891 +  output_queue_.pop();
   1.892 +  output_queue_length_--;
   1.893 +}
   1.894 +
   1.895 +// Called by libevent when we can write to the pipe without blocking.
   1.896 +void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
   1.897 +  if (!ProcessOutgoingMessages()) {
   1.898 +    Close();
   1.899 +    listener_->OnChannelError();
   1.900 +  }
   1.901 +}
   1.902 +
   1.903 +void Channel::ChannelImpl::Close() {
   1.904 +  // Close can be called multiple times, so we need to make sure we're
   1.905 +  // idempotent.
   1.906 +
   1.907 +  // Unregister libevent for the listening socket and close it.
   1.908 +  server_listen_connection_watcher_.StopWatchingFileDescriptor();
   1.909 +
   1.910 +  if (server_listen_pipe_ != -1) {
   1.911 +    HANDLE_EINTR(close(server_listen_pipe_));
   1.912 +    server_listen_pipe_ = -1;
   1.913 +  }
   1.914 +
   1.915 +  // Unregister libevent for the FIFO and close it.
   1.916 +  read_watcher_.StopWatchingFileDescriptor();
   1.917 +  write_watcher_.StopWatchingFileDescriptor();
   1.918 +  if (pipe_ != -1) {
   1.919 +    HANDLE_EINTR(close(pipe_));
   1.920 +    pipe_ = -1;
   1.921 +  }
   1.922 +  if (client_pipe_ != -1) {
   1.923 +    Singleton<PipeMap>()->Remove(pipe_name_);
   1.924 +    HANDLE_EINTR(close(client_pipe_));
   1.925 +    client_pipe_ = -1;
   1.926 +  }
   1.927 +
   1.928 +  if (uses_fifo_) {
   1.929 +    // Unlink the FIFO
   1.930 +    unlink(pipe_name_.c_str());
   1.931 +  }
   1.932 +
   1.933 +  while (!output_queue_.empty()) {
   1.934 +    Message* m = output_queue_.front();
   1.935 +    OutputQueuePop();
   1.936 +    delete m;
   1.937 +  }
   1.938 +
   1.939 +  // Close any outstanding, received file descriptors
   1.940 +  for (std::vector<int>::iterator
   1.941 +       i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
   1.942 +    HANDLE_EINTR(close(*i));
   1.943 +  }
   1.944 +  input_overflow_fds_.clear();
   1.945 +
   1.946 +#if defined(OS_MACOSX)
   1.947 +  for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
   1.948 +       i != pending_fds_.end();
   1.949 +       i++) {
   1.950 +    (*i).fds->CommitAll();
   1.951 +  }
   1.952 +  pending_fds_.clear();
   1.953 +#endif
   1.954 +
   1.955 +  closed_ = true;
   1.956 +}
   1.957 +
   1.958 +bool Channel::ChannelImpl::Unsound_IsClosed() const
   1.959 +{
   1.960 +  return closed_;
   1.961 +}
   1.962 +
   1.963 +uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const
   1.964 +{
   1.965 +  return output_queue_length_;
   1.966 +}
   1.967 +
   1.968 +//------------------------------------------------------------------------------
   1.969 +// Channel's methods simply call through to ChannelImpl.
   1.970 +Channel::Channel(const std::wstring& channel_id, Mode mode,
   1.971 +                 Listener* listener)
   1.972 +    : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
   1.973 +}
   1.974 +
   1.975 +Channel::Channel(int fd, Mode mode, Listener* listener)
   1.976 +    : channel_impl_(new ChannelImpl(fd, mode, listener)) {
   1.977 +}
   1.978 +
   1.979 +Channel::~Channel() {
   1.980 +  delete channel_impl_;
   1.981 +}
   1.982 +
   1.983 +bool Channel::Connect() {
   1.984 +  return channel_impl_->Connect();
   1.985 +}
   1.986 +
   1.987 +void Channel::Close() {
   1.988 +  channel_impl_->Close();
   1.989 +}
   1.990 +
   1.991 +Channel::Listener* Channel::set_listener(Listener* listener) {
   1.992 +  return channel_impl_->set_listener(listener);
   1.993 +}
   1.994 +
   1.995 +bool Channel::Send(Message* message) {
   1.996 +  return channel_impl_->Send(message);
   1.997 +}
   1.998 +
   1.999 +void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
  1.1000 +  return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
  1.1001 +}
  1.1002 +
  1.1003 +void Channel::ResetFileDescriptor(int fd) {
  1.1004 +  channel_impl_->ResetFileDescriptor(fd);
  1.1005 +}
  1.1006 +
  1.1007 +int Channel::GetFileDescriptor() const {
  1.1008 +    return channel_impl_->GetFileDescriptor();
  1.1009 +}
  1.1010 +
  1.1011 +void Channel::CloseClientFileDescriptor() {
  1.1012 +  channel_impl_->CloseClientFileDescriptor();
  1.1013 +}
  1.1014 +
  1.1015 +bool Channel::Unsound_IsClosed() const {
  1.1016 +  return channel_impl_->Unsound_IsClosed();
  1.1017 +}
  1.1018 +
  1.1019 +uint32_t Channel::Unsound_NumQueuedMessages() const {
  1.1020 +  return channel_impl_->Unsound_NumQueuedMessages();
  1.1021 +}
  1.1022 +
  1.1023 +}  // namespace IPC

mercurial