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

Unified 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 Clang build + sync 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 side-by-side diff with in-line comments
Download patch
Index: tools/android/forwarder2/host_forwarder_main.cc
diff --git a/tools/android/forwarder2/host_forwarder_main.cc b/tools/android/forwarder2/host_forwarder_main.cc
index 6e541894cead6671d1a3e7b97d85a11976bc92f9..dff0c8f42e975da0e7ca4dd67a7cc174cf844d75 100644
--- a/tools/android/forwarder2/host_forwarder_main.cc
+++ b/tools/android/forwarder2/host_forwarder_main.cc
@@ -6,32 +6,49 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <vector>
#include <string>
#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
+#include "base/safe_strerror_posix.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_split.h"
+#include "base/string_util.h"
#include "base/stringprintf.h"
-#include "tools/android/common/daemon.h"
+#include "tools/android/forwarder2/common.h"
+#include "tools/android/forwarder2/daemon.h"
#include "tools/android/forwarder2/host_controller.h"
#include "tools/android/forwarder2/pipe_notifier.h"
+#include "tools/android/forwarder2/socket.h"
using base::StringToInt;
-using forwarder2::HostController;
+namespace forwarder2 {
namespace {
-const int kDefaultAdbPort = 3000;
+const char kPIDFilePath[] = "/tmp/host_forwarder_pid";
+const char kCommandSocketPath[] = "host_forwarder_command_socket";
+const char kWelcomeMessage[] = "forwarder2";
+const int kBufSize = 256;
// Need to be global to be able to accessed from the signal handler.
-forwarder2::PipeNotifier* g_notifier;
+PipeNotifier* g_notifier;
-void KillHandler(int /* unused */) {
+void KillHandler(int signal_number) {
+ if (signal_number != SIGTERM && signal_number != SIGINT) {
+ char buf[kBufSize];
+ snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
+ SIGNAL_SAFE_LOG(WARNING, buf);
+ return;
+ }
static int s_kill_handler_count = 0;
CHECK(g_notifier);
// If for some reason the forwarder get stuck in any socket waiting forever,
@@ -42,110 +59,224 @@ void KillHandler(int /* unused */) {
exit(1);
}
-// Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
-bool ParseForwardArg(const std::string& arg,
- int* device_port,
- std::string* forward_to_host,
- int* forward_to_port) {
- std::vector<std::string> arg_pieces;
- base::SplitString(arg, ':', &arg_pieces);
- if (arg_pieces.size() == 0 || !StringToInt(arg_pieces[0], device_port))
+enum {
+ kConnectSingleTry = 1,
+ kConnectNoIdleTime = 0,
+};
+
+scoped_ptr<Socket> ConnectToDaemon(int tries_count, int idle_time_msec) {
+ for (int i = 0; i < tries_count; ++i) {
+ scoped_ptr<Socket> socket(new Socket());
+ if (!socket->ConnectUnix(kCommandSocketPath, true)) {
+ if (idle_time_msec)
+ usleep(idle_time_msec * 1000);
+ continue;
+ }
+ char buf[sizeof(kWelcomeMessage)];
+ memset(buf, 0, sizeof(buf));
+ if (socket->Read(buf, sizeof(buf)) < 0) {
+ perror("read");
+ continue;
+ }
+ if (strcmp(buf, kWelcomeMessage)) {
+ LOG(ERROR) << "Unexpected message read from daemon: " << buf;
+ break;
+ }
+ return socket.Pass();
+ }
+ return scoped_ptr<Socket>(NULL);
+}
+
+// Format of |command|:
+// <ADB port>:<Device port>[:<Forward to port>:<Forward to address>].
+bool ParseForwardCommand(const std::string& command,
+ int* adb_port,
+ int* device_port,
+ std::string* forward_to_host,
+ int* forward_to_port) {
+ std::vector<std::string> command_pieces;
+ base::SplitString(command, ':', &command_pieces);
+
+ if (command_pieces.size() < 2 ||
+ !StringToInt(command_pieces[0], adb_port) ||
+ !StringToInt(command_pieces[1], device_port))
return false;
- if (arg_pieces.size() > 1) {
- if (!StringToInt(arg_pieces[1], forward_to_port))
+ if (command_pieces.size() > 2) {
+ if (!StringToInt(command_pieces[2], forward_to_port))
return false;
- if (arg_pieces.size() > 2)
- *forward_to_host = arg_pieces[2];
+ if (command_pieces.size() > 3)
+ *forward_to_host = command_pieces[3];
} else {
*forward_to_port = *device_port;
}
return true;
}
-} // namespace
+bool IsForwardCommandValid(const std::string& command) {
+ int adb_port, device_port, forward_to_port;
+ std::string forward_to_host;
+ std::vector<std::string> command_pieces;
+ return ParseForwardCommand(
+ command, &adb_port, &device_port, &forward_to_host, &forward_to_port);
+}
-int main(int argc, char** argv) {
- printf("Host forwarder to handle incoming connections from Android.\n");
- printf("Like 'adb forward' but in the reverse direction\n");
-
- CommandLine command_line(argc, argv);
- bool show_help = tools::HasHelpSwitch(command_line);
- std::string adb_port_str = command_line.GetSwitchValueASCII("adb_port");
- int adb_port = kDefaultAdbPort;
- if (!adb_port_str.empty() && !StringToInt(adb_port_str, &adb_port)) {
- printf("Could not parse adb port number: %s\n", adb_port_str.c_str());
- show_help = true;
- }
- if (adb_port <= 0) {
- printf("Invalid adb port number: %s. Adb port must be a "
- "postivie integer.\n", adb_port_str.c_str());
- show_help = true;
- }
- CommandLine::StringVector forward_args = command_line.GetArgs();
- if (show_help || forward_args.empty()) {
- tools::ShowHelp(
- argv[0],
- "[--adb_port=<adb port>] "
- "<Device port>[:<Forward to port>:<Forward to address>] ...",
- base::StringPrintf(
- " <adb port> is the TCP port Adb is configured to forward to."
- " Default is %d\n"
- " <Forward to port> default is <Device port>\n"
- " <Forward to address> default is 127.0.0.1.",
- kDefaultAdbPort).c_str());
- return 1;
+bool DaemonHandler() {
+ LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
+ DCHECK(!g_notifier);
+ g_notifier = new PipeNotifier();
+
+ const int notifier_fd = g_notifier->receiver_fd();
+ Socket command_socket;
+ if (!command_socket.BindUnix(kCommandSocketPath, true)) {
+ LOG(ERROR) << "Could not bind Unix Domain Socket";
+ return false;
}
+ command_socket.set_exit_notifier_fd(notifier_fd);
+
+ signal(SIGTERM, KillHandler);
+ signal(SIGINT, KillHandler);
- g_notifier = new forwarder2::PipeNotifier();
ScopedVector<HostController> controllers;
int failed_count = 0;
- for (size_t i = 0; i < forward_args.size(); ++i) {
+
+ for (;;) {
+ Socket client_socket;
+ if (!command_socket.Accept(&client_socket)) {
+ if (command_socket.exited())
+ return true;
+ PError("Accept()");
+ return false;
+ }
+ if (!client_socket.Write(kWelcomeMessage, sizeof(kWelcomeMessage))) {
+ PError("Write()");
+ continue;
+ }
+ char buf[kBufSize];
+ const int bytes_read = client_socket.Read(buf, sizeof(buf));
+ if (bytes_read <= 0) {
+ if (client_socket.exited())
+ break;
+ PError("Read()");
+ ++failed_count;
+ }
+ const std::string command(buf, bytes_read);
+ int adb_port = 0;
int device_port = 0;
std::string forward_to_host;
int forward_to_port = 0;
- if (ParseForwardArg(forward_args[i],
- &device_port,
- &forward_to_host,
- &forward_to_port)) {
- scoped_ptr<HostController> host_controller(
- new HostController(device_port,
- forward_to_host,
- forward_to_port,
- adb_port,
- g_notifier->receiver_fd()));
- if (!host_controller->Connect())
- continue;
- host_controller->Start();
- // Get the current allocated port.
- device_port = host_controller->device_port();
- printf("Forwarding device port %d to host %d:%s\n",
- device_port, forward_to_port, forward_to_host.c_str());
-
- controllers.push_back(host_controller.release());
- } else {
- printf("Couldn't start forwarder server for port spec: %s\n",
- forward_args[i].c_str());
+ const bool succeeded = ParseForwardCommand(
+ command, &adb_port, &device_port, &forward_to_host, &forward_to_port);
+ if (!succeeded) {
+ ++failed_count;
+ client_socket.WriteString(
+ base::StringPrintf("ERROR: Could not parse forward command '%s'",
+ command.c_str()));
+ continue;
+ }
+ scoped_ptr<HostController> host_controller(
+ new HostController(device_port, forward_to_host, forward_to_port,
+ adb_port, notifier_fd));
+ if (!host_controller->Connect()) {
++failed_count;
+ client_socket.WriteString("ERROR: Connection to device failed.");
+ continue;
}
+ // Get the current allocated port.
+ device_port = host_controller->device_port();
+ LOG(INFO) << "Forwarding device port " << device_port << " to host "
+ << forward_to_host << ":" << forward_to_port;
+ if (!client_socket.WriteString(
+ base::StringPrintf("%d:%d", device_port, forward_to_port))) {
+ ++failed_count;
+ continue;
+ }
+ host_controller->Start();
+ controllers.push_back(host_controller.release());
}
-
- // Signal handler must be installed after the for loop above where we start
- // the host_controllers and push_back into the vector. Otherwise a race
- // condition may occur.
- signal(SIGTERM, KillHandler);
- signal(SIGINT, KillHandler);
+ for (int i = 0; i < controllers.size(); ++i)
+ controllers[i]->Join();
if (controllers.size() == 0) {
- printf("No forwarder servers could be started. Exiting.\n");
- return failed_count;
+ LOG(ERROR) << "No forwarder servers could be started. Exiting.";
+ return false;
}
+ return true;
+}
- // TODO(felipeg): We should check if the controllers are really alive before
- // printing Ready.
- printf("Host Forwarder Ready.\n");
- for (int i = 0; i < controllers.size(); ++i)
- controllers[i]->Join();
+void PrintUsage(const char* program_name) {
+ LOG(ERROR) << program_name << " adb_port:from_port:to_port:to_host\n"
+ "<adb port> is the TCP port Adb is configured to forward to.";
+}
+
+int RunHostForwarder(int argc, char** argv) {
+ if (!CommandLine::Init(argc, argv)) {
+ LOG(ERROR) << "Could not initialize command line";
+ return 1;
+ }
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ std::string command;
+ int adb_port = 0;
+ if (argc != 2) {
+ PrintUsage(argv[0]);
+ return 1;
+ }
+ if (!strcmp(argv[1], "kill-server")) {
+ command = "kill-server";
+ } else {
+ command = "forward";
+ if (!IsForwardCommandValid(argv[1])) {
+ PrintUsage(argv[0]);
+ return 1;
+ }
+ }
+
+ Daemon daemon(kPIDFilePath);
+
+ if (command == "kill-server")
+ return !daemon.Kill();
+
+ bool is_daemon = false;
+ scoped_ptr<Socket> daemon_socket = ConnectToDaemon(
+ kConnectSingleTry, kConnectNoIdleTime);
+ if (!daemon_socket) {
+ if (!daemon.Spawn(&is_daemon))
+ return 1;
+ }
+
+ if (is_daemon)
+ return !DaemonHandler();
+
+ if (!daemon_socket) {
+ const int kTries = 10;
+ const int kIdleTimeMsec = 10;
+ daemon_socket = ConnectToDaemon(kTries, kIdleTimeMsec);
+ if (!daemon_socket) {
+ LOG(ERROR) << "Could not connect to daemon.";
+ return 1;
+ }
+ }
+ // Send the forward command to the daemon.
+ CHECK(daemon_socket->Write(argv[1], strlen(argv[1])));
+ char buf[kBufSize];
+ const int bytes_read = daemon_socket->Read(
+ buf, sizeof(buf) - 1 /* leave space for null terminator */);
+ CHECK_GT(bytes_read, 0);
+ DCHECK(bytes_read < sizeof(buf));
+ buf[bytes_read] = 0;
+ base::StringPiece msg(buf, bytes_read);
+ if (msg.starts_with("ERROR")) {
+ LOG(ERROR) << msg;
+ return 1;
+ }
+ printf("%s\n", buf);
return 0;
}
+
+} // namespace
+} // namespace forwarder2
+
+int main(int argc, char** argv) {
+ return forwarder2::RunHostForwarder(argc, argv);
+}

Powered by Google App Engine
This is Rietveld 408576698