Enables several ports in socket_forward_proxy host

Replaces --port with --ports as a comma-separated list of ports

BUG: 72654144
Change-Id: I3137bd11e602cd0d2e8c1bb63fd7c2ac2f8a7b1d
diff --git a/common/frontend/socket_forward_proxy/main.cpp b/common/frontend/socket_forward_proxy/main.cpp
index f9837fc..6022d41 100644
--- a/common/frontend/socket_forward_proxy/main.cpp
+++ b/common/frontend/socket_forward_proxy/main.cpp
@@ -19,8 +19,10 @@
 #include <iostream>
 #include <memory>
 #include <mutex>
+#include <sstream>
 #include <string>
 #include <thread>
+#include <vector>
 #include <glog/logging.h>
 #include <gflags/gflags.h>
 
@@ -36,9 +38,10 @@
 using vsoc::socket_forward::Packet;
 using vsoc::socket_forward::SocketForwardRegionView;
 
-// TODO(haining) accept multiple ports
 #ifdef CUTTLEFISH_HOST
-DEFINE_uint32(port, 0, "Port from which to forward TCP connections.");
+DEFINE_string(ports, "",
+              "Comma-separated list of ports from which to forward TCP "
+              "connections.");
 #endif
 
 namespace {
@@ -151,7 +154,15 @@
 }
 
 #ifdef CUTTLEFISH_HOST
-[[noreturn]] void host(SocketForwardRegionView* shm, int port) {
+[[noreturn]] void host_impl(SocketForwardRegionView* shm,
+                            std::vector<int> ports, std::size_t index) {
+  // launch a worker for the following port before handling the current port.
+  // recursion (instead of a loop) removes the need fore any join() or having
+  // the main thread do no work.
+  if (index + 1 < ports.size()) {
+    std::thread(host_impl, shm, ports, index + 1).detach();
+  }
+  auto port = ports[index];
   LOG(INFO) << "starting server on " << port;
   auto server = cvd::SharedFD::SocketLocalServer(port, SOCK_STREAM);
   CHECK(server->IsOpen()) << "Could not start server on port " << port;
@@ -164,6 +175,23 @@
     LaunchWorkers(std::move(conn), std::move(client_socket));
   }
 }
+
+[[noreturn]] void host(SocketForwardRegionView* shm,
+                           std::vector<int> ports) {
+  CHECK(!ports.empty());
+  host_impl(shm, ports, 0);
+}
+
+std::vector<int> ParsePortsList(const std::string& ports_flag) {
+  std::istringstream ports_stream{ports_flag};
+  std::vector<int> ports;
+  std::string port_str{};
+  while (std::getline(ports_stream, port_str, ',')) {
+    ports.push_back(std::stoi(port_str));
+  }
+  return ports;
+}
+
 #else
 [[noreturn]] void guest(SocketForwardRegionView* shm) {
   LOG(INFO) << "Starting guest mainloop";
@@ -210,8 +238,8 @@
   auto worker = shm->StartWorker();
 
 #ifdef CUTTLEFISH_HOST
-  CHECK_NE(FLAGS_port, 0u) << "Must specify --port flag";
-  host(shm, FLAGS_port);
+  CHECK(!FLAGS_ports.empty()) << "Must specify --ports flag";
+  host(shm, ParsePortsList(FLAGS_ports));
 #else
   guest(shm);
 #endif
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index a2930e3..eb172b5 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -120,8 +120,8 @@
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
                   "/bin/socket_forward_proxy",
               "Location of the socket_forward_proxy binary.");
-DEFINE_int32(socket_forward_proxy_port, 5555, "port on which to run the "
-             "socket_forward_proxy server");
+DEFINE_string(socket_forward_proxy_ports, "5555", "Comma-separated list of "
+              "ports on which to run the socket_forward_proxy server");
 
 DECLARE_string(uuid);
 
@@ -412,8 +412,7 @@
 
   std::string entropy_source = "/dev/urandom";
 
-  auto port_arg = std::string{"--port="} +
-    std::to_string(FLAGS_socket_forward_proxy_port);
+  auto port_arg = std::string{"--ports="} + FLAGS_socket_forward_proxy_ports;
   const char* const socket_proxy[] =
     {FLAGS_socket_forward_proxy_binary.c_str(), port_arg.c_str(), NULL};
   subprocess(socket_proxy, nullptr, false);