| 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);
|
| +}
|
|
|