Support socket activation by fd passing
Client: cpp
Patch: Federico Giovanardi

This closes #3211
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
index 858fffa..dc95af6 100644
--- a/test/cpp/src/TestServer.cpp
+++ b/test/cpp/src/TestServer.cpp
@@ -31,6 +31,7 @@
 #include <thrift/server/TSimpleServer.h>
 #include <thrift/server/TThreadPoolServer.h>
 #include <thrift/server/TThreadedServer.h>
+#include <thrift/transport/PlatformSocket.h>
 #include <thrift/transport/THttpServer.h>
 #include <thrift/transport/THttpTransport.h>
 #include <thrift/transport/TNonblockingSSLServerSocket.h>
@@ -54,14 +55,21 @@
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
 #endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
 
 #include <iostream>
-#include <stdexcept>
+#include <memory>
 #include <sstream>
+#include <stdexcept>
 
 #include <boost/algorithm/string.hpp>
-#include <boost/program_options.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
 
 #if _WIN32
 #include <thrift/windows/TWinsockSingleton.h>
@@ -570,6 +578,47 @@
   std::shared_ptr<TestHandler> _delegate;
 };
 
+struct DomainSocketFd {
+  THRIFT_SOCKET socket_fd;
+  std::string path;
+  DomainSocketFd(const std::string& path) : path(path) {
+#ifdef HAVE_SYS_UN_H
+    unlink(path.c_str());
+    socket_fd = socket(AF_UNIX, SOCK_STREAM, IPPROTO_IP);
+    if (socket_fd == -1) {
+      std::ostringstream os;
+      os << "Cannot create domain socket: " << strerror(errno);
+      throw std::runtime_error(os.str());
+    }
+    if (path.size() > sizeof(sockaddr_un::sun_path) - 1)
+      throw std::runtime_error("Path size on domain socket too big");
+    struct sockaddr_un sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sun_family = AF_UNIX;
+    strcpy(sa.sun_path, path.c_str());
+    int rv = bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa));
+    if (rv == -1) {
+      std::ostringstream os;
+      os << "Cannot bind domain socket: " << strerror(errno);
+      throw std::runtime_error(os.str());
+    }
+
+    rv = ::listen(socket_fd, 16);
+    if (rv == -1) {
+      std::ostringstream os;
+      os << "Cannot listen on domain socket: " << strerror(errno);
+      throw std::runtime_error(os.str());
+    }
+#else
+    throw std::runtime_error("Cannot create a domain socket without AF_UNIX");
+#endif
+  }
+  ~DomainSocketFd() {
+    ::THRIFT_CLOSESOCKET(socket_fd);
+    unlink(path.c_str());
+  }
+};
+
 namespace po = boost::program_options;
 
 int main(int argc, char** argv) {
@@ -589,6 +638,8 @@
   string server_type = "simple";
   string domain_socket = "";
   bool abstract_namespace = false;
+  bool emulate_socketactivation = false;
+  std::unique_ptr<DomainSocketFd> domain_socket_fd;
   size_t workers = 4;
   int string_limit = 0;
   int container_limit = 0;
@@ -599,6 +650,7 @@
     ("port", po::value<int>(&port)->default_value(port), "Port number to listen")
     ("domain-socket", po::value<string>(&domain_socket) ->default_value(domain_socket), "Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)")
     ("abstract-namespace", "Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames)")
+    ("emulate-socketactivation","Open the socket from the tester program and pass the library an already open fd")
     ("server-type", po::value<string>(&server_type)->default_value(server_type), "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"")
     ("transport", po::value<string>(&transport_type)->default_value(transport_type), "transport: buffered, framed, http, websocket, zlib")
     ("protocol", po::value<string>(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json, multi, multic, multih, multij")
@@ -678,6 +730,9 @@
   if (vm.count("abstract-namespace")) {
     abstract_namespace = true;
   }
+  if (vm.count("emulate-socketactivation")) {
+    emulate_socketactivation = true;
+  }
 
   // Dispatcher
   std::shared_ptr<TProtocolFactory> protocolFactory;
@@ -727,8 +782,16 @@
         abstract_socket += domain_socket;
         serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(abstract_socket));
       } else {
-        unlink(domain_socket.c_str());
-        serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(domain_socket));
+        if (emulate_socketactivation) {
+          unlink(domain_socket.c_str());
+          // open and bind the socket
+          domain_socket_fd.reset(new DomainSocketFd(domain_socket));
+          serverSocket = std::shared_ptr<TServerSocket>(
+              new TServerSocket(domain_socket_fd->socket_fd, SocketType::UNIX));
+        } else {
+          unlink(domain_socket.c_str());
+          serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(domain_socket));
+        }
       }
       port = 0;
     } else {