Home | History | Annotate | Download | only in ipc
      1 // Copyright 2013 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 "ipc/ipc_channel_factory.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/logging.h"
      9 #include "ipc/unix_domain_socket_util.h"
     10 
     11 namespace IPC {
     12 
     13 ChannelFactory::ChannelFactory(const base::FilePath& path, Delegate* delegate)
     14     : path_(path), delegate_(delegate), listen_fd_(-1) {
     15   DCHECK(delegate_);
     16   CreateSocket();
     17 }
     18 
     19 ChannelFactory::~ChannelFactory() {
     20   Close();
     21 }
     22 
     23 bool ChannelFactory::CreateSocket() {
     24   DCHECK(listen_fd_ < 0);
     25 
     26   // Create the socket.
     27   return CreateServerUnixDomainSocket(path_, &listen_fd_);
     28 }
     29 
     30 bool ChannelFactory::Listen() {
     31   if (listen_fd_ < 0)
     32     return false;
     33 
     34   // Watch the fd for connections, and turn any connections into
     35   // active sockets.
     36   base::MessageLoopForIO::current()->WatchFileDescriptor(
     37       listen_fd_,
     38       true,
     39       base::MessageLoopForIO::WATCH_READ,
     40       &server_listen_connection_watcher_,
     41       this);
     42   return true;
     43 }
     44 
     45 // Called by libevent when we can read from the fd without blocking.
     46 void ChannelFactory::OnFileCanReadWithoutBlocking(int fd) {
     47   DCHECK(fd == listen_fd_);
     48   int new_fd = -1;
     49   if (!ServerAcceptConnection(listen_fd_, &new_fd)) {
     50     Close();
     51     delegate_->OnListenError();
     52     return;
     53   }
     54 
     55   if (new_fd < 0) {
     56     // The accept() failed, but not in such a way that the factory needs to be
     57     // shut down.
     58     return;
     59   }
     60 
     61   file_util::ScopedFD scoped_fd(&new_fd);
     62 
     63   // Verify that the IPC channel peer is running as the same user.
     64   if (!IsPeerAuthorized(new_fd))
     65     return;
     66 
     67   ChannelHandle handle(std::string(),
     68                        base::FileDescriptor(*scoped_fd.release(), true));
     69   delegate_->OnClientConnected(handle);
     70 }
     71 
     72 void ChannelFactory::OnFileCanWriteWithoutBlocking(int fd) {
     73   NOTREACHED() << "Listen fd should never be writable.";
     74 }
     75 
     76 void ChannelFactory::Close() {
     77   if (listen_fd_ < 0)
     78     return;
     79   if (IGNORE_EINTR(close(listen_fd_)) < 0)
     80     PLOG(ERROR) << "close";
     81   listen_fd_ = -1;
     82   if (unlink(path_.value().c_str()) < 0)
     83     PLOG(ERROR) << "unlink";
     84 
     85   // Unregister libevent for the listening socket and close it.
     86   server_listen_connection_watcher_.StopWatchingFileDescriptor();
     87 }
     88 
     89 }  // namespace IPC
     90