ipc_handler_linux.cc revision fe65fb7978bc9257a36d1e5eae59c5f412dbdb49
1fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// 2fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// Copyright (C) 2015 Google, Inc. 3fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// 4fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// Licensed under the Apache License, Version 2.0 (the "License"); 5fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// you may not use this file except in compliance with the License. 6fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// You may obtain a copy of the License at: 7fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// 8fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// http://www.apache.org/licenses/LICENSE-2.0 9fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// 10fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// Unless required by applicable law or agreed to in writing, software 11fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// distributed under the License is distributed on an "AS IS" BASIS, 12fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// See the License for the specific language governing permissions and 14fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// limitations under the License. 15fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray// 16fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 17fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/ipc/ipc_handler_unix.h" 18fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 19fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include <sys/socket.h> 20fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include <sys/un.h> 21fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 22fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include <base/bind.h> 23fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 24fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/daemon.h" 25fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/ipc/unix_ipc_host.h" 26fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/settings.h" 27fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 28fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguraynamespace ipc { 29fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 30fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman UgurayIPCHandlerUnix::IPCHandlerUnix(bluetooth::CoreStack* core_stack) 31fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray : IPCHandler(core_stack), 32fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray running_(false), 33fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray thread_("IPCHandlerUnix") { 34fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} 35fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 36fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman UgurayIPCHandlerUnix::~IPCHandlerUnix() { 37fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} 38fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 39fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguraybool IPCHandlerUnix::Run() { 40fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray CHECK(!running_); 41fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 42fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray const base::FilePath& path = 43fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray bluetooth::Daemon::Get()->settings()->ipc_socket_path(); 44fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (path.empty()) { 45fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "No domain socket path provided"; 46fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return false; 47fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 48fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 49fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray CHECK(base::MessageLoop::current()); // An origin event loop is required. 50fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray origin_task_runner_ = base::MessageLoop::current()->task_runner(); 51fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 52fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // TODO(armansito): This is opens the door to potentially unlinking files in 53fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // the current directory that we're not supposed to. For now we will have an 54fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // assumption that the daemon runs in a sandbox but we should generally do 55fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // this properly. 56fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // 57fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // Also, the daemon should clean this up properly as it shuts down. 58fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray unlink(path.value().c_str()); 59fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 60fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0)); 61fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (!server_socket.is_valid()) { 62fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "Failed to open domain socket for IPC"; 63fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return false; 64fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 65fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 66fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray struct sockaddr_un address; 67fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray memset(&address, 0, sizeof(address)); 68fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray address.sun_family = AF_UNIX; 69fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray strncpy(address.sun_path, path.value().c_str(), sizeof(address.sun_path) - 1); 70fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (bind(server_socket.get(), (struct sockaddr*)&address, 71fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray sizeof(address)) < 0) { 72fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno); 73fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return false; 74fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 75fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 76fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray socket_.swap(server_socket); 77fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray running_ = true; // Set this here before launching the thread. 78fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 79fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // Start an IO thread and post the listening task. 80fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); 81fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (!thread_.StartWithOptions(options)) { 82fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "Failed to start IPCHandlerUnix thread"; 83fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray running_ = false; 84fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return false; 85fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 86fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 87fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray thread_.task_runner()->PostTask( 88fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray FROM_HERE, 89fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray base::Bind(&IPCHandlerUnix::StartListeningOnThread, this)); 90fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 91fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return true; 92fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} 93fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 94fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Ugurayvoid IPCHandlerUnix::StartListeningOnThread() { 95fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray CHECK(socket_.is_valid()); 96fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray CHECK(core_stack_); 97fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray CHECK(running_); 98fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 99fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(INFO) << "Listening to incoming connections"; 100fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 101fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray int status = listen(socket_.get(), SOMAXCONN); 102fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (status < 0) { 103fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno); 104fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray origin_task_runner_->PostTask( 105fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray FROM_HERE, 106fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray base::Bind(&IPCHandlerUnix::ShutDownOnOriginThread, this)); 107fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray return; 108fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 109fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 110fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // TODO(icoolidge): accept simultaneous clients 111fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray while (true) { 112fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray int client_socket = accept4(socket_.get(), nullptr, nullptr, SOCK_NONBLOCK); 113fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray if (status == -1) { 114fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(ERROR) << "Failed to accept client connection: " << strerror(errno); 115fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray continue; 116fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 117fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 118fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(INFO) << "Established client connection: fd=" << client_socket; 119fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray UnixIPCHost ipc_host(client_socket, core_stack_); 120fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // TODO(armansito): Use |thread_|'s MessageLoopForIO instead of using a 121fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // custom event loop to poll from the socket. 122fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray ipc_host.EventLoop(); 123fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray } 124fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} 125fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 126fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Ugurayvoid IPCHandlerUnix::ShutDownOnOriginThread() { 127fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray LOG(INFO) << "Shutting down IPCHandlerUnix thread"; 128fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray thread_.Stop(); 129fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray running_ = false; 130fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 131fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // TODO(armansito): Notify the upper layer so that they can perform clean-up 132fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray // tasks on unexpected shut-down. 133fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} 134fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray 135fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray} // namespace ipc 136