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