diff options
29 files changed, 680 insertions, 487 deletions
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index c40a24f056d..c7228e18403 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -1,4 +1,7 @@ include(CheckCXXSymbolExists) +include(CheckSymbolExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) set(LLDB_PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) set(LLDB_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/source") @@ -426,10 +429,14 @@ if ((CMAKE_SYSTEM_NAME MATCHES "Android") AND LLVM_BUILD_STATIC AND endif() find_package(Backtrace) +set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) +check_symbol_exists(ppoll poll.h HAVE_PPOLL) +set(CMAKE_REQUIRED_DEFINITIONS) +check_symbol_exists(sigaction signal.h HAVE_SIGACTION) include(CheckIncludeFile) check_include_file(termios.h HAVE_TERMIOS_H) -check_include_file(sys/event.h HAVE_SYS_EVENT_H) +check_include_files("sys/types.h;sys/event.h" HAVE_SYS_EVENT_H) # These checks exist in LLVM's configuration, so I want to match the LLVM names # so that the check isn't duplicated, but we translate them into the LLDB names diff --git a/lldb/include/lldb/Host/Config.h b/lldb/include/lldb/Host/Config.h index 95d0191397b..3fa19e77452 100644 --- a/lldb/include/lldb/Host/Config.h +++ b/lldb/include/lldb/Host/Config.h @@ -18,6 +18,10 @@ #define HAVE_SYS_EVENT_H 1 +#define HAVE_PPOLL 0 + +#define HAVE_SIGACTION 1 + #else #error This file is only used by the Xcode build. diff --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake index d072c1a0868..5a16425fe0a 100644 --- a/lldb/include/lldb/Host/Config.h.cmake +++ b/lldb/include/lldb/Host/Config.h.cmake @@ -16,4 +16,8 @@ #cmakedefine01 HAVE_SYS_EVENT_H +#cmakedefine01 HAVE_PPOLL + +#cmakedefine01 HAVE_SIGACTION + #endif // #ifndef LLDB_HOST_CONFIG_H diff --git a/lldb/include/lldb/Host/MainLoop.h b/lldb/include/lldb/Host/MainLoop.h index 8aa26b63183..3ecad3afd14 100644 --- a/lldb/include/lldb/Host/MainLoop.h +++ b/lldb/include/lldb/Host/MainLoop.h @@ -10,16 +10,95 @@ #ifndef lldb_Host_MainLoop_h_ #define lldb_Host_MainLoop_h_ -#ifdef _WIN32 +#include "lldb/Host/Config.h" #include "lldb/Host/MainLoopBase.h" + +#include "llvm/ADT/DenseMap.h" + +#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H +#define SIGNAL_POLLING_UNSUPPORTED 1 +#endif + namespace lldb_private { -typedef MainLoopBase MainLoop; -} -#else -#include "lldb/Host/posix/MainLoopPosix.h" -namespace lldb_private { -typedef MainLoopPosix MainLoop; -} + +// Implementation of the MainLoopBase class. It can monitor file descriptors for +// readability using ppoll, kqueue, poll or WSAPoll. On Windows it only supports +// polling sockets, and will not work on generic file handles or pipes. On +// systems without kqueue or ppoll handling singnals is not supported. In +// addition to the common base, this class provides the ability to invoke a +// given handler when a signal is received. +// +// Since this class is primarily intended to be used for single-threaded +// processing, it does not attempt to perform any internal synchronisation and +// any concurrent accesses must be protected externally. However, it is +// perfectly legitimate to have more than one instance of this class running on +// separate threads, or even a single thread (with some limitations on signal +// monitoring). +// TODO: Add locking if this class is to be used in a multi-threaded context. +class MainLoop : public MainLoopBase { +private: + class SignalHandle; + +public: + typedef std::unique_ptr<SignalHandle> SignalHandleUP; + + ~MainLoop() override; + + ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, + const Callback &callback, + Error &error) override; + + // Listening for signals from multiple MainLoop instances is perfectly safe as + // long as they don't try to listen for the same signal. The callback function + // is invoked when the control returns to the Run() function, not when the + // hander is executed. This mean that you can treat the callback as a normal + // function and perform things which would not be safe in a signal handler. + // However, since the callback is not invoked synchronously, you cannot use + // this mechanism to handle SIGSEGV and the like. + SignalHandleUP RegisterSignal(int signo, const Callback &callback, + Error &error); + + Error Run() override; + + // This should only be performed from a callback. Do not attempt to terminate + // the processing from another thread. + // TODO: Add synchronization if we want to be terminated from another thread. + void RequestTermination() override { m_terminate_request = true; } + +protected: + void UnregisterReadObject(IOObject::WaitableHandle handle) override; + + void UnregisterSignal(int signo); + +private: + class SignalHandle { + public: + ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } + + private: + SignalHandle(MainLoop &mainloop, int signo) + : m_mainloop(mainloop), m_signo(signo) {} + + MainLoop &m_mainloop; + int m_signo; + + friend class MainLoop; + DISALLOW_COPY_AND_ASSIGN(SignalHandle); + }; + + struct SignalInfo { + Callback callback; +#if HAVE_SIGACTION + struct sigaction old_action; #endif + bool was_blocked : 1; + }; + + llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; + llvm::DenseMap<int, SignalInfo> m_signals; + bool m_terminate_request : 1; +}; + +} // namespace lldb_private #endif // lldb_Host_MainLoop_h_ diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h index 386133e9695..36d506281cf 100644 --- a/lldb/include/lldb/Host/Socket.h +++ b/lldb/include/lldb/Host/Socket.h @@ -57,8 +57,7 @@ public: virtual Error Connect(llvm::StringRef name) = 0; virtual Error Listen(llvm::StringRef name, int backlog) = 0; - virtual Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) = 0; + virtual Error Accept(Socket *&socket) = 0; // Initialize a Tcp Socket object in listening mode. listen and accept are // implemented @@ -103,7 +102,8 @@ public: int32_t &port, Error *error_ptr); protected: - Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); + Socket(SocketProtocol protocol, bool should_close, + bool m_child_process_inherit); virtual size_t Send(const void *buf, const size_t num_bytes); @@ -117,6 +117,7 @@ protected: SocketProtocol m_protocol; NativeSocket m_socket; + bool m_child_processes_inherit; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Host/common/TCPSocket.h b/lldb/include/lldb/Host/common/TCPSocket.h index 2ce8d824f0a..5b72f344019 100644 --- a/lldb/include/lldb/Host/common/TCPSocket.h +++ b/lldb/include/lldb/Host/common/TCPSocket.h @@ -11,12 +11,16 @@ #define liblldb_TCPSocket_h_ #include "lldb/Host/Socket.h" +#include "lldb/Host/SocketAddress.h" +#include <map> namespace lldb_private { class TCPSocket : public Socket { public: - TCPSocket(NativeSocket socket, bool should_close); - TCPSocket(bool child_processes_inherit, Error &error); + TCPSocket(bool should_close, bool child_processes_inherit); + TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit); + ~TCPSocket() override; // returns port number or 0 if error uint16_t GetLocalPortNumber() const; @@ -37,8 +41,18 @@ public: Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&conn_socket) override; + Error Accept(Socket *&conn_socket) override; + + Error CreateSocket(int domain); + + bool IsValid() const override; + +private: + TCPSocket(NativeSocket socket, const TCPSocket &listen_socket); + + void CloseListenSockets(); + + std::map<int, SocketAddress> m_listen_sockets; }; } diff --git a/lldb/include/lldb/Host/common/UDPSocket.h b/lldb/include/lldb/Host/common/UDPSocket.h index 507c9827caf..38524fa8f62 100644 --- a/lldb/include/lldb/Host/common/UDPSocket.h +++ b/lldb/include/lldb/Host/common/UDPSocket.h @@ -15,19 +15,20 @@ namespace lldb_private { class UDPSocket : public Socket { public: - UDPSocket(bool child_processes_inherit, Error &error); + UDPSocket(bool should_close, bool child_processes_inherit); static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket); private: - UDPSocket(NativeSocket socket); + UDPSocket(NativeSocket socket, const UDPSocket &listen_socket); size_t Send(const void *buf, const size_t num_bytes) override; Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) override; + Error Accept(Socket *&socket) override; + + Error CreateSocket(); SocketAddress m_sockaddr; }; diff --git a/lldb/include/lldb/Host/linux/AbstractSocket.h b/lldb/include/lldb/Host/linux/AbstractSocket.h index f73a287cb3f..3b38cde0552 100644 --- a/lldb/include/lldb/Host/linux/AbstractSocket.h +++ b/lldb/include/lldb/Host/linux/AbstractSocket.h @@ -15,7 +15,7 @@ namespace lldb_private { class AbstractSocket : public DomainSocket { public: - AbstractSocket(bool child_processes_inherit, Error &error); + AbstractSocket(bool child_processes_inherit); protected: size_t GetNameOffset() const override; diff --git a/lldb/include/lldb/Host/posix/DomainSocket.h b/lldb/include/lldb/Host/posix/DomainSocket.h index 3bd4e014133..78a3dc89828 100644 --- a/lldb/include/lldb/Host/posix/DomainSocket.h +++ b/lldb/include/lldb/Host/posix/DomainSocket.h @@ -15,22 +15,20 @@ namespace lldb_private { class DomainSocket : public Socket { public: - DomainSocket(bool child_processes_inherit, Error &error); + DomainSocket(bool should_close, bool child_processes_inherit); Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) override; + Error Accept(Socket *&socket) override; protected: - DomainSocket(SocketProtocol protocol, bool child_processes_inherit, - Error &error); + DomainSocket(SocketProtocol protocol, bool child_processes_inherit); virtual size_t GetNameOffset() const; virtual void DeleteSocketFile(llvm::StringRef name); private: - DomainSocket(NativeSocket socket); + DomainSocket(NativeSocket socket, const DomainSocket &listen_socket); }; } diff --git a/lldb/include/lldb/Host/posix/MainLoopPosix.h b/lldb/include/lldb/Host/posix/MainLoopPosix.h deleted file mode 100644 index 21e02becf87..00000000000 --- a/lldb/include/lldb/Host/posix/MainLoopPosix.h +++ /dev/null @@ -1,104 +0,0 @@ -//===-- MainLoopPosix.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_Host_posix_MainLoopPosix_h_ -#define lldb_Host_posix_MainLoopPosix_h_ - -#include "lldb/Host/MainLoopBase.h" - -#include "llvm/ADT/DenseMap.h" - -namespace lldb_private { - -// Posix implementation of the MainLoopBase class. It can monitor file -// descriptors for -// readability using pselect. In addition to the common base, this class -// provides the ability to -// invoke a given handler when a signal is received. -// -// Since this class is primarily intended to be used for single-threaded -// processing, it does not -// attempt to perform any internal synchronisation and any concurrent accesses -// must be protected -// externally. However, it is perfectly legitimate to have more than one -// instance of this class -// running on separate threads, or even a single thread (with some limitations -// on signal -// monitoring). -// TODO: Add locking if this class is to be used in a multi-threaded context. -class MainLoopPosix : public MainLoopBase { -private: - class SignalHandle; - -public: - typedef std::unique_ptr<SignalHandle> SignalHandleUP; - - ~MainLoopPosix() override; - - ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, - const Callback &callback, - Error &error) override; - - // Listening for signals from multiple MainLoopPosix instances is perfectly - // safe as long as they - // don't try to listen for the same signal. The callback function is invoked - // when the control - // returns to the Run() function, not when the hander is executed. This means - // that you can - // treat the callback as a normal function and perform things which would not - // be safe in a - // signal handler. However, since the callback is not invoked synchronously, - // you cannot use - // this mechanism to handle SIGSEGV and the like. - SignalHandleUP RegisterSignal(int signo, const Callback &callback, - Error &error); - - Error Run() override; - - // This should only be performed from a callback. Do not attempt to terminate - // the processing - // from another thread. - // TODO: Add synchronization if we want to be terminated from another thread. - void RequestTermination() override { m_terminate_request = true; } - -protected: - void UnregisterReadObject(IOObject::WaitableHandle handle) override; - - void UnregisterSignal(int signo); - -private: - class SignalHandle { - public: - ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } - - private: - SignalHandle(MainLoopPosix &mainloop, int signo) - : m_mainloop(mainloop), m_signo(signo) {} - - MainLoopPosix &m_mainloop; - int m_signo; - - friend class MainLoopPosix; - DISALLOW_COPY_AND_ASSIGN(SignalHandle); - }; - - struct SignalInfo { - Callback callback; - struct sigaction old_action; - bool was_blocked : 1; - }; - - llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; - llvm::DenseMap<int, SignalInfo> m_signals; - bool m_terminate_request : 1; -}; - -} // namespace lldb_private - -#endif // lldb_Host_posix_MainLoopPosix_h_ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 6bcd8619f0b..5b7276e4593 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -665,7 +665,6 @@ 26FFC19D14FC072100087D58 /* DynamicLoaderPOSIXDYLD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26FFC19714FC072100087D58 /* DynamicLoaderPOSIXDYLD.cpp */; }; 304B2E461CAAA57B007829FE /* ClangUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3032B1B61CAAA3D1004BE1AB /* ClangUtil.cpp */; }; 30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 3032B1B91CAAA400004BE1AB /* ClangUtil.h */; }; - 30DED5DE1B4ECB49004CC508 /* MainLoopPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */; }; 332CCB181AFF41620034D4C4 /* SBLanguageRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 3392EBB71AFF402200858B9F /* SBLanguageRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; 33E5E8471A674FB60024ED68 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33E5E8411A672A240024ED68 /* StringConvert.cpp */; }; 3F8160A61AB9F7DD001DA9DF /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F8160A51AB9F7DD001DA9DF /* Logging.cpp */; }; @@ -978,6 +977,7 @@ B2A58724143119D50092BFBA /* SBWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2A58723143119D50092BFBA /* SBWatchpoint.cpp */; }; B2B7CCEB15D1BD6700EEFB57 /* CommandObjectWatchpointCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2B7CCEA15D1BD6600EEFB57 /* CommandObjectWatchpointCommand.cpp */; }; B2B7CCF015D1C20F00EEFB57 /* WatchpointOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */; }; + D67521381EA17C4200439694 /* MainLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D67521351EA17C3900439694 /* MainLoop.cpp */; }; E769331C1A94D15400C73337 /* lldb-gdbserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D6F3F4183E7F9300194858 /* lldb-gdbserver.cpp */; }; E769331E1A94D18100C73337 /* lldb-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E769331D1A94D18100C73337 /* lldb-server.cpp */; }; E7723D441AC4A7FB002BA082 /* RegisterContextPOSIXCore_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E7723D421AC4A7FB002BA082 /* RegisterContextPOSIXCore_arm64.cpp */; }; @@ -2319,7 +2319,6 @@ 26FFC19814FC072100087D58 /* DynamicLoaderPOSIXDYLD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLoaderPOSIXDYLD.h; sourceTree = "<group>"; }; 3032B1B61CAAA3D1004BE1AB /* ClangUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangUtil.cpp; path = source/Symbol/ClangUtil.cpp; sourceTree = "<group>"; }; 3032B1B91CAAA400004BE1AB /* ClangUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUtil.h; path = include/lldb/Symbol/ClangUtil.h; sourceTree = "<group>"; }; - 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MainLoopPosix.cpp; sourceTree = "<group>"; }; 33064C991A5C7A330033D415 /* UriParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UriParser.cpp; path = source/Utility/UriParser.cpp; sourceTree = "<group>"; }; 3392EBB71AFF402200858B9F /* SBLanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBLanguageRuntime.h; path = include/lldb/API/SBLanguageRuntime.h; sourceTree = "<group>"; }; 33E5E8411A672A240024ED68 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringConvert.cpp; sourceTree = "<group>"; }; @@ -3051,6 +3050,7 @@ B2B7CCED15D1BFB700EEFB57 /* WatchpointOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WatchpointOptions.h; path = include/lldb/Breakpoint/WatchpointOptions.h; sourceTree = "<group>"; }; B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WatchpointOptions.cpp; path = source/Breakpoint/WatchpointOptions.cpp; sourceTree = "<group>"; }; B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InstructionUtils.h; path = Utility/InstructionUtils.h; sourceTree = "<group>"; }; + D67521351EA17C3900439694 /* MainLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MainLoop.cpp; sourceTree = "<group>"; }; E73A15A41B548EC500786197 /* GDBRemoteSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GDBRemoteSignals.cpp; path = Utility/GDBRemoteSignals.cpp; sourceTree = "<group>"; }; E73A15A51B548EC500786197 /* GDBRemoteSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GDBRemoteSignals.h; path = Utility/GDBRemoteSignals.h; sourceTree = "<group>"; }; E769331D1A94D18100C73337 /* lldb-server.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-server.cpp"; path = "tools/lldb-server/lldb-server.cpp"; sourceTree = "<group>"; }; @@ -5667,7 +5667,6 @@ children = ( 2579065E1BD0488D00178368 /* DomainSocket.cpp */, 255EFF751AFABA950069F277 /* LockFilePosix.cpp */, - 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */, AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */, 3FDFDDC5199D37ED009756A7 /* FileSystem.cpp */, 3FDFE53019A292F0009756A7 /* HostInfoPosix.cpp */, @@ -5902,6 +5901,7 @@ 69A01E1A1236C5D400C660B5 /* common */ = { isa = PBXGroup; children = ( + D67521351EA17C3900439694 /* MainLoop.cpp */, 2579065A1BD0488100178368 /* TCPSocket.cpp */, 2579065B1BD0488100178368 /* UDPSocket.cpp */, 255EFF731AFABA720069F277 /* LockFileBase.cpp */, @@ -7292,6 +7292,7 @@ 945261C41B9A11FC00BF138D /* LibCxxUnorderedMap.cpp in Sources */, 26CEB5F218762056008F575A /* CommandObjectGUI.cpp in Sources */, AF3A4AD21EA05C4700B5DEB4 /* PlatformRemoteDarwinDevice.cpp in Sources */, + D67521381EA17C4200439694 /* MainLoop.cpp in Sources */, 2689008013353E2200698AC0 /* CommandInterpreter.cpp in Sources */, AF77E0A41A033D360096C0EA /* RegisterContextPOSIX_powerpc.cpp in Sources */, 4CDB8D6D1DBA91B6006C5B13 /* LibStdcppUniquePointer.cpp in Sources */, @@ -7784,7 +7785,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30DED5DE1B4ECB49004CC508 /* MainLoopPosix.cpp in Sources */, E769331C1A94D15400C73337 /* lldb-gdbserver.cpp in Sources */, 26DC6A1D1337FECA00FF7998 /* lldb-platform.cpp in Sources */, E769331E1A94D18100C73337 /* lldb-server.cpp in Sources */, diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index f00d67420fa..2a73c30f852 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -15,6 +15,7 @@ add_host_subdirectory(common common/HostThread.cpp common/IOObject.cpp common/LockFileBase.cpp + common/MainLoop.cpp common/MonitoringProcessLauncher.cpp common/NativeBreakpoint.cpp common/NativeBreakpointList.cpp @@ -85,7 +86,6 @@ else() posix/HostProcessPosix.cpp posix/HostThreadPosix.cpp posix/LockFilePosix.cpp - posix/MainLoopPosix.cpp posix/PipePosix.cpp posix/ProcessLauncherPosixFork.cpp ) diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/common/MainLoop.cpp index a73187e730f..d73a80581b1 100644 --- a/lldb/source/Host/posix/MainLoopPosix.cpp +++ b/lldb/source/Host/common/MainLoop.cpp @@ -1,4 +1,4 @@ -//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===// +//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,47 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Host/posix/MainLoopPosix.h" +#include "llvm/Config/config.h" + +#include "lldb/Host/MainLoop.h" #include "lldb/Utility/Error.h" #include <algorithm> #include <cassert> #include <cerrno> #include <csignal> -#include <sys/select.h> #include <vector> +#include <time.h> + +#if HAVE_SYS_EVENT_H +#include <sys/event.h> +#elif defined(LLVM_ON_WIN32) +#include <winsock2.h> +#else +#include <poll.h> +#endif + +#ifdef LLVM_ON_WIN32 +#define POLL WSAPoll +#else +#define POLL poll +#endif + +#if SIGNAL_POLLING_UNSUPPORTED +#ifdef LLVM_ON_WIN32 +typedef int sigset_t; +typedef int siginfo_t; +#endif + +int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts, + const sigset_t *) { + int timeout = + (timeout_ts == nullptr) + ? -1 + : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); + return POLL(fds, nfds, timeout); +} + +#endif using namespace lldb; using namespace lldb_private; @@ -26,14 +59,20 @@ static void SignalHandler(int signo, siginfo_t *info, void *) { g_signal_flags[signo] = 1; } -MainLoopPosix::~MainLoopPosix() { +MainLoop::~MainLoop() { assert(m_read_fds.size() == 0); assert(m_signals.size() == 0); } -MainLoopPosix::ReadHandleUP -MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, +MainLoop::ReadHandleUP +MainLoop::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error) { +#ifdef LLVM_ON_WIN32 + if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) { + error.SetErrorString("MainLoop: non-socket types unsupported on Windows"); + return nullptr; + } +#endif if (!object_sp || !object_sp->IsValid()) { error.SetErrorString("IO object is not valid."); return nullptr; @@ -53,9 +92,13 @@ MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, // We shall block the signal, then install the signal handler. The signal will // be unblocked in // the Run() function to check for signal delivery. -MainLoopPosix::SignalHandleUP -MainLoopPosix::RegisterSignal(int signo, const Callback &callback, +MainLoop::SignalHandleUP +MainLoop::RegisterSignal(int signo, const Callback &callback, Error &error) { +#ifdef SIGNAL_POLLING_UNSUPPORTED + error.SetErrorString("Signal polling is not supported on this platform."); + return nullptr; +#else if (m_signals.find(signo) != m_signals.end()) { error.SetErrorStringWithFormat("Signal %d already monitored.", signo); return nullptr; @@ -88,15 +131,19 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback, g_signal_flags[signo] = 0; return SignalHandleUP(new SignalHandle(*this, signo)); +#endif } -void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) { +void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) { bool erased = m_read_fds.erase(handle); UNUSED_IF_ASSERT_DISABLED(erased); assert(erased); } -void MainLoopPosix::UnregisterSignal(int signo) { +void MainLoop::UnregisterSignal(int signo) { +#if SIGNAL_POLLING_UNSUPPORTED + Error("Signal polling is not supported on this platform."); +#else // We undo the actions of RegisterSignal on a best-effort basis. auto it = m_signals.find(signo); assert(it != m_signals.end()); @@ -110,14 +157,26 @@ void MainLoopPosix::UnregisterSignal(int signo) { nullptr); m_signals.erase(it); +#endif } -Error MainLoopPosix::Run() { +Error MainLoop::Run() { std::vector<int> signals; - sigset_t sigmask; - std::vector<int> read_fds; - fd_set read_fd_set; m_terminate_request = false; + signals.reserve(m_signals.size()); + +#if HAVE_SYS_EVENT_H + int queue_id = kqueue(); + if (queue_id < 0) + Error("kqueue failed with error %d\n", queue_id); + + std::vector<struct kevent> events; + events.reserve(m_read_fds.size() + m_signals.size()); +#else + sigset_t sigmask; + std::vector<struct pollfd> read_fds; + read_fds.reserve(m_read_fds.size()); +#endif // run until termination or until we run out of things to listen to while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { @@ -125,28 +184,51 @@ Error MainLoopPosix::Run() { // listen to, we // will store the *real* list of events separately. signals.clear(); + +#if HAVE_SYS_EVENT_H + events.resize(m_read_fds.size() + m_signals.size()); + int i = 0; + for (auto &fd: m_read_fds) { + EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0); + } + + for (const auto &sig : m_signals) { + signals.push_back(sig.first); + EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); + } + + struct kevent event_list[4]; + int num_events = + kevent(queue_id, events.data(), events.size(), event_list, 4, NULL); + + if (num_events < 0) + return Error("kevent() failed with error %d\n", num_events); + +#else read_fds.clear(); - FD_ZERO(&read_fd_set); - int nfds = 0; +#if !SIGNAL_POLLING_UNSUPPORTED if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) return Error("pthread_sigmask failed with error %d\n", ret); - for (const auto &fd : m_read_fds) { - read_fds.push_back(fd.first); - FD_SET(fd.first, &read_fd_set); - nfds = std::max(nfds, fd.first + 1); - } - for (const auto &sig : m_signals) { signals.push_back(sig.first); sigdelset(&sigmask, sig.first); } +#endif - if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == - -1 && + for (const auto &fd : m_read_fds) { + struct pollfd pfd; + pfd.fd = fd.first; + pfd.events = POLLIN; + pfd.revents = 0; + read_fds.push_back(pfd); + } + + if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && errno != EINTR) return Error(errno, eErrorTypePOSIX); +#endif for (int sig : signals) { if (g_signal_flags[sig] == 0) @@ -163,15 +245,19 @@ Error MainLoopPosix::Run() { return Error(); } - for (int fd : read_fds) { - if (!FD_ISSET(fd, &read_fd_set)) - continue; // Not ready +#if HAVE_SYS_EVENT_H + for (int i = 0; i < num_events; ++i) { + auto it = m_read_fds.find(event_list[i].ident); +#else + for (auto fd : read_fds) { + if ((fd.revents & POLLIN) == 0) + continue; - auto it = m_read_fds.find(fd); + auto it = m_read_fds.find(fd.fd); +#endif if (it == m_read_fds.end()) continue; // File descriptor must have gotten unregistered in the // meantime - it->second(*this); // Do the work if (m_terminate_request) diff --git a/lldb/source/Host/common/Socket.cpp b/lldb/source/Host/common/Socket.cpp index 2a665ddacb6..d73b5d0ad07 100644 --- a/lldb/source/Host/common/Socket.cpp +++ b/lldb/source/Host/common/Socket.cpp @@ -18,6 +18,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "llvm/ADT/STLExtras.h" + #ifndef LLDB_DISABLE_POSIX #include "lldb/Host/posix/DomainSocket.h" @@ -67,9 +69,11 @@ bool IsInterrupted() { } } -Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) +Socket::Socket(SocketProtocol protocol, bool should_close, + bool child_processes_inherit) : IOObject(eFDTypeSocket, should_close), m_protocol(protocol), - m_socket(socket) {} + m_socket(kInvalidSocketValue), + m_child_processes_inherit(child_processes_inherit) {} Socket::~Socket() { Close(); } @@ -81,14 +85,17 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, std::unique_ptr<Socket> socket_up; switch (protocol) { case ProtocolTcp: - socket_up.reset(new TCPSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<TCPSocket>(true, child_processes_inherit); break; case ProtocolUdp: - socket_up.reset(new UDPSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<UDPSocket>(true, child_processes_inherit); break; case ProtocolUnixDomain: #ifndef LLDB_DISABLE_POSIX - socket_up.reset(new DomainSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<DomainSocket>(true, child_processes_inherit); #else error.SetErrorString( "Unix domain sockets are not supported on this platform."); @@ -96,7 +103,8 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, break; case ProtocolUnixAbstract: #ifdef __linux__ - socket_up.reset(new AbstractSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<AbstractSocket>(child_processes_inherit); #else error.SetErrorString( "Abstract domain sockets are not supported on this platform."); @@ -145,7 +153,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, return error; std::unique_ptr<TCPSocket> listen_socket( - new TCPSocket(child_processes_inherit, error)); + new TCPSocket(true, child_processes_inherit)); if (error.Fail()) return error; @@ -208,7 +216,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } @@ -240,18 +248,22 @@ Error Socket::UnixAbstractAccept(llvm::StringRef name, if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } bool Socket::DecodeHostAndPort(llvm::StringRef host_and_port, std::string &host_str, std::string &port_str, int32_t &port, Error *error_ptr) { - static RegularExpression g_regex(llvm::StringRef("([^:]+):([0-9]+)")); + static RegularExpression g_regex( + llvm::StringRef("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)")); RegularExpression::Match regex_match(2); if (g_regex.Execute(host_and_port, ®ex_match)) { if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) && regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) { + // IPv6 addresses are wrapped in [] when specified with ports + if (host_str.front() == '[' && host_str.back() == ']') + host_str = host_str.substr(1, host_str.size() - 2); bool ok = false; port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok); if (ok && port <= UINT16_MAX) { @@ -404,12 +416,12 @@ NativeSocket Socket::CreateSocket(const int domain, const int type, const int protocol, bool child_processes_inherit, Error &error) { error.Clear(); - auto socketType = type; + auto socket_type = type; #ifdef SOCK_CLOEXEC if (!child_processes_inherit) - socketType |= SOCK_CLOEXEC; + socket_type |= SOCK_CLOEXEC; #endif - auto sock = ::socket(domain, socketType, protocol); + auto sock = ::socket(domain, socket_type, protocol); if (sock == kInvalidSocketValue) SetLastError(error); diff --git a/lldb/source/Host/common/SocketAddress.cpp b/lldb/source/Host/common/SocketAddress.cpp index b41cef6ca2e..542382433b4 100644 --- a/lldb/source/Host/common/SocketAddress.cpp +++ b/lldb/source/Host/common/SocketAddress.cpp @@ -227,7 +227,8 @@ bool SocketAddress::getaddrinfo(const char *host, const char *service, int ai_flags) { Clear(); - auto addresses = GetAddressInfo(host, service, ai_family, ai_socktype, ai_protocol, ai_flags); + auto addresses = GetAddressInfo(host, service, ai_family, ai_socktype, + ai_protocol, ai_flags); if (!addresses.empty()) *this = addresses[0]; return IsValid(); diff --git a/lldb/source/Host/common/TCPSocket.cpp b/lldb/source/Host/common/TCPSocket.cpp index 9a009280a90..27788e875cd 100644 --- a/lldb/source/Host/common/TCPSocket.cpp +++ b/lldb/source/Host/common/TCPSocket.cpp @@ -14,30 +14,55 @@ #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/Config.h" +#include "lldb/Host/MainLoop.h" #include "lldb/Utility/Log.h" +#include "llvm/Config/config.h" +#include "llvm/Support/raw_ostream.h" + #ifndef LLDB_DISABLE_POSIX #include <arpa/inet.h> #include <netinet/tcp.h> #include <sys/socket.h> #endif +#if defined(LLVM_ON_WIN32) +#include <winsock2.h> +#endif + +#ifdef LLVM_ON_WIN32 +#define CLOSE_SOCKET closesocket +#else +#define CLOSE_SOCKET ::close +#endif + using namespace lldb; using namespace lldb_private; namespace { - -const int kDomain = AF_INET; const int kType = SOCK_STREAM; } -TCPSocket::TCPSocket(NativeSocket socket, bool should_close) - : Socket(socket, ProtocolTcp, should_close) {} +TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) {} -TCPSocket::TCPSocket(bool child_processes_inherit, Error &error) - : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, - child_processes_inherit, error), - true) {} +TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) + : Socket(ProtocolTcp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::~TCPSocket() { CloseListenSockets(); } + +bool TCPSocket::IsValid() const { + return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; +} // Return the port number that is being used by the socket. uint16_t TCPSocket::GetLocalPortNumber() const { @@ -46,6 +71,12 @@ uint16_t TCPSocket::GetLocalPortNumber() const { socklen_t sock_addr_len = sock_addr.GetMaxLength(); if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) return sock_addr.GetPort(); + } else if (!m_listen_sockets.empty()) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getsockname(m_listen_sockets.begin()->first, sock_addr, + &sock_addr_len) == 0) + return sock_addr.GetPort(); } return 0; } @@ -84,9 +115,18 @@ std::string TCPSocket::GetRemoteIPAddress() const { return ""; } +Error TCPSocket::CreateSocket(int domain) { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, + m_child_processes_inherit, error); + return error; +} + Error TCPSocket::Connect(llvm::StringRef name) { - if (m_socket == kInvalidSocketValue) - return Error("Invalid socket"); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); if (log) @@ -99,146 +139,136 @@ Error TCPSocket::Connect(llvm::StringRef name) { if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - struct sockaddr_in sa; - ::memset(&sa, 0, sizeof(sa)); - sa.sin_family = kDomain; - sa.sin_port = htons(port); - - int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - - if (inet_pton_result <= 0) { - struct hostent *host_entry = gethostbyname(host_str.c_str()); - if (host_entry) - host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list); - inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - if (inet_pton_result <= 0) { - if (inet_pton_result == -1) - SetLastError(error); - else - error.SetErrorStringWithFormat("invalid host string: '%s'", - host_str.c_str()); + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + for (auto address : addresses) { + error = CreateSocket(address.GetFamily()); + if (error.Fail()) + continue; - return error; + address.SetPort(port); + + if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(), + address.GetLength())) { + CLOSE_SOCKET(GetNativeSocket()); + continue; } - } - if (-1 == - ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) { - SetLastError(error); + SetOptionNoDelay(); + + error.Clear(); return error; } - // Keep our TCP packets coming without any delays. - SetOptionNoDelay(); - error.Clear(); + error.SetErrorString("Failed to connect port"); return error; } Error TCPSocket::Listen(llvm::StringRef name, int backlog) { - Error error; - - // enable local address reuse - SetOptionReuseAddress(); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); + Error error; std::string host_str; std::string port_str; int32_t port = INT32_MIN; if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - SocketAddress bind_addr; + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + for (auto address : addresses) { + int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, + m_child_processes_inherit, error); + if (error.Fail()) { + error.Clear(); + continue; + } - // Only bind to the loopback address if we are expecting a connection from - // localhost to avoid any firewall issues. - const bool bind_addr_success = (host_str == "127.0.0.1") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + // enable local address reuse + int option_value = 1; + ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option_value, + sizeof(option_value)); - if (!bind_addr_success) { - error.SetErrorString("Failed to bind port"); - return error; - } + address.SetPort(port); + + int err = ::bind(fd, &address.sockaddr(), address.GetLength()); + if (-1 != err) + err = ::listen(fd, backlog); - int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength()); - if (err != -1) - err = ::listen(GetNativeSocket(), backlog); + if (-1 == err) { + CLOSE_SOCKET(fd); + continue; + } - if (err == -1) - SetLastError(error); + if (port == 0) { + socklen_t sa_len = address.GetLength(); + if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) + port = address.GetPort(); + } + m_listen_sockets[fd] = address; + } + if (m_listen_sockets.size() == 0) + error.SetErrorString("Failed to connect port"); return error; } -Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&conn_socket) { +void TCPSocket::CloseListenSockets() { + for (auto socket : m_listen_sockets) + CLOSE_SOCKET(socket.first); + m_listen_sockets.clear(); +} + +Error TCPSocket::Accept(Socket *&conn_socket) { Error error; - std::string host_str; - std::string port_str; - int32_t port; - if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + if (m_listen_sockets.size() == 0) { + error.SetErrorString("No open listening sockets!"); return error; + } - const sa_family_t family = kDomain; - const int socktype = kType; - const int protocol = IPPROTO_TCP; - SocketAddress listen_addr; - if (host_str.empty()) - listen_addr.SetToLocalhost(family, port); - else if (host_str.compare("*") == 0) - listen_addr.SetToAnyAddress(family, port); - else { - if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, - socktype, protocol)) { - error.SetErrorStringWithFormat("unable to resolve hostname '%s'", - host_str.c_str()); + int sock = -1; + int listen_sock = -1; + lldb_private::SocketAddress AcceptAddr; + MainLoop accept_loop; + std::vector<MainLoopBase::ReadHandleUP> handles; + for (auto socket : m_listen_sockets) { + auto fd = socket.first; + auto inherit = this->m_child_processes_inherit; + auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); + handles.emplace_back(accept_loop.RegisterReadObject( + io_sp, [fd, inherit, &sock, &AcceptAddr, &error, + &listen_sock](MainLoopBase &loop) { + socklen_t sa_len = AcceptAddr.GetMaxLength(); + sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, + error); + listen_sock = fd; + loop.RequestTermination(); + }, error)); + if (error.Fail()) return error; - } } bool accept_connection = false; std::unique_ptr<TCPSocket> accepted_socket; - // Loop until we are happy with our connection while (!accept_connection) { - struct sockaddr_in accept_addr; - ::memset(&accept_addr, 0, sizeof accept_addr); -#if !(defined(__linux__) || defined(_WIN32)) - accept_addr.sin_len = sizeof accept_addr; -#endif - socklen_t accept_addr_len = sizeof accept_addr; - - int sock = AcceptSocket(GetNativeSocket(), (struct sockaddr *)&accept_addr, - &accept_addr_len, child_processes_inherit, error); - + accept_loop.Run(); + if (error.Fail()) - break; - - bool is_same_addr = true; -#if !(defined(__linux__) || (defined(_WIN32))) - is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); -#endif - if (is_same_addr) - is_same_addr = (accept_addr.sin_addr.s_addr == - listen_addr.sockaddr_in().sin_addr.s_addr); - - if (is_same_addr || - (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) { - accept_connection = true; - accepted_socket.reset(new TCPSocket(sock, true)); - } else { - const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = - (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; - ::fprintf(stderr, "error: rejecting incoming connection from %u.%u.%u.%u " - "(expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - accepted_socket.reset(); + return error; + + lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; + if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { + CLOSE_SOCKET(sock); + llvm::errs() << llvm::formatv( + "error: rejecting incoming connection from {0} (expecting {1})", + AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); + continue; } + accept_connection = true; + accepted_socket.reset(new TCPSocket(sock, *this)); } if (!accepted_socket) diff --git a/lldb/source/Host/common/UDPSocket.cpp b/lldb/source/Host/common/UDPSocket.cpp index 7ca62e7496b..a32657aab0a 100644 --- a/lldb/source/Host/common/UDPSocket.cpp +++ b/lldb/source/Host/common/UDPSocket.cpp @@ -28,13 +28,16 @@ const int kDomain = AF_INET; const int kType = SOCK_DGRAM; static const char *g_not_supported_error = "Not supported"; -} +} // namespace -UDPSocket::UDPSocket(NativeSocket socket) : Socket(socket, ProtocolUdp, true) {} +UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUdp, should_close, child_processes_inherit) {} -UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) - : UDPSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +UDPSocket::UDPSocket(NativeSocket socket, const UDPSocket &listen_socket) + : Socket(ProtocolUdp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, @@ -42,27 +45,14 @@ size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { } Error UDPSocket::Connect(llvm::StringRef name) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Listen(llvm::StringRef name, int backlog) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - std::unique_ptr<UDPSocket> final_socket; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); Error error; + if (error.Fail()) + return error; + std::string host_str; std::string port_str; int32_t port = INT32_MIN; @@ -94,12 +84,11 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, for (struct addrinfo *service_info_ptr = service_info_list; service_info_ptr != nullptr; service_info_ptr = service_info_ptr->ai_next) { - auto send_fd = CreateSocket( + m_socket = Socket::CreateSocket( service_info_ptr->ai_family, service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, child_processes_inherit, error); + service_info_ptr->ai_protocol, m_child_processes_inherit, error); if (error.Success()) { - final_socket.reset(new UDPSocket(send_fd)); - final_socket->m_sockaddr = service_info_ptr; + m_sockaddr = service_info_ptr; break; } else continue; @@ -107,16 +96,17 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, ::freeaddrinfo(service_info_list); - if (!final_socket) + if (IsValid()) return error; SocketAddress bind_addr; // Only bind to the loopback address if we are expecting a connection from // localhost to avoid any firewall issues. - const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + const bool bind_addr_success = + (host_str == "127.0.0.1" || host_str == "localhost") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); if (!bind_addr_success) { error.SetErrorString("Failed to get hostspec to bind for"); @@ -125,13 +115,37 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, bind_addr.SetPort(0); // Let the source port # be determined dynamically - err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); - - struct sockaddr_in source_info; - socklen_t address_len = sizeof (struct sockaddr_in); - err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); + err = ::bind(m_socket, bind_addr, bind_addr.GetLength()); - socket = final_socket.release(); error.Clear(); return error; } + +Error UDPSocket::Listen(llvm::StringRef name, int backlog) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Accept(Socket *&socket) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::CreateSocket() { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = + Socket::CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + return error; +} + +Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + std::unique_ptr<UDPSocket> final_socket( + new UDPSocket(true, child_processes_inherit)); + Error error = final_socket->Connect(name); + if (!error.Fail()) + socket = final_socket.release(); + return error; +} diff --git a/lldb/source/Host/linux/AbstractSocket.cpp b/lldb/source/Host/linux/AbstractSocket.cpp index b6b59ae403d..2d6f6adaf1e 100644 --- a/lldb/source/Host/linux/AbstractSocket.cpp +++ b/lldb/source/Host/linux/AbstractSocket.cpp @@ -14,8 +14,8 @@ using namespace lldb; using namespace lldb_private; -AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) {} +AbstractSocket::AbstractSocket(bool child_processes_inherit) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {} size_t AbstractSocket::GetNameOffset() const { return 1; } diff --git a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index a3ac36558e3..befc847d8a8 100644 --- a/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -218,7 +218,7 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, // assume we don't own it. std::unique_ptr<TCPSocket> tcp_socket; - tcp_socket.reset(new TCPSocket(fd, false)); + tcp_socket.reset(new TCPSocket(fd, false, false)); // Try and get a socket option from this file descriptor to // see if this is a socket and set m_is_socket accordingly. int resuse; @@ -720,7 +720,7 @@ ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s, listening_socket_up.reset(socket); socket = nullptr; - error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); + error = listening_socket_up->Accept(socket); listening_socket_up.reset(); if (error_ptr) *error_ptr = error; diff --git a/lldb/source/Host/posix/DomainSocket.cpp b/lldb/source/Host/posix/DomainSocket.cpp index 538979df2b6..33c71268c2e 100644 --- a/lldb/source/Host/posix/DomainSocket.cpp +++ b/lldb/source/Host/posix/DomainSocket.cpp @@ -56,19 +56,21 @@ bool SetSockAddr(llvm::StringRef name, const size_t name_offset, return true; } -} - -DomainSocket::DomainSocket(NativeSocket socket) - : Socket(socket, ProtocolUnixDomain, true) {} +} // namespace -DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) - : DomainSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} DomainSocket::DomainSocket(SocketProtocol protocol, - bool child_processes_inherit, Error &error) - : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), - protocol, true) {} + bool child_processes_inherit) + : Socket(protocol, true, child_processes_inherit) {} + +DomainSocket::DomainSocket(NativeSocket socket, + const DomainSocket &listen_socket) + : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} Error DomainSocket::Connect(llvm::StringRef name) { sockaddr_un saddr_un; @@ -77,6 +79,9 @@ Error DomainSocket::Connect(llvm::StringRef name) { return Error("Failed to set socket address"); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < 0) SetLastError(error); @@ -93,6 +98,9 @@ Error DomainSocket::Listen(llvm::StringRef name, int backlog) { DeleteSocketFile(name); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 0) if (::listen(GetNativeSocket(), backlog) == 0) @@ -102,13 +110,12 @@ Error DomainSocket::Listen(llvm::StringRef name, int backlog) { return error; } -Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { +Error DomainSocket::Accept(Socket *&socket) { Error error; auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, - child_processes_inherit, error); + m_child_processes_inherit, error); if (error.Success()) - socket = new DomainSocket(conn_fd); + socket = new DomainSocket(conn_fd, *this); return error; } diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index 0c5e478d470..034518c1d2e 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -67,7 +67,7 @@ static Error DeleteForwardPortWithAdb(uint16_t local_port, static Error FindUnusedPort(uint16_t &port) { Error error; - std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error)); + std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(true, false)); if (error.Fail()) return error; diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index e0d1b68db70..d97b438ce8e 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -101,6 +101,7 @@ AF48558D1D75127500D19C07 /* StdStringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */; }; AFA3FCA11E39984900218D5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; + D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -219,6 +220,7 @@ AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = "<group>"; }; AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = "<group>"; }; AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = "<group>"; }; + D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddress.cpp; path = ../../source/Host/common/SocketAddress.cpp; sourceTree = "<group>"; }; ED128B7918E1F163003F6A7B /* libpmenergy.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmenergy.dylib; path = usr/lib/libpmenergy.dylib; sourceTree = SDKROOT; }; ED128B7A18E1F163003F6A7B /* libpmsample.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmsample.dylib; path = usr/lib/libpmsample.dylib; sourceTree = SDKROOT; }; EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = "<group>"; }; @@ -251,6 +253,7 @@ 08FB7794FE84155DC02AAC07 /* dbgnub */ = { isa = PBXGroup; children = ( + D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */, 26ACA3330D3E94F200A2120B /* Framework */, 26C637D50C71334A0024798E /* source */, 1AB674ADFE9D54B511CA2CBB /* Products */, @@ -577,6 +580,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */, 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */, 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */, 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */, diff --git a/lldb/tools/debugserver/source/CMakeLists.txt b/lldb/tools/debugserver/source/CMakeLists.txt index 782c946f702..775a1a127b6 100644 --- a/lldb/tools/debugserver/source/CMakeLists.txt +++ b/lldb/tools/debugserver/source/CMakeLists.txt @@ -62,6 +62,7 @@ set(lldbDebugserverCommonSources StdStringExtractor.cpp # JSON reader depends on the following LLDB-common files ${LLDB_SOURCE_DIR}/source/Host/common/StringConvert.cpp + ${LLDB_SOURCE_DIR}/source/Host/common/SocketAddress.cpp # end JSON reader dependencies libdebugserver.cpp PseudoTerminal.cpp diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp index a8d119e455f..62a3e4f9adf 100644 --- a/lldb/tools/debugserver/source/RNBSocket.cpp +++ b/lldb/tools/debugserver/source/RNBSocket.cpp @@ -17,10 +17,15 @@ #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> +#include <map> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> +#include <sys/event.h> #include <termios.h> +#include <vector> + +#include "lldb/Host/SocketAddress.h" #ifdef WITH_LOCKDOWN #include "lockdown.h" @@ -66,176 +71,161 @@ rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, // Disconnect without saving errno Disconnect(false); - // Now figure out the hostname that will be attaching and palce it into - struct sockaddr_in listen_addr; - ::memset(&listen_addr, 0, sizeof listen_addr); - listen_addr.sin_len = sizeof listen_addr; - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons(port); - listen_addr.sin_addr.s_addr = INADDR_ANY; - - if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr)) { - DNBLogThreaded("error: failed to resolve connecting host '%s'", - listen_host); + DNBError err; + int queue_id = kqueue(); + if (queue_id < 0) { + err.SetError(errno, DNBError::MachKernel); + err.LogThreaded("error: failed to create kqueue."); return rnb_err; } - DNBError err; - int listen_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listen_fd == -1) - err.SetError(errno, DNBError::POSIX); + std::map<int, lldb_private::SocketAddress> sockets; + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + listen_host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol " - "= IPPROTO_TCP ) => socket = %i", - listen_fd); + for (auto address : addresses) { + int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); + if (sock_fd == -1) + continue; - if (err.Fail()) - return rnb_err; + SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1); - // enable local address reuse - SetSocketOption(listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); - - struct sockaddr_in sa; - ::memset(&sa, 0, sizeof sa); - sa.sin_len = sizeof sa; - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host - // network interface (this is NOT who can - // connect to us) - int error = ::bind(listen_fd, (struct sockaddr *)&sa, sizeof(sa)); - if (error == -1) - err.SetError(errno, DNBError::POSIX); + address.SetPort(port); - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded( - "::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", - listen_fd); + int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength()); + if (error == -1) { + ClosePort(sock_fd, false); + continue; + } - if (err.Fail()) { - ClosePort(listen_fd, false); - return rnb_err; - } + error = ::listen(sock_fd, 5); + if (error == -1) { + ClosePort(sock_fd, false); + continue; + } - error = ::listen(listen_fd, 5); - if (error == -1) - err.SetError(errno, DNBError::POSIX); + // We were asked to listen on port zero which means we must now read the + // actual port that was given to us as port zero is a special code for "find + // an open port for me". This will only execute on the first socket created, + // subesquent sockets will reuse this port number. + if (port == 0) { + socklen_t sa_len = address.GetLength(); + if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0) + port = address.GetPort(); + } - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd); + sockets[sock_fd] = address; + } - if (err.Fail()) { - ClosePort(listen_fd, false); + if (sockets.size() == 0) { + err.SetError(errno, DNBError::POSIX); + err.LogThreaded("::listen or ::bind failed"); return rnb_err; } - if (callback) { - // We were asked to listen on port zero which means we - // must now read the actual port that was given to us - // as port zero is a special code for "find an open port - // for me". - if (port == 0) { - socklen_t sa_len = sizeof(sa); - if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) { - port = ntohs(sa.sin_port); - callback(callback_baton, port); - } - } else { - callback(callback_baton, port); - } - } + if (callback) + callback(callback_baton, port); - struct sockaddr_in accept_addr; - ::memset(&accept_addr, 0, sizeof accept_addr); - accept_addr.sin_len = sizeof accept_addr; + std::vector<struct kevent> events; + events.resize(sockets.size()); + int i = 0; + for (auto socket : sockets) { + EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0); + } bool accept_connection = false; // Loop until we are happy with our connection while (!accept_connection) { - socklen_t accept_addr_len = sizeof accept_addr; - m_fd = - ::accept(listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len); - if (m_fd == -1) - err.SetError(errno, DNBError::POSIX); + struct kevent event_list[4]; + int num_events = + kevent(queue_id, events.data(), events.size(), event_list, 4, NULL); - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded( - "::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, - &accept_addr, accept_addr_len); + if (num_events < 0) { + err.SetError(errno, DNBError::MachKernel); + err.LogThreaded("error: kevent() failed."); + } - if (err.Fail()) - break; + for (int i = 0; i < num_events; ++i) { + auto sock_fd = event_list[i].ident; + auto socket_pair = sockets.find(sock_fd); + if (socket_pair == sockets.end()) + continue; - if (listen_addr.sin_addr.s_addr == INADDR_ANY) - accept_connection = true; - else { - if (accept_addr_len == listen_addr.sin_len && - accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr) { + lldb_private::SocketAddress &addr_in = socket_pair->second; + lldb_private::SocketAddress accept_addr; + socklen_t sa_len = accept_addr.GetMaxLength(); + m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len); + + if (m_fd == -1) { + err.SetError(errno, DNBError::POSIX); + err.LogThreaded("error: Socket accept failed."); + } + + if (addr_in.IsAnyAddr()) accept_connection = true; - } else { - ::close(m_fd); - m_fd = -1; - const uint8_t *accept_ip = - (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = - (const uint8_t *)&listen_addr.sin_addr.s_addr; - ::fprintf(stderr, "error: rejecting incoming connection from " - "%u.%u.%u.%u (expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - DNBLogThreaded("error: rejecting connection from %u.%u.%u.%u " - "(expecting %u.%u.%u.%u)", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + else { + if (accept_addr == addr_in) + accept_connection = true; + else { + ::close(m_fd); + m_fd = -1; + ::fprintf( + stderr, + "error: rejecting incoming connection from %s (expecting %s)\n", + accept_addr.GetIPAddress().c_str(), + addr_in.GetIPAddress().c_str()); + DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n", + accept_addr.GetIPAddress().c_str(), + addr_in.GetIPAddress().c_str()); + } } } + if (err.Fail()) + break; + } + for (auto socket : sockets) { + int ListenFd = socket.first; + ClosePort(ListenFd, false); } - ClosePort(listen_fd, false); - - if (err.Fail()) { + if (err.Fail()) return rnb_err; - } else { - // Keep our TCP packets coming without any delays. - SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - } + + // Keep our TCP packets coming without any delays. + SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); return rnb_success; } rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) { + auto result = rnb_err; Disconnect(false); - // Create the socket - m_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (m_fd == -1) - return rnb_err; + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); - // Enable local address reuse - SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1); + for (auto address : addresses) { + m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP); + if (m_fd == -1) + continue; - struct sockaddr_in sa; - ::memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); + // Enable local address reuse + SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1); - if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr)) { - DNBLogThreaded("error: failed to resolve host '%s'", host); - Disconnect(false); - return rnb_err; - } + address.SetPort(port); - if (-1 == ::connect(m_fd, (const struct sockaddr *)&sa, sizeof(sa))) { - Disconnect(false); - return rnb_err; - } + if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) { + Disconnect(false); + continue; + } + SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - // Keep our TCP packets coming without any delays. - SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - return rnb_success; + result = rnb_success; + break; + } + return result; } rnb_err_t RNBSocket::useFD(int fd) { diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index 0cb72f4ece4..bc1954de334 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -1345,10 +1345,18 @@ int main(int argc, char *argv[]) { show_usage_and_exit(1); } // accept 'localhost:' prefix on port number - - int items_scanned = ::sscanf(argv[0], "%[^:]:%i", str, &port); - if (items_scanned == 2) { - host = str; + std::string host_specifier = argv[0]; + auto colon_location = host_specifier.rfind(':'); + if (colon_location != std::string::npos) { + host = host_specifier.substr(0, colon_location); + std::string port_str = + host_specifier.substr(colon_location + 1, std::string::npos); + char *end_ptr; + port = strtoul(port_str.c_str(), &end_ptr, 0); + if (end_ptr < port_str.c_str() + port_str.size()) + show_usage_and_exit(2); + if (host.front() == '[' && host.back() == ']') + host = host.substr(1, host.size() - 2); DNBLogDebug("host = '%s' port = %i", host.c_str(), port); } else { // No hostname means "localhost" diff --git a/lldb/tools/lldb-server/Acceptor.cpp b/lldb/tools/lldb-server/Acceptor.cpp index e6e73f8bdb6..48a364886dc 100644 --- a/lldb/tools/lldb-server/Acceptor.cpp +++ b/lldb/tools/lldb-server/Acceptor.cpp @@ -62,8 +62,7 @@ Error Acceptor::Listen(int 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), child_processes_inherit, conn_socket); + auto error = m_listener_socket_up->Accept(conn_socket); if (error.Success()) conn = new ConnectionFileDescriptor(conn_socket); diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp index 7abb010a908..eda3a11fc10 100644 --- a/lldb/unittests/Host/SocketTest.cpp +++ b/lldb/unittests/Host/SocketTest.cpp @@ -44,8 +44,7 @@ protected: const char *listen_remote_address, bool child_processes_inherit, Socket **accept_socket, Error *error) { - *error = listen_socket->Accept(listen_remote_address, - child_processes_inherit, *accept_socket); + *error = listen_socket->Accept(*accept_socket); } template <typename SocketType> @@ -56,7 +55,7 @@ protected: bool child_processes_inherit = false; Error error; std::unique_ptr<SocketType> listen_socket_up( - new SocketType(child_processes_inherit, error)); + new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = listen_socket_up->Listen(listen_remote_address, 5); EXPECT_FALSE(error.Fail()); @@ -70,7 +69,7 @@ protected: std::string connect_remote_address = get_connect_addr(*listen_socket_up); std::unique_ptr<SocketType> connect_socket_up( - new SocketType(child_processes_inherit, error)); + new SocketType(true, child_processes_inherit)); EXPECT_FALSE(error.Fail()); error = connect_socket_up->Connect(connect_remote_address); EXPECT_FALSE(error.Fail()); @@ -141,6 +140,20 @@ TEST_F(SocketTest, DecodeHostAndPort) { EXPECT_STREQ("65535", port_str.c_str()); EXPECT_EQ(65535, port); EXPECT_TRUE(error.Success()); + + EXPECT_TRUE( + Socket::DecodeHostAndPort("[::1]:12345", host_str, port_str, port, &error)); + EXPECT_STREQ("::1", host_str.c_str()); + EXPECT_STREQ("12345", port_str.c_str()); + EXPECT_EQ(12345, port); + EXPECT_TRUE(error.Success()); + + EXPECT_TRUE( + Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345", host_str, port_str, port, &error)); + EXPECT_STREQ("abcd:12fg:AF58::1", host_str.c_str()); + EXPECT_STREQ("12345", port_str.c_str()); + EXPECT_EQ(12345, port); + EXPECT_TRUE(error.Success()); } #ifndef LLDB_DISABLE_POSIX diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp index 08501f50f65..6440e814efd 100644 --- a/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp +++ b/lldb/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp @@ -33,15 +33,14 @@ void GDBRemoteTest::TearDownTestCase() { void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) { bool child_processes_inherit = false; Error error; - TCPSocket listen_socket(child_processes_inherit, error); + TCPSocket listen_socket(true, child_processes_inherit); ASSERT_FALSE(error.Fail()); error = listen_socket.Listen("127.0.0.1:0", 5); ASSERT_FALSE(error.Fail()); Socket *accept_socket; std::future<Error> accept_error = std::async(std::launch::async, [&] { - return listen_socket.Accept("127.0.0.1:0", child_processes_inherit, - accept_socket); + return listen_socket.Accept(accept_socket); }); char connect_remote_address[64]; diff --git a/lldb/unittests/debugserver/RNBSocketTest.cpp b/lldb/unittests/debugserver/RNBSocketTest.cpp index 997041f6154..76a1b49064f 100644 --- a/lldb/unittests/debugserver/RNBSocketTest.cpp +++ b/lldb/unittests/debugserver/RNBSocketTest.cpp @@ -53,9 +53,21 @@ static void ServerCallbackv4(const void *baton, in_port_t port) { } void TestSocketListen(const char *addr) { + // Skip IPv6 tests if there isn't a valid interafce + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + if (addresses.size() == 0) + return; + + char addr_wrap[256]; + if (addresses.front().GetFamily() == AF_INET6) + sprintf(addr_wrap, "[%s]", addr); + else + sprintf(addr_wrap, "%s", addr); + RNBSocket server_socket; auto result = - server_socket.Listen(addr, 0, ServerCallbackv4, (const void *)addr); + server_socket.Listen(addr, 0, ServerCallbackv4, (const void *)addr_wrap); ASSERT_TRUE(result == rnb_success); result = server_socket.Write(hello.c_str(), hello.length()); ASSERT_TRUE(result == rnb_success); @@ -71,9 +83,20 @@ void TestSocketListen(const char *addr) { TEST(RNBSocket, LoopBackListenIPv4) { TestSocketListen("127.0.0.1"); } +TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen("::1"); } + void TestSocketConnect(const char *addr) { + // Skip IPv6 tests if there isn't a valid interafce + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + if (addresses.size() == 0) + return; + char addr_wrap[256]; - sprintf(addr_wrap, "%s:0", addr); + if (addresses.front().GetFamily() == AF_INET6) + sprintf(addr_wrap, "[%s]:0", addr); + else + sprintf(addr_wrap, "%s:0", addr); Socket *server_socket; Predicate<uint16_t> port_predicate; @@ -96,7 +119,7 @@ void TestSocketConnect(const char *addr) { ASSERT_EQ(bye, goodbye); } else { Socket *connected_socket; - err = server_socket->Accept(addr_wrap, false, connected_socket); + err = server_socket->Accept(connected_socket); if (err.Fail()) { llvm::errs() << err.AsCString(); abort(); @@ -131,3 +154,5 @@ void TestSocketConnect(const char *addr) { } TEST(RNBSocket, LoopBackConnectIPv4) { TestSocketConnect("127.0.0.1"); } + +TEST(RNBSocket, LoopBackConnectIPv6) { TestSocketConnect("::1"); } |