Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- source/Plugins/Platform/Android/AdbClient.h +++ source/Plugins/Platform/Android/AdbClient.h @@ -48,10 +48,10 @@ GetDevices (DeviceIDList &device_list); Error - SetPortForwarding (const uint16_t port); + SetPortForwarding (const uint16_t local_port, const uint16_t remote_port); Error - DeletePortForwarding (const uint16_t port); + DeletePortForwarding (const uint16_t local_port); Error PullFile (const FileSpec &remote_file, const FileSpec &local_file); Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- source/Plugins/Platform/Android/AdbClient.cpp +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -131,10 +131,10 @@ } Error -AdbClient::SetPortForwarding (const uint16_t port) +AdbClient::SetPortForwarding (const uint16_t local_port, const uint16_t remote_port) { char message[48]; - snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", port, port); + snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", local_port, remote_port); const auto error = SendDeviceMessage (message); if (error.Fail ()) @@ -144,10 +144,10 @@ } Error -AdbClient::DeletePortForwarding (const uint16_t port) +AdbClient::DeletePortForwarding (const uint16_t local_port) { char message[32]; - snprintf (message, sizeof (message), "killforward:tcp:%d", port); + snprintf (message, sizeof (message), "killforward:tcp:%d", local_port); const auto error = SendDeviceMessage (message); if (error.Fail ()) Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -50,9 +50,13 @@ DeleteForwardPort (lldb::pid_t pid); std::string - MakeServerUrl(const char* scheme, - const char* hostname, - uint16_t port) override; + MakeUrl(const char* scheme, + const char* hostname, + uint16_t port, + const char* path) override; + + Error + SetPortForwarding(const lldb::pid_t pid, const uint16_t remote_port, uint16_t &local_port); private: DISALLOW_COPY_AND_ASSIGN (PlatformAndroidRemoteGDBServer); Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -10,6 +10,7 @@ // Other libraries and framework includes #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/Host/Socket.h" // Project includes #include "AdbClient.h" @@ -25,7 +26,7 @@ static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform static Error -ForwardPortWithAdb (uint16_t port, std::string& device_id) +ForwardPortWithAdb (const uint16_t local_port, const uint16_t remote_port, std::string& device_id) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); @@ -38,14 +39,27 @@ if (log) log->Printf("Connected to Android device \"%s\"", device_id.c_str ()); - return adb.SetPortForwarding(port); + return adb.SetPortForwarding(local_port, remote_port); } static Error -DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id) +DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id) { AdbClient adb (device_id); - return adb.DeletePortForwarding (port); + return adb.DeletePortForwarding (local_port); +} + +static Error +FindUnusedPort (uint16_t& port) +{ + Socket* socket = nullptr; + auto error = Socket::TcpListen ("localhost:0", false, socket, nullptr); + if (error.Success ()) + { + port = socket->GetLocalPortNumber (); + delete socket; + } + return error; } PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer () @@ -61,17 +75,13 @@ uint16_t PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) { - uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); - if (port == 0) - return port; - - Error error = ForwardPortWithAdb(port, m_device_id); - if (error.Fail ()) - return 0; + uint16_t remote_port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); + if (remote_port == 0) + return remote_port; - m_port_forwards[pid] = port; - - return port; + uint16_t local_port = 0; + auto error = SetPortForwarding (pid, remote_port, local_port); + return error.Success() ? local_port : 0; } bool @@ -89,21 +99,28 @@ if (args.GetArgumentCount() != 1) return Error("\"platform connect\" takes a single argument: "); - int port; + int remote_port; std::string scheme, host, path; const char *url = args.GetArgumentAtIndex (0); if (!url) return Error("URL is null."); - if (!UriParser::Parse (url, scheme, host, port, path)) + if (!UriParser::Parse (url, scheme, host, remote_port, path)) return Error("Invalid URL: %s", url); if (scheme == "adb") m_device_id = host; - Error error = ForwardPortWithAdb(port, m_device_id); - if (error.Fail()) + uint16_t local_port = 0; + auto error = SetPortForwarding (g_remote_platform_pid, remote_port, local_port); + if (error.Fail ()) return error; - m_port_forwards[g_remote_platform_pid] = port; + const std::string new_url = MakeUrl( + scheme.c_str(), host.c_str(), local_port, path.c_str()); + args.ReplaceArgumentAtIndex (0, new_url.c_str ()); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Rewritten URL: %s", new_url.c_str()); error = PlatformRemoteGDBServer::ConnectRemote(args); if (error.Fail ()) @@ -138,10 +155,39 @@ m_port_forwards.erase(it); } +Error +PlatformAndroidRemoteGDBServer::SetPortForwarding(const lldb::pid_t pid, + const uint16_t remote_port, + uint16_t &local_port) +{ + static const int kAttempsNum = 5; + + Error error; + // There is a race possibility that somebody will occupy + // a port while we're in between FindUnusedPort and ForwardPortWithAdb - + // adding the loop to mitigate such problem. + for (auto i = 0; i < kAttempsNum; ++i) + { + error = FindUnusedPort(local_port); + if (error.Fail()) + return error; + + error = ForwardPortWithAdb(local_port, remote_port, m_device_id); + if (error.Success()) + { + m_port_forwards[pid] = local_port; + break; + } + } + + return error; +} + std::string -PlatformAndroidRemoteGDBServer::MakeServerUrl(const char* scheme, - const char* hostname, - uint16_t port) +PlatformAndroidRemoteGDBServer::MakeUrl(const char* scheme, + const char* hostname, + uint16_t port, + const char* path) { std::ostringstream hostname_str; if (!strcmp(scheme, "adb")) @@ -149,7 +195,8 @@ else hostname_str << hostname; - return PlatformRemoteGDBServer::MakeServerUrl(scheme, - hostname_str.str().c_str(), - port); + return PlatformRemoteGDBServer::MakeUrl(scheme, + hostname_str.str().c_str(), + port, + path); } Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -235,9 +235,10 @@ KillSpawnedProcess (lldb::pid_t pid); virtual std::string - MakeServerUrl(const char* scheme, - const char* hostname, - uint16_t port); + MakeUrl(const char* scheme, + const char* hostname, + uint16_t port, + const char* path); private: std::string Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -963,17 +963,21 @@ const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; - return MakeServerUrl(override_scheme ? override_scheme : platform_scheme.c_str(), - override_hostname ? override_hostname : platform_hostname.c_str(), - port + port_offset); + return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), + override_hostname ? override_hostname : platform_hostname.c_str(), + port + port_offset, + nullptr); } std::string -PlatformRemoteGDBServer::MakeServerUrl(const char* scheme, +PlatformRemoteGDBServer::MakeUrl(const char* scheme, const char* hostname, - uint16_t port) + uint16_t port, + const char* path) { StreamString result; result.Printf("%s://%s:%u", scheme, hostname, port); + if (path) + result.Write(path, strlen(path)); return result.GetString(); }