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

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

Issue 11269036: Support HTTP test-server based net unit tests on Android. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix potential invalid write in host_forwarder_main.cc Created 8 years, 1 month 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
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 <stdio.h> 7 #include <stdio.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <unistd.h>
9 10
10 #include <vector> 11 #include <vector>
11 #include <string> 12 #include <string>
12 13
13 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/eintr_wrapper.h"
16 #include "base/file_path.h"
17 #include "base/file_util.h"
14 #include "base/logging.h" 18 #include "base/logging.h"
15 #include "base/memory/scoped_vector.h" 19 #include "base/memory/scoped_vector.h"
20 #include "base/safe_strerror_posix.h"
16 #include "base/string_number_conversions.h" 21 #include "base/string_number_conversions.h"
17 #include "base/string_piece.h" 22 #include "base/string_piece.h"
18 #include "base/string_split.h" 23 #include "base/string_split.h"
24 #include "base/string_util.h"
19 #include "base/stringprintf.h" 25 #include "base/stringprintf.h"
20 #include "tools/android/common/daemon.h" 26 #include "tools/android/forwarder2/common.h"
27 #include "tools/android/forwarder2/daemon.h"
21 #include "tools/android/forwarder2/host_controller.h" 28 #include "tools/android/forwarder2/host_controller.h"
22 #include "tools/android/forwarder2/pipe_notifier.h" 29 #include "tools/android/forwarder2/pipe_notifier.h"
30 #include "tools/android/forwarder2/socket.h"
23 31
24 using base::StringToInt; 32 using base::StringToInt;
25 using forwarder2::HostController;
26 33
34 namespace forwarder2 {
27 namespace { 35 namespace {
28 36
29 const int kDefaultAdbPort = 3000; 37 const char kPIDFilePath[] = "/tmp/host_forwarder_pid";
38 const char kCommandSocketPath[] = "host_forwarder_command_socket";
39 const char kWelcomeMessage[] = "forwarder2";
30 40
31 // Need to be global to be able to accessed from the signal handler. 41 // Need to be global to be able to accessed from the signal handler.
32 forwarder2::PipeNotifier* g_notifier; 42 PipeNotifier* g_notifier;
33 43
34 void KillHandler(int /* unused */) { 44 void KillHandler(int signal_number) {
45 if (signal_number != SIGTERM && signal_number != SIGINT) {
46 char buf[128];
47 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
48 SIGNAL_SAFE_LOG(WARNING, buf);
49 return;
50 }
35 static int s_kill_handler_count = 0; 51 static int s_kill_handler_count = 0;
36 CHECK(g_notifier); 52 CHECK(g_notifier);
37 // If for some reason the forwarder get stuck in any socket waiting forever, 53 // If for some reason the forwarder get stuck in any socket waiting forever,
38 // we can send a SIGKILL or SIGINT three times to force it die 54 // we can send a SIGKILL or SIGINT three times to force it die
39 // (non-nicely). This is useful when debugging. 55 // (non-nicely). This is useful when debugging.
40 ++s_kill_handler_count; 56 ++s_kill_handler_count;
41 if (!g_notifier->Notify() || s_kill_handler_count > 2) 57 if (!g_notifier->Notify() || s_kill_handler_count > 2)
42 exit(1); 58 exit(1);
43 } 59 }
44 60
45 // Format of arg: <Device port>[:<Forward to port>:<Forward to address>] 61 enum {
46 bool ParseForwardArg(const std::string& arg, 62 kConnectSingleTry = 1,
47 int* device_port, 63 kConnectNoIdleTime = 0,
48 std::string* forward_to_host, 64 };
49 int* forward_to_port) { 65
50 std::vector<std::string> arg_pieces; 66 scoped_ptr<Socket> ConnectToDaemon(int tries_count, int idle_time_msec) {
51 base::SplitString(arg, ':', &arg_pieces); 67 for (int i = 0; i < tries_count; ++i) {
52 if (arg_pieces.size() == 0 || !StringToInt(arg_pieces[0], device_port)) 68 scoped_ptr<Socket> socket(new Socket());
69 if (!socket->ConnectUnix(kCommandSocketPath, true)) {
70 if (idle_time_msec)
71 usleep(idle_time_msec * 1000);
72 continue;
73 }
74 char buf[sizeof(kWelcomeMessage)];
75 memset(buf, 0, sizeof(buf));
76 if (socket->Read(buf, sizeof(buf)) < 0) {
77 perror("read");
78 continue;
79 }
80 if (strcmp(buf, kWelcomeMessage)) {
81 LOG(ERROR) << "Unexpected message read from daemon: " << buf;
82 break;
83 }
84 return socket.Pass();
85 }
86 return scoped_ptr<Socket>(NULL);
87 }
88
89 // Format of |command|:
90 // <ADB port>:<Device port>[:<Forward to port>:<Forward to address>].
91 bool ParseForwardCommand(const std::string& command,
92 int* adb_port,
93 int* device_port,
94 std::string* forward_to_host,
95 int* forward_to_port) {
96 std::vector<std::string> command_pieces;
97 base::SplitString(command, ':', &command_pieces);
98
99 if (command_pieces.size() < 2 ||
100 !StringToInt(command_pieces[0], adb_port) ||
101 !StringToInt(command_pieces[1], device_port))
53 return false; 102 return false;
54 103
55 if (arg_pieces.size() > 1) { 104 if (command_pieces.size() > 2) {
56 if (!StringToInt(arg_pieces[1], forward_to_port)) 105 if (!StringToInt(command_pieces[2], forward_to_port))
57 return false; 106 return false;
58 if (arg_pieces.size() > 2) 107 if (command_pieces.size() > 3)
59 *forward_to_host = arg_pieces[2]; 108 *forward_to_host = command_pieces[3];
60 } else { 109 } else {
61 *forward_to_port = *device_port; 110 *forward_to_port = *device_port;
62 } 111 }
63 return true; 112 return true;
64 } 113 }
65 114
66 } // namespace 115 bool IsForwardCommandValid(const std::string& command) {
67 116 int adb_port, device_port, forward_to_port;
68 int main(int argc, char** argv) { 117 std::string forward_to_host;
69 printf("Host forwarder to handle incoming connections from Android.\n"); 118 std::vector<std::string> command_pieces;
70 printf("Like 'adb forward' but in the reverse direction\n"); 119 return ParseForwardCommand(
71 120 command, &adb_port, &device_port, &forward_to_host, &forward_to_port);
72 CommandLine command_line(argc, argv); 121 }
73 bool show_help = tools::HasHelpSwitch(command_line); 122
74 std::string adb_port_str = command_line.GetSwitchValueASCII("adb_port"); 123 bool DaemonHandler() {
75 int adb_port = kDefaultAdbPort; 124 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
76 if (!adb_port_str.empty() && !StringToInt(adb_port_str, &adb_port)) { 125 DCHECK(!g_notifier);
77 printf("Could not parse adb port number: %s\n", adb_port_str.c_str()); 126 g_notifier = new PipeNotifier();
78 show_help = true; 127
79 } 128 signal(SIGTERM, KillHandler);
80 if (adb_port <= 0) { 129 signal(SIGINT, KillHandler);
81 printf("Invalid adb port number: %s. Adb port must be a " 130
82 "postivie integer.\n", adb_port_str.c_str()); 131 const int notifier_fd = g_notifier->receiver_fd();
83 show_help = true; 132 Socket command_socket;
84 } 133 if (!command_socket.BindUnix(kCommandSocketPath, true)) {
85 CommandLine::StringVector forward_args = command_line.GetArgs(); 134 LOG(ERROR) << "Could not bind Unix Domain Socket";
86 if (show_help || forward_args.empty()) { 135 return false;
87 tools::ShowHelp( 136 }
88 argv[0], 137 command_socket.set_exit_notifier_fd(notifier_fd);
89 "[--adb_port=<adb port>] " 138
90 "<Device port>[:<Forward to port>:<Forward to address>] ...",
91 base::StringPrintf(
92 " <adb port> is the TCP port Adb is configured to forward to."
93 " Default is %d\n"
94 " <Forward to port> default is <Device port>\n"
95 " <Forward to address> default is 127.0.0.1.",
96 kDefaultAdbPort).c_str());
97 return 1;
98 }
99
100 g_notifier = new forwarder2::PipeNotifier();
101 ScopedVector<HostController> controllers; 139 ScopedVector<HostController> controllers;
102 int failed_count = 0; 140 int failed_count = 0;
103 for (size_t i = 0; i < forward_args.size(); ++i) { 141
142 for (;;) {
143 Socket client_socket;
144 if (!command_socket.Accept(&client_socket)) {
145 if (command_socket.exited())
146 return true;
147 PError("Accept()");
148 return false;
149 }
150 if (!client_socket.Write(kWelcomeMessage, sizeof(kWelcomeMessage))) {
151 PError("Write()");
152 continue;
153 }
154 char buf[128];
155 const int bytes_read = client_socket.Read(buf, sizeof(buf));
156 if (bytes_read <= 0) {
157 if (client_socket.exited())
158 break;
159 PError("Read()");
160 ++failed_count;
161 }
162 const std::string command(buf, bytes_read);
163 int adb_port = 0;
104 int device_port = 0; 164 int device_port = 0;
105 std::string forward_to_host; 165 std::string forward_to_host;
106 int forward_to_port = 0; 166 int forward_to_port = 0;
107 if (ParseForwardArg(forward_args[i], 167 // Note that the command is checked on the CLI side. In the worst case,
108 &device_port, 168 // Connect() will fail below.
109 &forward_to_host, 169 ParseForwardCommand(
felipeg 2012/11/01 15:23:10 ParseForwardCommand can succeed in the client side
Philippe 2012/11/05 12:05:23 Done.
110 &forward_to_port)) { 170 command, &adb_port, &device_port, &forward_to_host, &forward_to_port);
111 scoped_ptr<HostController> host_controller( 171 scoped_ptr<HostController> host_controller(
112 new HostController(device_port, 172 new HostController(device_port,
113 forward_to_host, 173 forward_to_host,
114 forward_to_port, 174 forward_to_port,
115 adb_port, 175 adb_port,
116 g_notifier->receiver_fd())); 176 g_notifier->receiver_fd()));
117 if (!host_controller->Connect()) 177 if (!host_controller->Connect()) {
118 continue;
119 host_controller->Start();
120 // Get the current allocated port.
121 device_port = host_controller->device_port();
122 printf("Forwarding device port %d to host %d:%s\n",
123 device_port, forward_to_port, forward_to_host.c_str());
124
125 controllers.push_back(host_controller.release());
126 } else {
127 printf("Couldn't start forwarder server for port spec: %s\n",
128 forward_args[i].c_str());
129 ++failed_count; 178 ++failed_count;
130 } 179 client_socket.WriteString("ERROR: Connection to device failed.");
131 } 180 continue;
132 181 }
133 // Signal handler must be installed after the for loop above where we start 182 // Get the current allocated port.
134 // the host_controllers and push_back into the vector. Otherwise a race 183 device_port = host_controller->device_port();
135 // condition may occur. 184 LOG(INFO) << "Forwarding device port " << device_port << " to host "
136 signal(SIGTERM, KillHandler); 185 << forward_to_host << ":" << forward_to_port;
137 signal(SIGINT, KillHandler); 186 if (!client_socket.WriteString(
138 187 base::StringPrintf("%d:%d", device_port, forward_to_port))) {
139 if (controllers.size() == 0) { 188 ++failed_count;
140 printf("No forwarder servers could be started. Exiting.\n"); 189 continue;
141 return failed_count; 190 }
142 } 191 host_controller->Start();
felipeg 2012/11/01 15:23:10 Maybe adding a comment about the racecondition reg
Philippe 2012/11/05 12:05:23 Do you mean the one related to signal handlers?
143 192 controllers.push_back(host_controller.release());
144 // TODO(felipeg): We should check if the controllers are really alive before 193 }
145 // printing Ready.
146 printf("Host Forwarder Ready.\n");
147 for (int i = 0; i < controllers.size(); ++i) 194 for (int i = 0; i < controllers.size(); ++i)
148 controllers[i]->Join(); 195 controllers[i]->Join();
149 196
197 if (controllers.size() == 0) {
198 LOG(ERROR) << "No forwarder servers could be started. Exiting.";
199 return false;
200 }
201 return true;
202 }
203
204 void PrintUsage(const char* program_name) {
205 LOG(ERROR) << program_name << " adb_port:from_port:to_port:to_host\n"
206 "<adb port> is the TCP port Adb is configured to forward to.";
207 }
208
209 int RunHostForwarder(int argc, char** argv) {
210 if (!CommandLine::Init(argc, argv)) {
211 LOG(ERROR) << "Could not initialize command line";
212 return 1;
213 }
214 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
215 std::string command;
216 int adb_port = 0;
217 if (argc != 2) {
218 PrintUsage(argv[0]);
219 return 1;
220 }
221 if (!strcmp(argv[1], "kill-server")) {
222 command = "kill-server";
223 } else {
224 command = "forward";
225 if (!IsForwardCommandValid(argv[1])) {
226 PrintUsage(argv[0]);
227 return 1;
228 }
229 }
230
231 Daemon daemon(kPIDFilePath);
232
233 if (command == "kill-server")
234 return !daemon.Kill();
235
236 bool is_daemon = false;
237 scoped_ptr<Socket> daemon_socket = ConnectToDaemon(
238 kConnectSingleTry, kConnectNoIdleTime);
239 if (!daemon_socket) {
240 if (!daemon.Spawn(&is_daemon))
241 return 1;
242 }
243
244 if (is_daemon)
245 return !DaemonHandler();
246
247 if (!daemon_socket) {
248 daemon_socket = ConnectToDaemon(10 /* tries */, 10 /* idle msec */);
249 if (!daemon_socket) {
250 LOG(ERROR) << "Could not connect to daemon.";
251 return 1;
252 }
253 }
254
255 // Send the forward command to the daemon.
256 CHECK(daemon_socket->Write(argv[1], strlen(argv[1])));
257 char buf[256];
felipeg 2012/11/01 15:23:10 Maybe you could use one single constant to set all
Philippe 2012/11/05 12:05:23 Done.
258 const int bytes_read = daemon_socket->Read(
259 buf, sizeof(buf) - 1 /* leave space for null terminator */);
260 CHECK_GT(bytes_read, 0);
261 DCHECK(bytes_read < sizeof(buf));
262 buf[bytes_read] = 0;
263 base::StringPiece msg(buf, bytes_read);
264 if (msg.starts_with("ERROR")) {
265 LOG(ERROR) << msg;
266 return 1;
267 }
268 printf("%s\n", buf);
150 return 0; 269 return 0;
151 } 270 }
271
272 } // namespace
273 } // namespace forwarder2
274
275 int main(int argc, char** argv) {
276 return forwarder2::RunHostForwarder(argc, argv);
277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698