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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
     5 #include "chrome/common/ipc_channel_posix.h"
     7 #include <errno.h>
     8 #include <fcntl.h>
     9 #include <stddef.h>
    10 #include <unistd.h>
    11 #include <sys/types.h>
    12 #include <sys/socket.h>
    13 #include <sys/stat.h>
    14 #include <sys/un.h>
    15 #include <sys/uio.h>
    17 #include <string>
    18 #include <map>
    20 #include "base/command_line.h"
    21 #include "base/eintr_wrapper.h"
    22 #include "base/lock.h"
    23 #include "base/logging.h"
    24 #include "base/process_util.h"
    25 #include "base/scoped_ptr.h"
    26 #include "base/string_util.h"
    27 #include "base/singleton.h"
    28 #include "base/stats_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 #include "mozilla/ipc/ProtocolUtils.h"
    35 #ifdef MOZ_TASK_TRACER
    36 #include "GeckoTaskTracerImpl.h"
    37 using namespace mozilla::tasktracer;
    38 #endif
    40 namespace IPC {
    42 // IPC channels on Windows use named pipes (CreateNamedPipe()) with
    43 // channel ids as the pipe names.  Channels on POSIX use anonymous
    44 // Unix domain sockets created via socketpair() as pipes.  These don't
    45 // quite line up.
    46 //
    47 // When creating a child subprocess, the parent side of the fork
    48 // arranges it such that the initial control channel ends up on the
    49 // magic file descriptor kClientChannelFd in the child.  Future
    50 // connections (file descriptors) can then be passed via that
    51 // connection via sendmsg().
    53 //------------------------------------------------------------------------------
    54 namespace {
    56 // The PipeMap class works around this quirk related to unit tests:
    57 //
    58 // When running as a server, we install the client socket in a
    59 // specific file descriptor number (@kClientChannelFd). However, we
    60 // also have to support the case where we are running unittests in the
    61 // same process.  (We do not support forking without execing.)
    62 //
    63 // Case 1: normal running
    64 //   The IPC server object will install a mapping in PipeMap from the
    65 //   name which it was given to the client pipe. When forking the client, the
    66 //   GetClientFileDescriptorMapping will ensure that the socket is installed in
    67 //   the magic slot (@kClientChannelFd). The client will search for the
    68 //   mapping, but it won't find any since we are in a new process. Thus the
    69 //   magic fd number is returned. Once the client connects, the server will
    70 //   close its copy of the client socket and remove the mapping.
    71 //
    72 // Case 2: unittests - client and server in the same process
    73 //   The IPC server will install a mapping as before. The client will search
    74 //   for a mapping and find out. It duplicates the file descriptor and
    75 //   connects. Once the client connects, the server will close the original
    76 //   copy of the client socket and remove the mapping. Thus, when the client
    77 //   object closes, it will close the only remaining copy of the client socket
    78 //   in the fd table and the server will see EOF on its side.
    79 //
    80 // TODO(port): a client process cannot connect to multiple IPC channels with
    81 // this scheme.
    83 class PipeMap {
    84  public:
    85   // Lookup a given channel id. Return -1 if not found.
    86   int Lookup(const std::string& channel_id) {
    87     AutoLock locked(lock_);
    89     ChannelToFDMap::const_iterator i = map_.find(channel_id);
    90     if (i == map_.end())
    91       return -1;
    92     return i->second;
    93   }
    95   // Remove the mapping for the given channel id. No error is signaled if the
    96   // channel_id doesn't exist
    97   void Remove(const std::string& channel_id) {
    98     AutoLock locked(lock_);
   100     ChannelToFDMap::iterator i = map_.find(channel_id);
   101     if (i != map_.end())
   102       map_.erase(i);
   103   }
   105   // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
   106   // mapping if one already exists for the given channel_id
   107   void Insert(const std::string& channel_id, int fd) {
   108     AutoLock locked(lock_);
   109     DCHECK(fd != -1);
   111     ChannelToFDMap::const_iterator i = map_.find(channel_id);
   112     CHECK(i == map_.end()) << "Creating second IPC server for '"
   113                            << channel_id
   114                            << "' while first still exists";
   115     map_[channel_id] = fd;
   116   }
   118  private:
   119   Lock lock_;
   120   typedef std::map<std::string, int> ChannelToFDMap;
   121   ChannelToFDMap map_;
   122 };
   124 // This is the file descriptor number that a client process expects to find its
   125 // IPC socket.
   126 static const int kClientChannelFd = 3;
   128 // Used to map a channel name to the equivalent FD # in the client process.
   129 int ChannelNameToClientFD(const std::string& channel_id) {
   130   // See the large block comment above PipeMap for the reasoning here.
   131   const int fd = Singleton<PipeMap>()->Lookup(channel_id);
   132   if (fd != -1)
   133     return dup(fd);
   135   // If we don't find an entry, we assume that the correct value has been
   136   // inserted in the magic slot.
   137   return kClientChannelFd;
   138 }
   140 //------------------------------------------------------------------------------
   141 const size_t kMaxPipeNameLength = sizeof(((sockaddr_un*)0)->sun_path);
   143 // Creates a Fifo with the specified name ready to listen on.
   144 bool CreateServerFifo(const std::string& pipe_name, int* server_listen_fd) {
   145   DCHECK(server_listen_fd);
   146   DCHECK_GT(pipe_name.length(), 0u);
   147   DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
   149   if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
   150     return false;
   151   }
   153   // Create socket.
   154   int fd = socket(AF_UNIX, SOCK_STREAM, 0);
   155   if (fd < 0) {
   156     return false;
   157   }
   159   // Make socket non-blocking
   160   if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
   161     HANDLE_EINTR(close(fd));
   162     return false;
   163   }
   165   // Delete any old FS instances.
   166   unlink(pipe_name.c_str());
   168   // Create unix_addr structure
   169   struct sockaddr_un unix_addr;
   170   memset(&unix_addr, 0, sizeof(unix_addr));
   171   unix_addr.sun_family = AF_UNIX;
   172   snprintf(unix_addr.sun_path, kMaxPipeNameLength, "%s", pipe_name.c_str());
   173   size_t unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
   174       strlen(unix_addr.sun_path) + 1;
   176   // Bind the socket.
   177   if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
   178            unix_addr_len) != 0) {
   179     HANDLE_EINTR(close(fd));
   180     return false;
   181   }
   183   // Start listening on the socket.
   184   const int listen_queue_length = 1;
   185   if (listen(fd, listen_queue_length) != 0) {
   186     HANDLE_EINTR(close(fd));
   187     return false;
   188   }
   190   *server_listen_fd = fd;
   191   return true;
   192 }
   194 // Accept a connection on a fifo.
   195 bool ServerAcceptFifoConnection(int server_listen_fd, int* server_socket) {
   196   DCHECK(server_socket);
   198   int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
   199   if (accept_fd < 0)
   200     return false;
   201   if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
   202     HANDLE_EINTR(close(accept_fd));
   203     return false;
   204   }
   206   *server_socket = accept_fd;
   207   return true;
   208 }
   210 bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) {
   211   DCHECK(client_socket);
   212   DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
   214   // Create socket.
   215   int fd = socket(AF_UNIX, SOCK_STREAM, 0);
   216   if (fd < 0) {
   217     CHROMIUM_LOG(ERROR) << "fd is invalid";
   218     return false;
   219   }
   221   // Make socket non-blocking
   222   if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
   223     CHROMIUM_LOG(ERROR) << "fcntl failed";
   224     HANDLE_EINTR(close(fd));
   225     return false;
   226   }
   228   // Create server side of socket.
   229   struct sockaddr_un  server_unix_addr;
   230   memset(&server_unix_addr, 0, sizeof(server_unix_addr));
   231   server_unix_addr.sun_family = AF_UNIX;
   232   snprintf(server_unix_addr.sun_path, kMaxPipeNameLength, "%s",
   233            pipe_name.c_str());
   234   size_t server_unix_addr_len = offsetof(struct sockaddr_un, sun_path) +
   235       strlen(server_unix_addr.sun_path) + 1;
   237   if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
   238                            server_unix_addr_len)) != 0) {
   239     HANDLE_EINTR(close(fd));
   240     return false;
   241   }
   243   *client_socket = fd;
   244   return true;
   245 }
   247 bool SetCloseOnExec(int fd) {
   248   int flags = fcntl(fd, F_GETFD);
   249   if (flags == -1)
   250     return false;
   252   flags |= FD_CLOEXEC;
   253   if (fcntl(fd, F_SETFD, flags) == -1)
   254     return false;
   256   return true;
   257 }
   259 }  // namespace
   260 //------------------------------------------------------------------------------
   262 Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
   263                                   Listener* listener)
   264     : factory_(this) {
   265   Init(mode, listener);
   266   uses_fifo_ = CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO);
   268   if (!CreatePipe(channel_id, mode)) {
   269     // The pipe may have been closed already.
   270     CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
   271                              "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
   272                              " mode error(" << strerror(errno) << ").";
   273   }
   274 }
   276 Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
   277     : factory_(this) {
   278   Init(mode, listener);
   279   pipe_ = fd;
   280   waiting_connect_ = (MODE_SERVER == mode);
   282   EnqueueHelloMessage();
   283 }
   285 void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
   286   mode_ = mode;
   287   is_blocked_on_write_ = false;
   288   message_send_bytes_written_ = 0;
   289   uses_fifo_ = false;
   290   server_listen_pipe_ = -1;
   291   pipe_ = -1;
   292   client_pipe_ = -1;
   293   listener_ = listener;
   294   waiting_connect_ = true;
   295   processing_incoming_ = false;
   296   closed_ = false;
   297 #if defined(OS_MACOSX)
   298   last_pending_fd_id_ = 0;
   299 #endif
   300   output_queue_length_ = 0;
   301 }
   303 bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
   304                                       Mode mode) {
   305   DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
   307   if (uses_fifo_) {
   308     // This only happens in unit tests; see the comment above PipeMap.
   309     // TODO(playmobil): We shouldn't need to create fifos on disk.
   310     // TODO(playmobil): If we do, they should be in the user data directory.
   311     // TODO(playmobil): Cleanup any stale fifos.
   312     pipe_name_ = "/var/tmp/chrome_" + WideToASCII(channel_id);
   313     if (mode == MODE_SERVER) {
   314       if (!CreateServerFifo(pipe_name_, &server_listen_pipe_)) {
   315         return false;
   316       }
   317     } else {
   318       if (!ClientConnectToFifo(pipe_name_, &pipe_)) {
   319         return false;
   320       }
   321       waiting_connect_ = false;
   322     }
   323   } else {
   324     // socketpair()
   325     pipe_name_ = WideToASCII(channel_id);
   326     if (mode == MODE_SERVER) {
   327       int pipe_fds[2];
   328       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
   329         return false;
   330       }
   331       // Set both ends to be non-blocking.
   332       if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
   333           fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
   334         HANDLE_EINTR(close(pipe_fds[0]));
   335         HANDLE_EINTR(close(pipe_fds[1]));
   336         return false;
   337       }
   339       if (!SetCloseOnExec(pipe_fds[0]) ||
   340           !SetCloseOnExec(pipe_fds[1])) {
   341         HANDLE_EINTR(close(pipe_fds[0]));
   342         HANDLE_EINTR(close(pipe_fds[1]));
   343         return false;
   344       }
   346       pipe_ = pipe_fds[0];
   347       client_pipe_ = pipe_fds[1];
   349       if (pipe_name_.length()) {
   350         Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
   351       }
   352     } else {
   353       pipe_ = ChannelNameToClientFD(pipe_name_);
   354       DCHECK(pipe_ > 0);
   355       waiting_connect_ = false;
   356     }
   357   }
   359   // Create the Hello message to be sent when Connect is called
   360   return EnqueueHelloMessage();
   361 }
   363 /**
   364  * Reset the file descriptor for communication with the peer.
   365  */
   366 void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
   367   NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
   369   EnqueueHelloMessage();
   370 }
   372 bool Channel::ChannelImpl::EnqueueHelloMessage() {
   373   scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
   374                                       HELLO_MESSAGE_TYPE,
   375                                       IPC::Message::PRIORITY_NORMAL));
   376   if (!msg->WriteInt(base::GetCurrentProcId())) {
   377     Close();
   378     return false;
   379   }
   381   OutputQueuePush(msg.release());
   382   return true;
   383 }
   385 static void
   386 ClearAndShrink(std::string& s, size_t capacity)
   387 {
   388   // This swap trick is the closest thing C++ has to a guaranteed way to
   389   // shrink the capacity of a string.
   390   std::string tmp;
   391   tmp.reserve(capacity);
   392   s.swap(tmp);
   393 }
   395 bool Channel::ChannelImpl::Connect() {
   396   if (mode_ == MODE_SERVER && uses_fifo_) {
   397     if (server_listen_pipe_ == -1) {
   398       return false;
   399     }
   400     MessageLoopForIO::current()->WatchFileDescriptor(
   401         server_listen_pipe_,
   402         true,
   403         MessageLoopForIO::WATCH_READ,
   404         &server_listen_connection_watcher_,
   405         this);
   406   } else {
   407     if (pipe_ == -1) {
   408       return false;
   409     }
   410     MessageLoopForIO::current()->WatchFileDescriptor(
   411         pipe_,
   412         true,
   413         MessageLoopForIO::WATCH_READ,
   414         &read_watcher_,
   415         this);
   416     waiting_connect_ = false;
   417   }
   419   if (!waiting_connect_)
   420     return ProcessOutgoingMessages();
   421   return true;
   422 }
   424 bool Channel::ChannelImpl::ProcessIncomingMessages() {
   425   ssize_t bytes_read = 0;
   427   struct msghdr msg = {0};
   428   struct iovec iov = {input_buf_, Channel::kReadBufferSize};
   430   msg.msg_iov = &iov;
   431   msg.msg_iovlen = 1;
   432   msg.msg_control = input_cmsg_buf_;
   434   for (;;) {
   435     msg.msg_controllen = sizeof(input_cmsg_buf_);
   437     if (bytes_read == 0) {
   438       if (pipe_ == -1)
   439         return false;
   441       // Read from pipe.
   442       // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
   443       // is waiting on the pipe.
   444       bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
   446       if (bytes_read < 0) {
   447         if (errno == EAGAIN) {
   448           return true;
   449         } else {
   450           CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
   451           return false;
   452         }
   453       } else if (bytes_read == 0) {
   454         // The pipe has closed...
   455         Close();
   456         return false;
   457       }
   458     }
   459     DCHECK(bytes_read);
   461     if (client_pipe_ != -1) {
   462       Singleton<PipeMap>()->Remove(pipe_name_);
   463       HANDLE_EINTR(close(client_pipe_));
   464       client_pipe_ = -1;
   465     }
   467     // a pointer to an array of |num_wire_fds| file descriptors from the read
   468     const int* wire_fds = NULL;
   469     unsigned num_wire_fds = 0;
   471     // walk the list of control messages and, if we find an array of file
   472     // descriptors, save a pointer to the array
   474     // This next if statement is to work around an OSX issue where
   475     // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
   476     // Here's a test case:
   477     //
   478     // int main() {
   479     // struct msghdr msg;
   480     //   msg.msg_control = &msg;
   481     //   msg.msg_controllen = 0;
   482     //   if (CMSG_FIRSTHDR(&msg))
   483     //     printf("Bug found!\n");
   484     // }
   485     if (msg.msg_controllen > 0) {
   486       // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
   487       // and will return a pointer into nowhere.
   488       for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
   489            cmsg = CMSG_NXTHDR(&msg, cmsg)) {
   490         if (cmsg->cmsg_level == SOL_SOCKET &&
   491             cmsg->cmsg_type == SCM_RIGHTS) {
   492           const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
   493           DCHECK(payload_len % sizeof(int) == 0);
   494           wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
   495           num_wire_fds = payload_len / 4;
   497           if (msg.msg_flags & MSG_CTRUNC) {
   498             CHROMIUM_LOG(ERROR) << "SCM_RIGHTS message was truncated"
   499                                 << " cmsg_len:" << cmsg->cmsg_len
   500                                 << " fd:" << pipe_;
   501             for (unsigned i = 0; i < num_wire_fds; ++i)
   502               HANDLE_EINTR(close(wire_fds[i]));
   503             return false;
   504           }
   505           break;
   506         }
   507       }
   508     }
   510     // Process messages from input buffer.
   511     const char *p;
   512     const char *overflowp;
   513     const char *end;
   514     if (input_overflow_buf_.empty()) {
   515       overflowp = NULL;
   516       p = input_buf_;
   517       end = p + bytes_read;
   518     } else {
   519       if (input_overflow_buf_.size() >
   520          static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
   521         ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize);
   522         CHROMIUM_LOG(ERROR) << "IPC message is too big";
   523         return false;
   524       }
   525       input_overflow_buf_.append(input_buf_, bytes_read);
   526       overflowp = p = input_overflow_buf_.data();
   527       end = p + input_overflow_buf_.size();
   528     }
   530     // A pointer to an array of |num_fds| file descriptors which includes any
   531     // fds that have spilled over from a previous read.
   532     const int* fds;
   533     unsigned num_fds;
   534     unsigned fds_i = 0;  // the index of the first unused descriptor
   536     if (input_overflow_fds_.empty()) {
   537       fds = wire_fds;
   538       num_fds = num_wire_fds;
   539     } else {
   540       const size_t prev_size = input_overflow_fds_.size();
   541       input_overflow_fds_.resize(prev_size + num_wire_fds);
   542       memcpy(&input_overflow_fds_[prev_size], wire_fds,
   543              num_wire_fds * sizeof(int));
   544       fds = &input_overflow_fds_[0];
   545       num_fds = input_overflow_fds_.size();
   546     }
   548     while (p < end) {
   549       const char* message_tail = Message::FindNext(p, end);
   550       if (message_tail) {
   551         int len = static_cast<int>(message_tail - p);
   552         Message m(p, len);
   553         if (m.header()->num_fds) {
   554           // the message has file descriptors
   555           const char* error = NULL;
   556           if (m.header()->num_fds > num_fds - fds_i) {
   557             // the message has been completely received, but we didn't get
   558             // enough file descriptors.
   559             error = "Message needs unreceived descriptors";
   560           }
   562           if (m.header()->num_fds >
   563               FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
   564             // There are too many descriptors in this message
   565             error = "Message requires an excessive number of descriptors";
   566           }
   568           if (error) {
   569             CHROMIUM_LOG(WARNING) << error
   570                                   << " channel:" << this
   571                                   << " message-type:" << m.type()
   572                                   << " header()->num_fds:" << m.header()->num_fds
   573                                   << " num_fds:" << num_fds
   574                                   << " fds_i:" << fds_i;
   575             // close the existing file descriptors so that we don't leak them
   576             for (unsigned i = fds_i; i < num_fds; ++i)
   577               HANDLE_EINTR(close(fds[i]));
   578             input_overflow_fds_.clear();
   579             // abort the connection
   580             return false;
   581           }
   583 #if defined(OS_MACOSX)
   584           // Send a message to the other side, indicating that we are now
   585           // responsible for closing the descriptor.
   586           Message *fdAck = new Message(MSG_ROUTING_NONE,
   587                                        RECEIVED_FDS_MESSAGE_TYPE,
   588                                        IPC::Message::PRIORITY_NORMAL);
   589           DCHECK(m.fd_cookie() != 0);
   590           fdAck->set_fd_cookie(m.fd_cookie());
   591           OutputQueuePush(fdAck);
   592 #endif
   594           m.file_descriptor_set()->SetDescriptors(
   595               &fds[fds_i], m.header()->num_fds);
   596           fds_i += m.header()->num_fds;
   597         }
   598 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   599         DLOG(INFO) << "received message on channel @" << this <<
   600                       " with type " << m.type();
   601 #endif
   603 #ifdef MOZ_TASK_TRACER
   604         AutoSaveCurTraceInfo saveCurTraceInfo;
   605         SetCurTraceInfo(m.header()->source_event_id,
   606                         m.header()->parent_task_id,
   607                         m.header()->source_event_type);
   608 #endif
   610         if (m.routing_id() == MSG_ROUTING_NONE &&
   611             m.type() == HELLO_MESSAGE_TYPE) {
   612           // The Hello message contains only the process id.
   613           listener_->OnChannelConnected(MessageIterator(m).NextInt());
   614 #if defined(OS_MACOSX)
   615         } else if (m.routing_id() == MSG_ROUTING_NONE &&
   616                    m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
   617           DCHECK(m.fd_cookie() != 0);
   618           CloseDescriptors(m.fd_cookie());
   619 #endif
   620         } else {
   621           listener_->OnMessageReceived(m);
   622         }
   623         p = message_tail;
   624       } else {
   625         // Last message is partial.
   626         break;
   627       }
   628     }
   629     if (end == p) {
   630       ClearAndShrink(input_overflow_buf_, Channel::kReadBufferSize);
   631     } else if (!overflowp) {
   632       // p is from input_buf_
   633       input_overflow_buf_.assign(p, end - p);
   634     } else if (p > overflowp) {
   635       // p is from input_overflow_buf_
   636       input_overflow_buf_.erase(0, p - overflowp);
   637     }
   638     input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
   640     // When the input data buffer is empty, the overflow fds should be too. If
   641     // this is not the case, we probably have a rogue renderer which is trying
   642     // to fill our descriptor table.
   643     if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
   644       // We close these descriptors in Close()
   645       return false;
   646     }
   648     bytes_read = 0;  // Get more data.
   649   }
   651   return true;
   652 }
   654 bool Channel::ChannelImpl::ProcessOutgoingMessages() {
   655   DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
   656                               // no connection?
   657   is_blocked_on_write_ = false;
   659   if (output_queue_.empty())
   660     return true;
   662   if (pipe_ == -1)
   663     return false;
   665   // Write out all the messages we can till the write blocks or there are no
   666   // more outgoing messages.
   667   while (!output_queue_.empty()) {
   668     Message* msg = output_queue_.front();
   670     struct msghdr msgh = {0};
   672     static const int tmp = CMSG_SPACE(sizeof(
   673         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
   674     char buf[tmp];
   676     if (message_send_bytes_written_ == 0 &&
   677         !msg->file_descriptor_set()->empty()) {
   678       // This is the first chunk of a message which has descriptors to send
   679       struct cmsghdr *cmsg;
   680       const unsigned num_fds = msg->file_descriptor_set()->size();
   682       if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
   683         CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
   684         // This should not be reached.
   685         return false;
   686       }
   688       msgh.msg_control = buf;
   689       msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
   690       cmsg = CMSG_FIRSTHDR(&msgh);
   691       cmsg->cmsg_level = SOL_SOCKET;
   692       cmsg->cmsg_type = SCM_RIGHTS;
   693       cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
   694       msg->file_descriptor_set()->GetDescriptors(
   695           reinterpret_cast<int*>(CMSG_DATA(cmsg)));
   696       msgh.msg_controllen = cmsg->cmsg_len;
   698       msg->header()->num_fds = num_fds;
   699 #if defined(OS_MACOSX)
   700       msg->set_fd_cookie(++last_pending_fd_id_);
   701 #endif
   702     }
   703 #ifdef MOZ_TASK_TRACER
   704     GetCurTraceInfo(&msg->header()->source_event_id,
   705                     &msg->header()->parent_task_id,
   706                     &msg->header()->source_event_type);
   707 #endif
   709     size_t amt_to_write = msg->size() - message_send_bytes_written_;
   710     DCHECK(amt_to_write != 0);
   711     const char *out_bytes = reinterpret_cast<const char*>(msg->data()) +
   712         message_send_bytes_written_;
   714     struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
   715     msgh.msg_iov = &iov;
   716     msgh.msg_iovlen = 1;
   718     ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
   719 #if !defined(OS_MACOSX)
   720     // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
   721     // message.
   722     if (bytes_written > 0)
   723       msg->file_descriptor_set()->CommitAll();
   724 #endif
   726     if (bytes_written < 0 && errno != EAGAIN) {
   727       CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
   728       return false;
   729     }
   731     if (static_cast<size_t>(bytes_written) != amt_to_write) {
   732       if (bytes_written > 0) {
   733         // If write() fails with EAGAIN then bytes_written will be -1.
   734         message_send_bytes_written_ += bytes_written;
   735       }
   737       // Tell libevent to call us back once things are unblocked.
   738       is_blocked_on_write_ = true;
   739       MessageLoopForIO::current()->WatchFileDescriptor(
   740           pipe_,
   741           false,  // One shot
   742           MessageLoopForIO::WATCH_WRITE,
   743           &write_watcher_,
   744           this);
   745       return true;
   746     } else {
   747       message_send_bytes_written_ = 0;
   749 #if defined(OS_MACOSX)
   750       if (!msg->file_descriptor_set()->empty())
   751         pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(),
   752                                                   msg->file_descriptor_set()));
   753 #endif
   755       // Message sent OK!
   756 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   757       DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
   758                     " with type " << msg->type();
   759 #endif
   760       OutputQueuePop();
   761       delete msg;
   762     }
   763   }
   764   return true;
   765 }
   767 bool Channel::ChannelImpl::Send(Message* message) {
   768 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   769   DLOG(INFO) << "sending message @" << message << " on channel @" << this
   770              << " with type " << message->type()
   771              << " (" << output_queue_.size() << " in queue)";
   772 #endif
   774 #ifdef IPC_MESSAGE_LOG_ENABLED
   775   Logging::current()->OnSendMessage(message, L"");
   776 #endif
   778   // If the channel has been closed, ProcessOutgoingMessages() is never going
   779   // to pop anything off output_queue; output_queue will only get emptied when
   780   // the channel is destructed.  We might as well delete message now, instead
   781   // of waiting for the channel to be destructed.
   782   if (closed_) {
   783     if (mozilla::ipc::LoggingEnabled()) {
   784       fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
   785               message->name());
   786     }
   787     delete message;
   788     return false;
   789   }
   791   OutputQueuePush(message);
   792   if (!waiting_connect_) {
   793     if (!is_blocked_on_write_) {
   794       if (!ProcessOutgoingMessages())
   795         return false;
   796     }
   797   }
   799   return true;
   800 }
   802 void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
   803                                                           int *dest_fd) const {
   804   DCHECK(mode_ == MODE_SERVER);
   805   *src_fd = client_pipe_;
   806   *dest_fd = kClientChannelFd;
   807 }
   809 void Channel::ChannelImpl::CloseClientFileDescriptor() {
   810   if (client_pipe_ != -1) {
   811     Singleton<PipeMap>()->Remove(pipe_name_);
   812     HANDLE_EINTR(close(client_pipe_));
   813     client_pipe_ = -1;
   814   }
   815 }
   817 // Called by libevent when we can read from th pipe without blocking.
   818 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
   819   bool send_server_hello_msg = false;
   820   if (waiting_connect_ && mode_ == MODE_SERVER) {
   821     // In the case of a socketpair() the server starts listening on its end
   822     // of the pipe in Connect().
   823     DCHECK(uses_fifo_);
   825     if (!ServerAcceptFifoConnection(server_listen_pipe_, &pipe_)) {
   826       Close();
   827     }
   829     // No need to watch the listening socket any longer since only one client
   830     // can connect.  So unregister with libevent.
   831     server_listen_connection_watcher_.StopWatchingFileDescriptor();
   833     // Start watching our end of the socket.
   834     MessageLoopForIO::current()->WatchFileDescriptor(
   835         pipe_,
   836         true,
   837         MessageLoopForIO::WATCH_READ,
   838         &read_watcher_,
   839         this);
   841     waiting_connect_ = false;
   842     send_server_hello_msg = true;
   843   }
   845   if (!waiting_connect_ && fd == pipe_) {
   846     if (!ProcessIncomingMessages()) {
   847       Close();
   848       listener_->OnChannelError();
   849     }
   850   }
   852   // If we're a server and handshaking, then we want to make sure that we
   853   // only send our handshake message after we've processed the client's.
   854   // This gives us a chance to kill the client if the incoming handshake
   855   // is invalid.
   856   if (send_server_hello_msg) {
   857     // This should be our first write so there's no chance we can block here...
   858     DCHECK(is_blocked_on_write_ == false);
   859     ProcessOutgoingMessages();
   860   }
   861 }
   863 #if defined(OS_MACOSX)
   864 void Channel::ChannelImpl::CloseDescriptors(uint32_t pending_fd_id)
   865 {
   866   DCHECK(pending_fd_id != 0);
   867   for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
   868        i != pending_fds_.end();
   869        i++) {
   870     if ((*i).id == pending_fd_id) {
   871       (*i).fds->CommitAll();
   872       pending_fds_.erase(i);
   873       return;
   874     }
   875   }
   876   DCHECK(false) << "pending_fd_id not in our list!";
   877 }
   878 #endif
   880 void Channel::ChannelImpl::OutputQueuePush(Message* msg)
   881 {
   882   output_queue_.push(msg);
   883   output_queue_length_++;
   884 }
   886 void Channel::ChannelImpl::OutputQueuePop()
   887 {
   888   output_queue_.pop();
   889   output_queue_length_--;
   890 }
   892 // Called by libevent when we can write to the pipe without blocking.
   893 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
   894   if (!ProcessOutgoingMessages()) {
   895     Close();
   896     listener_->OnChannelError();
   897   }
   898 }
   900 void Channel::ChannelImpl::Close() {
   901   // Close can be called multiple times, so we need to make sure we're
   902   // idempotent.
   904   // Unregister libevent for the listening socket and close it.
   905   server_listen_connection_watcher_.StopWatchingFileDescriptor();
   907   if (server_listen_pipe_ != -1) {
   908     HANDLE_EINTR(close(server_listen_pipe_));
   909     server_listen_pipe_ = -1;
   910   }
   912   // Unregister libevent for the FIFO and close it.
   913   read_watcher_.StopWatchingFileDescriptor();
   914   write_watcher_.StopWatchingFileDescriptor();
   915   if (pipe_ != -1) {
   916     HANDLE_EINTR(close(pipe_));
   917     pipe_ = -1;
   918   }
   919   if (client_pipe_ != -1) {
   920     Singleton<PipeMap>()->Remove(pipe_name_);
   921     HANDLE_EINTR(close(client_pipe_));
   922     client_pipe_ = -1;
   923   }
   925   if (uses_fifo_) {
   926     // Unlink the FIFO
   927     unlink(pipe_name_.c_str());
   928   }
   930   while (!output_queue_.empty()) {
   931     Message* m = output_queue_.front();
   932     OutputQueuePop();
   933     delete m;
   934   }
   936   // Close any outstanding, received file descriptors
   937   for (std::vector<int>::iterator
   938        i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
   939     HANDLE_EINTR(close(*i));
   940   }
   941   input_overflow_fds_.clear();
   943 #if defined(OS_MACOSX)
   944   for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
   945        i != pending_fds_.end();
   946        i++) {
   947     (*i).fds->CommitAll();
   948   }
   949   pending_fds_.clear();
   950 #endif
   952   closed_ = true;
   953 }
   955 bool Channel::ChannelImpl::Unsound_IsClosed() const
   956 {
   957   return closed_;
   958 }
   960 uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const
   961 {
   962   return output_queue_length_;
   963 }
   965 //------------------------------------------------------------------------------
   966 // Channel's methods simply call through to ChannelImpl.
   967 Channel::Channel(const std::wstring& channel_id, Mode mode,
   968                  Listener* listener)
   969     : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
   970 }
   972 Channel::Channel(int fd, Mode mode, Listener* listener)
   973     : channel_impl_(new ChannelImpl(fd, mode, listener)) {
   974 }
   976 Channel::~Channel() {
   977   delete channel_impl_;
   978 }
   980 bool Channel::Connect() {
   981   return channel_impl_->Connect();
   982 }
   984 void Channel::Close() {
   985   channel_impl_->Close();
   986 }
   988 Channel::Listener* Channel::set_listener(Listener* listener) {
   989   return channel_impl_->set_listener(listener);
   990 }
   992 bool Channel::Send(Message* message) {
   993   return channel_impl_->Send(message);
   994 }
   996 void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
   997   return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
   998 }
  1000 void Channel::ResetFileDescriptor(int fd) {
  1001   channel_impl_->ResetFileDescriptor(fd);
  1004 int Channel::GetFileDescriptor() const {
  1005     return channel_impl_->GetFileDescriptor();
  1008 void Channel::CloseClientFileDescriptor() {
  1009   channel_impl_->CloseClientFileDescriptor();
  1012 bool Channel::Unsound_IsClosed() const {
  1013   return channel_impl_->Unsound_IsClosed();
  1016 uint32_t Channel::Unsound_NumQueuedMessages() const {
  1017   return channel_impl_->Unsound_NumQueuedMessages();
  1020 }  // namespace IPC

mercurial