Re-landing IPv6 support for LLDB Host

This support was landed in r300579, and reverted in r300669 due to failures on the bots.

The failures were caused by sockets not being properly closed, and this updated version of the patches should resolve that.

Summary from the original change:

This patch adds IPv6 support to LLDB/Host's TCP socket implementation. Supporting IPv6 involved a few significant changes to the implementation of the socket layers, and I have performed some significant code cleanup along the way.

This patch changes the Socket constructors for all types of sockets to not create sockets until first use. This is required for IPv6 support because the socket type will vary based on the address you are connecting to. This also has the benefit of removing code that could have errors from the Socket subclass constructors (which seems like a win to me).

The patch also slightly changes the API and behaviors of the Listen/Accept pattern. Previously both Listen and Accept calls took an address specified as a string. Now only listen does. This change was made because the Listen call can result in opening more than one socket. In order to support listening for both IPv4 and IPv6 connections we need to open one AF_INET socket and one AF_INET6 socket. During the listen call we construct a map of file descriptors to addrin structures which represent the allowable incoming connection address. This map removes the need for taking an address into the Accept call.

This does have a change in functionality. Previously you could Listen for connections based on one address, and Accept connections from a different address. This is no longer supported. I could not find anywhere in LLDB where we actually used the APIs in that way. The new API does still support AnyAddr for allowing incoming connections from any address.

The Listen implementation is implemented using kqueue on FreeBSD and Darwin, WSAPoll on Windows and poll(2) everywhere else.

https://reviews.llvm.org/D31823

llvm-svn: 301492
This commit is contained in:
Chris Bieneman 2017-04-26 23:17:20 +00:00
parent 0fcbb2893e
commit 1182779917
29 changed files with 690 additions and 497 deletions

View File

@ -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

View File

@ -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.

View File

@ -16,4 +16,8 @@
#cmakedefine01 HAVE_SYS_EVENT_H
#cmakedefine01 HAVE_PPOLL
#cmakedefine01 HAVE_SIGACTION
#endif // #ifndef LLDB_HOST_CONFIG_H

View File

@ -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"
namespace lldb_private {
typedef MainLoopBase MainLoop;
}
#else
#include "lldb/Host/posix/MainLoopPosix.h"
namespace lldb_private {
typedef MainLoopPosix MainLoop;
}
#include "llvm/ADT/DenseMap.h"
#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H
#define SIGNAL_POLLING_UNSUPPORTED 1
#endif
namespace lldb_private {
// 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_

View File

@ -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

View File

@ -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;
};
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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);
};
}

View File

@ -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_

View File

@ -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 */,

View File

@ -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
)

View File

@ -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();
read_fds.clear();
FD_ZERO(&read_fd_set);
int nfds = 0;
#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();
#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)

View File

@ -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, &regex_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);

View File

@ -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();

View File

@ -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);
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;
int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr);
address.SetPort(port);
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(), &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);
if (-1 == err) {
CLOSE_SOCKET(fd);
continue;
}
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;
}
int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength());
if (err != -1)
err = ::listen(GetNativeSocket(), backlog);
if (err == -1)
SetLastError(error);
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) {
Error error;
std::string host_str;
std::string port_str;
int32_t port;
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
void TCPSocket::CloseListenSockets() {
for (auto socket : m_listen_sockets)
CLOSE_SOCKET(socket.first);
m_listen_sockets.clear();
}
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());
Error TCPSocket::Accept(Socket *&conn_socket) {
Error error;
if (m_listen_sockets.size() == 0) {
error.SetErrorString("No open listening sockets!");
return error;
}
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;
return error;
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();
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)

View File

@ -28,41 +28,31 @@ const int kDomain = AF_INET;
const int kType = SOCK_DGRAM;
static const char *g_not_supported_error = "Not supported";
} // namespace
UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit)
: Socket(ProtocolUdp, should_close, child_processes_inherit) {}
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;
}
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<const char *>(buf), num_bytes, 0,
m_sockaddr, m_sockaddr.GetLength());
}
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());
err = ::bind(m_socket, 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);
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;
}

View File

@ -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; }

View File

@ -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;

View File

@ -56,19 +56,21 @@ bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
return true;
}
}
} // namespace
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(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;
}

View File

@ -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;

View File

@ -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 */,

View File

@ -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

View File

@ -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);
return rnb_err;
}
DNBError err;
int listen_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_fd == -1)
err.SetError(errno, DNBError::POSIX);
if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol "
"= IPPROTO_TCP ) => socket = %i",
listen_fd);
if (err.Fail())
return rnb_err;
// 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);
if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
err.LogThreaded(
"::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )",
listen_fd);
if (err.Fail()) {
ClosePort(listen_fd, false);
int queue_id = kqueue();
if (queue_id < 0) {
err.SetError(errno, DNBError::MachKernel);
err.LogThreaded("error: failed to create kqueue.");
return rnb_err;
}
error = ::listen(listen_fd, 5);
if (error == -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("::listen ( socket = %i, backlog = 1 )", listen_fd);
for (auto address : addresses) {
int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
if (sock_fd == -1)
continue;
if (err.Fail()) {
ClosePort(listen_fd, false);
return rnb_err;
}
SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
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);
address.SetPort(port);
int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength());
if (error == -1) {
ClosePort(sock_fd, false);
continue;
}
error = ::listen(sock_fd, 5);
if (error == -1) {
ClosePort(sock_fd, false);
continue;
}
// 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();
}
sockets[sock_fd] = address;
}
struct sockaddr_in accept_addr;
::memset(&accept_addr, 0, sizeof accept_addr);
accept_addr.sin_len = sizeof accept_addr;
if (sockets.size() == 0) {
err.SetError(errno, DNBError::POSIX);
err.LogThreaded("::listen or ::bind failed");
return rnb_err;
}
if (callback)
callback(callback_baton, port);
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, &address.sockaddr(), address.GetLength())) {
Disconnect(false);
continue;
}
SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
result = rnb_success;
break;
}
if (-1 == ::connect(m_fd, (const struct sockaddr *)&sa, sizeof(sa))) {
Disconnect(false);
return rnb_err;
}
// Keep our TCP packets coming without any delays.
SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
return rnb_success;
return result;
}
rnb_err_t RNBSocket::useFD(int fd) {

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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];

View File

@ -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"); }