Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -103,6 +103,8 @@ 2579065C1BD0488100178368 /* TCPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065A1BD0488100178368 /* TCPSocket.cpp */; }; 2579065D1BD0488100178368 /* UDPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065B1BD0488100178368 /* UDPSocket.cpp */; }; 2579065F1BD0488D00178368 /* DomainSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2579065E1BD0488D00178368 /* DomainSocket.cpp */; }; + 257906641BD5AFD000178368 /* Acceptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257906621BD5AFD000178368 /* Acceptor.cpp */; }; + 257906651BD5AFD000178368 /* Acceptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 257906631BD5AFD000178368 /* Acceptor.h */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -1207,6 +1209,8 @@ 2579065A1BD0488100178368 /* TCPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TCPSocket.cpp; sourceTree = ""; }; 2579065B1BD0488100178368 /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = ""; }; 2579065E1BD0488D00178368 /* DomainSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DomainSocket.cpp; sourceTree = ""; }; + 257906621BD5AFD000178368 /* Acceptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acceptor.cpp; path = "tools/lldb-server/Acceptor.cpp"; sourceTree = ""; }; + 257906631BD5AFD000178368 /* Acceptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Acceptor.h; path = "tools/lldb-server/Acceptor.h"; sourceTree = ""; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; @@ -5588,6 +5592,8 @@ E769331B1A94D10E00C73337 /* lldb-server */ = { isa = PBXGroup; children = ( + 257906621BD5AFD000178368 /* Acceptor.cpp */, + 257906631BD5AFD000178368 /* Acceptor.h */, 6D762BEC1B1605CD006C929D /* LLDBServerUtilities.cpp */, 6D762BED1B1605CD006C929D /* LLDBServerUtilities.h */, E769331D1A94D18100C73337 /* lldb-server.cpp */, @@ -5703,6 +5709,7 @@ buildActionMask = 2147483647; files = ( 4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */, + 257906651BD5AFD000178368 /* Acceptor.h in Headers */, 260A63171861008E00FECF8E /* IOHandler.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6539,6 +6546,7 @@ 268900E513353E6F00698AC0 /* UnwindTable.cpp in Sources */, 268900E613353E6F00698AC0 /* Variable.cpp in Sources */, 268900E713353E6F00698AC0 /* VariableList.cpp in Sources */, + 257906641BD5AFD000178368 /* Acceptor.cpp in Sources */, 268900E813353E6F00698AC0 /* ABI.cpp in Sources */, 4C56543119D1EFAA002E9C44 /* ThreadPlanPython.cpp in Sources */, 26AB92121819D74600E63F3E /* DWARFDataExtractor.cpp in Sources */, Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp =================================================================== --- source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -50,8 +50,6 @@ #include "lldb/Host/common/TCPSocket.h" #include "lldb/Interpreter/Args.h" -#include "Utility/UriParser.h" - using namespace lldb; using namespace lldb_private; @@ -171,20 +169,6 @@ // unix://SOCKNAME return NamedSocketAccept(s + strlen("unix-accept://"), error_ptr); } - else if (strstr(s, "adb://") == s) - { - int port = -1; - std::string scheme, host, path; - if (!UriParser::Parse(s, scheme, host, port, path)) - { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("Failed to parse URL '%s'", s); - return eConnectionStatusError; - } - std::ostringstream host_and_port; - host_and_port << "localhost:" << port; - return ConnectTCP(host_and_port.str().c_str(), error_ptr); - } else if (strstr(s, "connect://") == s) { return ConnectTCP(s + strlen("connect://"), error_ptr); @@ -197,6 +181,11 @@ { return ConnectUDP(s + strlen("udp://"), error_ptr); } + else if (strstr(s, "unix-connect://") == s) + { + // unix-connect://SOCKNAME + return NamedSocketConnect(s + strlen("unix-connect://"), error_ptr); + } #ifndef LLDB_DISABLE_POSIX else if (strstr(s, "fd://") == s) { Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- source/Plugins/Platform/Android/AdbClient.h +++ source/Plugins/Platform/Android/AdbClient.h @@ -51,6 +51,9 @@ SetPortForwarding (const uint16_t local_port, const uint16_t remote_port); Error + SetPortForwarding (const uint16_t local_port, const char* remote_socket_name); + + Error DeletePortForwarding (const uint16_t local_port); Error Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- source/Plugins/Platform/Android/AdbClient.cpp +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -145,6 +145,19 @@ } Error +AdbClient::SetPortForwarding (const uint16_t local_port, const char* remote_socket_name) +{ + char message[PATH_MAX]; + snprintf (message, sizeof (message), "forward:tcp:%d;localfilesystem:%s", local_port, remote_socket_name); + + const auto error = SendDeviceMessage (message); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error AdbClient::DeletePortForwarding (const uint16_t local_port) { char message[32]; Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.cpp +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -196,8 +196,7 @@ return Error("URL is null."); if (!UriParser::Parse(url, scheme, host, port, path)) return Error("Invalid URL: %s", url); - if (scheme == "adb") - m_device_id = host; + m_device_id = host; auto error = PlatformLinux::ConnectRemote(args); if (error.Success()) Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -40,8 +40,8 @@ std::string m_device_id; std::map m_port_forwards; - uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid) override; + bool + LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) override; bool KillSpawnedProcess (lldb::pid_t pid) override; @@ -49,14 +49,11 @@ void DeleteForwardPort (lldb::pid_t pid); - std::string - 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); + MakeConnectURL(const lldb::pid_t pid, + const uint16_t remote_port, + const char* remote_socket_name, + std::string& connect_url); 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 @@ -24,7 +24,10 @@ static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform static Error -ForwardPortWithAdb (const uint16_t local_port, const uint16_t remote_port, std::string& device_id) +ForwardPortWithAdb (const uint16_t local_port, + const uint16_t remote_port, + const char* remote_socket_name, + std::string& device_id) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); @@ -37,7 +40,16 @@ if (log) log->Printf("Connected to Android device \"%s\"", device_id.c_str ()); - return adb.SetPortForwarding(local_port, remote_port); + if (remote_port != 0) + { + if (log) + log->Printf("Forwarding remote TCP port %d to local TCP port %d", remote_port, local_port); + return adb.SetPortForwarding(local_port, remote_port); + } + + if (log) + log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port); + return adb.SetPortForwarding(local_port, remote_socket_name); } static Error @@ -72,16 +84,24 @@ DeleteForwardPortWithAdb(it.second, m_device_id); } -uint16_t -PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +bool +PlatformAndroidRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) { - uint16_t remote_port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); - if (remote_port == 0) - return remote_port; + uint16_t remote_port = 0; + std::string socket_name; + if (!m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, remote_port, socket_name)) + return false; - uint16_t local_port = 0; - auto error = SetPortForwarding (pid, remote_port, local_port); - return error.Success() ? local_port : 0; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + auto error = MakeConnectURL (pid, + remote_port, + socket_name.c_str (), + connect_url); + if (error.Success() && log) + log->Printf("gdbserver connect URL: %s", connect_url.c_str()); + + return error.Success(); } bool @@ -106,21 +126,22 @@ return Error("URL is null."); if (!UriParser::Parse (url, scheme, host, remote_port, path)) return Error("Invalid URL: %s", url); - if (scheme == "adb") - m_device_id = host; + m_device_id = host; + + std::string connect_url; + auto error = MakeConnectURL (g_remote_platform_pid, + (remote_port < 0) ? 0 : remote_port, + path.c_str (), + connect_url); - uint16_t local_port = 0; - auto error = SetPortForwarding (g_remote_platform_pid, remote_port, local_port); if (error.Fail ()) return error; - const std::string new_url = MakeUrl( - scheme.c_str(), host.c_str(), local_port, path.c_str()); - args.ReplaceArgumentAtIndex (0, new_url.c_str ()); + args.ReplaceArgumentAtIndex (0, connect_url.c_str ()); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) - log->Printf("Rewritten URL: %s", new_url.c_str()); + log->Printf("Rewritten platform connect URL: %s", connect_url.c_str()); error = PlatformRemoteGDBServer::ConnectRemote(args); if (error.Fail ()) @@ -156,9 +177,10 @@ } Error -PlatformAndroidRemoteGDBServer::SetPortForwarding(const lldb::pid_t pid, - const uint16_t remote_port, - uint16_t &local_port) +PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, + const uint16_t remote_port, + const char* remote_socket_name, + std::string& connect_url) { static const int kAttempsNum = 5; @@ -168,35 +190,21 @@ // adding the loop to mitigate such problem. for (auto i = 0; i < kAttempsNum; ++i) { + uint16_t local_port = 0; error = FindUnusedPort(local_port); if (error.Fail()) return error; - error = ForwardPortWithAdb(local_port, remote_port, m_device_id); + error = ForwardPortWithAdb(local_port, remote_port, remote_socket_name, m_device_id); if (error.Success()) { m_port_forwards[pid] = local_port; + std::ostringstream url_str; + url_str << "connect://localhost:" << local_port; + connect_url = url_str.str(); break; } } return error; } - -std::string -PlatformAndroidRemoteGDBServer::MakeUrl(const char* scheme, - const char* hostname, - uint16_t port, - const char* path) -{ - std::ostringstream hostname_str; - if (!strcmp(scheme, "adb")) - hostname_str << "[" << hostname << "]"; - else - hostname_str << hostname; - - 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 @@ -225,11 +225,12 @@ lldb::UnixSignalsSP m_remote_signals_sp; - // Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on - // failure. Subclasses should override this method if they want to do extra actions before or - // after launching the lldb-gdbserver. - virtual uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid); + // Launch the debug server on the remote host - caller connects to launched + // debug server using connect_url. + // Subclasses should override this method if they want to do extra actions before or + // after launching the debug server. + virtual bool + LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url); virtual bool KillSpawnedProcess (lldb::pid_t pid); @@ -244,7 +245,8 @@ std::string MakeGdbServerUrl(const std::string &platform_scheme, const std::string &platform_hostname, - uint16_t port); + uint16_t port, + const char* socket_name); DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer); Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -34,6 +34,10 @@ #include "Plugins/Process/Utility/GDBRemoteSignals.h" +#include +#include +#include + using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_gdb_server; @@ -573,9 +577,8 @@ if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); - - if (port == 0) + std::string connect_url; + if (!LaunchGDBServer(debugserver_pid, connect_url)) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } @@ -606,8 +609,6 @@ if (process_sp) { - std::string connect_url = - MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port); error = process_sp->ConnectRemote (nullptr, connect_url.c_str()); // Retry the connect remote one time... if (error.Fail()) @@ -632,23 +633,36 @@ } -uint16_t -PlatformRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +bool +PlatformRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) { ArchSpec remote_arch = GetRemoteSystemArchitecture (); llvm::Triple &remote_triple = remote_arch.GetTriple (); + + uint16_t port = 0; + std::string socket_name; + bool launch_result = false; if (remote_triple.getVendor () == llvm::Triple::Apple && remote_triple.getOS () == llvm::Triple::IOS) { // When remote debugging to iOS, we use a USB mux that always talks // to localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is - return m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); + launch_result = m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, port, socket_name); } else { // All other hosts should use their actual hostname - return m_gdb_client.LaunchGDBserverAndGetPort (pid, NULL); + launch_result = m_gdb_client.LaunchGDBServer (nullptr, pid, port, socket_name); } + + if (!launch_result) + return false; + + connect_url = MakeGdbServerUrl(m_platform_scheme, + m_platform_hostname, + port, + (socket_name.empty()) ? nullptr : socket_name.c_str()); + return true; } bool @@ -669,9 +683,8 @@ if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); - - if (port == 0) + std::string connect_url; + if (!LaunchGDBServer(debugserver_pid, connect_url)) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } @@ -699,11 +712,8 @@ // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); - if (process_sp) { - std::string connect_url = - MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port); error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); if (error.Success()) { @@ -950,7 +960,8 @@ std::string PlatformRemoteGDBServer::MakeGdbServerUrl(const std::string &platform_scheme, const std::string &platform_hostname, - uint16_t port) + uint16_t port, + const char* socket_name) { const char *override_scheme = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); @@ -960,17 +971,19 @@ return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), override_hostname ? override_hostname : platform_hostname.c_str(), port + port_offset, - nullptr); + socket_name); } std::string PlatformRemoteGDBServer::MakeUrl(const char* scheme, - const char* hostname, - uint16_t port, - const char* path) + const char* hostname, + uint16_t port, + const char* path) { StreamString result; - result.Printf("%s://%s:%u", scheme, hostname, port); + result.Printf("%s://%s", scheme, hostname); + if (port != 0) + result.Printf(":%u", port); if (path) result.Write(path, strlen(path)); return result.GetString(); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -167,11 +167,10 @@ // supplied connection URL. //------------------------------------------------------------------ Error - StartDebugserverProcess (const char *hostname, - uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit + StartDebugserverProcess (const char *url, Platform *platform, // If non NULL, then check with the platform for the GDB server binary if it can't be located ProcessLaunchInfo &launch_info, - uint16_t &out_port); + uint16_t *port); void DumpHistory(Stream &strm); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1112,17 +1112,15 @@ } Error -GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, - uint16_t in_port, +GDBRemoteCommunication::StartDebugserverProcess (const char *url, Platform *platform, ProcessLaunchInfo &launch_info, - uint16_t &out_port) + uint16_t *port) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) - log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "", in_port, out_port); + log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16, __FUNCTION__, url ? url : "", port ? *port : uint16_t(0)); - out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; @@ -1193,17 +1191,9 @@ debugserver_args.AppendArgument("gdbserver"); #endif - // If a host and port is supplied then use it - char host_and_port[128]; - if (hostname) - { - snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); - debugserver_args.AppendArgument(host_and_port); - } - else - { - host_and_port[0] = '\0'; - } + // If a url is supplied then use it + if (url) + debugserver_args.AppendArgument(url); // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); @@ -1214,11 +1204,18 @@ } llvm::SmallString named_pipe_path; - Pipe port_pipe; - - if (in_port == 0) + // socket_pipe is used by debug server to communicate back either + // TCP port or domain socket name which it listens on. + // The second purpose of the pipe to serve as a synchronization point - + // once data is written to the pipe, debug server is up and running. + Pipe socket_pipe; + + // port is null when debug server should listen on domain socket - + // we're not interested in port value but rather waiting for debug server + // to become available. + if ((port != nullptr && *port == 0) || port == nullptr) { - if (host_and_port[0]) + if (url) { // 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 @@ -1227,7 +1224,7 @@ #if defined(__APPLE__) // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... - error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); + error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); if (error.Fail()) { if (log) @@ -1241,7 +1238,7 @@ #else // Binding to port zero, we need to figure out what port it ends up // using using an unnamed pipe... - error = port_pipe.CreateNew(true); + error = socket_pipe.CreateNew(true); if (error.Fail()) { if (log) @@ -1250,10 +1247,10 @@ __FUNCTION__, error.AsCString()); return error; } - int write_fd = port_pipe.GetWriteFileDescriptor(); + int write_fd = socket_pipe.GetWriteFileDescriptor(); debugserver_args.AppendArgument("--pipe"); debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); - launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); + launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif } else @@ -1270,11 +1267,11 @@ ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); // Wait for 10 seconds to resolve the bound port - out_port = connection->GetListeningPort(10); - if (out_port > 0) + *port = connection->GetListeningPort(10); + if (*port > 0) { char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); + snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%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"); @@ -1343,11 +1340,12 @@ error = Host::LaunchProcess(launch_info); - if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + if (error.Success() && + launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { if (named_pipe_path.size() > 0) { - error = port_pipe.OpenAsReader(named_pipe_path, false); + error = socket_pipe.OpenAsReader(named_pipe_path, false); if (error.Fail()) if (log) log->Printf("GDBRemoteCommunication::%s() " @@ -1355,24 +1353,24 @@ __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } - if (port_pipe.CanWrite()) - port_pipe.CloseWriteFileDescriptor(); - if (port_pipe.CanRead()) + if (socket_pipe.CanWrite()) + socket_pipe.CloseWriteFileDescriptor(); + if (socket_pipe.CanRead()) { - char port_cstr[256]; + char port_cstr[PATH_MAX] = {0}; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); // Read port from pipe with 10 second timeout. - error = port_pipe.ReadWithTimeout(port_cstr, num_bytes, + error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); - if (error.Success()) + if (error.Success() && (port != nullptr)) { assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - out_port = StringConvert::ToUInt32(port_cstr, 0); + *port = StringConvert::ToUInt32(port_cstr, 0); if (log) log->Printf("GDBRemoteCommunication::%s() " - "debugserver listens %u port", - __FUNCTION__, out_port); + "debugserver listens %u port", + __FUNCTION__, *port); } else { @@ -1382,12 +1380,12 @@ __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } - port_pipe.Close(); + socket_pipe.Close(); } if (named_pipe_path.size() > 0) { - const auto err = port_pipe.Delete(named_pipe_path); + const auto err = socket_pipe.Delete(named_pipe_path); if (err.Fail()) { if (log) Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -114,8 +114,11 @@ bool GetLaunchSuccess (std::string &error_str); - uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname); + bool + LaunchGDBServer (const char *remote_accept_hostname, + lldb::pid_t &pid, + uint16_t &port, + std::string &socket_name); bool KillSpawnedProcess (lldb::pid_t pid); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3315,10 +3315,16 @@ return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; } -uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname) +bool +GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostname, + lldb::pid_t &pid, + uint16_t &port, + std::string &socket_name) { pid = LLDB_INVALID_PROCESS_ID; + port = 0; + socket_name.clear(); + StringExtractorGDBRemote response; StreamString stream; stream.PutCString("qLaunchGDBServer;"); @@ -3343,22 +3349,30 @@ // give the process a few seconds to startup GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); - + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; - uint16_t port = 0; + StringExtractor extractor; while (response.GetNameColonValue(name, value)) { if (name.compare("port") == 0) port = StringConvert::ToUInt32(value.c_str(), 0, 0); else if (name.compare("pid") == 0) pid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); + else if (name.compare("socket_name") == 0) + { + extractor.GetStringRef().swap(value); + extractor.SetFilePos(0); + extractor.GetHexByteString(value); + + socket_name = value; + } } - return port; + return true; } - return 0; + return false; } bool Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -12,6 +12,8 @@ #include "GDBRemoteCommunicationServerCommon.h" +#include "lldb/Host/Socket.h" + #include namespace lldb_private { @@ -23,7 +25,7 @@ public: typedef std::map PortMap; - GDBRemoteCommunicationServerPlatform(); + GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol); virtual ~GDBRemoteCommunicationServerPlatform(); @@ -61,6 +63,7 @@ SetPortOffset (uint16_t port_offset); protected: + const Socket::SocketProtocol m_socket_protocol; Mutex m_spawned_pids_mutex; std::set m_spawned_pids; lldb::PlatformSP m_platform_sp; @@ -103,6 +106,12 @@ int signal, int status); + static const FileSpec& + GetDomainSocketDir(); + + static FileSpec + GetDomainSocketPath(const char* prefix); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServerPlatform only //------------------------------------------------------------------ Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -15,14 +15,20 @@ // C++ Includes #include #include +#include +#include // Other libraries and framework includes +#include "llvm/Support/FileSystem.h" + #include "lldb/Core/Log.h" +#include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StructuredData.h" #include "lldb/Host/Config.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" @@ -40,8 +46,9 @@ //---------------------------------------------------------------------- // GDBRemoteCommunicationServerPlatform constructor //---------------------------------------------------------------------- -GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() : +GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const Socket::SocketProtocol socket_protocol) : GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"), + m_socket_protocol(socket_protocol), m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_platform_sp (Platform::GetHostPlatform ()), m_port_map (), @@ -138,11 +145,24 @@ bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path); UNUSED_IF_ASSERT_DISABLED(ok); assert(ok); - Error error = StartDebugserverProcess (platform_ip.c_str(), - port, + + std::string socket_name; + std::ostringstream url; + + uint16_t* port_ptr = &port; + if (m_socket_protocol == Socket::ProtocolTcp) + url << platform_ip << ":" << port; + else + { + socket_name = GetDomainSocketPath("gdbserver").GetPath(); + url << socket_name; + port_ptr = nullptr; + } + + Error error = StartDebugserverProcess (url.str().c_str(), nullptr, debugserver_launch_info, - port); + port_ptr); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -165,11 +185,16 @@ if (log) log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < (int)sizeof(response)); - PacketResult packet_result = SendPacketNoLock (response, response_len); + StreamGDBRemote response; + response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + if (!socket_name.empty()) + { + response.PutCString("socket_name:"); + response.PutCStringAsRawHex8(socket_name.c_str()); + response.PutChar(';'); + } + PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) @@ -494,6 +519,36 @@ return false; } +const FileSpec& +GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() +{ + static FileSpec g_domainsocket_dir; + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + const char* domainsocket_dir_env = ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); + if (domainsocket_dir_env != nullptr) + g_domainsocket_dir = FileSpec(domainsocket_dir_env, false); + else + HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, g_domainsocket_dir); + }); + + return g_domainsocket_dir; +} + +FileSpec +GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix) +{ + llvm::SmallString socket_path; + llvm::SmallString socket_name((llvm::StringRef(prefix) + ".%%%%%%").str()); + + FileSpec socket_path_spec(GetDomainSocketDir()); + socket_path_spec.AppendPathComponent(socket_name.c_str()); + + llvm::sys::fs::createUniqueFile(socket_path_spec.GetCString(), socket_path); + return FileSpec(socket_path.c_str(), false); +} + void GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset) { Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -3562,15 +3562,22 @@ // Set hostname being NULL to do the reverse connect where debugserver // will bind to port zero and it will communicate back to us the port // that we will connect to - const char *hostname = NULL; + const char *hostname = nullptr; uint16_t port = 0; #endif - error = m_gdb_comm.StartDebugserverProcess (hostname, - port, + StreamString url_str; + const char* url = nullptr; + if (hostname != nullptr) + { + url_str.Printf("%s:%u", hostname, port); + url = url_str.GetData(); + } + + error = m_gdb_comm.StartDebugserverProcess (url, GetTarget().GetPlatform().get(), debugserver_launch_info, - port); + &port); if (error.Success ()) m_debugserver_pid = debugserver_launch_info.GetProcessID(); Index: tools/lldb-server/Acceptor.h =================================================================== --- /dev/null +++ tools/lldb-server/Acceptor.h @@ -0,0 +1,63 @@ +//===-- Acceptor.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef lldb_server_Acceptor_h_ +#define lldb_server_Acceptor_h_ + +#include "lldb/Core/Connection.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/Socket.h" + +#include +#include +#include + +namespace llvm +{ + class StringRef; +} + +namespace lldb_private { +namespace lldb_server { + +class Acceptor +{ +public: + virtual ~Acceptor() = default; + + Error + Listen(int backlog); + + Error + Accept(const bool child_processes_inherit, Connection *&conn); + + static std::unique_ptr + Create(llvm::StringRef name, const bool child_processes_inherit, Error &error); + + Socket::SocketProtocol GetSocketProtocol() const; + + // Returns either TCP port number as string or domain socket path. + // Empty string is returned in case of error. + std::string GetLocalSocketId() const; + +private: + typedef std::function LocalSocketIdFunc; + + Acceptor(std::unique_ptr &&listener_socket, + llvm::StringRef name, + const LocalSocketIdFunc &local_socket_id); + + const std::unique_ptr m_listener_socket_up; + const std::string m_name; + const LocalSocketIdFunc m_local_socket_id; +}; + +} // namespace lldb_server +} // namespace lldb_private + +#endif // lldb_server_Acceptor_h_ Index: tools/lldb-server/Acceptor.cpp =================================================================== --- /dev/null +++ tools/lldb-server/Acceptor.cpp @@ -0,0 +1,98 @@ +//===-- Acceptor.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Acceptor.h" + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/posix/DomainSocket.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::lldb_server; +using namespace llvm; + +Error +Acceptor::Listen(int backlog) +{ + return m_listener_socket_up->Listen(StringRef(m_name.c_str()), + backlog); +} + +Error +Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) +{ + Socket* conn_socket = nullptr; + auto error = m_listener_socket_up->Accept(StringRef(m_name.c_str()), + child_processes_inherit, + conn_socket); + if (error.Success()) + conn = new ConnectionFileDescriptor(conn_socket); + + return error; +} + +Socket::SocketProtocol +Acceptor::GetSocketProtocol() const +{ + return m_listener_socket_up->GetSocketProtocol(); +} + +std::string +Acceptor::GetLocalSocketId() const +{ + return m_local_socket_id(); +} + +std::unique_ptr +Acceptor::Create(StringRef name, const bool child_processes_inherit, Error &error) +{ + error.Clear(); + + LocalSocketIdFunc local_socket_id; + std::unique_ptr listener_socket = nullptr; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (Socket::DecodeHostAndPort (name, host_str, port_str, port, &error)) + { + auto tcp_socket = new TCPSocket(child_processes_inherit, error); + local_socket_id = [tcp_socket]() { + auto local_port = tcp_socket->GetLocalPortNumber(); + return (local_port != 0) ? std::to_string(local_port) : ""; + }; + listener_socket.reset(tcp_socket); + } + else + { + const std::string socket_name = name; + local_socket_id = [socket_name](){ + return socket_name; + }; + listener_socket.reset(new DomainSocket(child_processes_inherit, error)); + } + + if (error.Success()) + return std::unique_ptr( + new Acceptor(std::move(listener_socket), name, local_socket_id)); + + return std::unique_ptr(); +} + +Acceptor::Acceptor(std::unique_ptr &&listener_socket, + StringRef name, + const LocalSocketIdFunc &local_socket_id) + : m_listener_socket_up(std::move(listener_socket)), + m_name(name.str()), + m_local_socket_id(local_socket_id) +{ +} Index: tools/lldb-server/CMakeLists.txt =================================================================== --- tools/lldb-server/CMakeLists.txt +++ tools/lldb-server/CMakeLists.txt @@ -18,24 +18,18 @@ include(../../cmake/LLDBDependencies.cmake) -if (BUILD_SHARED_LIBS ) - add_lldb_executable(lldb-server +add_lldb_executable(lldb-server + Acceptor.cpp lldb-gdbserver.cpp lldb-platform.cpp lldb-server.cpp LLDBServerUtilities.cpp - ) +) +if (BUILD_SHARED_LIBS ) target_link_libraries(lldb-server liblldb) target_link_libraries(lldb-server ${LLDB_SYSTEM_LIBS}) else() - add_lldb_executable(lldb-server - lldb-gdbserver.cpp - lldb-platform.cpp - lldb-server.cpp - LLDBServerUtilities.cpp - ) - # The Darwin linker doesn't understand --start-group/--end-group. if (LLDB_LINKER_SUPPORTS_GROUPS) target_link_libraries(lldb-server Index: tools/lldb-server/lldb-gdbserver.cpp =================================================================== --- tools/lldb-server/lldb-gdbserver.cpp +++ tools/lldb-server/lldb-gdbserver.cpp @@ -24,18 +24,16 @@ // Other libraries and framework includes #include "llvm/ADT/StringRef.h" -#include "lldb/Core/ConnectionMachPort.h" #include "lldb/Core/Error.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/HostGetOpt.h" -#include "lldb/Host/HostThread.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/Platform.h" +#include "Acceptor.h" #include "LLDBServerUtilities.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" @@ -54,15 +52,6 @@ using namespace lldb_private::lldb_server; using namespace lldb_private::process_gdb_remote; -// lldb-gdbserver state - -namespace -{ -HostThread s_listen_thread; - std::unique_ptr s_listen_connection_up; - std::string s_listen_url; -} - //---------------------------------------------------------------------- // option descriptors for getopt_long_only() //---------------------------------------------------------------------- @@ -263,64 +252,16 @@ } } -static lldb::thread_result_t -ListenThread (lldb::thread_arg_t /* arg */) -{ - Error error; - - if (s_listen_connection_up) - { - // Do the listen on another thread so we can continue on... - if (s_listen_connection_up->Connect(s_listen_url.c_str(), &error) != eConnectionStatusSuccess) - s_listen_connection_up.reset(); - } - return nullptr; -} - -static Error -StartListenThread (const char *hostname, uint16_t port) -{ - Error error; - if (s_listen_thread.IsJoinable()) - { - 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, port); - else - snprintf(listen_url, sizeof(listen_url), "listen://%i", port); - - s_listen_url = listen_url; - s_listen_connection_up.reset (new ConnectionFileDescriptor ()); - s_listen_thread = ThreadLauncher::LaunchThread(listen_url, ListenThread, nullptr, &error); - } - return error; -} - -static bool -JoinListenThread () -{ - if (s_listen_thread.IsJoinable()) - s_listen_thread.Join(nullptr); - return true; -} - Error -WritePortToPipe(Pipe &port_pipe, const uint16_t port) +writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) { - char port_str[64]; - const auto port_str_len = ::snprintf(port_str, sizeof(port_str), "%u", port); - size_t bytes_written = 0; // Write the port number as a C string with the NULL terminator. - return port_pipe.Write(port_str, port_str_len + 1, bytes_written); + return port_pipe.Write(socket_id.c_str(), socket_id.size(), bytes_written); } Error -writePortToPipe(const char *const named_pipe_path, const uint16_t port) +writeSocketIdToPipe(const char *const named_pipe_path, const std::string &socket_id) { Pipe port_name_pipe; // Wait for 10 seconds for pipe to be opened. @@ -328,17 +269,17 @@ std::chrono::seconds{10}); if (error.Fail()) return error; - return WritePortToPipe(port_name_pipe, port); + return writeSocketIdToPipe(port_name_pipe, socket_id); } Error -writePortToPipe(int unnamed_pipe_fd, const uint16_t port) +writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) { #if defined(_WIN32) return Error("Unnamed pipes are not supported on Windows."); #else Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd}; - return WritePortToPipe(port_pipe, port); + return writeSocketIdToPipe(port_pipe, socket_id); #endif } @@ -370,14 +311,8 @@ connection_port = final_host_and_port.substr (colon_pos + 1); connection_portno = StringConvert::ToUInt32 (connection_port.c_str (), 0); } - else - { - fprintf (stderr, "failed to parse host and port from connection string '%s'\n", final_host_and_port.c_str ()); - display_usage (progname, subcommand); - exit (1); - } - std::unique_ptr connection_up; + std::unique_ptr connection_up; if (reverse_connect) { @@ -410,66 +345,51 @@ } else { - // llgs will listen for connections on the given port from the given address. - // Start the listener on a new thread. We need to do this so we can resolve the - // bound listener port. - StartListenThread(connection_host.c_str (), static_cast (connection_portno)); - printf ("Listening to port %s for a connection from %s...\n", connection_port.c_str (), connection_host.c_str ()); - - // If we have a named pipe to write the port number back to, do that now. - if (named_pipe_path && named_pipe_path[0] && connection_portno == 0) + std::unique_ptr acceptor_up(Acceptor::Create(final_host_and_port, false, error)); + if (error.Fail()) + { + fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); + exit(1); + } + error = acceptor_up->Listen(1); + if (error.Fail()) { - const uint16_t bound_port = s_listen_connection_up->GetListeningPort (10); - if (bound_port > 0) + fprintf(stderr, "failed to listen: %s\n", error.AsCString()); + exit(1); + } + const std::string socket_id = acceptor_up->GetLocalSocketId(); + if (!socket_id.empty()) + { + // If we have a named pipe to write the socket id back to, do that now. + if (named_pipe_path && named_pipe_path[0]) { - error = writePortToPipe (named_pipe_path, bound_port); + error = writeSocketIdToPipe (named_pipe_path, socket_id); if (error.Fail ()) - { - fprintf (stderr, "failed to write to the named pipe \'%s\': %s", named_pipe_path, error.AsCString()); - } + fprintf (stderr, "failed to write to the named pipe \'%s\': %s", + named_pipe_path, error.AsCString()); } - else + // If we have an unnamed pipe to write the socket id back to, do that now. + else if (unnamed_pipe_fd >= 0) { - fprintf (stderr, "unable to get the bound port for the listening connection\n"); - } - } - - // If we have an unnamed pipe to write the port number back to, do that now. - if (unnamed_pipe_fd >= 0 && connection_portno == 0) - { - const uint16_t bound_port = s_listen_connection_up->GetListeningPort(10); - if (bound_port > 0) - { - error = writePortToPipe(unnamed_pipe_fd, bound_port); + error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id); if (error.Fail()) - { fprintf(stderr, "failed to write to the unnamed pipe: %s", error.AsCString()); - } - } - else - { - fprintf(stderr, "unable to get the bound port for the listening connection\n"); } } - - // Join the listener thread. - if (!JoinListenThread ()) + else { - fprintf (stderr, "failed to join the listener thread\n"); - display_usage (progname, subcommand); - exit (1); + fprintf (stderr, "unable to get the socket id for the listening connection\n"); } - // Ensure we connected. - if (s_listen_connection_up) - connection_up = std::move(s_listen_connection_up); - else + Connection* conn = nullptr; + error = acceptor_up->Accept(false, conn); + if (error.Fail()) { - fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ()); - display_usage (progname, subcommand); - exit (1); + printf ("failed to accept new connection: %s\n", error.AsCString()); + exit(1); } + connection_up.reset(conn); } error = gdb_server.InitializeConnection (std::move(connection_up)); if (error.Fail()) Index: tools/lldb-server/lldb-platform.cpp =================================================================== --- tools/lldb-server/lldb-platform.cpp +++ tools/lldb-server/lldb-platform.cpp @@ -23,6 +23,9 @@ #include // Other libraries and framework includes +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" + #include "lldb/Core/Error.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" @@ -30,8 +33,7 @@ #include "lldb/Host/HostGetOpt.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/common/TCPSocket.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FileUtilities.h" +#include "Acceptor.h" #include "LLDBServerUtilities.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" @@ -61,7 +63,7 @@ { "gdbserver-port", required_argument, NULL, 'P' }, { "min-gdbserver-port", required_argument, NULL, 'm' }, { "max-gdbserver-port", required_argument, NULL, 'M' }, - { "port-file", required_argument, NULL, 'f' }, + { "socket-file", required_argument, NULL, 'f' }, { "server", no_argument, &g_server, 1 }, { NULL, 0, NULL, 0 } }; @@ -100,9 +102,9 @@ } static Error -save_port_to_file(const uint16_t port, const FileSpec &port_file_spec) +save_socket_id_to_file(const std::string &socket_id, const FileSpec &file_spec) { - FileSpec temp_file_spec(port_file_spec.GetDirectory().AsCString(), false); + FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false); auto error = FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault); if (error.Fail()) return Error("Failed to create directory %s: %s", temp_file_spec.GetCString(), error.AsCString()); @@ -119,13 +121,13 @@ std::ofstream temp_file(temp_file_path.c_str(), std::ios::out); if (!temp_file.is_open()) return Error("Failed to open temp file %s", temp_file_path.c_str()); - temp_file << port; + temp_file << socket_id; } - err_code = llvm::sys::fs::rename(temp_file_path.c_str(), port_file_spec.GetPath().c_str()); + err_code = llvm::sys::fs::rename(temp_file_path.c_str(), file_spec.GetPath().c_str()); if (err_code) return Error("Failed to rename file %s to %s: %s", - temp_file_path.c_str(), port_file_spec.GetPath().c_str(), err_code.message().c_str()); + temp_file_path.c_str(), file_spec.GetPath().c_str(), err_code.message().c_str()); tmp_file_remover.releaseFile(); return Error(); @@ -156,7 +158,7 @@ int max_gdbserver_port = 0; uint16_t port_offset = 0; - FileSpec port_file; + FileSpec socket_file; bool show_usage = false; int option_error = 0; int socket_error = -1; @@ -191,9 +193,9 @@ log_channels = StringRef(optarg); break; - case 'f': // Port file + case 'f': // Socket file if (optarg && optarg[0]) - port_file.SetFile(optarg, false); + socket_file.SetFile(optarg, false); break; case 'p': @@ -282,39 +284,38 @@ display_usage(progname, subcommand); exit(option_error); } - - Socket *socket = nullptr; - const bool children_inherit_listen_socket = false; + const bool children_inherit_listen_socket = false; // the test suite makes many connections in parallel, let's not miss any. - // The highest this should get reasonably is a function of the number - // of target CPUs. For now, let's just use 100 + // The highest this should get reasonably is a function of the number + // of target CPUs. For now, let's just use 100. const int backlog = 100; - std::unique_ptr listening_socket_up(new TCPSocket(children_inherit_listen_socket, error)); + + std::unique_ptr acceptor_up(Acceptor::Create(listen_host_port, children_inherit_listen_socket, error)); if (error.Fail()) { - fprintf(stderr, "failed to create socket: %s", error.AsCString()); + fprintf(stderr, "failed to create acceptor: %s", error.AsCString()); exit(socket_error); } - error = listening_socket_up->Listen(listen_host_port.c_str(), backlog); + error = acceptor_up->Listen(backlog); if (error.Fail()) { - printf("error: %s\n", error.AsCString()); + printf("failed to listen: %s\n", error.AsCString()); exit(socket_error); } - if (port_file) + if (socket_file) { - error = save_port_to_file(listening_socket_up->GetLocalPortNumber(), port_file); + error = save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); if (error.Fail()) { - fprintf(stderr, "failed to write port to %s: %s", port_file.GetPath().c_str(), error.AsCString()); + fprintf(stderr, "failed to write socket id to %s: %s", socket_file.GetPath().c_str(), error.AsCString()); return 1; } } do { - GDBRemoteCommunicationServerPlatform platform; + GDBRemoteCommunicationServerPlatform platform(acceptor_up->GetSocketProtocol()); if (port_offset > 0) platform.SetPortOffset(port_offset); @@ -325,8 +326,8 @@ } const bool children_inherit_accept_socket = true; - socket = nullptr; - error = listening_socket_up->Accept(listen_host_port.c_str(), children_inherit_accept_socket, socket); + Connection* conn = nullptr; + error = acceptor_up->Accept(children_inherit_accept_socket, conn); if (error.Fail()) { printf ("error: %s\n", error.AsCString()); @@ -340,8 +341,7 @@ if (fork()) { // Parent doesn't need a connection to the lldb client - delete socket; - socket = nullptr; + delete conn; // Parent will continue to listen for new connections. continue; @@ -351,16 +351,16 @@ // Child process will handle the connection and exit. g_server = 0; // Listening socket is owned by parent process. - listening_socket_up.release(); + acceptor_up.release(); } } else { // If not running as a server, this process will not accept // connections while a connection is active. - listening_socket_up.reset(); + acceptor_up.reset(); } - platform.SetConnection (new ConnectionFileDescriptor(socket)); + platform.SetConnection (conn); if (platform.IsConnected()) {