Minor Python style clean-up
[chromium-blink-merge.git] / tools / android / forwarder2 / host_forwarder_main.cc
blob9e4ef6ea40f6789a154550c85b7f4960646caa8c
1 // Copyright (c) 2012 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.
5 #include <errno.h>
6 #include <signal.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
11 #include <cstdio>
12 #include <iostream>
13 #include <limits>
14 #include <string>
15 #include <utility>
16 #include <vector>
18 #include "base/at_exit.h"
19 #include "base/basictypes.h"
20 #include "base/bind.h"
21 #include "base/command_line.h"
22 #include "base/compiler_specific.h"
23 #include "base/containers/hash_tables.h"
24 #include "base/files/file_path.h"
25 #include "base/files/file_util.h"
26 #include "base/logging.h"
27 #include "base/memory/linked_ptr.h"
28 #include "base/memory/weak_ptr.h"
29 #include "base/pickle.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/strings/string_piece.h"
32 #include "base/strings/string_split.h"
33 #include "base/strings/string_util.h"
34 #include "base/strings/stringprintf.h"
35 #include "base/task_runner.h"
36 #include "base/threading/thread.h"
37 #include "tools/android/forwarder2/common.h"
38 #include "tools/android/forwarder2/daemon.h"
39 #include "tools/android/forwarder2/host_controller.h"
40 #include "tools/android/forwarder2/pipe_notifier.h"
41 #include "tools/android/forwarder2/socket.h"
42 #include "tools/android/forwarder2/util.h"
44 namespace forwarder2 {
45 namespace {
47 const char kLogFilePath[] = "/tmp/host_forwarder_log";
48 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon";
50 const int kBufSize = 256;
52 // Needs to be global to be able to be accessed from the signal handler.
53 PipeNotifier* g_notifier = NULL;
55 // Lets the daemon fetch the exit notifier file descriptor.
56 int GetExitNotifierFD() {
57 DCHECK(g_notifier);
58 return g_notifier->receiver_fd();
61 void KillHandler(int signal_number) {
62 char buf[kBufSize];
63 if (signal_number != SIGTERM && signal_number != SIGINT) {
64 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
65 SIGNAL_SAFE_LOG(WARNING, buf);
66 return;
68 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number);
69 SIGNAL_SAFE_LOG(WARNING, buf);
70 static int s_kill_handler_count = 0;
71 CHECK(g_notifier);
72 // If for some reason the forwarder get stuck in any socket waiting forever,
73 // we can send a SIGKILL or SIGINT three times to force it die
74 // (non-nicely). This is useful when debugging.
75 ++s_kill_handler_count;
76 if (!g_notifier->Notify() || s_kill_handler_count > 2)
77 exit(1);
80 // Manages HostController instances. There is one HostController instance for
81 // each connection being forwarded. Note that forwarding can happen with many
82 // devices (identified with a serial id).
83 class HostControllersManager {
84 public:
85 HostControllersManager()
86 : controllers_(new HostControllerMap()),
87 has_failed_(false),
88 weak_ptr_factory_(this) {
91 ~HostControllersManager() {
92 if (!thread_.get())
93 return;
94 // Delete the controllers on the thread they were created on.
95 thread_->task_runner()->DeleteSoon(
96 FROM_HERE, controllers_.release());
99 void HandleRequest(const std::string& adb_path,
100 const std::string& device_serial,
101 int device_port,
102 int host_port,
103 scoped_ptr<Socket> client_socket) {
104 // Lazy initialize so that the CLI process doesn't get this thread created.
105 InitOnce();
106 thread_->task_runner()->PostTask(
107 FROM_HERE,
108 base::Bind(&HostControllersManager::HandleRequestOnInternalThread,
109 base::Unretained(this), adb_path, device_serial, device_port,
110 host_port, base::Passed(&client_socket)));
113 bool has_failed() const { return has_failed_; }
115 private:
116 typedef base::hash_map<
117 std::string, linked_ptr<HostController> > HostControllerMap;
119 static std::string MakeHostControllerMapKey(int adb_port, int device_port) {
120 return base::StringPrintf("%d:%d", adb_port, device_port);
123 void InitOnce() {
124 if (thread_.get())
125 return;
126 at_exit_manager_.reset(new base::AtExitManager());
127 thread_.reset(new base::Thread("HostControllersManagerThread"));
128 thread_->Start();
131 // Invoked when a HostController instance reports an error (e.g. due to a
132 // device connectivity issue). Note that this could be called after the
133 // controller manager was destroyed which is why a weak pointer is used.
134 static void DeleteHostController(
135 const base::WeakPtr<HostControllersManager>& manager_ptr,
136 scoped_ptr<HostController> host_controller) {
137 HostController* const controller = host_controller.release();
138 HostControllersManager* const manager = manager_ptr.get();
139 if (!manager) {
140 // Note that |controller| is not leaked in this case since the host
141 // controllers manager owns the controllers. If the manager was deleted
142 // then all the controllers (including |controller|) were also deleted.
143 return;
145 DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread());
146 // Note that this will delete |controller| which is owned by the map.
147 DeleteRefCountedValueInMap(
148 MakeHostControllerMapKey(
149 controller->adb_port(), controller->device_port()),
150 manager->controllers_.get());
153 void HandleRequestOnInternalThread(const std::string& adb_path,
154 const std::string& device_serial,
155 int device_port,
156 int host_port,
157 scoped_ptr<Socket> client_socket) {
158 const int adb_port = GetAdbPortForDevice(adb_path, device_serial);
159 if (adb_port < 0) {
160 SendMessage(
161 "ERROR: could not get adb port for device. You might need to add "
162 "'adb' to your PATH or provide the device serial id.",
163 client_socket.get());
164 return;
166 if (device_port < 0) {
167 // Remove the previously created host controller.
168 const std::string controller_key = MakeHostControllerMapKey(
169 adb_port, -device_port);
170 const bool controller_did_exist = DeleteRefCountedValueInMap(
171 controller_key, controllers_.get());
172 if (!controller_did_exist) {
173 SendMessage("ERROR: could not unmap port.", client_socket.get());
174 LogExistingControllers(client_socket);
175 } else {
176 SendMessage("OK", client_socket.get());
179 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
180 return;
182 if (host_port < 0) {
183 SendMessage("ERROR: missing host port", client_socket.get());
184 return;
186 const bool use_dynamic_port_allocation = device_port == 0;
187 if (!use_dynamic_port_allocation) {
188 const std::string controller_key = MakeHostControllerMapKey(
189 adb_port, device_port);
190 if (controllers_->find(controller_key) != controllers_->end()) {
191 LOG(INFO) << "Already forwarding device port " << device_port
192 << " to host port " << host_port;
193 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
194 client_socket.get());
195 return;
198 // Create a new host controller.
199 scoped_ptr<HostController> host_controller(
200 HostController::Create(
201 device_port, host_port, adb_port, GetExitNotifierFD(),
202 base::Bind(&HostControllersManager::DeleteHostController,
203 weak_ptr_factory_.GetWeakPtr())));
204 if (!host_controller.get()) {
205 has_failed_ = true;
206 SendMessage("ERROR: Connection to device failed.", client_socket.get());
207 LogExistingControllers(client_socket);
208 return;
210 // Get the current allocated port.
211 device_port = host_controller->device_port();
212 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
213 << host_port;
214 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
215 if (!SendMessage(msg, client_socket.get()))
216 return;
217 host_controller->Start();
218 controllers_->insert(
219 std::make_pair(MakeHostControllerMapKey(adb_port, device_port),
220 linked_ptr<HostController>(host_controller.release())));
223 void LogExistingControllers(const scoped_ptr<Socket>& client_socket) {
224 SendMessage("ERROR: Existing controllers:", client_socket.get());
225 for (const auto& controller : *controllers_) {
226 SendMessage(base::StringPrintf("ERROR: %s", controller.first.c_str()),
227 client_socket.get());
231 void RemoveAdbPortForDeviceIfNeeded(const std::string& adb_path,
232 const std::string& device_serial) {
233 base::hash_map<std::string, int>::const_iterator it =
234 device_serial_to_adb_port_map_.find(device_serial);
235 if (it == device_serial_to_adb_port_map_.end())
236 return;
238 int port = it->second;
239 const std::string prefix = base::StringPrintf("%d:", port);
240 for (HostControllerMap::const_iterator others = controllers_->begin();
241 others != controllers_->end(); ++others) {
242 if (others->first.find(prefix) == 0U)
243 return;
245 // No other port is being forwarded to this device:
246 // - Remove it from our internal serial -> adb port map.
247 // - Remove from "adb forward" command.
248 LOG(INFO) << "Device " << device_serial << " has no more ports.";
249 device_serial_to_adb_port_map_.erase(device_serial);
250 const std::string serial_part = device_serial.empty() ?
251 std::string() : std::string("-s ") + device_serial;
252 const std::string command = base::StringPrintf(
253 "%s %s forward --remove tcp:%d",
254 adb_path.c_str(),
255 serial_part.c_str(),
256 port);
257 const int ret = system(command.c_str());
258 LOG(INFO) << command << " ret: " << ret;
259 // Wait for the socket to be fully unmapped.
260 const std::string port_mapped_cmd = base::StringPrintf(
261 "lsof -nPi:%d",
262 port);
263 const int poll_interval_us = 500 * 1000;
264 int retries = 3;
265 while (retries) {
266 const int port_unmapped = system(port_mapped_cmd.c_str());
267 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap "
268 << port_unmapped;
269 if (port_unmapped)
270 break;
271 --retries;
272 usleep(poll_interval_us);
276 int GetAdbPortForDevice(const std::string adb_path,
277 const std::string& device_serial) {
278 base::hash_map<std::string, int>::const_iterator it =
279 device_serial_to_adb_port_map_.find(device_serial);
280 if (it != device_serial_to_adb_port_map_.end())
281 return it->second;
282 Socket bind_socket;
283 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
284 const int port = bind_socket.GetPort();
285 bind_socket.Close();
286 const std::string serial_part = device_serial.empty() ?
287 std::string() : std::string("-s ") + device_serial;
288 const std::string command = base::StringPrintf(
289 "%s %s forward tcp:%d localabstract:chrome_device_forwarder",
290 adb_path.c_str(),
291 serial_part.c_str(),
292 port);
293 LOG(INFO) << command;
294 const int ret = system(command.c_str());
295 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
296 return -1;
297 device_serial_to_adb_port_map_[device_serial] = port;
298 return port;
301 bool SendMessage(const std::string& msg, Socket* client_socket) {
302 bool result = client_socket->WriteString(msg);
303 DCHECK(result);
304 if (!result)
305 has_failed_ = true;
306 return result;
309 base::hash_map<std::string, int> device_serial_to_adb_port_map_;
310 scoped_ptr<HostControllerMap> controllers_;
311 bool has_failed_;
312 scoped_ptr<base::AtExitManager> at_exit_manager_; // Needed by base::Thread.
313 scoped_ptr<base::Thread> thread_;
314 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_;
317 class ServerDelegate : public Daemon::ServerDelegate {
318 public:
319 ServerDelegate(const std::string& adb_path)
320 : adb_path_(adb_path), has_failed_(false) {}
322 bool has_failed() const {
323 return has_failed_ || controllers_manager_.has_failed();
326 // Daemon::ServerDelegate:
327 void Init() override {
328 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
329 DCHECK(!g_notifier);
330 g_notifier = new PipeNotifier();
331 signal(SIGTERM, KillHandler);
332 signal(SIGINT, KillHandler);
335 void OnClientConnected(scoped_ptr<Socket> client_socket) override {
336 char buf[kBufSize];
337 const int bytes_read = client_socket->Read(buf, sizeof(buf));
338 if (bytes_read <= 0) {
339 if (client_socket->DidReceiveEvent())
340 return;
341 PError("Read()");
342 has_failed_ = true;
343 return;
345 const base::Pickle command_pickle(buf, bytes_read);
346 base::PickleIterator pickle_it(command_pickle);
347 std::string device_serial;
348 CHECK(pickle_it.ReadString(&device_serial));
349 int device_port;
350 if (!pickle_it.ReadInt(&device_port)) {
351 client_socket->WriteString("ERROR: missing device port");
352 return;
354 int host_port;
355 if (!pickle_it.ReadInt(&host_port))
356 host_port = -1;
357 controllers_manager_.HandleRequest(adb_path_, device_serial, device_port,
358 host_port, client_socket.Pass());
361 private:
362 std::string adb_path_;
363 bool has_failed_;
364 HostControllersManager controllers_manager_;
366 DISALLOW_COPY_AND_ASSIGN(ServerDelegate);
369 class ClientDelegate : public Daemon::ClientDelegate {
370 public:
371 ClientDelegate(const base::Pickle& command_pickle)
372 : command_pickle_(command_pickle), has_failed_(false) {}
374 bool has_failed() const { return has_failed_; }
376 // Daemon::ClientDelegate:
377 void OnDaemonReady(Socket* daemon_socket) override {
378 // Send the forward command to the daemon.
379 CHECK_EQ(static_cast<long>(command_pickle_.size()),
380 daemon_socket->WriteNumBytes(command_pickle_.data(),
381 command_pickle_.size()));
382 char buf[kBufSize];
383 const int bytes_read = daemon_socket->Read(
384 buf, sizeof(buf) - 1 /* leave space for null terminator */);
385 CHECK_GT(bytes_read, 0);
386 DCHECK(static_cast<size_t>(bytes_read) < sizeof(buf));
387 buf[bytes_read] = 0;
388 base::StringPiece msg(buf, bytes_read);
389 if (msg.starts_with("ERROR")) {
390 LOG(ERROR) << msg;
391 has_failed_ = true;
392 return;
394 printf("%s\n", buf);
397 private:
398 const base::Pickle command_pickle_;
399 bool has_failed_;
402 void ExitWithUsage() {
403 std::cerr << "Usage: host_forwarder [options]\n\n"
404 "Options:\n"
405 " --serial-id=[0-9A-Z]{16}]\n"
406 " --map DEVICE_PORT HOST_PORT\n"
407 " --unmap DEVICE_PORT\n"
408 " --adb PATH_TO_ADB\n"
409 " --kill-server\n";
410 exit(1);
413 int PortToInt(const std::string& s) {
414 int value;
415 // Note that 0 is a valid port (used for dynamic port allocation).
416 if (!base::StringToInt(s, &value) || value < 0 ||
417 value > std::numeric_limits<uint16>::max()) {
418 LOG(ERROR) << "Could not convert string " << s << " to port";
419 ExitWithUsage();
421 return value;
424 int RunHostForwarder(int argc, char** argv) {
425 base::CommandLine::Init(argc, argv);
426 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
427 std::string adb_path = "adb";
428 bool kill_server = false;
430 base::Pickle pickle;
431 pickle.WriteString(
432 cmd_line.HasSwitch("serial-id") ?
433 cmd_line.GetSwitchValueASCII("serial-id") : std::string());
435 const std::vector<std::string> args = cmd_line.GetArgs();
436 if (cmd_line.HasSwitch("kill-server")) {
437 kill_server = true;
438 } else if (cmd_line.HasSwitch("unmap")) {
439 if (args.size() != 1)
440 ExitWithUsage();
441 // Note the minus sign below.
442 pickle.WriteInt(-PortToInt(args[0]));
443 } else if (cmd_line.HasSwitch("map")) {
444 if (args.size() != 2)
445 ExitWithUsage();
446 pickle.WriteInt(PortToInt(args[0]));
447 pickle.WriteInt(PortToInt(args[1]));
448 } else {
449 ExitWithUsage();
452 if (cmd_line.HasSwitch("adb")) {
453 adb_path = cmd_line.GetSwitchValueASCII("adb");
456 if (kill_server && args.size() > 0)
457 ExitWithUsage();
459 ClientDelegate client_delegate(pickle);
460 ServerDelegate daemon_delegate(adb_path);
461 Daemon daemon(
462 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate,
463 &GetExitNotifierFD);
465 if (kill_server)
466 return !daemon.Kill();
467 if (!daemon.SpawnIfNeeded())
468 return 1;
470 return client_delegate.has_failed() || daemon_delegate.has_failed();
473 } // namespace
474 } // namespace forwarder2
476 int main(int argc, char** argv) {
477 return forwarder2::RunHostForwarder(argc, argv);