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

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

Issue 18635005: Reland "Add --serial-id option to host_forwarder." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « tools/android/forwarder2/device_forwarder_main.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> 5 #include <errno.h>
6 #include <signal.h> 6 #include <signal.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
7 #include <unistd.h> 9 #include <unistd.h>
8 10
9 #include <cstdio> 11 #include <cstdio>
10 #include <cstring> 12 #include <iostream>
13 #include <limits>
11 #include <string> 14 #include <string>
12 #include <utility> 15 #include <utility>
13 #include <vector> 16 #include <vector>
14 17
15 #include "base/command_line.h" 18 #include "base/command_line.h"
16 #include "base/compiler_specific.h" 19 #include "base/compiler_specific.h"
17 #include "base/containers/hash_tables.h" 20 #include "base/containers/hash_tables.h"
18 #include "base/file_util.h" 21 #include "base/file_util.h"
19 #include "base/files/file_path.h" 22 #include "base/files/file_path.h"
20 #include "base/logging.h" 23 #include "base/logging.h"
21 #include "base/memory/linked_ptr.h" 24 #include "base/memory/linked_ptr.h"
22 #include "base/memory/scoped_vector.h" 25 #include "base/memory/scoped_vector.h"
26 #include "base/pickle.h"
23 #include "base/posix/eintr_wrapper.h" 27 #include "base/posix/eintr_wrapper.h"
24 #include "base/safe_strerror_posix.h" 28 #include "base/safe_strerror_posix.h"
25 #include "base/strings/string_number_conversions.h" 29 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_piece.h" 30 #include "base/strings/string_piece.h"
27 #include "base/strings/string_split.h" 31 #include "base/strings/string_split.h"
28 #include "base/strings/string_util.h" 32 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h" 33 #include "base/strings/stringprintf.h"
30 #include "tools/android/forwarder2/common.h" 34 #include "tools/android/forwarder2/common.h"
31 #include "tools/android/forwarder2/daemon.h" 35 #include "tools/android/forwarder2/daemon.h"
32 #include "tools/android/forwarder2/host_controller.h" 36 #include "tools/android/forwarder2/host_controller.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 static int s_kill_handler_count = 0; 69 static int s_kill_handler_count = 0;
66 CHECK(g_notifier); 70 CHECK(g_notifier);
67 // If for some reason the forwarder get stuck in any socket waiting forever, 71 // If for some reason the forwarder get stuck in any socket waiting forever,
68 // we can send a SIGKILL or SIGINT three times to force it die 72 // we can send a SIGKILL or SIGINT three times to force it die
69 // (non-nicely). This is useful when debugging. 73 // (non-nicely). This is useful when debugging.
70 ++s_kill_handler_count; 74 ++s_kill_handler_count;
71 if (!g_notifier->Notify() || s_kill_handler_count > 2) 75 if (!g_notifier->Notify() || s_kill_handler_count > 2)
72 exit(1); 76 exit(1);
73 } 77 }
74 78
75 // Format of |command|:
76 // <ADB port>:<Device port>[:<Forward to port>:<Forward to address>].
77 bool ParseForwardCommand(const std::string& command,
78 int* adb_port,
79 int* device_port,
80 std::string* forward_to_host,
81 int* forward_to_port) {
82 std::vector<std::string> command_pieces;
83 base::SplitString(command, ':', &command_pieces);
84
85 if (command_pieces.size() < 2 ||
86 !base::StringToInt(command_pieces[0], adb_port) ||
87 !base::StringToInt(command_pieces[1], device_port))
88 return false;
89
90 if (command_pieces.size() > 2) {
91 if (!base::StringToInt(command_pieces[2], forward_to_port))
92 return false;
93 if (command_pieces.size() > 3)
94 *forward_to_host = command_pieces[3];
95 } else {
96 *forward_to_port = *device_port;
97 }
98 return true;
99 }
100
101 bool IsForwardCommandValid(const std::string& command) {
102 int adb_port, device_port, forward_to_port;
103 std::string forward_to_host;
104 std::vector<std::string> command_pieces;
105 return ParseForwardCommand(
106 command, &adb_port, &device_port, &forward_to_host, &forward_to_port);
107 }
108
109 class ServerDelegate : public Daemon::ServerDelegate { 79 class ServerDelegate : public Daemon::ServerDelegate {
110 public: 80 public:
111 ServerDelegate() : has_failed_(false) {} 81 ServerDelegate() : has_failed_(false) {}
112 82
113 bool has_failed() const { return has_failed_; } 83 bool has_failed() const { return has_failed_; }
114 84
115 // Daemon::ServerDelegate: 85 // Daemon::ServerDelegate:
116 virtual void Init() OVERRIDE { 86 virtual void Init() OVERRIDE {
117 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; 87 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
118 DCHECK(!g_notifier); 88 DCHECK(!g_notifier);
119 g_notifier = new PipeNotifier(); 89 g_notifier = new PipeNotifier();
120 signal(SIGTERM, KillHandler); 90 signal(SIGTERM, KillHandler);
121 signal(SIGINT, KillHandler); 91 signal(SIGINT, KillHandler);
122 } 92 }
123 93
124 virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE { 94 virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
125 char buf[kBufSize]; 95 char buf[kBufSize];
126 const int bytes_read = client_socket->Read(buf, sizeof(buf)); 96 const int bytes_read = client_socket->Read(buf, sizeof(buf));
127 if (bytes_read <= 0) { 97 if (bytes_read <= 0) {
128 if (client_socket->DidReceiveEvent()) 98 if (client_socket->DidReceiveEvent())
129 return; 99 return;
130 PError("Read()"); 100 PError("Read()");
131 has_failed_ = true; 101 has_failed_ = true;
132 return; 102 return;
133 } 103 }
134 const std::string command(buf, bytes_read); 104 const Pickle command_pickle(buf, bytes_read);
135 int adb_port = 0; 105 PickleIterator pickle_it(command_pickle);
136 int device_port = 0; 106 std::string device_serial;
137 std::string forward_to_host; 107 CHECK(pickle_it.ReadString(&device_serial));
138 int forward_to_port = 0; 108 int device_port;
139 const bool succeeded = ParseForwardCommand( 109 if (!pickle_it.ReadInt(&device_port)) {
140 command, &adb_port, &device_port, &forward_to_host, &forward_to_port); 110 SendMessage("ERROR: missing device port", client_socket.get());
141 if (!succeeded) { 111 return;
142 has_failed_ = true; 112 }
143 const std::string msg = base::StringPrintf( 113 const int adb_port = GetAdbPortForDevice(device_serial);
144 "ERROR: Could not parse forward command '%s'", command.c_str()); 114 if (adb_port < 0) {
145 SendMessage(msg, client_socket.get()); 115 SendMessage(
116 "ERROR: could not get adb port for device. You might need to add "
117 "'adb' to your PATH or provide the device serial id.",
118 client_socket.get());
146 return; 119 return;
147 } 120 }
148 if (device_port < 0) { 121 if (device_port < 0) {
149 // Remove the previously created host controller. 122 // Remove the previously created host controller.
150 const std::string controller_key = MakeHostControllerMapKey( 123 const std::string controller_key = MakeHostControllerMapKey(
151 adb_port, -device_port); 124 adb_port, -device_port);
152 const HostControllerMap::size_type removed_elements = controllers_.erase( 125 const HostControllerMap::size_type removed_elements = controllers_.erase(
153 controller_key); 126 controller_key);
154 SendMessage( 127 SendMessage(
155 !removed_elements ? "ERROR: could not unmap port" : "OK", 128 !removed_elements ? "ERROR: could not unmap port" : "OK",
156 client_socket.get()); 129 client_socket.get());
157 return; 130 return;
158 } 131 }
132 int host_port;
133 if (!pickle_it.ReadInt(&host_port)) {
134 SendMessage("ERROR: missing host port", client_socket.get());
135 return;
136 }
159 // Create a new host controller. 137 // Create a new host controller.
160 scoped_ptr<HostController> host_controller( 138 scoped_ptr<HostController> host_controller(
161 new HostController(device_port, forward_to_host, forward_to_port, 139 new HostController(device_port, "127.0.0.1", host_port, adb_port,
162 adb_port, GetExitNotifierFD())); 140 GetExitNotifierFD()));
163 if (!host_controller->Connect()) { 141 if (!host_controller->Connect()) {
164 has_failed_ = true; 142 has_failed_ = true;
165 SendMessage("ERROR: Connection to device failed.", client_socket.get()); 143 SendMessage("ERROR: Connection to device failed.", client_socket.get());
166 return; 144 return;
167 } 145 }
168 // Get the current allocated port. 146 // Get the current allocated port.
169 device_port = host_controller->device_port(); 147 device_port = host_controller->device_port();
170 LOG(INFO) << "Forwarding device port " << device_port << " to host " 148 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
171 << forward_to_host << ":" << forward_to_port; 149 << host_port;
172 const std::string msg = base::StringPrintf( 150 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
173 "%d:%d", device_port, forward_to_port);
174 if (!SendMessage(msg, client_socket.get())) 151 if (!SendMessage(msg, client_socket.get()))
175 return; 152 return;
176 host_controller->Start(); 153 host_controller->Start();
177 const std::string controller_key = MakeHostControllerMapKey( 154 const std::string controller_key = MakeHostControllerMapKey(
178 adb_port, device_port); 155 adb_port, device_port);
179 controllers_.insert( 156 controllers_.insert(
180 std::make_pair(controller_key, 157 std::make_pair(controller_key,
181 linked_ptr<HostController>(host_controller.release()))); 158 linked_ptr<HostController>(host_controller.release())));
182 } 159 }
183 160
(...skipping 10 matching lines...) Expand all
194 } 171 }
195 172
196 private: 173 private:
197 typedef base::hash_map< 174 typedef base::hash_map<
198 std::string, linked_ptr<HostController> > HostControllerMap; 175 std::string, linked_ptr<HostController> > HostControllerMap;
199 176
200 static std::string MakeHostControllerMapKey(int adb_port, int device_port) { 177 static std::string MakeHostControllerMapKey(int adb_port, int device_port) {
201 return base::StringPrintf("%d:%d", adb_port, device_port); 178 return base::StringPrintf("%d:%d", adb_port, device_port);
202 } 179 }
203 180
181 int GetAdbPortForDevice(const std::string& device_serial) {
182 base::hash_map<std::string, int>::const_iterator it =
183 device_serial_to_adb_port_map_.find(device_serial);
184 if (it != device_serial_to_adb_port_map_.end())
185 return it->second;
186 Socket bind_socket;
187 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
188 const int port = bind_socket.GetPort();
189 bind_socket.Close();
190 const std::string serial_part = device_serial.empty() ?
191 std::string() : std::string("-s ") + device_serial;
192 const std::string command = base::StringPrintf(
193 "adb %s forward tcp:%d localabstract:chrome_device_forwarder",
194 device_serial.empty() ? "" : serial_part.c_str(),
195 port);
196 LOG(INFO) << command;
197 const int ret = system(command.c_str());
198 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
199 return -1;
200 device_serial_to_adb_port_map_[device_serial] = port;
201 return port;
202 }
203
204 bool SendMessage(const std::string& msg, Socket* client_socket) { 204 bool SendMessage(const std::string& msg, Socket* client_socket) {
205 bool result = client_socket->WriteString(msg); 205 bool result = client_socket->WriteString(msg);
206 DCHECK(result); 206 DCHECK(result);
207 if (!result) 207 if (!result)
208 has_failed_ = true; 208 has_failed_ = true;
209 return result; 209 return result;
210 } 210 }
211 211
212 base::hash_map<std::string, int> device_serial_to_adb_port_map_;
212 HostControllerMap controllers_; 213 HostControllerMap controllers_;
213 bool has_failed_; 214 bool has_failed_;
214 215
215 DISALLOW_COPY_AND_ASSIGN(ServerDelegate); 216 DISALLOW_COPY_AND_ASSIGN(ServerDelegate);
216 }; 217 };
217 218
218 class ClientDelegate : public Daemon::ClientDelegate { 219 class ClientDelegate : public Daemon::ClientDelegate {
219 public: 220 public:
220 ClientDelegate(const std::string& forward_command) 221 ClientDelegate(const Pickle& command_pickle)
221 : forward_command_(forward_command), 222 : command_pickle_(command_pickle),
222 has_failed_(false) { 223 has_failed_(false) {
223 } 224 }
224 225
225 bool has_failed() const { return has_failed_; } 226 bool has_failed() const { return has_failed_; }
226 227
227 // Daemon::ClientDelegate: 228 // Daemon::ClientDelegate:
228 virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE { 229 virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
229 // Send the forward command to the daemon. 230 // Send the forward command to the daemon.
230 CHECK(daemon_socket->WriteString(forward_command_)); 231 CHECK_EQ(command_pickle_.size(),
232 daemon_socket->WriteNumBytes(command_pickle_.data(),
233 command_pickle_.size()));
231 char buf[kBufSize]; 234 char buf[kBufSize];
232 const int bytes_read = daemon_socket->Read( 235 const int bytes_read = daemon_socket->Read(
233 buf, sizeof(buf) - 1 /* leave space for null terminator */); 236 buf, sizeof(buf) - 1 /* leave space for null terminator */);
234 CHECK_GT(bytes_read, 0); 237 CHECK_GT(bytes_read, 0);
235 DCHECK(bytes_read < sizeof(buf)); 238 DCHECK(bytes_read < sizeof(buf));
236 buf[bytes_read] = 0; 239 buf[bytes_read] = 0;
237 base::StringPiece msg(buf, bytes_read); 240 base::StringPiece msg(buf, bytes_read);
238 if (msg.starts_with("ERROR")) { 241 if (msg.starts_with("ERROR")) {
239 LOG(ERROR) << msg; 242 LOG(ERROR) << msg;
240 has_failed_ = true; 243 has_failed_ = true;
241 return; 244 return;
242 } 245 }
243 printf("%s\n", buf); 246 printf("%s\n", buf);
244 } 247 }
245 248
246 private: 249 private:
247 const std::string forward_command_; 250 const Pickle command_pickle_;
248 bool has_failed_; 251 bool has_failed_;
249 }; 252 };
250 253
251 void PrintUsage(const char* program_name) { 254 void ExitWithUsage() {
252 LOG(ERROR) << program_name 255 std::cerr << "Usage: host_forwarder [options]\n\n"
253 << " adb_port:from_port:to_port:to_host\n" 256 "Options:\n"
254 "<adb port> is the TCP port Adb is configured to forward to.\n" 257 " --serial-id=[0-9A-Z]{16}]\n"
255 "Note that <from_port> can be unmapped by making it negative."; 258 " --map DEVICE_PORT HOST_PORT\n"
259 " --unmap DEVICE_PORT\n"
260 " --kill-server\n";
261 exit(1);
262 }
263
264 int PortToInt(const std::string& s) {
265 int value;
266 // Note that 0 is a valid port (used for dynamic port allocation).
267 if (!base::StringToInt(s, &value) || value < 0 ||
268 value > std::numeric_limits<uint16>::max()) {
269 LOG(ERROR) << "Could not convert string " << s << " to port";
270 ExitWithUsage();
271 }
272 return value;
256 } 273 }
257 274
258 int RunHostForwarder(int argc, char** argv) { 275 int RunHostForwarder(int argc, char** argv) {
259 if (!CommandLine::Init(argc, argv)) { 276 CommandLine::Init(argc, argv);
260 LOG(ERROR) << "Could not initialize command line"; 277 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
261 return 1; 278 bool kill_server = false;
262 } 279
263 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 280 Pickle pickle;
264 const char* command = NULL; 281 pickle.WriteString(
265 int adb_port = 0; 282 cmd_line.HasSwitch("serial-id") ?
266 if (argc != 2) { 283 cmd_line.GetSwitchValueASCII("serial-id") : std::string());
267 PrintUsage(argv[0]); 284
268 return 1; 285 const std::vector<std::string> args = cmd_line.GetArgs();
269 } 286 if (cmd_line.HasSwitch("kill-server")) {
270 if (!strcmp(argv[1], kKillServerCommand)) { 287 kill_server = true;
271 command = kKillServerCommand; 288 } else if (cmd_line.HasSwitch("unmap")) {
289 if (args.size() != 1)
290 ExitWithUsage();
291 // Note the minus sign below.
292 pickle.WriteInt(-PortToInt(args[0]));
293 } else if (cmd_line.HasSwitch("map")) {
294 if (args.size() != 2)
295 ExitWithUsage();
296 pickle.WriteInt(PortToInt(args[0]));
297 pickle.WriteInt(PortToInt(args[1]));
272 } else { 298 } else {
273 command = kForwardCommand; 299 ExitWithUsage();
274 if (!IsForwardCommandValid(argv[1])) {
275 PrintUsage(argv[0]);
276 return 1;
277 }
278 } 300 }
279 301
280 ClientDelegate client_delegate(argv[1]); 302 if (kill_server && args.size() > 0)
303 ExitWithUsage();
304
305 ClientDelegate client_delegate(pickle);
281 ServerDelegate daemon_delegate; 306 ServerDelegate daemon_delegate;
282 Daemon daemon( 307 Daemon daemon(
283 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate, 308 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate,
284 &GetExitNotifierFD); 309 &GetExitNotifierFD);
285 310
286 if (command == kKillServerCommand) 311 if (kill_server)
287 return !daemon.Kill(); 312 return !daemon.Kill();
288
289 DCHECK(command == kForwardCommand);
290 if (!daemon.SpawnIfNeeded()) 313 if (!daemon.SpawnIfNeeded())
291 return 1; 314 return 1;
292 315
293 return client_delegate.has_failed() || daemon_delegate.has_failed(); 316 return client_delegate.has_failed() || daemon_delegate.has_failed();
294 } 317 }
295 318
296 } // namespace 319 } // namespace
297 } // namespace forwarder2 320 } // namespace forwarder2
298 321
299 int main(int argc, char** argv) { 322 int main(int argc, char** argv) {
300 return forwarder2::RunHostForwarder(argc, argv); 323 return forwarder2::RunHostForwarder(argc, argv);
301 } 324 }
OLDNEW
« no previous file with comments | « tools/android/forwarder2/device_forwarder_main.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698