Modified local spawning in debugserver processes to use a new --reverse-connect option so that debugserver actually connects back to LLDB instead of LLDB connecting to debugserver.

This gets rid of our hacky "get_random_port()" which would grab a random port and tell debugserver to open that port. Now LLDB creates, binds, listens and accepts a connection by binding to port zero and sending the correctly bound port down as the host:port to connect back to.

Fixed the "ConnectionFileDescriptor" to be able to correctly listen for connections from a specified host, localhost, or any host. Prior to this fix "listen://" only accepted the following format:

listen://<port>

But now it can accept:

listen://<port>         // Listen for connection from localhost on port <port>
listen://<host>:<port>  // Listen for connection from <host> and <port>    
listen://*:<port>       // Listen for connection from any host on port <port>

llvm-svn: 196547
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index d53347a..04de58b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -17,6 +17,7 @@
 
 // C++ Includes
 // Other libraries and framework includes
+#include "lldb/Core/ConnectionFileDescriptor.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Core/StreamString.h"
@@ -144,7 +145,9 @@
     m_private_is_running (false),
     m_history (512),
     m_send_acks (true),
-    m_is_platform (is_platform)
+    m_is_platform (is_platform),
+    m_listen_thread (LLDB_INVALID_HOST_THREAD),
+    m_listen_url ()
 {
 }
 
@@ -539,7 +542,56 @@
 }
 
 Error
-GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
+GDBRemoteCommunication::StartListenThread (const char *hostname, in_port_t port)
+{
+    Error error;
+    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
+    {
+        error.SetErrorString("listen thread already running");
+    }
+    else
+    {
+        char listen_url[512];
+        if (hostname && hostname[0])
+            snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname ? hostname : "localhost", port);
+        else
+            snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+        m_listen_url = listen_url;
+        SetConnection(new ConnectionFileDescriptor());
+        m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error);
+    }
+    return error;
+}
+
+bool
+GDBRemoteCommunication::JoinListenThread ()
+{
+    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
+    {
+        Host::ThreadJoin(m_listen_thread, NULL, NULL);
+        m_listen_thread = LLDB_INVALID_HOST_THREAD;
+    }
+    return true;
+}
+
+lldb::thread_result_t
+GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)
+{
+    GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg;
+    Error error;
+    ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection ();
+    
+    if (connection)
+    {
+        // Do the listen on another thread so we can continue on...
+        if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess)
+            comm->SetConnection(NULL);
+    }
+    return NULL;
+}
+
+Error
+GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
                                                  lldb_private::ProcessLaunchInfo &launch_info,
                                                  uint16_t &port)
 {
@@ -594,42 +646,69 @@
         
         // Start args with "debugserver /file/path -r --"
         debugserver_args.AppendArgument(debugserver_path);
-        debugserver_args.AppendArgument(debugserver_url);
+
+        // If a host and port is supplied then use it
+        if (host_and_port)
+            debugserver_args.AppendArgument(host_and_port);
         // use native registers, not the GDB registers
         debugserver_args.AppendArgument("--native-regs");   
         // make debugserver run in its own session so signals generated by 
         // special terminal key sequences (^C) don't affect debugserver
         debugserver_args.AppendArgument("--setsid");
-        
-        char named_pipe_path[PATH_MAX];
-        
-        // Create a temporary file to get the stdout/stderr and redirect the
-        // output of the command into this file. We will later read this file
-        // if all goes well and fill the data into "command_output_ptr"
-        FileSpec tmpdir_file_spec;
-        if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
-        {
-            tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
-            strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
-        }
-        else
-        {
-            strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
-        }
 
-        if (::mktemp (named_pipe_path))
+        char named_pipe_path[PATH_MAX];
+
+        if (host_and_port)
         {
-            if (::mkfifo(named_pipe_path, 0600) == 0)
+            // Create a temporary file to get the stdout/stderr and redirect the
+            // output of the command into this file. We will later read this file
+            // if all goes well and fill the data into "command_output_ptr"
+            FileSpec tmpdir_file_spec;
+            if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
             {
-                debugserver_args.AppendArgument("--named-pipe");
-                debugserver_args.AppendArgument(named_pipe_path);
+                tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
+                strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
+            }
+            else
+            {
+                strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
+            }
+
+            if (::mktemp (named_pipe_path))
+            {
+                if (::mkfifo(named_pipe_path, 0600) == 0)
+                {
+                    debugserver_args.AppendArgument("--named-pipe");
+                    debugserver_args.AppendArgument(named_pipe_path);
+                }
+                else
+                    named_pipe_path[0] = '\0';
             }
             else
                 named_pipe_path[0] = '\0';
         }
         else
+        {
             named_pipe_path[0] = '\0';
+        
+            // No host and port given, so lets listen on our end and make the debugserver
+            // connect to us..
+            error = StartListenThread ("localhost", 0);
+            if (error.Fail())
+                return error;
 
+            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
+            port = connection->GetBoundPort(3);
+            assert (port != 0);
+            char port_cstr[32];
+            snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", port);
+            // Send the host and port down that debugserver and specify an option
+            // so that it connects back to the port we are listening to in this process
+            debugserver_args.AppendArgument("--reverse-connect");
+            debugserver_args.AppendArgument(port_cstr);
+        }
+
+        
         const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
         if (env_debugserver_log_file)
         {
@@ -669,7 +748,11 @@
             }
             Host::Unlink(named_pipe_path);
         }
-
+        else
+        {
+            // Make sure we actually connect with the debugserver...
+            JoinListenThread();
+        }
     }
     else
     {