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