12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_channel_factory.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/unix_domain_socket_util.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace IPC {
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChannelFactory::ChannelFactory(const base::FilePath& path, Delegate* delegate)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : path_(path), delegate_(delegate), listen_fd_(-1) {
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(delegate_);
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CreateSocket();
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChannelFactory::~ChannelFactory() {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Close();
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ChannelFactory::CreateSocket() {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(listen_fd_ < 0);
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the socket.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return CreateServerUnixDomainSocket(path_, &listen_fd_);
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ChannelFactory::Listen() {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (listen_fd_ < 0)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Watch the fd for connections, and turn any connections into
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // active sockets.
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoopForIO::current()->WatchFileDescriptor(
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      listen_fd_,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      true,
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::MessageLoopForIO::WATCH_READ,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &server_listen_connection_watcher_,
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called by libevent when we can read from the fd without blocking.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChannelFactory::OnFileCanReadWithoutBlocking(int fd) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(fd == listen_fd_);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int new_fd = -1;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!ServerAcceptConnection(listen_fd_, &new_fd)) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Close();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->OnListenError();
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_fd < 0) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The accept() failed, but not in such a way that the factory needs to be
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // shut down.
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  file_util::ScopedFD scoped_fd(&new_fd);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verify that the IPC channel peer is running as the same user.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsPeerAuthorized(new_fd))
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ChannelHandle handle(std::string(),
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::FileDescriptor(*scoped_fd.release(), true));
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->OnClientConnected(handle);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChannelFactory::OnFileCanWriteWithoutBlocking(int fd) {
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED() << "Listen fd should never be writable.";
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChannelFactory::Close() {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (listen_fd_ < 0)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IGNORE_EINTR(close(listen_fd_)) < 0)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PLOG(ERROR) << "close";
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listen_fd_ = -1;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (unlink(path_.value().c_str()) < 0)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PLOG(ERROR) << "unlink";
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Unregister libevent for the listening socket and close it.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  server_listen_connection_watcher_.StopWatchingFileDescriptor();
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace IPC
90