Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: tools/android/forwarder2/host_forwarder_main.cc

Issue 2736053003: [Android] Fix port leak in the forwarder. (Closed)
Patch Set: tedchoc comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/android/forwarder2/host_controllers_manager_unittest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <errno.h>
6 #include <signal.h> 5 #include <signal.h>
7 #include <stddef.h> 6 #include <stddef.h>
8 #include <stdint.h> 7 #include <stdint.h>
9 #include <sys/types.h> 8 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 9
13 #include <cstdio> 10 #include <cstdio>
14 #include <iostream> 11 #include <iostream>
15 #include <limits> 12 #include <limits>
13 #include <memory>
16 #include <string> 14 #include <string>
17 #include <utility> 15 #include <utility>
18 #include <vector> 16 #include <vector>
19 17
20 #include "base/at_exit.h"
21 #include "base/bind.h" 18 #include "base/bind.h"
22 #include "base/command_line.h" 19 #include "base/command_line.h"
23 #include "base/compiler_specific.h"
24 #include "base/containers/hash_tables.h"
25 #include "base/files/file_path.h"
26 #include "base/files/file_util.h"
27 #include "base/logging.h" 20 #include "base/logging.h"
28 #include "base/macros.h" 21 #include "base/macros.h"
29 #include "base/memory/linked_ptr.h"
30 #include "base/memory/weak_ptr.h"
31 #include "base/pickle.h" 22 #include "base/pickle.h"
32 #include "base/process/launch.h"
33 #include "base/strings/string_number_conversions.h" 23 #include "base/strings/string_number_conversions.h"
34 #include "base/strings/string_piece.h" 24 #include "base/strings/string_piece.h"
35 #include "base/strings/string_split.h"
36 #include "base/strings/string_util.h"
37 #include "base/strings/stringprintf.h"
38 #include "base/task_runner.h"
39 #include "base/threading/thread.h"
40 #include "tools/android/forwarder2/common.h" 25 #include "tools/android/forwarder2/common.h"
41 #include "tools/android/forwarder2/daemon.h" 26 #include "tools/android/forwarder2/daemon.h"
42 #include "tools/android/forwarder2/host_controller.h" 27 #include "tools/android/forwarder2/host_controllers_manager.h"
43 #include "tools/android/forwarder2/pipe_notifier.h" 28 #include "tools/android/forwarder2/pipe_notifier.h"
44 #include "tools/android/forwarder2/socket.h"
45 #include "tools/android/forwarder2/util.h"
46 29
47 namespace forwarder2 { 30 namespace forwarder2 {
31
32 // Needs to be global to be able to be accessed from the signal handler.
33 PipeNotifier* g_notifier = NULL;
34
48 namespace { 35 namespace {
49 36
50 const char kLogFilePath[] = "/tmp/host_forwarder_log"; 37 const char kLogFilePath[] = "/tmp/host_forwarder_log";
51 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon"; 38 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon";
52 39
53 const int kBufSize = 256; 40 const int kBufSize = 256;
54 41
55 enum : int {
56 MAP = 0,
57 UNMAP = 1,
58 UNMAP_ALL = 2,
59 };
60
61 // Needs to be global to be able to be accessed from the signal handler.
62 PipeNotifier* g_notifier = NULL;
63
64 // Lets the daemon fetch the exit notifier file descriptor. 42 // Lets the daemon fetch the exit notifier file descriptor.
65 int GetExitNotifierFD() { 43 int GetExitNotifierFD() {
66 DCHECK(g_notifier); 44 DCHECK(g_notifier);
67 return g_notifier->receiver_fd(); 45 return g_notifier->receiver_fd();
68 } 46 }
69 47
70 void KillHandler(int signal_number) { 48 void KillHandler(int signal_number) {
71 char buf[kBufSize]; 49 char buf[kBufSize];
72 if (signal_number != SIGTERM && signal_number != SIGINT) { 50 if (signal_number != SIGTERM && signal_number != SIGINT) {
73 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number); 51 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
74 SIGNAL_SAFE_LOG(WARNING, buf); 52 SIGNAL_SAFE_LOG(WARNING, buf);
75 return; 53 return;
76 } 54 }
77 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number); 55 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number);
78 SIGNAL_SAFE_LOG(WARNING, buf); 56 SIGNAL_SAFE_LOG(WARNING, buf);
79 static int s_kill_handler_count = 0; 57 static int s_kill_handler_count = 0;
80 CHECK(g_notifier); 58 CHECK(g_notifier);
81 // If for some reason the forwarder get stuck in any socket waiting forever, 59 // If for some reason the forwarder get stuck in any socket waiting forever,
82 // we can send a SIGKILL or SIGINT three times to force it die 60 // we can send a SIGKILL or SIGINT three times to force it die
83 // (non-nicely). This is useful when debugging. 61 // (non-nicely). This is useful when debugging.
84 ++s_kill_handler_count; 62 ++s_kill_handler_count;
85 if (!g_notifier->Notify() || s_kill_handler_count > 2) 63 if (!g_notifier->Notify() || s_kill_handler_count > 2)
86 exit(1); 64 exit(1);
87 } 65 }
88 66
89 // Manages HostController instances. There is one HostController instance for
90 // each connection being forwarded. Note that forwarding can happen with many
91 // devices (identified with a serial id).
92 class HostControllersManager {
93 public:
94 HostControllersManager()
95 : controllers_(new HostControllerMap()),
96 has_failed_(false),
97 weak_ptr_factory_(this) {
98 }
99
100 ~HostControllersManager() {
101 if (!thread_.get())
102 return;
103 // Delete the controllers on the thread they were created on.
104 thread_->task_runner()->DeleteSoon(
105 FROM_HERE, controllers_.release());
106 }
107
108 void HandleRequest(const std::string& adb_path,
109 const std::string& device_serial,
110 int command,
111 int device_port,
112 int host_port,
113 std::unique_ptr<Socket> client_socket) {
114 // Lazy initialize so that the CLI process doesn't get this thread created.
115 InitOnce();
116 thread_->task_runner()->PostTask(
117 FROM_HERE,
118 base::Bind(&HostControllersManager::HandleRequestOnInternalThread,
119 base::Unretained(this), adb_path, device_serial, command,
120 device_port, host_port, base::Passed(&client_socket)));
121 }
122
123 bool has_failed() const { return has_failed_; }
124
125 private:
126 typedef base::hash_map<
127 std::string, linked_ptr<HostController> > HostControllerMap;
128
129 static std::string MakeHostControllerMapKey(int adb_port, int device_port) {
130 return base::StringPrintf("%d:%d", adb_port, device_port);
131 }
132
133 void InitOnce() {
134 if (thread_.get())
135 return;
136 at_exit_manager_.reset(new base::AtExitManager());
137 thread_.reset(new base::Thread("HostControllersManagerThread"));
138 thread_->Start();
139 }
140
141 // Invoked when a HostController instance reports an error (e.g. due to a
142 // device connectivity issue). Note that this could be called after the
143 // controller manager was destroyed which is why a weak pointer is used.
144 static void DeleteHostController(
145 const base::WeakPtr<HostControllersManager>& manager_ptr,
146 std::unique_ptr<HostController> host_controller) {
147 HostController* const controller = host_controller.release();
148 HostControllersManager* const manager = manager_ptr.get();
149 if (!manager) {
150 // Note that |controller| is not leaked in this case since the host
151 // controllers manager owns the controllers. If the manager was deleted
152 // then all the controllers (including |controller|) were also deleted.
153 return;
154 }
155 DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread());
156 // Note that this will delete |controller| which is owned by the map.
157 DeleteRefCountedValueInMap(
158 MakeHostControllerMapKey(
159 controller->adb_port(), controller->device_port()),
160 manager->controllers_.get());
161 }
162
163 void Map(const std::string& adb_path,
164 const std::string& device_serial,
165 int adb_port,
166 int device_port,
167 int host_port,
168 Socket* client_socket) {
169 if (host_port < 0) {
170 SendMessage("ERROR: missing host port\n", client_socket);
171 return;
172 }
173 const bool use_dynamic_port_allocation = device_port == 0;
174 if (!use_dynamic_port_allocation) {
175 const std::string controller_key = MakeHostControllerMapKey(
176 adb_port, device_port);
177 if (controllers_->find(controller_key) != controllers_->end()) {
178 LOG(INFO) << "Already forwarding device port " << device_port
179 << " to host port " << host_port;
180 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
181 client_socket);
182 return;
183 }
184 }
185 // Create a new host controller.
186 std::unique_ptr<HostController> host_controller(HostController::Create(
187 device_serial, device_port, host_port, adb_port, GetExitNotifierFD(),
188 base::Bind(&HostControllersManager::DeleteHostController,
189 weak_ptr_factory_.GetWeakPtr())));
190 if (!host_controller.get()) {
191 has_failed_ = true;
192 SendMessage("ERROR: Connection to device failed.\n", client_socket);
193 LogExistingControllers(client_socket);
194 return;
195 }
196 // Get the current allocated port.
197 device_port = host_controller->device_port();
198 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
199 << host_port;
200 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
201 if (!SendMessage(msg, client_socket))
202 return;
203 host_controller->Start();
204 controllers_->insert(
205 std::make_pair(MakeHostControllerMapKey(adb_port, device_port),
206 linked_ptr<HostController>(host_controller.release())));
207 }
208
209 void Unmap(const std::string& adb_path,
210 const std::string& device_serial,
211 int adb_port,
212 int device_port,
213 Socket* client_socket) {
214 // Remove the previously created host controller.
215 const std::string controller_key =
216 MakeHostControllerMapKey(adb_port, device_port);
217 const bool controller_did_exist =
218 DeleteRefCountedValueInMap(controller_key, controllers_.get());
219 if (!controller_did_exist) {
220 SendMessage("ERROR: could not unmap port.\n", client_socket);
221 LogExistingControllers(client_socket);
222 } else {
223 SendMessage("OK", client_socket);
224 }
225
226 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
227 }
228
229 void UnmapAll(const std::string& adb_path,
230 const std::string& device_serial,
231 int adb_port,
232 Socket* client_socket) {
233 const std::string adb_port_str = base::StringPrintf("%d", adb_port);
234 for (HostControllerMap::const_iterator controller_key =
235 controllers_->cbegin();
236 controller_key != controllers_->cend(); ++controller_key) {
237 std::vector<std::string> pieces =
238 base::SplitString(controller_key->first, ":", base::KEEP_WHITESPACE,
239 base::SPLIT_WANT_ALL);
240 if (pieces.size() == 2) {
241 if (pieces[0] == adb_port_str) {
242 DeleteRefCountedValueInMapFromIterator(controller_key,
243 controllers_.get());
244 }
245 } else {
246 LOG(ERROR) << "Unexpected controller key: " << controller_key->first;
247 }
248 }
249
250 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
251 SendMessage("OK", client_socket);
252 }
253
254 void HandleRequestOnInternalThread(const std::string& adb_path,
255 const std::string& device_serial,
256 int command,
257 int device_port,
258 int host_port,
259 std::unique_ptr<Socket> client_socket) {
260 const int adb_port = GetAdbPortForDevice(adb_path, device_serial);
261 if (adb_port < 0) {
262 SendMessage(
263 "ERROR: could not get adb port for device. You might need to add "
264 "'adb' to your PATH or provide the device serial id.\n",
265 client_socket.get());
266 return;
267 }
268 switch (command) {
269 case MAP:
270 Map(adb_path, device_serial, adb_port, device_port, host_port,
271 client_socket.get());
272 break;
273 case UNMAP:
274 Unmap(adb_path, device_serial, adb_port, device_port,
275 client_socket.get());
276 break;
277 case UNMAP_ALL:
278 UnmapAll(adb_path, device_serial, adb_port, client_socket.get());
279 break;
280 default:
281 SendMessage(
282 base::StringPrintf("ERROR: unrecognized command %d\n", command),
283 client_socket.get());
284 break;
285 }
286 }
287
288 void LogExistingControllers(Socket* client_socket) {
289 SendMessage("ERROR: Existing controllers:\n", client_socket);
290 for (const auto& controller : *controllers_) {
291 SendMessage(base::StringPrintf("ERROR: %s\n", controller.first.c_str()),
292 client_socket);
293 }
294 }
295
296 void RemoveAdbPortForDeviceIfNeeded(const std::string& adb_path,
297 const std::string& device_serial) {
298 base::hash_map<std::string, int>::const_iterator it =
299 device_serial_to_adb_port_map_.find(device_serial);
300 if (it == device_serial_to_adb_port_map_.end())
301 return;
302
303 int port = it->second;
304 const std::string prefix = base::StringPrintf("%d:", port);
305 for (HostControllerMap::const_iterator others = controllers_->begin();
306 others != controllers_->end(); ++others) {
307 if (base::StartsWith(others->first, prefix, base::CompareCase::SENSITIVE))
308 return;
309 }
310 // No other port is being forwarded to this device:
311 // - Remove it from our internal serial -> adb port map.
312 // - Remove from "adb forward" command.
313 LOG(INFO) << "Device " << device_serial << " has no more ports.";
314 device_serial_to_adb_port_map_.erase(device_serial);
315 const std::string serial_part = device_serial.empty() ?
316 std::string() : std::string("-s ") + device_serial;
317 const std::string command = base::StringPrintf(
318 "%s %s forward --remove tcp:%d",
319 adb_path.c_str(),
320 serial_part.c_str(),
321 port);
322 const base::CommandLine command_line(base::SplitString(
323 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
324 int ret;
325 std::string output;
326 base::GetAppOutputWithExitCode(command_line, &output, &ret);
327 LOG(INFO) << command << " ret: " << ret << " output: " << output;
328 // Wait for the socket to be fully unmapped.
329 const std::string port_mapped_cmd = base::StringPrintf(
330 "lsof -nPi:%d",
331 port);
332 const base::CommandLine port_mapped_cmd_line(
333 base::SplitString(port_mapped_cmd, " ", base::TRIM_WHITESPACE,
334 base::SPLIT_WANT_NONEMPTY));
335 const int poll_interval_us = 500 * 1000;
336 int retries = 3;
337 while (retries) {
338 int port_unmapped;
339 base::GetAppOutputWithExitCode(port_mapped_cmd_line, &output,
340 &port_unmapped);
341 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap "
342 << port_unmapped;
343 if (port_unmapped)
344 break;
345 --retries;
346 usleep(poll_interval_us);
347 }
348 }
349
350 int GetAdbPortForDevice(const std::string adb_path,
351 const std::string& device_serial) {
352 base::hash_map<std::string, int>::const_iterator it =
353 device_serial_to_adb_port_map_.find(device_serial);
354 if (it != device_serial_to_adb_port_map_.end())
355 return it->second;
356 Socket bind_socket;
357 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
358 const int port = bind_socket.GetPort();
359 bind_socket.Close();
360 const std::string serial_part = device_serial.empty() ?
361 std::string() : std::string("-s ") + device_serial;
362 const std::string command = base::StringPrintf(
363 "%s %s forward tcp:%d localabstract:chrome_device_forwarder",
364 adb_path.c_str(),
365 serial_part.c_str(),
366 port);
367 const base::CommandLine command_line(base::SplitString(
368 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
369 int ret;
370 std::string output;
371 base::GetAppOutputWithExitCode(command_line, &output, &ret);
372 LOG(INFO) << command << " ret: " << ret << " output: " << output;
373 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
374 return -1;
375 device_serial_to_adb_port_map_[device_serial] = port;
376 return port;
377 }
378
379 bool SendMessage(const std::string& msg, Socket* client_socket) {
380 bool result = client_socket->WriteString(msg);
381 DCHECK(result);
382 if (!result)
383 has_failed_ = true;
384 return result;
385 }
386
387 base::hash_map<std::string, int> device_serial_to_adb_port_map_;
388 std::unique_ptr<HostControllerMap> controllers_;
389 bool has_failed_;
390 std::unique_ptr<base::AtExitManager>
391 at_exit_manager_; // Needed by base::Thread.
392 std::unique_ptr<base::Thread> thread_;
393 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_;
394 };
395
396 class ServerDelegate : public Daemon::ServerDelegate { 67 class ServerDelegate : public Daemon::ServerDelegate {
397 public: 68 public:
398 explicit ServerDelegate(const std::string& adb_path) 69 explicit ServerDelegate(const std::string& adb_path)
399 : adb_path_(adb_path), has_failed_(false) {} 70 : adb_path_(adb_path),
71 has_failed_(false),
72 controllers_manager_(base::Bind(&GetExitNotifierFD)) {}
400 73
401 bool has_failed() const { 74 bool has_failed() const {
402 return has_failed_ || controllers_manager_.has_failed(); 75 return has_failed_ || controllers_manager_.has_failed();
403 } 76 }
404 77
405 // Daemon::ServerDelegate: 78 // Daemon::ServerDelegate:
406 void Init() override { 79 void Init() override {
407 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; 80 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
408 DCHECK(!g_notifier); 81 DCHECK(!g_notifier);
409 g_notifier = new PipeNotifier(); 82 g_notifier = new PipeNotifier();
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 233
561 return client_delegate.has_failed() || daemon_delegate.has_failed(); 234 return client_delegate.has_failed() || daemon_delegate.has_failed();
562 } 235 }
563 236
564 } // namespace 237 } // namespace
565 } // namespace forwarder2 238 } // namespace forwarder2
566 239
567 int main(int argc, char** argv) { 240 int main(int argc, char** argv) {
568 return forwarder2::RunHostForwarder(argc, argv); 241 return forwarder2::RunHostForwarder(argc, argv);
569 } 242 }
OLDNEW
« no previous file with comments | « tools/android/forwarder2/host_controllers_manager_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698