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
17e415c050edbb2710e8807dd2602c851412953268Scott James Remnant#include "service/ipc/ipc_handler_linux.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
24c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge#include "osi/include/socket_utils/sockets.h"
25fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/daemon.h"
26e415c050edbb2710e8807dd2602c851412953268Scott James Remnant#include "service/ipc/linux_ipc_host.h"
27fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray#include "service/settings.h"
28fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
29fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguraynamespace ipc {
30fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
31e415c050edbb2710e8807dd2602c851412953268Scott James RemnantIPCHandlerLinux::IPCHandlerLinux(bluetooth::Adapter* adapter,
32911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson                                 IPCManager::Delegate* delegate)
33d6a4b0c950f44d3eab34825880d26c19e362d22bArman Uguray    : IPCHandler(adapter, delegate),
34fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray      running_(false),
35e415c050edbb2710e8807dd2602c851412953268Scott James Remnant      thread_("IPCHandlerLinux"),
36911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      keep_running_(true) {}
37fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
38e415c050edbb2710e8807dd2602c851412953268Scott James RemnantIPCHandlerLinux::~IPCHandlerLinux() {
39e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // This will only be set if the Settings::create_ipc_socket_path() was
40e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // originally provided.
41911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!socket_path_.empty()) unlink(socket_path_.value().c_str());
42fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray}
43fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
44e415c050edbb2710e8807dd2602c851412953268Scott James Remnantbool IPCHandlerLinux::Run() {
45fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  CHECK(!running_);
46fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
47c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  const std::string& android_suffix =
48f8881fee3d08cb50896b22adc0841223694d51d2Arman Uguray      bluetooth::Daemon::Get()->GetSettings()->android_ipc_socket_suffix();
49fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  const base::FilePath& path =
50f8881fee3d08cb50896b22adc0841223694d51d2Arman Uguray      bluetooth::Daemon::Get()->GetSettings()->create_ipc_socket_path();
51c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge
52c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  // Both flags cannot be set at the same time.
53c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  CHECK(android_suffix.empty() || path.empty());
54c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  if (android_suffix.empty() && path.empty()) {
55fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    LOG(ERROR) << "No domain socket path provided";
56fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    return false;
57fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  }
58fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
59fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  CHECK(base::MessageLoop::current());  // An origin event loop is required.
60fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  origin_task_runner_ = base::MessageLoop::current()->task_runner();
61fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
62c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  if (!android_suffix.empty()) {
63c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    int server_fd = osi_android_get_control_socket(android_suffix.c_str());
64c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    if (server_fd == -1) {
65c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      LOG(ERROR) << "Unable to get Android socket from: " << android_suffix;
66c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      return false;
67c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    }
68c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    LOG(INFO) << "Binding to Android server socket:" << android_suffix;
69c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    socket_.reset(server_fd);
70c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  } else {
71c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    LOG(INFO) << "Creating a Unix domain socket:" << path.value();
72c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge
73c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    // TODO(armansito): This is opens the door to potentially unlinking files in
74c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    // the current directory that we're not supposed to. For now we will have an
75c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    // assumption that the daemon runs in a sandbox but we should generally do
76c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    // this properly.
77c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    unlink(path.value().c_str());
78c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge
79c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
80c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    if (!server_socket.is_valid()) {
81c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      LOG(ERROR) << "Failed to open domain socket for IPC";
82c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      return false;
83c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    }
84c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge
85c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    struct sockaddr_un address;
86c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    memset(&address, 0, sizeof(address));
87c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    address.sun_family = AF_UNIX;
88c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    strncpy(address.sun_path, path.value().c_str(),
89c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge            sizeof(address.sun_path) - 1);
90c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    if (bind(server_socket.get(), (struct sockaddr*)&address, sizeof(address)) <
91c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge        0) {
92c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
93c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge      return false;
94c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    }
95c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge
96c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge    socket_.swap(server_socket);
97e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray    socket_path_ = path;
98fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  }
99fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
100c6760d82357f46943406c579f5b1c291a20afdebIan Coolidge  CHECK(socket_.is_valid());
101fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
102fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  running_ = true;  // Set this here before launching the thread.
103fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
104fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  // Start an IO thread and post the listening task.
105fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
106fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  if (!thread_.StartWithOptions(options)) {
107e415c050edbb2710e8807dd2602c851412953268Scott James Remnant    LOG(ERROR) << "Failed to start IPCHandlerLinux thread";
108fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    running_ = false;
109fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    return false;
110fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  }
111fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
112fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  thread_.task_runner()->PostTask(
113911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson      FROM_HERE, base::Bind(&IPCHandlerLinux::StartListeningOnThread, this));
114fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
115fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  return true;
116fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray}
117fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
118e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::Stop() {
119e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  keep_running_ = false;
120e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
121e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // At this moment the listening thread might be blocking on the accept
122e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // syscall. Shutdown and close the server socket before joining the thread to
123e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // interrupt accept so that the main thread doesn't keep blocking.
124e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  shutdown(socket_.get(), SHUT_RDWR);
125e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  socket_.reset();
126e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
127e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // Join and clean up the thread.
128e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  thread_.Stop();
129e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
130e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // Thread exited. Notify the delegate. Post this on the event loop so that the
131e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // callback isn't reentrant.
132e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  NotifyStoppedOnOriginThread();
133e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray}
134e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
135e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::StartListeningOnThread() {
136fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  CHECK(socket_.is_valid());
137d6a4b0c950f44d3eab34825880d26c19e362d22bArman Uguray  CHECK(adapter());
138fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  CHECK(running_);
139fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
140fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  LOG(INFO) << "Listening to incoming connections";
141fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
142fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  int status = listen(socket_.get(), SOMAXCONN);
143fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  if (status < 0) {
144fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno);
145fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    origin_task_runner_->PostTask(
146911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson        FROM_HERE, base::Bind(&IPCHandlerLinux::ShutDownOnOriginThread, this));
147fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    return;
148fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  }
149fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
150e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  NotifyStartedOnOriginThread();
151e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
152e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // TODO(armansito): The code below can cause the daemon to run indefinitely if
153e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // the thread is joined while it's in the middle of the EventLoop() call. The
154e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // EventLoop() won't exit until a client terminates the connection, however
155e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // this can be fixed by using the |thread_|'s MessageLoopForIO instead (since
156e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  // it gets stopped along with the thread).
157fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  // TODO(icoolidge): accept simultaneous clients
158e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  while (keep_running_.load()) {
159fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    int client_socket = accept4(socket_.get(), nullptr, nullptr, SOCK_NONBLOCK);
160e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray    if (client_socket < 0) {
161fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray      LOG(ERROR) << "Failed to accept client connection: " << strerror(errno);
162fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray      continue;
163fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    }
164fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
165fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    LOG(INFO) << "Established client connection: fd=" << client_socket;
166d6a4b0c950f44d3eab34825880d26c19e362d22bArman Uguray
167e415c050edbb2710e8807dd2602c851412953268Scott James Remnant    LinuxIPCHost ipc_host(client_socket, adapter());
168d6a4b0c950f44d3eab34825880d26c19e362d22bArman Uguray
169fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    // TODO(armansito): Use |thread_|'s MessageLoopForIO instead of using a
170fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    // custom event loop to poll from the socket.
171fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray    ipc_host.EventLoop();
172fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  }
173fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray}
174fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
175e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::ShutDownOnOriginThread() {
176e415c050edbb2710e8807dd2602c851412953268Scott James Remnant  LOG(INFO) << "Shutting down IPCHandlerLinux thread";
177fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  thread_.Stop();
178fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray  running_ = false;
179fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
180e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  NotifyStoppedOnCurrentThread();
181e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray}
182e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
183e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::NotifyStartedOnOriginThread() {
184911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!delegate()) return;
185e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
186e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  origin_task_runner_->PostTask(
187e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray      FROM_HERE,
188e415c050edbb2710e8807dd2602c851412953268Scott James Remnant      base::Bind(&IPCHandlerLinux::NotifyStartedOnCurrentThread, this));
189e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray}
190e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
191e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::NotifyStartedOnCurrentThread() {
192911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (delegate()) delegate()->OnIPCHandlerStarted(IPCManager::TYPE_LINUX);
193e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray}
194e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
195e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::NotifyStoppedOnOriginThread() {
196911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (!delegate()) return;
197e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
198e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray  origin_task_runner_->PostTask(
199e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray      FROM_HERE,
200e415c050edbb2710e8807dd2602c851412953268Scott James Remnant      base::Bind(&IPCHandlerLinux::NotifyStoppedOnCurrentThread, this));
201e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray}
202e0d08c9fecdf92c386b52375501a306c8f67d63eArman Uguray
203e415c050edbb2710e8807dd2602c851412953268Scott James Remnantvoid IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
204911d1ae03efec2d54c3b1b605589d790d1745488Myles Watson  if (delegate()) delegate()->OnIPCHandlerStopped(IPCManager::TYPE_LINUX);
205fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray}
206fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray
207fe65fb7978bc9257a36d1e5eae59c5f412dbdb49Arman Uguray}  // namespace ipc
208