Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -74,6 +74,8 @@ lldbPluginProcessElfCore lldbPluginJITLoaderGDB lldbPluginExpressionParserClang + lldbPluginTCPSocket + lldbPluginUDPSocket ) # Windows-only libraries @@ -91,6 +93,8 @@ list(APPEND LLDB_USED_LIBS lldbPluginProcessLinux lldbPluginProcessPOSIX + lldbPluginLinuxSocket + lldbPluginPOSIXSocket ) endif () @@ -99,6 +103,7 @@ list(APPEND LLDB_USED_LIBS lldbPluginProcessFreeBSD lldbPluginProcessPOSIX + lldbPluginPOSIXSocket ) endif () @@ -110,6 +115,7 @@ lldbPluginProcessMachCore lldbPluginProcessMacOSXKernel lldbPluginSymbolVendorMacOSX + lldbPluginPOSIXSocket ) endif() Index: include/lldb/Core/PluginManager.h =================================================================== --- include/lldb/Core/PluginManager.h +++ include/lldb/Core/PluginManager.h @@ -466,7 +466,21 @@ static REPLEnumerateSupportedLanguages GetREPLSystemEnumerateSupportedLanguagesCallbackForPluginName (const ConstString &name); - + + //------------------------------------------------------------------ + // Socket + //------------------------------------------------------------------ + static bool + RegisterPlugin (const ConstString &name, + const char *description, + SocketCreateInstance create_callback); + + static bool + UnregisterPlugin (SocketCreateInstance create_callback); + + static SocketCreateInstance + GetSocketCreateCallbackForPluginName (const ConstString &name); + //------------------------------------------------------------------ // Some plug-ins might register a DebuggerInitializeCallback // callback when registering the plug-in. After a new Debugger Index: include/lldb/Host/Socket.h =================================================================== --- include/lldb/Host/Socket.h +++ include/lldb/Host/Socket.h @@ -10,11 +10,13 @@ #ifndef liblldb_Host_Socket_h_ #define liblldb_Host_Socket_h_ +#include #include #include "lldb/lldb-private.h" #include "lldb/Core/Error.h" +#include "lldb/Core/PluginInterface.h" #include "lldb/Host/IOObject.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/SocketAddress.h" @@ -38,7 +40,8 @@ typedef int NativeSocket; #endif -class Socket : public IOObject +class Socket : public IOObject, + public PluginInterface { public: typedef enum @@ -49,10 +52,20 @@ ProtocolUnixAbstract } SocketProtocol; + static const char *TCP; + static const char *UDP; + static const char *UNIX; + static const char *UNIX_ABSTRACT; + static const NativeSocket kInvalidSocketValue; ~Socket() override; + static std::unique_ptr Create(const char* scheme, bool child_processes_inherit, Error& error); + + static void + Initialize(); + 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; @@ -78,6 +91,7 @@ NativeSocket GetNativeSocket () const { return m_socket; } SocketProtocol GetSocketProtocol () const { return m_protocol; } + virtual const char* GetScheme() const = 0; Error Read (void *buf, size_t &num_bytes) override; Error Write (const void *buf, size_t &num_bytes) override; @@ -95,6 +109,20 @@ int32_t& port, Error *error_ptr); + // returns port number or 0 if error + uint16_t GetLocalPortNumber () const; + + // returns ip address string or empty string if error + std::string GetLocalIPAddress () const; + + // must be connected + // returns port number or 0 if error + uint16_t GetRemotePortNumber () const; + + // must be connected + // returns ip address string or empty string if error + std::string GetRemoteIPAddress () const; + protected: Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); @@ -108,7 +136,7 @@ SocketProtocol m_protocol; NativeSocket m_socket; -}; + }; } // namespace lldb_private Index: include/lldb/Host/common/TCPSocket.h =================================================================== --- include/lldb/Host/common/TCPSocket.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- TCPSocket.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_TCPSocket_h_ -#define liblldb_TCPSocket_h_ - -#include "lldb/Host/Socket.h" - -namespace lldb_private -{ - class TCPSocket: public Socket - { - public: - TCPSocket(NativeSocket socket, bool should_close); - TCPSocket(bool child_processes_inherit, Error &error); - - // returns port number or 0 if error - uint16_t GetLocalPortNumber () const; - - // returns ip address string or empty string if error - std::string GetLocalIPAddress () const; - - // must be connected - // returns port number or 0 if error - uint16_t GetRemotePortNumber () const; - - // must be connected - // returns ip address string or empty string if error - std::string GetRemoteIPAddress () const; - - int SetOptionNoDelay(); - int SetOptionReuseAddress(); - - 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; - }; -} - -#endif // ifndef liblldb_TCPSocket_h_ Index: include/lldb/Host/common/UDPSocket.h =================================================================== --- include/lldb/Host/common/UDPSocket.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- UDPSocket.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_UDPSocket_h_ -#define liblldb_UDPSocket_h_ - -#include "lldb/Host/Socket.h" - -namespace lldb_private -{ - class UDPSocket: public Socket - { - public: - static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket); - - private: - UDPSocket(NativeSocket socket); - UDPSocket(bool child_processes_inherit, Error &error); - - 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; - - SocketAddress m_send_sockaddr; - }; -} - -#endif // ifndef liblldb_UDPSocket_h_ Index: include/lldb/Host/linux/AbstractSocket.h =================================================================== --- include/lldb/Host/linux/AbstractSocket.h +++ /dev/null @@ -1,28 +0,0 @@ -//===-- AbstractSocket.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_AbstractSocket_h_ -#define liblldb_AbstractSocket_h_ - -#include "lldb/Host/posix/DomainSocket.h" - -namespace lldb_private -{ - class AbstractSocket: public DomainSocket - { - public: - AbstractSocket(bool child_processes_inherit, Error &error); - - protected: - size_t GetNameOffset() const override; - void DeleteSocketFile(llvm::StringRef name) override; - }; -} - -#endif // ifndef liblldb_AbstractSocket_h_ Index: include/lldb/Host/posix/DomainSocket.h =================================================================== --- include/lldb/Host/posix/DomainSocket.h +++ /dev/null @@ -1,37 +0,0 @@ -//===-- DomainSocket.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_DomainSocket_h_ -#define liblldb_DomainSocket_h_ - -#include "lldb/Host/Socket.h" - -namespace lldb_private -{ - class DomainSocket: public Socket - { - public: - DomainSocket(bool child_processes_inherit, Error &error); - - 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; - - protected: - DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error); - - virtual size_t GetNameOffset() const; - virtual void DeleteSocketFile(llvm::StringRef name); - - private: - DomainSocket(NativeSocket socket); - }; -} - -#endif // ifndef liblldb_DomainSocket_h_ Index: include/lldb/lldb-forward.h =================================================================== --- include/lldb/lldb-forward.h +++ include/lldb/lldb-forward.h @@ -195,6 +195,7 @@ class SectionLoadHistory; class SectionLoadList; class Settings; +class Socket; class SourceManager; class SourceManagerImpl; class StackFrame; Index: include/lldb/lldb-private-interfaces.h =================================================================== --- include/lldb/lldb-private-interfaces.h +++ include/lldb/lldb-private-interfaces.h @@ -52,6 +52,7 @@ typedef lldb::REPLSP (*REPLCreateInstance) (Error &error, lldb::LanguageType language, Debugger *debugger, Target *target, const char *repl_options); typedef void (*TypeSystemEnumerateSupportedLanguages) (std::set &languages_for_types, std::set &languages_for_expressions); typedef void (*REPLEnumerateSupportedLanguages) (std::set &languages); + typedef Socket* (*SocketCreateInstance) (bool child_processes_inherit, Error &error); typedef int (*ComparisonFunction)(const void *, const void *); typedef void (*DebuggerInitializeCallback)(Debugger &debugger); Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -111,12 +111,17 @@ 256CBDBA1ADD107200BC6CDC /* RegisterContextLinux_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDB61ADD107200BC6CDC /* RegisterContextLinux_arm.cpp */; }; 256CBDBC1ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDB81ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp */; }; 256CBDC01ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDBE1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp */; }; - 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 */; }; + 25B4C4611BDEA2CD005B956D /* AbstractSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B4C4521BDEA2CD005B956D /* AbstractSocket.cpp */; }; + 25B4C4621BDEA2CD005B956D /* AbstractSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B4C4531BDEA2CD005B956D /* AbstractSocket.h */; }; + 25B4C4631BDEA2CD005B956D /* DomainSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B4C4571BDEA2CD005B956D /* DomainSocket.cpp */; }; + 25B4C4641BDEA2CD005B956D /* DomainSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B4C4581BDEA2CD005B956D /* DomainSocket.h */; }; + 25B4C4651BDEA2CD005B956D /* TCPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B4C45B1BDEA2CD005B956D /* TCPSocket.cpp */; }; + 25B4C4661BDEA2CD005B956D /* TCPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B4C45C1BDEA2CD005B956D /* TCPSocket.h */; }; + 25B4C4671BDEA2CD005B956D /* UDPSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B4C45F1BDEA2CD005B956D /* UDPSocket.cpp */; }; + 25B4C4681BDEA2CD005B956D /* UDPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 25B4C4601BDEA2CD005B956D /* UDPSocket.h */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -1231,13 +1236,23 @@ 256CBDB91ADD107200BC6CDC /* RegisterContextLinux_mips64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextLinux_mips64.h; path = Utility/RegisterContextLinux_mips64.h; sourceTree = ""; }; 256CBDBE1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextPOSIX_arm.cpp; path = Utility/RegisterContextPOSIX_arm.cpp; sourceTree = ""; }; 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm.h; path = Utility/RegisterContextPOSIX_arm.h; sourceTree = ""; }; - 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 = ""; }; + 25B4C4501BDEA2CD005B956D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 25B4C4521BDEA2CD005B956D /* AbstractSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractSocket.cpp; sourceTree = ""; }; + 25B4C4531BDEA2CD005B956D /* AbstractSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractSocket.h; sourceTree = ""; }; + 25B4C4541BDEA2CD005B956D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 25B4C4561BDEA2CD005B956D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 25B4C4571BDEA2CD005B956D /* DomainSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DomainSocket.cpp; sourceTree = ""; }; + 25B4C4581BDEA2CD005B956D /* DomainSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainSocket.h; sourceTree = ""; }; + 25B4C45A1BDEA2CD005B956D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 25B4C45B1BDEA2CD005B956D /* TCPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TCPSocket.cpp; sourceTree = ""; }; + 25B4C45C1BDEA2CD005B956D /* TCPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TCPSocket.h; sourceTree = ""; }; + 25B4C45E1BDEA2CD005B956D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 25B4C45F1BDEA2CD005B956D /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = ""; }; + 25B4C4601BDEA2CD005B956D /* UDPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UDPSocket.h; sourceTree = ""; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; 25EF23761AC09AD800908DF0 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdbClient.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; @@ -3119,9 +3134,62 @@ path = FreeBSD; sourceTree = ""; }; + 25B4C44F1BDEA2CD005B956D /* Socket */ = { + isa = PBXGroup; + children = ( + 25B4C4501BDEA2CD005B956D /* CMakeLists.txt */, + 25B4C4511BDEA2CD005B956D /* Linux */, + 25B4C4551BDEA2CD005B956D /* POSIX */, + 25B4C4591BDEA2CD005B956D /* TCP */, + 25B4C45D1BDEA2CD005B956D /* UDP */, + ); + path = Socket; + sourceTree = ""; + }; + 25B4C4511BDEA2CD005B956D /* Linux */ = { + isa = PBXGroup; + children = ( + 25B4C4521BDEA2CD005B956D /* AbstractSocket.cpp */, + 25B4C4531BDEA2CD005B956D /* AbstractSocket.h */, + 25B4C4541BDEA2CD005B956D /* CMakeLists.txt */, + ); + path = Linux; + sourceTree = ""; + }; + 25B4C4551BDEA2CD005B956D /* POSIX */ = { + isa = PBXGroup; + children = ( + 25B4C4561BDEA2CD005B956D /* CMakeLists.txt */, + 25B4C4571BDEA2CD005B956D /* DomainSocket.cpp */, + 25B4C4581BDEA2CD005B956D /* DomainSocket.h */, + ); + path = POSIX; + sourceTree = ""; + }; + 25B4C4591BDEA2CD005B956D /* TCP */ = { + isa = PBXGroup; + children = ( + 25B4C45A1BDEA2CD005B956D /* CMakeLists.txt */, + 25B4C45B1BDEA2CD005B956D /* TCPSocket.cpp */, + 25B4C45C1BDEA2CD005B956D /* TCPSocket.h */, + ); + path = TCP; + sourceTree = ""; + }; + 25B4C45D1BDEA2CD005B956D /* UDP */ = { + isa = PBXGroup; + children = ( + 25B4C45E1BDEA2CD005B956D /* CMakeLists.txt */, + 25B4C45F1BDEA2CD005B956D /* UDPSocket.cpp */, + 25B4C4601BDEA2CD005B956D /* UDPSocket.h */, + ); + path = UDP; + sourceTree = ""; + }; 260C897110F57C5600BB2B04 /* Plugins */ = { isa = PBXGroup; children = ( + 25B4C44F1BDEA2CD005B956D /* Socket */, 8CF02ADD19DCBEC200B14BE0 /* InstrumentationRuntime */, 8C2D6A58197A1FB9006989C9 /* MemoryHistory */, 26DB3E051379E7AD0080DC73 /* ABI */, @@ -5131,7 +5199,6 @@ 3FDFDDC4199D37BE009756A7 /* posix */ = { isa = PBXGroup; children = ( - 2579065E1BD0488D00178368 /* DomainSocket.cpp */, 255EFF751AFABA950069F277 /* LockFilePosix.cpp */, 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */, AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */, @@ -5338,8 +5405,6 @@ 69A01E1A1236C5D400C660B5 /* common */ = { isa = PBXGroup; children = ( - 2579065A1BD0488100178368 /* TCPSocket.cpp */, - 2579065B1BD0488100178368 /* UDPSocket.cpp */, 255EFF731AFABA720069F277 /* LockFileBase.cpp */, 250D6AE11A9679270049CC70 /* FileSystem.cpp */, 33E5E8411A672A240024ED68 /* StringConvert.cpp */, @@ -5783,9 +5848,13 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 25B4C4641BDEA2CD005B956D /* DomainSocket.h in Headers */, + 25B4C4661BDEA2CD005B956D /* TCPSocket.h in Headers */, 4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */, 257906651BD5AFD000178368 /* Acceptor.h in Headers */, 260A63171861008E00FECF8E /* IOHandler.h in Headers */, + 25B4C4681BDEA2CD005B956D /* UDPSocket.h in Headers */, + 25B4C4621BDEA2CD005B956D /* AbstractSocket.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6302,6 +6371,7 @@ 267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */, 2689FFF113353DB600698AC0 /* BreakpointID.cpp in Sources */, AF77E0A91A033D740096C0EA /* RegisterContextPOSIXCore_powerpc.cpp in Sources */, + 25B4C4631BDEA2CD005B956D /* DomainSocket.cpp in Sources */, 2689FFF313353DB600698AC0 /* BreakpointIDList.cpp in Sources */, 2689FFF513353DB600698AC0 /* BreakpointList.cpp in Sources */, AF77E08F1A033C700096C0EA /* ABISysV_ppc.cpp in Sources */, @@ -6524,13 +6594,13 @@ 2689008D13353E4200698AC0 /* DynamicLoaderMacOSXDYLD.cpp in Sources */, 2689008E13353E4200698AC0 /* DynamicLoaderStatic.cpp in Sources */, 2689009613353E4200698AC0 /* ObjectContainerBSDArchive.cpp in Sources */, - 2579065D1BD0488100178368 /* UDPSocket.cpp in Sources */, AE8F624919EF3E1E00326B21 /* OperatingSystemGo.cpp in Sources */, 26BC179A18C7F2B300D2196D /* JITLoaderList.cpp in Sources */, 2689009713353E4200698AC0 /* ObjectContainerUniversalMachO.cpp in Sources */, 2689009813353E4200698AC0 /* ELFHeader.cpp in Sources */, 2689009913353E4200698AC0 /* ObjectFileELF.cpp in Sources */, 2689009A13353E4200698AC0 /* ObjectFileMachO.cpp in Sources */, + 25B4C4671BDEA2CD005B956D /* UDPSocket.cpp in Sources */, 2689009B13353E4200698AC0 /* PlatformMacOSX.cpp in Sources */, 2689009C13353E4200698AC0 /* PlatformRemoteiOS.cpp in Sources */, 2689009D13353E4200698AC0 /* GDBRemoteCommunication.cpp in Sources */, @@ -6594,7 +6664,6 @@ 268900D313353E6F00698AC0 /* ClangExternalASTSourceCallbacks.cpp in Sources */, 268900D513353E6F00698AC0 /* CompileUnit.cpp in Sources */, 268900D613353E6F00698AC0 /* Declaration.cpp in Sources */, - 2579065C1BD0488100178368 /* TCPSocket.cpp in Sources */, 268900D713353E6F00698AC0 /* DWARFCallFrameInfo.cpp in Sources */, 268900D813353E6F00698AC0 /* Function.cpp in Sources */, 268900D913353E6F00698AC0 /* FuncUnwinders.cpp in Sources */, @@ -6654,7 +6723,6 @@ 94B6385D1B8FB178004FE1E4 /* CPlusPlusLanguage.cpp in Sources */, 268900FE13353E6F00698AC0 /* ThreadPlanCallUserExpression.cpp in Sources */, 268900FF13353E6F00698AC0 /* ThreadPlanShouldStopHere.cpp in Sources */, - 2579065F1BD0488D00178368 /* DomainSocket.cpp in Sources */, 2689010013353E6F00698AC0 /* ThreadPlanStepInstruction.cpp in Sources */, 232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */, 2689010113353E6F00698AC0 /* ThreadPlanStepOut.cpp in Sources */, @@ -6790,6 +6858,7 @@ 949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */, B27318421416AC12006039C8 /* WatchpointList.cpp in Sources */, 26CFDCA3186163A4000E63E5 /* Editline.cpp in Sources */, + 25B4C4611BDEA2CD005B956D /* AbstractSocket.cpp in Sources */, 26E152261419CAD4007967D0 /* ObjectFilePECOFF.cpp in Sources */, B2462247141AD37D00F3D409 /* OptionGroupWatchpoint.cpp in Sources */, 94B638631B8FB7F1004FE1E4 /* ObjCPlusPlusLanguage.cpp in Sources */, @@ -6820,6 +6889,7 @@ 26B1EFAE154638AF00E2DAC7 /* DWARFDeclContext.cpp in Sources */, 945215DF17F639EE00521C0B /* ValueObjectPrinter.cpp in Sources */, 260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */, + 25B4C4651BDEA2CD005B956D /* TCPSocket.cpp in Sources */, 260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */, 260CC64A15D0440D002BF2E0 /* OptionValueBoolean.cpp in Sources */, 260CC64B15D0440D002BF2E0 /* OptionValueProperties.cpp in Sources */, Index: source/Core/PluginManager.cpp =================================================================== --- source/Core/PluginManager.cpp +++ source/Core/PluginManager.cpp @@ -2780,6 +2780,93 @@ return NULL; } +#pragma mark Socket + +struct SocketInstance +{ + SocketInstance() : + name(), + description(), + create_callback(nullptr) + { + } + + ConstString name; + std::string description; + SocketCreateInstance create_callback; +}; + +typedef std::vector SocketInstances; + +static Mutex & +GetSocketMutex () +{ + static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static SocketInstances & +GetSocketInstances () +{ + static SocketInstances g_instances; + return g_instances; +} + +bool +PluginManager::RegisterPlugin (const ConstString &name, + const char *description, + SocketCreateInstance create_callback) +{ + if (!create_callback) + return false; + + SocketInstance instance; + assert ((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + Mutex::Locker locker (GetSocketMutex ()); + GetSocketInstances ().push_back (instance); + return true; +} + +bool +PluginManager::UnregisterPlugin (SocketCreateInstance create_callback) +{ + if (!create_callback) + return false; + + Mutex::Locker locker (GetSocketMutex ()); + SocketInstances &instances = GetSocketInstances (); + + auto end = instances.end(); + for (auto pos = instances.begin(); pos != end; ++pos) + { + if (pos->create_callback == create_callback) + { + instances.erase(pos); + return true; + } + } + return false; +} + +SocketCreateInstance +PluginManager::GetSocketCreateCallbackForPluginName (const ConstString &name) +{ + if (!name) + return nullptr; + + Mutex::Locker locker (GetSocketMutex ()); + for (auto pos: GetSocketInstances ()) + { + if (name == pos.name) + return pos.create_callback; + } + return nullptr; +} + #pragma mark PluginManager void Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -34,13 +34,11 @@ common/SoftwareBreakpoint.cpp common/StringConvert.cpp common/Symbols.cpp - common/TCPSocket.cpp common/Terminal.cpp common/ThisThread.cpp common/ThreadLauncher.cpp common/TimeValue.cpp common/XML.cpp - common/UDPSocket.cpp ) # Keep track of whether we want to provide a define for the @@ -83,7 +81,6 @@ endif() add_host_subdirectory(posix - posix/DomainSocket.cpp posix/FileSystem.cpp posix/HostInfoPosix.cpp posix/HostProcessPosix.cpp @@ -121,7 +118,6 @@ android/HostInfoAndroid.cpp android/LibcGlue.cpp android/ProcessLauncherAndroid.cpp - linux/AbstractSocket.cpp linux/Host.cpp linux/HostInfoLinux.cpp linux/HostThreadLinux.cpp @@ -130,7 +126,6 @@ ) else() add_host_subdirectory(linux - linux/AbstractSocket.cpp linux/Host.cpp linux/HostInfoLinux.cpp linux/HostThreadLinux.cpp Index: source/Host/common/Socket.cpp =================================================================== --- source/Host/common/Socket.cpp +++ source/Host/common/Socket.cpp @@ -10,17 +10,19 @@ #include "lldb/Host/Socket.h" #include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Host/Config.h" #include "lldb/Host/Host.h" #include "lldb/Host/SocketAddress.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Host/common/UDPSocket.h" + +#include "Plugins/Socket/TCP/TCPSocket.h" +#include "Plugins/Socket/UDP/UDPSocket.h" #ifndef LLDB_DISABLE_POSIX -#include "lldb/Host/posix/DomainSocket.h" +#include "Plugins/Socket/POSIX/DomainSocket.h" #include #include @@ -31,9 +33,11 @@ #endif #ifdef __linux__ -#include "lldb/Host/linux/AbstractSocket.h" +#include "Plugins/Socket/Linux/AbstractSocket.h" #endif +#include + #ifdef __ANDROID_NDK__ #include #include @@ -73,6 +77,11 @@ } +const char * Socket::TCP = "tcp"; +const char * Socket::UDP = "udp"; +const char * Socket::UNIX = "unix"; +const char * Socket::UNIX_ABSTRACT = "unix-abstract"; + Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) : IOObject(eFDTypeSocket, should_close) , m_protocol(protocol) @@ -86,6 +95,33 @@ Close(); } +std::unique_ptr Socket::Create(const char* scheme, bool child_processes_inherit, Error& error) +{ + ConstString const_plugin_name(scheme); + auto create_callback = PluginManager::GetSocketCreateCallbackForPluginName (const_plugin_name); + if (!create_callback) + return std::unique_ptr(); + + return std::unique_ptr(create_callback(child_processes_inherit, error)); +} + +void Socket::Initialize() +{ + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [](){ + TCPSocket::Initialize(); + UDPSocket::Initialize(); + +#ifndef LLDB_DISABLE_POSIX + DomainSocket::Initialize(); +#endif + +#ifdef __linux__ + AbstractSocket::Initialize(); +#endif + }); +} + Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); @@ -93,13 +129,13 @@ log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); Error error; - std::unique_ptr connect_socket(new TCPSocket(child_processes_inherit, error)); + auto socket_up(Create(TCP, child_processes_inherit, error)); if (error.Fail()) return error; - error = connect_socket->Connect(host_and_port); + error = socket_up->Connect(host_and_port); if (error.Success()) - socket = connect_socket.release(); + socket = socket_up.release(); return error; } @@ -122,11 +158,11 @@ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) return error; - std::unique_ptr listen_socket(new TCPSocket(child_processes_inherit, error)); + auto socket_up(Create(TCP, child_processes_inherit, error)); if (error.Fail()) return error; - error = listen_socket->Listen(host_and_port, backlog); + error = socket_up->Listen(host_and_port, backlog); if (error.Success()) { // We were asked to listen on port zero which means we @@ -134,7 +170,7 @@ // as port zero is a special code for "find an open port // for me". if (port == 0) - port = listen_socket->GetLocalPortNumber(); + port = socket_up->GetLocalPortNumber(); // Set the port predicate since when doing a listen://: // it often needs to accept the incoming connection which is a blocking @@ -143,7 +179,7 @@ // another thread in an efficient manor. if (predicate) predicate->SetValue (port, eBroadcastAlways); - socket = listen_socket.release(); + socket = socket_up.release(); } return error; @@ -162,13 +198,13 @@ { Error error; #ifndef LLDB_DISABLE_POSIX - std::unique_ptr connect_socket(new DomainSocket(child_processes_inherit, error)); + auto socket_up(Create(UNIX, child_processes_inherit, error)); if (error.Fail()) return error; - error = connect_socket->Connect(name); + error = socket_up->Connect(name); if (error.Success()) - socket = connect_socket.release(); + socket = socket_up.release(); #else error.SetErrorString("Unix domain sockets are not supported on this platform."); #endif @@ -179,15 +215,15 @@ { Error error; #ifndef LLDB_DISABLE_POSIX - std::unique_ptr listen_socket(new DomainSocket(child_processes_inherit, error)); + auto socket_up(Create(UNIX, child_processes_inherit, error)); if (error.Fail()) return error; - error = listen_socket->Listen(name, 5); + error = socket_up->Listen(name, 5); if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = socket_up->Accept(name, child_processes_inherit, socket); #else error.SetErrorString("Unix domain sockets are not supported on this platform."); #endif @@ -199,13 +235,13 @@ { Error error; #ifdef __linux__ - std::unique_ptr connect_socket(new AbstractSocket(child_processes_inherit, error)); + auto socket_up(Create(UNIX_ABSTRACT, child_processes_inherit, error)); if (error.Fail()) return error; - error = connect_socket->Connect(name); + error = socket_up->Connect(name); if (error.Success()) - socket = connect_socket.release(); + socket = socket_up.release(); #else error.SetErrorString("Abstract domain sockets are not supported on this platform."); #endif @@ -217,15 +253,15 @@ { Error error; #ifdef __linux__ - std::unique_ptr listen_socket(new AbstractSocket(child_processes_inherit, error)); + auto socket_up(Create(UNIX_ABSTRACT, child_processes_inherit, error)); if (error.Fail()) return error; - error = listen_socket->Listen(name, 5); + error = socket_up->Listen(name, 5); if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = socket_up->Accept(name, child_processes_inherit, socket); #else error.SetErrorString("Abstract domain sockets are not supported on this platform."); #endif @@ -467,3 +503,58 @@ SetLastError(error); return fd; } + +// Return the port number that is being used by the socket. +uint16_t +Socket::GetLocalPortNumber() const +{ + if (m_socket != kInvalidSocketValue) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort (); + } + return 0; +} + +std::string +Socket::GetLocalIPAddress() const +{ + // We bound to port zero, so we need to figure out which port we actually bound to + if (m_socket != kInvalidSocketValue) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress (); + } + return ""; +} + +uint16_t +Socket::GetRemotePortNumber() const +{ + if (m_socket != kInvalidSocketValue) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort (); + } + return 0; +} + +std::string +Socket::GetRemoteIPAddress () const +{ + // We bound to port zero, so we need to figure out which port we actually bound to + if (m_socket != kInvalidSocketValue) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress (); + } + return ""; +} Index: source/Host/common/TCPSocket.cpp =================================================================== --- source/Host/common/TCPSocket.cpp +++ /dev/null @@ -1,288 +0,0 @@ -//===-- TcpSocket.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/common/TCPSocket.h" - -#include "lldb/Core/Log.h" -#include "lldb/Host/Config.h" - -#ifndef LLDB_DISABLE_POSIX -#include -#include -#include -#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 child_processes_inherit, Error &error) - : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, child_processes_inherit, error), true) -{ -} - - -// Return the port number that is being used by the socket. -uint16_t -TCPSocket::GetLocalPortNumber() const -{ - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; -} - -std::string -TCPSocket::GetLocalIPAddress() const -{ - // We bound to port zero, so we need to figure out which port we actually bound to - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetIPAddress (); - } - return ""; -} - -uint16_t -TCPSocket::GetRemotePortNumber() const -{ - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; -} - -std::string -TCPSocket::GetRemoteIPAddress () const -{ - // We bound to port zero, so we need to figure out which port we actually bound to - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetIPAddress (); - } - return ""; -} - -Error -TCPSocket::Connect(llvm::StringRef name) -{ - if (m_socket == kInvalidSocketValue) - return Error("Invalid socket"); - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); - if (log) - log->Printf ("TCPSocket::%s (host/port = %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; - - // Enable local address reuse - SetOptionReuseAddress(); - - 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()); - - return error; - } - } - - if (-1 == ::connect (GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) - { - SetLastError (error); - return error; - } - - // Keep our TCP packets coming without any delays. - SetOptionNoDelay(); - error.Clear(); - 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()); - - 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; - - // 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); - - if (!bind_addr_success) - { - error.SetErrorString("Failed to bind port"); - return error; - } - - int err = ::bind (GetNativeSocket(), bind_addr, bind_addr.GetLength()); - if (err != -1) - err = ::listen (GetNativeSocket(), backlog); - - if (err == -1) - SetLastError (error); - - return error; -} - -Error -TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, 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)) - 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()); - return error; - } - } - - bool accept_connection = false; - std::unique_ptr 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); - - 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(); - } - } - - if (!accepted_socket) - return error; - - // Keep our TCP packets coming without any delays. - accepted_socket->SetOptionNoDelay(); - error.Clear(); - conn_socket = accepted_socket.release(); - return error; -} - -int -TCPSocket::SetOptionNoDelay() -{ - return SetOption (IPPROTO_TCP, TCP_NODELAY, 1); -} - -int -TCPSocket::SetOptionReuseAddress() -{ - return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); -} Index: source/Host/common/UDPSocket.cpp =================================================================== --- source/Host/common/UDPSocket.cpp +++ /dev/null @@ -1,158 +0,0 @@ -//===-- UdpSocket.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/common/UDPSocket.h" - -#include "lldb/Core/Log.h" -#include "lldb/Host/Config.h" - -#ifndef LLDB_DISABLE_POSIX -#include -#include -#endif - -#include - -using namespace lldb; -using namespace lldb_private; - -namespace { - -const int kDomain = AF_INET; -const int kType = SOCK_DGRAM; - -const Error kNotSupported("Not supported"); - -} - -UDPSocket::UDPSocket(NativeSocket socket) - : Socket(socket, ProtocolUdp, true) -{ -} - -UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) - : UDPSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) -{ -} - -size_t -UDPSocket::Send(const void *buf, const size_t num_bytes) -{ - return ::sendto (m_socket, - static_cast(buf), - num_bytes, - 0, - m_send_sockaddr, - m_send_sockaddr.GetLength()); -} - -Error -UDPSocket::Connect(llvm::StringRef name) -{ - return kNotSupported; -} - -Error -UDPSocket::Listen(llvm::StringRef name, int backlog) -{ - return kNotSupported; -} - -Error -UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - return kNotSupported; -} - -Error -UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) -{ - std::unique_ptr final_send_socket; - std::unique_ptr final_recv_socket; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("UDPSocket::%s (host/port = %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; - - // Setup the receiving end of the UDP connection on this localhost - // on port zero. After we bind to port zero we can read the port. - final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); - if (error.Success()) - { - // Socket was created, now lets bind to the requested port - SocketAddress addr; - addr.SetToAnyAddress (AF_INET, 0); - - if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1) - { - // Bind failed... - SetLastError (error); - } - } - - assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); - if (error.Fail()) - return error; - - // At this point we have setup the receive port, now we need to - // setup the UDP send socket - - struct addrinfo hints; - struct addrinfo *service_info_list = nullptr; - - ::memset (&hints, 0, sizeof(hints)); - hints.ai_family = kDomain; - hints.ai_socktype = kType; - int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); - if (err != 0) - { - error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", - host_str.c_str(), - port_str.c_str(), - err, - gai_strerror(err)); - return error; - } - - 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 (service_info_ptr->ai_family, - service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, - child_processes_inherit, - error); - if (error.Success()) - { - final_send_socket.reset(new UDPSocket(send_fd)); - final_send_socket->m_send_sockaddr = service_info_ptr; - break; - } - else - continue; - } - - :: freeaddrinfo (service_info_list); - - if (!final_send_socket) - return error; - - send_socket = final_send_socket.release(); - recv_socket = final_recv_socket.release(); - error.Clear(); - return error; -} Index: source/Host/linux/AbstractSocket.cpp =================================================================== --- source/Host/linux/AbstractSocket.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===-- AbstractSocket.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/linux/AbstractSocket.h" - -#include "llvm/ADT/StringRef.h" - -using namespace lldb; -using namespace lldb_private; - -AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error) - : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) -{ -} - -size_t -AbstractSocket::GetNameOffset() const -{ - return 1; -} - -void -AbstractSocket::DeleteSocketFile(llvm::StringRef name) -{ -} Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp =================================================================== --- source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -47,8 +47,8 @@ #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Socket.h" -#include "lldb/Host/common/TCPSocket.h" #include "lldb/Interpreter/Args.h" +#include "Plugins/Socket/TCP/TCPSocket.h" using namespace lldb; using namespace lldb_private; Index: source/Host/posix/DomainSocket.cpp =================================================================== --- source/Host/posix/DomainSocket.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/posix/DomainSocket.h" - -#include "lldb/Host/FileSystem.h" - -#include -#include - -using namespace lldb; -using namespace lldb_private; - -#ifdef __ANDROID__ -// Android does not have SUN_LEN -#ifndef SUN_LEN -#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) -#endif -#endif // #ifdef __ANDROID__ - -namespace { - -const int kDomain = AF_UNIX; -const int kType = SOCK_STREAM; - -bool SetSockAddr(llvm::StringRef name, const size_t name_offset, sockaddr_un* saddr_un) -{ - if (name.size() + name_offset > sizeof(saddr_un->sun_path)) - return false; - - saddr_un->sun_family = kDomain; - memset(saddr_un->sun_path, 0, sizeof(saddr_un->sun_path)); - - strncpy(&saddr_un->sun_path[name_offset], name.data(), name.size()); -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un->sun_len = SUN_LEN (saddr_un); -#endif - return true; -} - -} - -DomainSocket::DomainSocket(NativeSocket socket) - : Socket(socket, ProtocolUnixDomain, true) -{ -} - -DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) - : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) -{ -} - -DomainSocket::DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error) - : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), protocol, true) -{ -} - -Error -DomainSocket::Connect(llvm::StringRef name) -{ - sockaddr_un saddr_un; - if (!SetSockAddr(name, GetNameOffset(), &saddr_un)) - return Error("Failed to set socket address"); - - Error error; - if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) < 0) - SetLastError (error); - - return error; -} - -Error -DomainSocket::Listen(llvm::StringRef name, int backlog) -{ - sockaddr_un saddr_un; - if (!SetSockAddr(name, GetNameOffset(), &saddr_un)) - return Error("Failed to set socket address"); - - DeleteSocketFile(name); - - Error error; - if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) == 0) - if (::listen(GetNativeSocket(), backlog) == 0) - return error; - - SetLastError(error); - return error; -} - -Error -DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error); - if (error.Success()) - socket = new DomainSocket(conn_fd); - - return error; -} - -size_t -DomainSocket::GetNameOffset() const -{ - return 0; -} - -void -DomainSocket::DeleteSocketFile(llvm::StringRef name) -{ - FileSystem::Unlink(FileSpec{name, true}); -} Index: source/Initialization/SystemInitializerCommon.cpp =================================================================== --- source/Initialization/SystemInitializerCommon.cpp +++ source/Initialization/SystemInitializerCommon.cpp @@ -11,6 +11,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/Socket.h" #include "lldb/Core/Log.h" #include "lldb/Core/Timer.h" #include "lldb/Symbol/GoASTContext.h" @@ -96,6 +97,7 @@ Log::Initialize(); HostInfo::Initialize(); + Socket::Initialize(); Timer::Initialize(); Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); Index: source/Plugins/CMakeLists.txt =================================================================== --- source/Plugins/CMakeLists.txt +++ source/Plugins/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory(Platform) add_subdirectory(Process) add_subdirectory(ScriptInterpreter) +add_subdirectory(Socket) add_subdirectory(SymbolFile) add_subdirectory(SystemRuntime) add_subdirectory(SymbolVendor) Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -10,7 +10,7 @@ // Other libraries and framework includes #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" -#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/Socket.h" #include "AdbClient.h" #include "PlatformAndroidRemoteGDBServer.h" #include "Utility/UriParser.h" @@ -63,7 +63,7 @@ FindUnusedPort (uint16_t& port) { Error error; - std::unique_ptr tcp_socket(new TCPSocket(false, error)); + const std::unique_ptr tcp_socket(Socket::Create("tcp", false, error)); if (error.Fail()) return error; Index: source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp =================================================================== --- source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -25,7 +25,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/Socket.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" @@ -276,7 +276,7 @@ if (conn_ap->IsConnected()) { - const TCPSocket& socket = static_cast(*conn_ap->GetReadObject()); + const Socket& socket = static_cast(*conn_ap->GetReadObject()); const uint16_t reply_port = socket.GetLocalPortNumber(); if (reply_port != 0) Index: source/Plugins/Socket/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Socket/CMakeLists.txt @@ -0,0 +1,8 @@ +add_subdirectory(TCP) +add_subdirectory(UDP) +if (CMAKE_HOST_UNIX) + add_subdirectory(POSIX) +endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + add_subdirectory(Linux) +endif() Index: source/Plugins/Socket/Linux/AbstractSocket.h =================================================================== --- /dev/null +++ source/Plugins/Socket/Linux/AbstractSocket.h @@ -0,0 +1,54 @@ +//===-- AbstractSocket.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "Plugins/Socket/POSIX/DomainSocket.h" + +namespace lldb_private +{ + class AbstractSocket: public DomainSocket + { + public: + AbstractSocket(bool child_processes_inherit, Error &error); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static Socket* + CreateInstance(bool child_processes_inherit, Error &error); + + const char* GetScheme() const override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + + protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; + }; +} + +#endif // ifndef liblldb_AbstractSocket_h_ Index: source/Plugins/Socket/Linux/AbstractSocket.cpp =================================================================== --- /dev/null +++ source/Plugins/Socket/Linux/AbstractSocket.cpp @@ -0,0 +1,90 @@ +//===-- AbstractSocket.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) +{ +} + +void +AbstractSocket::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +AbstractSocket::Terminate() +{ +} + +ConstString +AbstractSocket::GetPluginNameStatic() +{ + static ConstString g_name(UNIX_ABSTRACT); + return g_name; +} + +const char * +AbstractSocket::GetPluginDescriptionStatic() +{ + return "Unix domain abstract socket plug-in"; +} + +Socket* +AbstractSocket::CreateInstance(bool child_processes_inherit, Error &error) +{ + error.Clear(); + std::unique_ptr socket_up(new AbstractSocket(child_processes_inherit, error)); + if (error.Fail()) + { + socket_up.reset(); + return nullptr; + } + return socket_up.release(); +} + +size_t +AbstractSocket::GetNameOffset() const +{ + return 1; +} + +void +AbstractSocket::DeleteSocketFile(llvm::StringRef name) +{ +} + +ConstString +AbstractSocket::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +AbstractSocket::GetPluginVersion() +{ + return 1; +} + +const char* AbstractSocket::GetScheme() const +{ + return GetPluginNameStatic().AsCString(); +} Index: source/Plugins/Socket/Linux/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Socket/Linux/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(.) + +add_lldb_library(lldbPluginLinuxSocket + AbstractSocket.cpp + ) Index: source/Plugins/Socket/POSIX/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Socket/POSIX/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(.) + +add_lldb_library(lldbPluginPOSIXSocket + DomainSocket.cpp + ) Index: source/Plugins/Socket/POSIX/DomainSocket.h =================================================================== --- /dev/null +++ source/Plugins/Socket/POSIX/DomainSocket.h @@ -0,0 +1,62 @@ +//===-- DomainSocket.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DomainSocket_h_ +#define liblldb_DomainSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class DomainSocket: public Socket + { + public: + DomainSocket(bool child_processes_inherit, Error &error); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static Socket* + CreateInstance(bool child_processes_inherit, Error &error); + + 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; + const char* GetScheme() const override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + + protected: + DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error); + + virtual size_t GetNameOffset() const; + virtual void DeleteSocketFile(llvm::StringRef name); + + private: + DomainSocket(NativeSocket socket); + }; +} + +#endif // ifndef liblldb_DomainSocket_h_ Index: source/Plugins/Socket/POSIX/DomainSocket.cpp =================================================================== --- /dev/null +++ source/Plugins/Socket/POSIX/DomainSocket.cpp @@ -0,0 +1,174 @@ +//===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DomainSocket.h" + +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSystem.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +#ifdef __ANDROID__ +// Android does not have SUN_LEN +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) +#endif +#endif // #ifdef __ANDROID__ + +namespace { + +const int kDomain = AF_UNIX; +const int kType = SOCK_STREAM; + +bool SetSockAddr(llvm::StringRef name, const size_t name_offset, sockaddr_un* saddr_un) +{ + if (name.size() + name_offset > sizeof(saddr_un->sun_path)) + return false; + + saddr_un->sun_family = kDomain; + memset(saddr_un->sun_path, 0, sizeof(saddr_un->sun_path)); + + strncpy(&saddr_un->sun_path[name_offset], name.data(), name.size()); +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) + saddr_un->sun_len = SUN_LEN (saddr_un); +#endif + return true; +} + +} + +DomainSocket::DomainSocket(NativeSocket socket) + : Socket(socket, ProtocolUnixDomain, true) +{ +} + +DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) + : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) +{ +} + +DomainSocket::DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error) + : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), protocol, true) +{ +} + +void +DomainSocket::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +DomainSocket::Terminate() +{ +} + +ConstString +DomainSocket::GetPluginNameStatic() +{ + static ConstString g_name(UNIX); + return g_name; +} + +const char * +DomainSocket::GetPluginDescriptionStatic() +{ + return "Unix domain socket plug-in"; +} + +Socket* +DomainSocket::CreateInstance(bool child_processes_inherit, Error &error) +{ + error.Clear(); + std::unique_ptr socket_up(new DomainSocket(child_processes_inherit, error)); + if (error.Fail()) + { + socket_up.reset(); + return nullptr; + } + return socket_up.release(); +} + +Error +DomainSocket::Connect(llvm::StringRef name) +{ + sockaddr_un saddr_un; + if (!SetSockAddr(name, GetNameOffset(), &saddr_un)) + return Error("Failed to set socket address"); + + Error error; + if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) < 0) + SetLastError (error); + + return error; +} + +Error +DomainSocket::Listen(llvm::StringRef name, int backlog) +{ + sockaddr_un saddr_un; + if (!SetSockAddr(name, GetNameOffset(), &saddr_un)) + return Error("Failed to set socket address"); + + DeleteSocketFile(name); + + Error error; + if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) == 0) + if (::listen(GetNativeSocket(), backlog) == 0) + return error; + + SetLastError(error); + return error; +} + +Error +DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) +{ + Error error; + auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error); + if (error.Success()) + socket = new DomainSocket(conn_fd); + + return error; +} + +size_t +DomainSocket::GetNameOffset() const +{ + return 0; +} + +void +DomainSocket::DeleteSocketFile(llvm::StringRef name) +{ + FileSystem::Unlink(FileSpec{name, true}); +} + +ConstString +DomainSocket::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +DomainSocket::GetPluginVersion() +{ + return 1; +} + +const char* DomainSocket::GetScheme() const +{ + return GetPluginNameStatic().AsCString(); +} Index: source/Plugins/Socket/TCP/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Socket/TCP/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(.) + +add_lldb_library(lldbPluginTCPSocket + TCPSocket.cpp + ) Index: source/Plugins/Socket/TCP/TCPSocket.h =================================================================== --- /dev/null +++ source/Plugins/Socket/TCP/TCPSocket.h @@ -0,0 +1,57 @@ +//===-- TCPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_TCPSocket_h_ +#define liblldb_TCPSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class TCPSocket: public Socket + { + public: + TCPSocket(NativeSocket socket, bool should_close); + TCPSocket(bool child_processes_inherit, Error &error); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static Socket* + CreateInstance(bool child_processes_inherit, Error &error); + + int SetOptionNoDelay(); + int SetOptionReuseAddress(); + + 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; + const char* GetScheme() const override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + }; +} + +#endif // ifndef liblldb_TCPSocket_h_ Index: source/Plugins/Socket/TCP/TCPSocket.cpp =================================================================== --- /dev/null +++ source/Plugins/Socket/TCP/TCPSocket.cpp @@ -0,0 +1,290 @@ +//===-- TcpSocket.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TCPSocket.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Config.h" + +#ifndef LLDB_DISABLE_POSIX +#include +#include +#include +#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 child_processes_inherit, Error &error) + : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, child_processes_inherit, error), true) +{ +} + + +void +TCPSocket::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +TCPSocket::Terminate() +{ +} + +ConstString +TCPSocket::GetPluginNameStatic() +{ + static ConstString g_name(TCP); + return g_name; +} + +const char * +TCPSocket::GetPluginDescriptionStatic() +{ + return "TCP socket plug-in"; +} + +Socket* +TCPSocket::CreateInstance(bool child_processes_inherit, Error &error) +{ + error.Clear(); + std::unique_ptr socket_up(new TCPSocket(child_processes_inherit, error)); + if (error.Fail()) + { + socket_up.reset(); + return nullptr; + } + return socket_up.release(); +} + +Error +TCPSocket::Connect(llvm::StringRef name) +{ + if (m_socket == kInvalidSocketValue) + return Error("Invalid socket"); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); + if (log) + log->Printf ("TCPSocket::%s (host/port = %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; + + // Enable local address reuse + SetOptionReuseAddress(); + + 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()); + + return error; + } + } + + if (-1 == ::connect (GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) + { + SetLastError (error); + return error; + } + + // Keep our TCP packets coming without any delays. + SetOptionNoDelay(); + error.Clear(); + 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()); + + 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; + + // 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); + + if (!bind_addr_success) + { + error.SetErrorString("Failed to bind port"); + return error; + } + + int err = ::bind (GetNativeSocket(), bind_addr, bind_addr.GetLength()); + if (err != -1) + err = ::listen (GetNativeSocket(), backlog); + + if (err == -1) + SetLastError (error); + + return error; +} + +Error +TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, 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)) + 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()); + return error; + } + } + + bool accept_connection = false; + std::unique_ptr 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); + + 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(); + } + } + + if (!accepted_socket) + return error; + + // Keep our TCP packets coming without any delays. + accepted_socket->SetOptionNoDelay(); + error.Clear(); + conn_socket = accepted_socket.release(); + return error; +} + +int +TCPSocket::SetOptionNoDelay() +{ + return SetOption (IPPROTO_TCP, TCP_NODELAY, 1); +} + +int +TCPSocket::SetOptionReuseAddress() +{ + return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); +} + +ConstString +TCPSocket::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +TCPSocket::GetPluginVersion() +{ + return 1; +} + +const char* TCPSocket::GetScheme() const +{ + return GetPluginNameStatic().AsCString(); +} Index: source/Plugins/Socket/UDP/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Socket/UDP/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories(.) + +add_lldb_library(lldbPluginUDPSocket + UDPSocket.cpp + ) Index: source/Plugins/Socket/UDP/UDPSocket.h =================================================================== --- /dev/null +++ source/Plugins/Socket/UDP/UDPSocket.h @@ -0,0 +1,60 @@ +//===-- UDPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UDPSocket_h_ +#define liblldb_UDPSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private +{ + class UDPSocket: public Socket + { + public: + static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static Socket* + CreateInstance(bool child_processes_inherit, Error &error); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + + const char* GetScheme() const override; + private: + UDPSocket(NativeSocket socket); + UDPSocket(bool child_processes_inherit, Error &error); + + 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; + + SocketAddress m_send_sockaddr; + }; +} + +#endif // ifndef liblldb_UDPSocket_h_ Index: source/Plugins/Socket/UDP/UDPSocket.cpp =================================================================== --- /dev/null +++ source/Plugins/Socket/UDP/UDPSocket.cpp @@ -0,0 +1,215 @@ +//===-- UdpSocket.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UDPSocket.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Config.h" + +#ifndef LLDB_DISABLE_POSIX +#include +#include +#endif + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const int kDomain = AF_INET; +const int kType = SOCK_DGRAM; + +const Error kNotSupported("Not supported"); + +} + +UDPSocket::UDPSocket(NativeSocket socket) + : Socket(socket, ProtocolUdp, true) +{ +} + +UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) + : UDPSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) +{ +} + +void +UDPSocket::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +UDPSocket::Terminate() +{ +} + +ConstString +UDPSocket::GetPluginNameStatic() +{ + static ConstString g_name(UDP); + return g_name; +} + +const char * +UDPSocket::GetPluginDescriptionStatic() +{ + return "UDP socket plug-in"; +} + +Socket* +UDPSocket::CreateInstance(bool child_processes_inherit, Error &error) +{ + error.Clear(); + std::unique_ptr socket_up(new UDPSocket(child_processes_inherit, error)); + if (error.Fail()) + { + socket_up.reset(); + return nullptr; + } + return socket_up.release(); +} + +size_t +UDPSocket::Send(const void *buf, const size_t num_bytes) +{ + return ::sendto (m_socket, + static_cast(buf), + num_bytes, + 0, + m_send_sockaddr, + m_send_sockaddr.GetLength()); +} + +Error +UDPSocket::Connect(llvm::StringRef name) +{ + return kNotSupported; +} + +Error +UDPSocket::Listen(llvm::StringRef name, int backlog) +{ + return kNotSupported; +} + +Error +UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) +{ + return kNotSupported; +} + +Error +UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) +{ + std::unique_ptr final_send_socket; + std::unique_ptr final_recv_socket; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf ("UDPSocket::%s (host/port = %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; + + // Setup the receiving end of the UDP connection on this localhost + // on port zero. After we bind to port zero we can read the port. + final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); + if (error.Success()) + { + // Socket was created, now lets bind to the requested port + SocketAddress addr; + addr.SetToAnyAddress (AF_INET, 0); + + if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1) + { + // Bind failed... + SetLastError (error); + } + } + + assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); + if (error.Fail()) + return error; + + // At this point we have setup the receive port, now we need to + // setup the UDP send socket + + struct addrinfo hints; + struct addrinfo *service_info_list = nullptr; + + ::memset (&hints, 0, sizeof(hints)); + hints.ai_family = kDomain; + hints.ai_socktype = kType; + int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); + if (err != 0) + { + error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", + host_str.c_str(), + port_str.c_str(), + err, + gai_strerror(err)); + return error; + } + + 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 (service_info_ptr->ai_family, + service_info_ptr->ai_socktype, + service_info_ptr->ai_protocol, + child_processes_inherit, + error); + if (error.Success()) + { + final_send_socket.reset(new UDPSocket(send_fd)); + final_send_socket->m_send_sockaddr = service_info_ptr; + break; + } + else + continue; + } + + :: freeaddrinfo (service_info_list); + + if (!final_send_socket) + return error; + + send_socket = final_send_socket.release(); + recv_socket = final_recv_socket.release(); + error.Clear(); + return error; +} + +ConstString +UDPSocket::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +UDPSocket::GetPluginVersion() +{ + return 1; +} + +const char* UDPSocket::GetScheme() const +{ + return GetPluginNameStatic().AsCString(); +} Index: tools/lldb-server/Acceptor.cpp =================================================================== --- tools/lldb-server/Acceptor.cpp +++ tools/lldb-server/Acceptor.cpp @@ -13,8 +13,9 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Host/posix/DomainSocket.h" +#include "lldb/Host/Socket.h" + +#include "Utility/UriParser.h" using namespace lldb; using namespace lldb_private; @@ -65,12 +66,15 @@ 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); + listener_socket = Socket::Create(Socket::TCP, child_processes_inherit, error); + if (error.Success()) + { + auto tcp_socket = listener_socket.get(); + local_socket_id = [tcp_socket]() { + auto local_port = tcp_socket->GetLocalPortNumber(); + return (local_port != 0) ? std::to_string(local_port) : ""; + }; + } } else { @@ -78,7 +82,7 @@ local_socket_id = [socket_name](){ return socket_name; }; - listener_socket.reset(new DomainSocket(child_processes_inherit, error)); + listener_socket = Socket::Create(Socket::UNIX, child_processes_inherit, error); } if (error.Success()) Index: tools/lldb-server/lldb-platform.cpp =================================================================== --- tools/lldb-server/lldb-platform.cpp +++ tools/lldb-server/lldb-platform.cpp @@ -32,7 +32,6 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostGetOpt.h" #include "lldb/Host/OptionParser.h" -#include "lldb/Host/common/TCPSocket.h" #include "Acceptor.h" #include "LLDBServerUtilities.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" Index: unittests/Host/SocketTest.cpp =================================================================== --- unittests/Host/SocketTest.cpp +++ unittests/Host/SocketTest.cpp @@ -21,12 +21,8 @@ #include "lldb/Host/Config.h" #include "lldb/Host/Socket.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Host/common/UDPSocket.h" -#ifndef LLDB_DISABLE_POSIX -#include "lldb/Host/posix/DomainSocket.h" -#endif +#include "Plugins/Socket/UDP/UDPSocket.h" using namespace lldb_private; @@ -40,6 +36,7 @@ WSADATA data; ::WSAStartup(MAKEWORD(2, 2), &data); #endif + Socket::Initialize(); } void @@ -58,13 +55,12 @@ *error = listen_socket->Accept(listen_remote_address, child_processes_inherit, *accept_socket); } - template void - CreateConnectedSockets(const char *listen_remote_address, const std::function &get_connect_addr, std::unique_ptr *a_up, std::unique_ptr *b_up) + CreateConnectedSockets(const char* scheme, const char *listen_remote_address, const std::function &get_connect_addr, std::unique_ptr *a_up, std::unique_ptr *b_up) { bool child_processes_inherit = false; Error error; - std::unique_ptr listen_socket_up(new SocketType(child_processes_inherit, error)); + std::unique_ptr listen_socket_up(Socket::Create(scheme, child_processes_inherit, error)); EXPECT_FALSE(error.Fail()); error = listen_socket_up->Listen(listen_remote_address, 5); EXPECT_FALSE(error.Fail()); @@ -76,7 +72,7 @@ &accept_socket, &accept_error); std::string connect_remote_address = get_connect_addr(*listen_socket_up); - std::unique_ptr connect_socket_up(new SocketType(child_processes_inherit, error)); + std::unique_ptr connect_socket_up(Socket::Create(scheme, child_processes_inherit, error)); EXPECT_FALSE(error.Fail()); error = connect_socket_up->Connect(connect_remote_address.c_str()); EXPECT_FALSE(error.Fail()); @@ -88,7 +84,7 @@ EXPECT_TRUE((*a_up)->IsValid()); accept_thread.join(); - b_up->reset(static_cast(accept_socket)); + b_up->reset(accept_socket); EXPECT_TRUE(accept_error.Success()); EXPECT_NE(nullptr, b_up->get()); EXPECT_TRUE((*b_up)->IsValid()); @@ -138,44 +134,47 @@ const std::string file_name(file_name_str); free(file_name_str); - std::unique_ptr socket_a_up; - std::unique_ptr socket_b_up; - CreateConnectedSockets(file_name.c_str(), - [=](const DomainSocket &) - { - return file_name; - }, - &socket_a_up, &socket_b_up); + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + CreateConnectedSockets("unix", + file_name.c_str(), + [=](const Socket &) + { + return file_name; + }, + &socket_a_up, &socket_b_up); } #endif TEST_F (SocketTest, TCPListen0ConnectAccept) { - std::unique_ptr socket_a_up; - std::unique_ptr socket_b_up; - CreateConnectedSockets("127.0.0.1:0", - [=](const TCPSocket &s) - { - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); - return std::string(connect_remote_address); - }, - &socket_a_up, &socket_b_up); + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + CreateConnectedSockets("tcp", + "127.0.0.1:0", + [=](const Socket &s) + { + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); + return std::string(connect_remote_address); + }, + &socket_a_up, &socket_b_up); } TEST_F (SocketTest, TCPGetAddress) { - std::unique_ptr socket_a_up; - std::unique_ptr socket_b_up; - CreateConnectedSockets("127.0.0.1:0", - [=](const TCPSocket &s) - { - char connect_remote_address[64]; - snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); - return std::string(connect_remote_address); - }, - &socket_a_up, - &socket_b_up); + std::unique_ptr socket_a_up; + std::unique_ptr socket_b_up; + CreateConnectedSockets("tcp", + "127.0.0.1:0", + [=](const Socket &s) + { + char connect_remote_address[64]; + snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber()); + return std::string(connect_remote_address); + }, + &socket_a_up, + &socket_b_up); EXPECT_EQ (socket_a_up->GetLocalPortNumber (), socket_b_up->GetRemotePortNumber ()); EXPECT_EQ (socket_b_up->GetLocalPortNumber (), socket_a_up->GetRemotePortNumber ());