LCOV - app.info - ipc/chromium/src/chrome/common/ipc_channel_posix.cc

LCOV - code coverage report
| Current view: | directory - ipc/chromium/src/chrome/common - ipc_channel_posix.cc (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 403 | 45 | 11.2 %
| Date: | 2012-06-02 | Functions: | 33 | 8 | 24.2 %

           1                 : // Copyright (c) 2008 The Chromium Authors. All rights reserved.
           2                 : // Use of this source code is governed by a BSD-style license that can be
           3                 : // found in the LICENSE file.
           4                 :
           5                 : #include "chrome/common/ipc_channel_posix.h"
           6                 :
           7                 : #include <errno.h>
           8                 : #include <fcntl.h>
           9                 : #include <stddef.h>
          10                 : #include <sys/types.h>
          11                 : #include <sys/socket.h>
          12                 : #include <sys/stat.h>
          13                 : #include <sys/un.h>
          14                 : #include <sys/uio.h>
          15                 :
          16                 : #include <string>
          17                 : #include <map>
          18                 :
          19                 : #include "base/command_line.h"
          20                 : #include "base/eintr_wrapper.h"
          21                 : #include "base/lock.h"
          22                 : #include "base/logging.h"
          23                 : #include "base/process_util.h"
          24                 : #include "base/scoped_ptr.h"
          25                 : #include "base/string_util.h"
          26                 : #include "base/singleton.h"
          27                 : #include "base/stats_counters.h"
          28                 : #include "chrome/common/chrome_counters.h"
          29                 : #include "chrome/common/chrome_switches.h"
          30                 : #include "chrome/common/file_descriptor_set_posix.h"
          31                 : #include "chrome/common/ipc_logging.h"
          32                 : #include "chrome/common/ipc_message_utils.h"
          33                 :
          34                 : namespace IPC {
          35                 :
          36                 : // IPC channels on Windows use named pipes (CreateNamedPipe()) with
          37                 : // channel ids as the pipe names.  Channels on POSIX use anonymous
          38                 : // Unix domain sockets created via socketpair() as pipes.  These don't
          39                 : // quite line up.
          40                 : //
          41                 : // When creating a child subprocess, the parent side of the fork
          42                 : // arranges it such that the initial control channel ends up on the
          43                 : // magic file descriptor kClientChannelFd in the child.  Future
          44                 : // connections (file descriptors) can then be passed via that
          45                 : // connection via sendmsg().
          46                 :
          47                 : //------------------------------------------------------------------------------
          48                 : namespace {
          49                 :
          50                 : // The PipeMap class works around this quirk related to unit tests:
          51                 : //
          52                 : // When running as a server, we install the client socket in a
          53                 : // specific file descriptor number (@kClientChannelFd). However, we
          54                 : // also have to support the case where we are running unittests in the
          55                 : // same process.  (We do not support forking without execing.)
          56                 : //
          57                 : // Case 1: normal running
          58                 : //   The IPC server object will install a mapping in PipeMap from the
          59                 : //   name which it was given to the client pipe. When forking the client, the
          60                 : //   GetClientFileDescriptorMapping will ensure that the socket is installed in
          61                 : //   the magic slot (@kClientChannelFd). The client will search for the
          62                 : //   mapping, but it won't find any since we are in a new process. Thus the
          63                 : //   magic fd number is returned. Once the client connects, the server will
          64                 : //   close its copy of the client socket and remove the mapping.
          65                 : //
          66                 : // Case 2: unittests - client and server in the same process
          67                 : //   The IPC server will install a mapping as before. The client will search
          68                 : //   for a mapping and find out. It duplicates the file descriptor and
          69                 : //   connects. Once the client connects, the server will close the original
          70                 : //   copy of the client socket and remove the mapping. Thus, when the client
          71                 : //   object closes, it will close the only remaining copy of the client socket
          72                 : //   in the fd table and the server will see EOF on its side.
          73                 : //
          74                 : // TODO(port): a client process cannot connect to multiple IPC channels with
          75                 : // this scheme.
          76                 :
          77               1 : class PipeMap {
          78                 :  public:
          79                 :   // Lookup a given channel id. Return -1 if not found.
          80               1 :   int Lookup(const std::string& channel_id) {
          81               2 :     AutoLock locked(lock_);
          82                 :
          83               1 :     ChannelToFDMap::const_iterator i = map_.find(channel_id);
          84               1 :     if (i == map_.end())
          85               1 :       return -1;
          86               0 :     return i->second;
          87                 :   }
          88                 :
          89                 :   // Remove the mapping for the given channel id. No error is signaled if the
          90                 :   // channel_id doesn't exist
          91               0 :   void Remove(const std::string& channel_id) {
          92               0 :     AutoLock locked(lock_);
          93                 :
          94               0 :     ChannelToFDMap::iterator i = map_.find(channel_id);
          95               0 :     if (i != map_.end())
          96               0 :       map_.erase(i);
          97               0 :   }
          98                 :
          99                 :   // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
         100                 :   // mapping if one already exists for the given channel_id
         101               0 :   void Insert(const std::string& channel_id, int fd) {
         102               0 :     AutoLock locked(lock_);
         103               0 :     DCHECK(fd != -1);
         104                 :
         105               0 :     ChannelToFDMap::const_iterator i = map_.find(channel_id);
         106               0 :     CHECK(i == map_.end()) << "Creating second IPC server for '"
         107               0 :                            << channel_id
         108               0 :                            << "' while first still exists";
         109               0 :     map_[channel_id] = fd;
         110               0 :   }
         111                 :
         112                 :  private:
         113                 :   Lock lock_;
         114                 :   typedef std::map<std::string, int> ChannelToFDMap;
         115                 :   ChannelToFDMap map_;
         116                 : };
         117                 :
         118                 : // This is the file descriptor number that a client process expects to find its
         119                 : // IPC socket.
         120                 : static const int kClientChannelFd = 3;
         121                 :
         122                 : // Used to map a channel name to the equivalent FD # in the client process.
         123               1 : int ChannelNameToClientFD(const std::string& channel_id) {
         124                 :   // See the large block comment above PipeMap for the reasoning here.
         125               1 :   const int fd = Singleton<PipeMap>()->Lookup(channel_id);
         126               1 :   if (fd != -1)
         127               0 :     return dup(fd);
         128                 :
         129                 :   // If we don't find an entry, we assume that the correct value has been
         130                 :   // inserted in the magic slot.
         131               1 :   return kClientChannelFd;
         132                 : }
         133                 :
         134                 : //------------------------------------------------------------------------------
         135                 : sockaddr_un sizecheck;
         136                 : const size_t kMaxPipeNameLength = sizeof(sizecheck.sun_path);
         137                 :
         138                 : // Creates a Fifo with the specified name ready to listen on.
         139               0 : bool CreateServerFifo(const std::string& pipe_name, int* server_listen_fd) {
         140               0 :   DCHECK(server_listen_fd);
         141               0 :   DCHECK_GT(pipe_name.length(), 0u);
         142               0 :   DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
         143                 :
         144               0 :   if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
         145               0 :     return false;
         146                 :   }
         147                 :
         148                 :   // Create socket.
         149               0 :   int fd = socket(AF_UNIX, SOCK_STREAM, 0);
         150               0 :   if (fd < 0) {
         151               0 :     return false;
         152                 :   }
         153                 :
         154                 :   // Make socket non-blocking
         155               0 :   if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
         156               0 :     HANDLE_EINTR(close(fd));
         157               0 :     return false;
         158                 :   }
         159                 :
         160                 :   // Delete any old FS instances.
         161               0 :   unlink(pipe_name.c_str());
         162                 :
         163                 :   // Create unix_addr structure
         164                 :   struct sockaddr_un unix_addr;
         165               0 :   memset(&unix_addr, 0, sizeof(unix_addr));
         166               0 :   unix_addr.sun_family = AF_UNIX;
         167               0 :   snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str());
         168                 :   size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
         169               0 :       strlen(unix_addr.sun_path) + 1;
         170                 :
         171                 :   // Bind the socket.
         172               0 :   if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
         173               0 :            unix_addr_len) != 0) {
         174               0 :     HANDLE_EINTR(close(fd));
         175               0 :     return false;
         176                 :   }
         177                 :
         178                 :   // Start listening on the socket.
         179               0 :   const int listen_queue_length = 1;
         180               0 :   if (listen(fd, listen_queue_length) != 0) {
         181               0 :     HANDLE_EINTR(close(fd));
         182               0 :     return false;
         183                 :   }
         184                 :
         185               0 :   *server_listen_fd = fd;
         186               0 :   return true;
         187                 : }
         188                 :
         189                 : // Accept a connection on a fifo.
         190               0 : bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) {
         191               0 :   DCHECK(server_socket);
         192                 :
         193               0 :   int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
         194               0 :   if (accept_fd < 0)
         195               0 :     return false;
         196               0 :   if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
         197               0 :     HANDLE_EINTR(close(accept_fd));
         198               0 :     return false;
         199                 :   }
         200                 :
         201               0 :   *server_socket = accept_fd;
         202               0 :   return true;
         203                 : }
         204                 :
         205               0 : bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) {
         206               0 :   DCHECK(client_socket);
         207               0 :   DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
         208                 :
         209                 :   // Create socket.
         210               0 :   int fd = socket(AF_UNIX, SOCK_STREAM, 0);
         211               0 :   if (fd < 0) {
         212               0 :     LOG(ERROR) << "fd is invalid";
         213               0 :     return false;
         214                 :   }
         215                 :
         216                 :   // Make socket non-blocking
         217               0 :   if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
         218               0 :     LOG(ERROR) << "fcntl failed";
         219               0 :     HANDLE_EINTR(close(fd));
         220               0 :     return false;
         221                 :   }
         222                 :
         223                 :   // Create server side of socket.
         224                 :   struct sockaddr_un  server_unix_addr;
         225               0 :   memset(&server_unix_addr, 0, sizeof(server_unix_addr));
         226               0 :   server_unix_addr.sun_family = AF_UNIX;
         227                 :   snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s",
         228               0 :            pipe_name.c_str());
         229                 :   size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
         230               0 :       strlen(server_unix_addr.sun_path) + 1;
         231                 :
         232               0 :   if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
         233                 :                            server_unix_addr_len)) != 0) {
         234               0 :     HANDLE_EINTR(close(fd));
         235               0 :     return false;
         236                 :   }
         237                 :
         238               0 :   *client_socket = fd;
         239               0 :   return true;
         240                 : }
         241                 :
         242               0 : bool SetCloseOnExec(int fd) {
         243               0 :   int flags = fcntl(fd, F_GETFD);
         244               0 :   if (flags == -1)
         245               0 :     return false;
         246                 :
         247               0 :   flags |= FD_CLOEXEC;
         248               0 :   if (fcntl(fd, F_SETFD, flags) == -1)
         249               0 :     return false;
         250                 :
         251               0 :   return true;
         252                 : }
         253                 :
         254                 : }  // namespace
         255                 : //------------------------------------------------------------------------------
         256                 :
         257               1 : Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
         258                 :                                   Listener* listener)
         259               1 :     : factory_(this) {
         260               1 :   Init(mode, listener);
         261               1 :   uses_fifo_ = CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO);
         262                 :
         263               1 :   if (!CreatePipe(channel_id, mode)) {
         264                 :     // The pipe may have been closed already.
         265               0 :     LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
         266               0 :                     "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
         267               0 :                     " mode error(" << strerror(errno) << ").";
         268                 :   }
         269               1 : }
         270                 :
         271               0 : Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
         272               0 :     : factory_(this) {
         273               0 :   Init(mode, listener);
         274               0 :   pipe_ = fd;
         275               0 :   waiting_connect_ = (MODE_SERVER == mode);
         276                 :
         277               0 :   EnqueueHelloMessage();
         278               0 : }
         279                 :
         280               1 : void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
         281               1 :   mode_ = mode;
         282               1 :   is_blocked_on_write_ = false;
         283               1 :   message_send_bytes_written_ = 0;
         284               1 :   uses_fifo_ = false;
         285               1 :   server_listen_pipe_ = -1;
         286               1 :   pipe_ = -1;
         287               1 :   client_pipe_ = -1;
         288               1 :   listener_ = listener;
         289               1 :   waiting_connect_ = true;
         290               1 :   processing_incoming_ = false;
         291               1 : }
         292                 :
         293               1 : bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
         294                 :                                       Mode mode) {
         295               1 :   DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
         296                 :
         297               1 :   if (uses_fifo_) {
         298                 :     // This only happens in unit tests; see the comment above PipeMap.
         299                 :     // TODO(playmobil): We shouldn't need to create fifos on disk.
         300                 :     // TODO(playmobil): If we do, they should be in the user data directory.
         301                 :     // TODO(playmobil): Cleanup any stale fifos.
         302               0 :     pipe_name_ = "/var/tmp/chrome_" + WideToASCII(channel_id);
         303               0 :     if (mode == MODE_SERVER) {
         304               0 :       if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) {
         305               0 :         return false;
         306                 :       }
         307                 :     } else {
         308               0 :       if (!ClientConnectToFifo(pipe_name_, &pipe_)) {
         309               0 :         return false;
         310                 :       }
         311               0 :       waiting_connect_ = false;
         312                 :     }
         313                 :   } else {
         314                 :     // socketpair()
         315               1 :     pipe_name_ = WideToASCII(channel_id);
         316               1 :     if (mode == MODE_SERVER) {
         317                 :       int pipe_fds[2];
         318               0 :       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
         319               0 :         return false;
         320                 :       }
         321                 :       // Set both ends to be non-blocking.
         322               0 :       if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
         323               0 :           fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
         324               0 :         HANDLE_EINTR(close(pipe_fds[0]));
         325               0 :         HANDLE_EINTR(close(pipe_fds[1]));
         326               0 :         return false;
         327                 :       }
         328                 :
         329               0 :       if (!SetCloseOnExec(pipe_fds[0]) ||
         330               0 :           !SetCloseOnExec(pipe_fds[1])) {
         331               0 :         HANDLE_EINTR(close(pipe_fds[0]));
         332               0 :         HANDLE_EINTR(close(pipe_fds[1]));
         333               0 :         return false;
         334                 :       }
         335                 :
         336               0 :       pipe_ = pipe_fds[0];
         337               0 :       client_pipe_ = pipe_fds[1];
         338                 :
         339               0 :       Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
         340                 :     } else {
         341               1 :       pipe_ = ChannelNameToClientFD(pipe_name_);
         342               1 :       DCHECK(pipe_ > 0);
         343               1 :       waiting_connect_ = false;
         344                 :     }
         345                 :   }
         346                 :
         347                 :   // Create the Hello message to be sent when Connect is called
         348               1 :   return EnqueueHelloMessage();
         349                 : }
         350                 :
         351               1 : bool Channel::ChannelImpl::EnqueueHelloMessage() {
         352                 :   scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
         353                 :                                       HELLO_MESSAGE_TYPE,
         354               2 :                                       IPC::Message::PRIORITY_NORMAL));
         355               1 :   if (!msg->WriteInt(base::GetCurrentProcId())) {
         356               0 :     Close();
         357               0 :     return false;
         358                 :   }
         359                 :
         360               1 :   output_queue_.push(msg.release());
         361               1 :   return true;
         362                 : }
         363                 :
         364               0 : bool Channel::ChannelImpl::Connect() {
         365               0 :   if (mode_ == MODE_SERVER && uses_fifo_) {
         366               0 :     if (server_listen_pipe_ == -1) {
         367               0 :       return false;
         368                 :     }
         369                 :     MessageLoopForIO::current()->WatchFileDescriptor(
         370                 :         server_listen_pipe_,
         371                 :         true,
         372                 :         MessageLoopForIO::WATCH_READ,
         373                 :         &server_listen_connection_watcher_,
         374               0 :         this);
         375                 :   } else {
         376               0 :     if (pipe_ == -1) {
         377               0 :       return false;
         378                 :     }
         379                 :     MessageLoopForIO::current()->WatchFileDescriptor(
         380                 :         pipe_,
         381                 :         true,
         382                 :         MessageLoopForIO::WATCH_READ,
         383                 :         &read_watcher_,
         384               0 :         this);
         385               0 :     waiting_connect_ = false;
         386                 :   }
         387                 :
         388               0 :   if (!waiting_connect_)
         389               0 :     return ProcessOutgoingMessages();
         390               0 :   return true;
         391                 : }
         392                 :
         393               0 : bool Channel::ChannelImpl::ProcessIncomingMessages() {
         394               0 :   ssize_t bytes_read = 0;
         395                 :
         396               0 :   struct msghdr msg = {0};
         397               0 :   struct iovec iov = {input_buf_, Channel::kReadBufferSize};
         398                 :
         399               0 :   msg.msg_iov = &iov;
         400               0 :   msg.msg_iovlen = 1;
         401               0 :   msg.msg_control = input_cmsg_buf_;
         402                 :
         403               0 :   for (;;) {
         404               0 :     msg.msg_controllen = sizeof(input_cmsg_buf_);
         405                 :
         406               0 :     if (bytes_read == 0) {
         407               0 :       if (pipe_ == -1)
         408               0 :         return false;
         409                 :
         410                 :       // Read from pipe.
         411                 :       // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
         412                 :       // is waiting on the pipe.
         413               0 :       bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
         414                 :
         415               0 :       if (bytes_read < 0) {
         416               0 :         if (errno == EAGAIN) {
         417               0 :           return true;
         418                 :         } else {
         419               0 :           LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
         420               0 :           return false;
         421                 :         }
         422               0 :       } else if (bytes_read == 0) {
         423                 :         // The pipe has closed...
         424               0 :         Close();
         425               0 :         return false;
         426                 :       }
         427                 :     }
         428               0 :     DCHECK(bytes_read);
         429                 :
         430               0 :     if (client_pipe_ != -1) {
         431               0 :       Singleton<PipeMap>()->Remove(pipe_name_);
         432               0 :       HANDLE_EINTR(close(client_pipe_));
         433               0 :       client_pipe_ = -1;
         434                 :     }
         435                 :
         436                 :     // a pointer to an array of |num_wire_fds| file descriptors from the read
         437               0 :     const int* wire_fds = NULL;
         438               0 :     unsigned num_wire_fds = 0;
         439                 :
         440                 :     // walk the list of control messages and, if we find an array of file
         441                 :     // descriptors, save a pointer to the array
         442                 :
         443                 :     // This next if statement is to work around an OSX issue where
         444                 :     // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
         445                 :     // Here's a test case:
         446                 :     //
         447                 :     // int main() {
         448                 :     // struct msghdr msg;
         449                 :     //   msg.msg_control = &msg;
         450                 :     //   msg.msg_controllen = 0;
         451                 :     //   if (CMSG_FIRSTHDR(&msg))
         452                 :     //     printf("Bug found!\n");
         453                 :     // }
         454               0 :     if (msg.msg_controllen > 0) {
         455                 :       // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
         456                 :       // and will return a pointer into nowhere.
         457               0 :       for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
         458                 :            cmsg = CMSG_NXTHDR(&msg, cmsg)) {
         459               0 :         if (cmsg->cmsg_level == SOL_SOCKET &&
         460                 :             cmsg->cmsg_type == SCM_RIGHTS) {
         461               0 :           const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
         462               0 :           DCHECK(payload_len % sizeof(int) == 0);
         463               0 :           wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
         464               0 :           num_wire_fds = payload_len / 4;
         465                 :
         466               0 :           if (msg.msg_flags & MSG_CTRUNC) {
         467               0 :             LOG(ERROR) << "SCM_RIGHTS message was truncated"
         468               0 :                        << " cmsg_len:" << cmsg->cmsg_len
         469               0 :                        << " fd:" << pipe_;
         470               0 :             for (unsigned i = 0; i < num_wire_fds; ++i)
         471               0 :               HANDLE_EINTR(close(wire_fds[i]));
         472               0 :             return false;
         473                 :           }
         474               0 :           break;
         475                 :         }
         476                 :       }
         477                 :     }
         478                 :
         479                 :     // Process messages from input buffer.
         480                 :     const char *p;
         481                 :     const char *overflowp;
         482                 :     const char *end;
         483               0 :     if (input_overflow_buf_.empty()) {
         484               0 :       overflowp = NULL;
         485               0 :       p = input_buf_;
         486               0 :       end = p + bytes_read;
         487                 :     } else {
         488               0 :       if (input_overflow_buf_.size() >
         489                 :          static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
         490               0 :         input_overflow_buf_.clear();
         491               0 :         LOG(ERROR) << "IPC message is too big";
         492               0 :         return false;
         493                 :       }
         494               0 :       input_overflow_buf_.append(input_buf_, bytes_read);
         495               0 :       overflowp = p = input_overflow_buf_.data();
         496               0 :       end = p + input_overflow_buf_.size();
         497                 :     }
         498                 :
         499                 :     // A pointer to an array of |num_fds| file descriptors which includes any
         500                 :     // fds that have spilled over from a previous read.
         501                 :     const int* fds;
         502                 :     unsigned num_fds;
         503               0 :     unsigned fds_i = 0;  // the index of the first unused descriptor
         504                 :
         505               0 :     if (input_overflow_fds_.empty()) {
         506               0 :       fds = wire_fds;
         507               0 :       num_fds = num_wire_fds;
         508                 :     } else {
         509               0 :       const size_t prev_size = input_overflow_fds_.size();
         510               0 :       input_overflow_fds_.resize(prev_size + num_wire_fds);
         511               0 :       memcpy(&input_overflow_fds_[prev_size], wire_fds,
         512               0 :              num_wire_fds * sizeof(int));
         513               0 :       fds = &input_overflow_fds_[0];
         514               0 :       num_fds = input_overflow_fds_.size();
         515                 :     }
         516                 :
         517               0 :     while (p < end) {
         518               0 :       const char* message_tail = Message::FindNext(p, end);
         519               0 :       if (message_tail) {
         520               0 :         int len = static_cast<int>(message_tail - p);
         521               0 :         Message m(p, len);
         522               0 :         if (m.header()->num_fds) {
         523                 :           // the message has file descriptors
         524               0 :           const char* error = NULL;
         525               0 :           if (m.header()->num_fds > num_fds - fds_i) {
         526                 :             // the message has been completely received, but we didn't get
         527                 :             // enough file descriptors.
         528               0 :             error = "Message needs unreceived descriptors";
         529                 :           }
         530                 :
         531               0 :           if (m.header()->num_fds >
         532                 :               FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
         533                 :             // There are too many descriptors in this message
         534               0 :             error = "Message requires an excessive number of descriptors";
         535                 :           }
         536                 :
         537               0 :           if (error) {
         538               0 :             LOG(WARNING) << error
         539               0 :                          << " channel:" << this
         540               0 :                          << " message-type:" << m.type()
         541               0 :                          << " header()->num_fds:" << m.header()->num_fds
         542               0 :                          << " num_fds:" << num_fds
         543               0 :                          << " fds_i:" << fds_i;
         544                 :             // close the existing file descriptors so that we don't leak them
         545               0 :             for (unsigned i = fds_i; i < num_fds; ++i)
         546               0 :               HANDLE_EINTR(close(fds[i]));
         547               0 :             input_overflow_fds_.clear();
         548                 :             // abort the connection
         549               0 :             return false;
         550                 :           }
         551                 :
         552                 :           m.file_descriptor_set()->SetDescriptors(
         553               0 :               &fds[fds_i], m.header()->num_fds);
         554               0 :           fds_i += m.header()->num_fds;
         555                 :         }
         556                 : #ifdef IPC_MESSAGE_DEBUG_EXTRA
         557                 :         DLOG(INFO) << "received message on channel @" << this <<
         558                 :                       " with type " << m.type();
         559                 : #endif
         560               0 :         if (m.routing_id() == MSG_ROUTING_NONE &&
         561               0 :             m.type() == HELLO_MESSAGE_TYPE) {
         562                 :           // The Hello message contains only the process id.
         563               0 :           listener_->OnChannelConnected(MessageIterator(m).NextInt());
         564                 :         } else {
         565               0 :           listener_->OnMessageReceived(m);
         566                 :         }
         567               0 :         p = message_tail;
         568                 :       } else {
         569                 :         // Last message is partial.
         570               0 :         break;
         571                 :       }
         572                 :     }
         573               0 :     if (end == p) {
         574               0 :       input_overflow_buf_.clear();
         575               0 :     } else if (!overflowp) {
         576                 :       // p is from input_buf_
         577               0 :       input_overflow_buf_.assign(p, end - p);
         578               0 :     } else if (p > overflowp) {
         579                 :       // p is from input_overflow_buf_
         580               0 :       input_overflow_buf_.erase(0, p - overflowp);
         581                 :     }
         582               0 :     input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
         583                 :
         584                 :     // When the input data buffer is empty, the overflow fds should be too. If
         585                 :     // this is not the case, we probably have a rogue renderer which is trying
         586                 :     // to fill our descriptor table.
         587               0 :     if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
         588                 :       // We close these descriptors in Close()
         589               0 :       return false;
         590                 :     }
         591                 :
         592               0 :     bytes_read = 0;  // Get more data.
         593                 :   }
         594                 :
         595                 :   return true;
         596                 : }
         597                 :
         598               0 : bool Channel::ChannelImpl::ProcessOutgoingMessages() {
         599               0 :   DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
         600                 :                               // no connection?
         601               0 :   is_blocked_on_write_ = false;
         602                 :
         603               0 :   if (output_queue_.empty())
         604               0 :     return true;
         605                 :
         606               0 :   if (pipe_ == -1)
         607               0 :     return false;
         608                 :
         609                 :   // Write out all the messages we can till the write blocks or there are no
         610                 :   // more outgoing messages.
         611               0 :   while (!output_queue_.empty()) {
         612               0 :     Message* msg = output_queue_.front();
         613                 :
         614               0 :     size_t amt_to_write = msg->size() - message_send_bytes_written_;
         615               0 :     DCHECK(amt_to_write != 0);
         616               0 :     const char *out_bytes = reinterpret_cast<const char*>(msg->data()) +
         617               0 :         message_send_bytes_written_;
         618                 :
         619               0 :     struct msghdr msgh = {0};
         620               0 :     struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
         621               0 :     msgh.msg_iov = &iov;
         622               0 :     msgh.msg_iovlen = 1;
         623                 :     static const int tmp = CMSG_SPACE(sizeof(
         624                 :         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
         625                 :     char buf[tmp];
         626                 :
         627               0 :     if (message_send_bytes_written_ == 0 &&
         628               0 :         !msg->file_descriptor_set()->empty()) {
         629                 :       // This is the first chunk of a message which has descriptors to send
         630                 :       struct cmsghdr *cmsg;
         631               0 :       const unsigned num_fds = msg->file_descriptor_set()->size();
         632                 :
         633               0 :       DCHECK_LE(num_fds, FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE);
         634                 :
         635               0 :       msgh.msg_control = buf;
         636               0 :       msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
         637               0 :       cmsg = CMSG_FIRSTHDR(&msgh);
         638               0 :       cmsg->cmsg_level = SOL_SOCKET;
         639               0 :       cmsg->cmsg_type = SCM_RIGHTS;
         640               0 :       cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
         641                 :       msg->file_descriptor_set()->GetDescriptors(
         642               0 :           reinterpret_cast<int*>(CMSG_DATA(cmsg)));
         643               0 :       msgh.msg_controllen = cmsg->cmsg_len;
         644                 :
         645               0 :       msg->header()->num_fds = num_fds;
         646                 :     }
         647                 :
         648               0 :     ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
         649               0 :     if (bytes_written > 0)
         650               0 :       msg->file_descriptor_set()->CommitAll();
         651                 :
         652               0 :     if (bytes_written < 0 && errno != EAGAIN) {
         653               0 :       LOG(ERROR) << "pipe error: " << strerror(errno);
         654               0 :       return false;
         655                 :     }
         656                 :
         657               0 :     if (static_cast<size_t>(bytes_written) != amt_to_write) {
         658               0 :       if (bytes_written > 0) {
         659                 :         // If write() fails with EAGAIN then bytes_written will be -1.
         660               0 :         message_send_bytes_written_ += bytes_written;
         661                 :       }
         662                 :
         663                 :       // Tell libevent to call us back once things are unblocked.
         664               0 :       is_blocked_on_write_ = true;
         665                 :       MessageLoopForIO::current()->WatchFileDescriptor(
         666                 :           pipe_,
         667                 :           false,  // One shot
         668                 :           MessageLoopForIO::WATCH_WRITE,
         669                 :           &write_watcher_,
         670               0 :           this);
         671               0 :       return true;
         672                 :     } else {
         673               0 :       message_send_bytes_written_ = 0;
         674                 :
         675                 :       // Message sent OK!
         676                 : #ifdef IPC_MESSAGE_DEBUG_EXTRA
         677                 :       DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
         678                 :                     " with type " << msg->type();
         679                 : #endif
         680               0 :       output_queue_.pop();
         681               0 :       delete msg;
         682                 :     }
         683                 :   }
         684               0 :   return true;
         685                 : }
         686                 :
         687               0 : bool Channel::ChannelImpl::Send(Message* message) {
         688                 : #ifdef IPC_MESSAGE_DEBUG_EXTRA
         689                 :   DLOG(INFO) << "sending message @" << message << " on channel @" << this
         690                 :              << " with type " << message->type()
         691                 :              << " (" << output_queue_.size() << " in queue)";
         692                 : #endif
         693                 :
         694                 : #ifdef IPC_MESSAGE_LOG_ENABLED
         695               0 :   Logging::current()->OnSendMessage(message, L"");
         696                 : #endif
         697                 :
         698               0 :   output_queue_.push(message);
         699               0 :   if (!waiting_connect_) {
         700               0 :     if (!is_blocked_on_write_) {
         701               0 :       if (!ProcessOutgoingMessages())
         702               0 :         return false;
         703                 :     }
         704                 :   }
         705                 :
         706               0 :   return true;
         707                 : }
         708                 :
         709               0 : void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
         710                 :                                                           int *dest_fd) const {
         711               0 :   DCHECK(mode_ == MODE_SERVER);
         712               0 :   *src_fd = client_pipe_;
         713               0 :   *dest_fd = kClientChannelFd;
         714               0 : }
         715                 :
         716                 : // Called by libevent when we can read from th pipe without blocking.
         717               0 : void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
         718               0 :   bool send_server_hello_msg = false;
         719               0 :   if (waiting_connect_ && mode_ == MODE_SERVER) {
         720                 :     // In the case of a socketpair() the server starts listening on its end
         721                 :     // of the pipe in Connect().
         722               0 :     DCHECK(uses_fifo_);
         723                 :
         724               0 :     if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) {
         725               0 :       Close();
         726                 :     }
         727                 :
         728                 :     // No need to watch the listening socket any longer since only one client
         729                 :     // can connect.  So unregister with libevent.
         730               0 :     server_listen_connection_watcher_.StopWatchingFileDescriptor();
         731                 :
         732                 :     // Start watching our end of the socket.
         733                 :     MessageLoopForIO::current()->WatchFileDescriptor(
         734                 :         pipe_,
         735                 :         true,
         736                 :         MessageLoopForIO::WATCH_READ,
         737                 :         &read_watcher_,
         738               0 :         this);
         739                 :
         740               0 :     waiting_connect_ = false;
         741               0 :     send_server_hello_msg = true;
         742                 :   }
         743                 :
         744               0 :   if (!waiting_connect_ && fd == pipe_) {
         745               0 :     if (!ProcessIncomingMessages()) {
         746               0 :       Close();
         747               0 :       listener_->OnChannelError();
         748                 :     }
         749                 :   }
         750                 :
         751                 :   // If we're a server and handshaking, then we want to make sure that we
         752                 :   // only send our handshake message after we've processed the client's.
         753                 :   // This gives us a chance to kill the client if the incoming handshake
         754                 :   // is invalid.
         755               0 :   if (send_server_hello_msg) {
         756                 :     // This should be our first write so there's no chance we can block here...
         757               0 :     DCHECK(is_blocked_on_write_ == false);
         758               0 :     ProcessOutgoingMessages();
         759                 :   }
         760               0 : }
         761                 :
         762                 : // Called by libevent when we can write to the pipe without blocking.
         763               0 : void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
         764               0 :   if (!ProcessOutgoingMessages()) {
         765               0 :     Close();
         766               0 :     listener_->OnChannelError();
         767                 :   }
         768               0 : }
         769                 :
         770               0 : void Channel::ChannelImpl::Close() {
         771                 :   // Close can be called multiple time, so we need to make sure we're
         772                 :   // idempotent.
         773                 :
         774                 :   // Unregister libevent for the listening socket and close it.
         775               0 :   server_listen_connection_watcher_.StopWatchingFileDescriptor();
         776                 :
         777               0 :   if (server_listen_pipe_ != -1) {
         778               0 :     HANDLE_EINTR(close(server_listen_pipe_));
         779               0 :     server_listen_pipe_ = -1;
         780                 :   }
         781                 :
         782                 :   // Unregister libevent for the FIFO and close it.
         783               0 :   read_watcher_.StopWatchingFileDescriptor();
         784               0 :   write_watcher_.StopWatchingFileDescriptor();
         785               0 :   if (pipe_ != -1) {
         786               0 :     HANDLE_EINTR(close(pipe_));
         787               0 :     pipe_ = -1;
         788                 :   }
         789               0 :   if (client_pipe_ != -1) {
         790               0 :     Singleton<PipeMap>()->Remove(pipe_name_);
         791               0 :     HANDLE_EINTR(close(client_pipe_));
         792               0 :     client_pipe_ = -1;
         793                 :   }
         794                 :
         795               0 :   if (uses_fifo_) {
         796                 :     // Unlink the FIFO
         797               0 :     unlink(pipe_name_.c_str());
         798                 :   }
         799                 :
         800               0 :   while (!output_queue_.empty()) {
         801               0 :     Message* m = output_queue_.front();
         802               0 :     output_queue_.pop();
         803               0 :     delete m;
         804                 :   }
         805                 :
         806                 :   // Close any outstanding, received file descriptors
         807               0 :   for (std::vector<int>::iterator
         808               0 :        i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
         809               0 :     HANDLE_EINTR(close(*i));
         810                 :   }
         811               0 :   input_overflow_fds_.clear();
         812               0 : }
         813                 :
         814                 : //------------------------------------------------------------------------------
         815                 : // Channel's methods simply call through to ChannelImpl.
         816               1 : Channel::Channel(const std::wstring& channel_id, Mode mode,
         817                 :                  Listener* listener)
         818               2 :     : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
         819               1 : }
         820                 :
         821               0 : Channel::Channel(int fd, Mode mode, Listener* listener)
         822               0 :     : channel_impl_(new ChannelImpl(fd, mode, listener)) {
         823               0 : }
         824                 :
         825               0 : Channel::~Channel() {
         826               0 :   delete channel_impl_;
         827               0 : }
         828                 :
         829               0 : bool Channel::Connect() {
         830               0 :   return channel_impl_->Connect();
         831                 : }
         832                 :
         833               0 : void Channel::Close() {
         834               0 :   channel_impl_->Close();
         835               0 : }
         836                 :
         837               0 : Channel::Listener* Channel::set_listener(Listener* listener) {
         838               0 :   return channel_impl_->set_listener(listener);
         839                 : }
         840                 :
         841               0 : bool Channel::Send(Message* message) {
         842               0 :   return channel_impl_->Send(message);
         843                 : }
         844                 :
         845               0 : void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
         846               0 :   return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
         847                 : }
         848                 :
         849               0 : int Channel::GetServerFileDescriptor() const {
         850               0 :   return channel_impl_->GetServerFileDescriptor();
         851                 : }
         852                 :
         853                 : }  // namespace IPC

Generated by: LCOV version 1.7