endif()
find_package(Backtrace)
-check_symbol_exists(ppoll poll.h HAVE_PPOLL)
-check_symbol_exists(sigaction signal.h HAVE_SIGACTION)
check_include_file(termios.h HAVE_TERMIOS_H)
-check_include_file(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
#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.
#cmakedefine01 HAVE_SYS_EVENT_H
-#cmakedefine01 HAVE_PPOLL
-
-#cmakedefine01 HAVE_SIGACTION
-
#endif // #ifndef LLDB_HOST_CONFIG_H
#ifndef lldb_Host_MainLoop_h_
#define lldb_Host_MainLoop_h_
-#include "lldb/Host/Config.h"
+#ifdef _WIN32
#include "lldb/Host/MainLoopBase.h"
-
-#include "llvm/ADT/DenseMap.h"
-
-#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H
-#define SIGNAL_POLLING_UNSUPPORTED 1
-#endif
-
namespace lldb_private {
-
-// 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;
+typedef MainLoopBase MainLoop;
+}
+#else
+#include "lldb/Host/posix/MainLoopPosix.h"
+namespace lldb_private {
+typedef MainLoopPosix MainLoop;
+}
#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_
virtual Error Connect(llvm::StringRef name) = 0;
virtual Error Listen(llvm::StringRef name, int backlog) = 0;
- virtual Error Accept(Socket *&socket) = 0;
+ virtual Error Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket) = 0;
// Initialize a Tcp Socket object in listening mode. listen and accept are
// implemented
int32_t &port, Error *error_ptr);
protected:
- Socket(SocketProtocol protocol, bool should_close,
- bool m_child_process_inherit);
+ Socket(NativeSocket socket, SocketProtocol protocol, bool should_close);
virtual size_t Send(const void *buf, const size_t num_bytes);
SocketProtocol m_protocol;
NativeSocket m_socket;
- bool m_child_processes_inherit;
};
} // namespace lldb_private
#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(bool should_close, bool child_processes_inherit);
- TCPSocket(NativeSocket socket, bool should_close,
- bool child_processes_inherit);
- ~TCPSocket();
+ TCPSocket(NativeSocket socket, bool should_close);
+ TCPSocket(bool child_processes_inherit, Error &error);
// returns port number or 0 if error
uint16_t GetLocalPortNumber() const;
Error Connect(llvm::StringRef name) override;
Error Listen(llvm::StringRef name, int backlog) 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;
+ Error Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&conn_socket) override;
};
}
namespace lldb_private {
class UDPSocket : public Socket {
public:
- UDPSocket(bool should_close, bool child_processes_inherit);
+ UDPSocket(bool child_processes_inherit, Error &error);
static Error Connect(llvm::StringRef name, bool child_processes_inherit,
Socket *&socket);
private:
- UDPSocket(NativeSocket socket, const UDPSocket &listen_socket);
+ UDPSocket(NativeSocket 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(Socket *&socket) override;
-
- Error CreateSocket();
+ Error Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket) override;
SocketAddress m_sockaddr;
};
namespace lldb_private {
class AbstractSocket : public DomainSocket {
public:
- AbstractSocket(bool child_processes_inherit);
+ AbstractSocket(bool child_processes_inherit, Error &error);
protected:
size_t GetNameOffset() const override;
namespace lldb_private {
class DomainSocket : public Socket {
public:
- DomainSocket(bool should_close, bool child_processes_inherit);
+ DomainSocket(bool child_processes_inherit, Error &error);
Error Connect(llvm::StringRef name) override;
Error Listen(llvm::StringRef name, int backlog) override;
- Error Accept(Socket *&socket) override;
+ Error Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket) override;
protected:
- DomainSocket(SocketProtocol protocol, bool child_processes_inherit);
+ DomainSocket(SocketProtocol protocol, bool child_processes_inherit,
+ Error &error);
virtual size_t GetNameOffset() const;
virtual void DeleteSocketFile(llvm::StringRef name);
private:
- DomainSocket(NativeSocket socket, const DomainSocket &listen_socket);
+ DomainSocket(NativeSocket socket);
};
}
--- /dev/null
+//===-- 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_
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 */; };
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 */; };
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>"; };
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>"; };
children = (
2579065E1BD0488D00178368 /* DomainSocket.cpp */,
255EFF751AFABA950069F277 /* LockFilePosix.cpp */,
+ 30DED5DC1B4ECB17004CC508 /* MainLoopPosix.cpp */,
AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */,
3FDFDDC5199D37ED009756A7 /* FileSystem.cpp */,
3FDFE53019A292F0009756A7 /* HostInfoPosix.cpp */,
69A01E1A1236C5D400C660B5 /* common */ = {
isa = PBXGroup;
children = (
- D67521351EA17C3900439694 /* MainLoop.cpp */,
2579065A1BD0488100178368 /* TCPSocket.cpp */,
2579065B1BD0488100178368 /* UDPSocket.cpp */,
255EFF731AFABA720069F277 /* LockFileBase.cpp */,
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 */,
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 */,
common/HostThread.cpp
common/IOObject.cpp
common/LockFileBase.cpp
- common/MainLoop.cpp
common/MonitoringProcessLauncher.cpp
common/NativeBreakpoint.cpp
common/NativeBreakpointList.cpp
posix/HostProcessPosix.cpp
posix/HostThreadPosix.cpp
posix/LockFilePosix.cpp
+ posix/MainLoopPosix.cpp
posix/PipePosix.cpp
posix/ProcessLauncherPosixFork.cpp
)
#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"
}
}
-Socket::Socket(SocketProtocol protocol, bool should_close,
- bool child_processes_inherit)
+Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
: IOObject(eFDTypeSocket, should_close), m_protocol(protocol),
- m_socket(kInvalidSocketValue),
- m_child_processes_inherit(child_processes_inherit) {}
+ m_socket(socket) {}
Socket::~Socket() { Close(); }
std::unique_ptr<Socket> socket_up;
switch (protocol) {
case ProtocolTcp:
- socket_up = llvm::make_unique<TCPSocket>(true, child_processes_inherit);
+ socket_up.reset(new TCPSocket(child_processes_inherit, error));
break;
case ProtocolUdp:
- socket_up = llvm::make_unique<UDPSocket>(true, child_processes_inherit);
+ socket_up.reset(new UDPSocket(child_processes_inherit, error));
break;
case ProtocolUnixDomain:
#ifndef LLDB_DISABLE_POSIX
- socket_up = llvm::make_unique<DomainSocket>(true, child_processes_inherit);
+ socket_up.reset(new DomainSocket(child_processes_inherit, error));
#else
error.SetErrorString(
"Unix domain sockets are not supported on this platform.");
break;
case ProtocolUnixAbstract:
#ifdef __linux__
- socket_up =
- llvm::make_unique<AbstractSocket>(child_processes_inherit);
+ socket_up.reset(new AbstractSocket(child_processes_inherit, error));
#else
error.SetErrorString(
"Abstract domain sockets are not supported on this platform.");
return error;
std::unique_ptr<TCPSocket> listen_socket(
- new TCPSocket(child_processes_inherit, true));
+ new TCPSocket(child_processes_inherit, error));
if (error.Fail())
return error;
if (error.Fail())
return error;
- error = listen_socket->Accept(socket);
+ error = listen_socket->Accept(name, child_processes_inherit, socket);
return error;
}
if (error.Fail())
return error;
- error = listen_socket->Accept(socket);
+ error = listen_socket->Accept(name, child_processes_inherit, 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-9a-fA-F:]+.*\\]):([0-9]+)"));
+ static RegularExpression g_regex(llvm::StringRef("([^:]+):([0-9]+)"));
RegularExpression::Match regex_match(2);
if (g_regex.Execute(host_and_port, ®ex_match)) {
if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) &&
regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) {
- // IPv6 addresses are wrapped in [] when specified with ports
- if (host_str.front() == '[' && host_str.back() == ']')
- host_str = host_str.substr(1, host_str.size() - 2);
bool ok = false;
port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok);
if (ok && port <= UINT16_MAX) {
const int protocol,
bool child_processes_inherit, Error &error) {
error.Clear();
- auto socket_type = type;
+ auto socketType = type;
#ifdef SOCK_CLOEXEC
if (!child_processes_inherit)
- socket_type |= SOCK_CLOEXEC;
+ socketType |= SOCK_CLOEXEC;
#endif
- auto sock = ::socket(domain, socket_type, protocol);
+ auto sock = ::socket(domain, socketType, protocol);
if (sock == kInvalidSocketValue)
SetLastError(error);
#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 kType = SOCK_STREAM;
-}
-TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
- : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
-
-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;
+const int kDomain = AF_INET;
+const int kType = SOCK_STREAM;
}
-TCPSocket::~TCPSocket() { CloseListenSockets(); }
+TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
+ : Socket(socket, ProtocolTcp, should_close) {}
-bool TCPSocket::IsValid() const {
- return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
-}
+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 {
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;
}
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)
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
- auto addresses =
- lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL);
- for (auto address : addresses) {
- error = CreateSocket(address.GetFamily());
- if (error.Fail())
- continue;
-
- address.SetPort(port);
+ 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());
- if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(),
- address.GetLength())) {
- continue;
+ return error;
}
+ }
- SetOptionNoDelay();
-
- error.Clear();
+ if (-1 ==
+ ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) {
+ SetLastError(error);
return error;
}
- error.SetErrorString("Failed to connect port");
+ // 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());
- 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;
- auto addresses =
- lldb_private::SocketAddress::GetAddressInfo(host_str.c_str(), NULL);
- for (auto address : addresses) {
- int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
- m_child_processes_inherit, error);
- if (error.Fail()) {
- error.Clear();
- continue;
- }
-
- // enable local address reuse
- SetOptionReuseAddress();
+ SocketAddress bind_addr;
- address.SetPort(port);
+ // 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);
- int err = ::bind(fd, &address.sockaddr(), address.GetLength());
- if (-1 != err)
- err = ::listen(fd, backlog);
+ if (!bind_addr_success) {
+ error.SetErrorString("Failed to bind port");
+ return error;
+ }
- if (-1 == err) {
- CLOSE_SOCKET(fd);
- continue;
- }
+ int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength());
+ if (err != -1)
+ err = ::listen(GetNativeSocket(), backlog);
- if (port == 0) {
- socklen_t sa_len = address.GetLength();
- if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
- port = address.GetPort();
- }
- m_listen_sockets[fd] = address;
- }
+ if (err == -1)
+ SetLastError(error);
- if (m_listen_sockets.size() == 0)
- error.SetErrorString("Failed to connect port");
return error;
}
-void TCPSocket::CloseListenSockets() {
- for (auto socket : m_listen_sockets)
- CLOSE_SOCKET(socket.first);
- m_listen_sockets.clear();
-}
-
-Error TCPSocket::Accept(Socket *&conn_socket) {
+Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&conn_socket) {
Error error;
- if (m_listen_sockets.size() == 0) {
- error.SetErrorString("No open listening sockets!");
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
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())
+ 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<TCPSocket> accepted_socket;
+
// Loop until we are happy with our connection
while (!accept_connection) {
- accept_loop.Run();
-
+ 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())
- return error;
-
- lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
- if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
- CLOSE_SOCKET(sock);
- llvm::errs() << llvm::formatv(
- "error: rejecting incoming connection from {0} (expecting {1})",
- AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
- continue;
+ 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();
}
- accept_connection = true;
- accepted_socket.reset(new TCPSocket(sock, *this));
}
if (!accepted_socket)
accepted_socket->SetOptionNoDelay();
error.Clear();
conn_socket = accepted_socket.release();
- CloseListenSockets();
return error;
}
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) : Socket(socket, ProtocolUdp, true) {}
-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(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,
}
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;
for (struct addrinfo *service_info_ptr = service_info_list;
service_info_ptr != nullptr;
service_info_ptr = service_info_ptr->ai_next) {
- m_socket = Socket::CreateSocket(
+ auto send_fd = CreateSocket(
service_info_ptr->ai_family, service_info_ptr->ai_socktype,
- service_info_ptr->ai_protocol, m_child_processes_inherit, error);
+ service_info_ptr->ai_protocol, child_processes_inherit, error);
if (error.Success()) {
- m_sockaddr = service_info_ptr;
+ final_socket.reset(new UDPSocket(send_fd));
+ final_socket->m_sockaddr = service_info_ptr;
break;
} else
continue;
::freeaddrinfo(service_info_list);
- if (IsValid())
+ if (!final_socket)
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");
bind_addr.SetPort(0); // Let the source port # be determined dynamically
- err = ::bind(m_socket, bind_addr, bind_addr.GetLength());
+ err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength());
- 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);
-}
+ struct sockaddr_in source_info;
+ socklen_t address_len = sizeof (struct sockaddr_in);
+ err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len);
-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();
+ socket = final_socket.release();
+ error.Clear();
return error;
}
using namespace lldb;
using namespace lldb_private;
-AbstractSocket::AbstractSocket(bool child_processes_inherit)
- : DomainSocket(ProtocolUnixAbstract, child_processes_inherit) {}
+AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error)
+ : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) {}
size_t AbstractSocket::GetNameOffset() const { return 1; }
// assume we don't own it.
std::unique_ptr<TCPSocket> tcp_socket;
- tcp_socket.reset(new TCPSocket(fd, false, false));
+ tcp_socket.reset(new TCPSocket(fd, 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;
listening_socket_up.reset(socket);
socket = nullptr;
- error = listening_socket_up->Accept(socket);
+ error = listening_socket_up->Accept(s, m_child_processes_inherit, socket);
listening_socket_up.reset();
if (error_ptr)
*error_ptr = error;
return true;
}
-} // namespace
+}
+
+DomainSocket::DomainSocket(NativeSocket socket)
+ : Socket(socket, ProtocolUnixDomain, true) {}
-DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
- : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
+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)
- : 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;
-}
+ 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;
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);
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)
return error;
}
-Error DomainSocket::Accept(Socket *&socket) {
+Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket) {
Error error;
auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
- m_child_processes_inherit, error);
+ child_processes_inherit, error);
if (error.Success())
- socket = new DomainSocket(conn_fd, *this);
+ socket = new DomainSocket(conn_fd);
return error;
}
-//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
+//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#include "llvm/Config/config.h"
-
-#include "lldb/Host/MainLoop.h"
+#include "lldb/Host/posix/MainLoopPosix.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;
g_signal_flags[signo] = 1;
}
-MainLoop::~MainLoop() {
+MainLoopPosix::~MainLoopPosix() {
assert(m_read_fds.size() == 0);
assert(m_signals.size() == 0);
}
-MainLoop::ReadHandleUP
-MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
+MainLoopPosix::ReadHandleUP
+MainLoopPosix::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;
// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
-MainLoop::SignalHandleUP
-MainLoop::RegisterSignal(int signo, const Callback &callback,
+MainLoopPosix::SignalHandleUP
+MainLoopPosix::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;
g_signal_flags[signo] = 0;
return SignalHandleUP(new SignalHandle(*this, signo));
-#endif
}
-void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
+void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
bool erased = m_read_fds.erase(handle);
UNUSED_IF_ASSERT_DISABLED(erased);
assert(erased);
}
-void MainLoop::UnregisterSignal(int signo) {
-#if SIGNAL_POLLING_UNSUPPORTED
- Error("Signal polling is not supported on this platform.");
-#else
+void MainLoopPosix::UnregisterSignal(int signo) {
// We undo the actions of RegisterSignal on a best-effort basis.
auto it = m_signals.find(signo);
assert(it != m_signals.end());
nullptr);
m_signals.erase(it);
-#endif
}
-Error MainLoop::Run() {
+Error MainLoopPosix::Run() {
std::vector<int> signals;
- 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
+ std::vector<int> read_fds;
+ fd_set read_fd_set;
+ m_terminate_request = false;
// run until termination or until we run out of things to listen to
while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
// listen to, we
// will store the *real* list of events separately.
signals.clear();
-
-#if HAVE_SYS_EVENT_H
- events.resize(m_read_fds.size() + m_signals.size());
- int i = 0;
- for (auto &fd: m_read_fds) {
- EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
- }
-
- for (const auto &sig : m_signals) {
- signals.push_back(sig.first);
- EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
- }
-
- struct kevent event_list[4];
- int num_events =
- kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
-
- if (num_events < 0)
- return Error("kevent() failed with error %d\n", num_events);
-
-#else
read_fds.clear();
+ FD_ZERO(&read_fd_set);
+ int nfds = 0;
-#if !SIGNAL_POLLING_UNSUPPORTED
if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
return Error("pthread_sigmask failed with error %d\n", ret);
+ for (const auto &fd : m_read_fds) {
+ read_fds.push_back(fd.first);
+ FD_SET(fd.first, &read_fd_set);
+ nfds = std::max(nfds, fd.first + 1);
+ }
+
for (const auto &sig : m_signals) {
signals.push_back(sig.first);
sigdelset(&sigmask, sig.first);
}
-#endif
- 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 &&
+ if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) ==
+ -1 &&
errno != EINTR)
return Error(errno, eErrorTypePOSIX);
-#endif
for (int sig : signals) {
if (g_signal_flags[sig] == 0)
return Error();
}
-#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;
+ for (int fd : read_fds) {
+ if (!FD_ISSET(fd, &read_fd_set))
+ continue; // Not ready
- auto it = m_read_fds.find(fd.fd);
-#endif
+ auto it = m_read_fds.find(fd);
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)
static Error FindUnusedPort(uint16_t &port) {
Error error;
- std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(true, false));
+ std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error));
if (error.Fail())
return error;
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 */
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>"; };
08FB7794FE84155DC02AAC07 /* dbgnub */ = {
isa = PBXGroup;
children = (
- D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */,
26ACA3330D3E94F200A2120B /* Framework */,
26C637D50C71334A0024798E /* source */,
1AB674ADFE9D54B511CA2CBB /* Products */,
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 */,
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
#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"
// Disconnect without saving errno
Disconnect(false);
- DNBError err;
- int queue_id = kqueue();
- if (queue_id < 0) {
- err.SetError(errno, DNBError::MachKernel);
- err.LogThreaded("error: failed to create kqueue.");
+ // 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;
}
- std::map<int, lldb_private::SocketAddress> sockets;
- auto addresses =
- lldb_private::SocketAddress::GetAddressInfo(listen_host, NULL);
-
- for (auto address : addresses) {
- int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
- if (sock_fd == -1)
- continue;
-
- SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+ DNBError err;
+ int listen_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_fd == -1)
+ err.SetError(errno, DNBError::POSIX);
- address.SetPort(port);
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol "
+ "= IPPROTO_TCP ) => socket = %i",
+ listen_fd);
- int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength());
- if (error == -1) {
- ClosePort(sock_fd, false);
- continue;
- }
+ if (err.Fail())
+ return rnb_err;
- error = ::listen(sock_fd, 5);
- if (error == -1) {
- ClosePort(sock_fd, false);
- continue;
- }
+ // 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);
- // We were asked to listen on port zero which means we must now read the
- // actual port that was given to us as port zero is a special code for "find
- // an open port for me". This will only execute on the first socket created,
- // subesquent sockets will reuse this port number.
- if (port == 0) {
- socklen_t sa_len = address.GetLength();
- if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
- port = address.GetPort();
- }
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded(
+ "::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )",
+ listen_fd);
- sockets[sock_fd] = address;
+ if (err.Fail()) {
+ ClosePort(listen_fd, false);
+ return rnb_err;
}
- if (sockets.size() == 0) {
+ error = ::listen(listen_fd, 5);
+ if (error == -1)
err.SetError(errno, DNBError::POSIX);
- err.LogThreaded("::listen or ::bind failed");
+
+ if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd);
+
+ if (err.Fail()) {
+ ClosePort(listen_fd, false);
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);
+ 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);
+ }
}
+ struct sockaddr_in accept_addr;
+ ::memset(&accept_addr, 0, sizeof accept_addr);
+ accept_addr.sin_len = sizeof accept_addr;
+
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);
- struct kevent event_list[4];
- int num_events =
- kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
-
- if (num_events < 0) {
- err.SetError(errno, DNBError::MachKernel);
- err.LogThreaded("error: kevent() failed.");
- }
-
- 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 (m_fd == -1)
+ err.SetError(errno, DNBError::POSIX);
- 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 (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
+ err.LogThreaded(
+ "::accept ( socket = %i, address = %p, address_len = %u )", listen_fd,
+ &accept_addr, accept_addr_len);
- if (m_fd == -1) {
- err.SetError(errno, DNBError::POSIX);
- err.LogThreaded("error: Socket accept failed.");
- }
+ if (err.Fail())
+ break;
- if (addr_in.IsAnyAddr())
+ 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) {
accept_connection = true;
- 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());
- }
+ } 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]);
}
}
- if (err.Fail())
- break;
- }
- for (auto socket : sockets) {
- int ListenFd = socket.first;
- ClosePort(ListenFd, false);
}
- if (err.Fail())
- return rnb_err;
+ ClosePort(listen_fd, false);
- // Keep our TCP packets coming without any delays.
- SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (err.Fail()) {
+ return rnb_err;
+ } else {
+ // 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);
- auto addresses = lldb_private::SocketAddress::GetAddressInfo(host, NULL);
-
- for (auto address : addresses) {
- m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
- if (m_fd == -1)
- continue;
+ // Create the socket
+ m_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd == -1)
+ return rnb_err;
- // Enable local address reuse
- SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+ // Enable local address reuse
+ SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
- address.SetPort(port);
+ struct sockaddr_in sa;
+ ::memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
- if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
- Disconnect(false);
- continue;
- }
- SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr)) {
+ DNBLogThreaded("error: failed to resolve host '%s'", host);
+ Disconnect(false);
+ return rnb_err;
+ }
- result = rnb_success;
- break;
+ if (-1 == ::connect(m_fd, (const struct sockaddr *)&sa, sizeof(sa))) {
+ Disconnect(false);
+ return rnb_err;
}
- return result;
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
+ return rnb_success;
}
rnb_err_t RNBSocket::useFD(int fd) {
show_usage_and_exit(1);
}
// accept 'localhost:' prefix on port number
- 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);
+
+ int items_scanned = ::sscanf(argv[0], "%[^:]:%i", str, &port);
+ if (items_scanned == 2) {
+ host = str;
DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
} else {
// No hostname means "localhost"
Error Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
Socket *conn_socket = nullptr;
- auto error = m_listener_socket_up->Accept(conn_socket);
+ auto error = m_listener_socket_up->Accept(
+ StringRef(m_name), child_processes_inherit, conn_socket);
if (error.Success())
conn = new ConnectionFileDescriptor(conn_socket);
const char *listen_remote_address,
bool child_processes_inherit, Socket **accept_socket,
Error *error) {
- *error = listen_socket->Accept(*accept_socket);
+ *error = listen_socket->Accept(listen_remote_address,
+ child_processes_inherit, *accept_socket);
}
template <typename SocketType>
bool child_processes_inherit = false;
Error error;
std::unique_ptr<SocketType> listen_socket_up(
- new SocketType(true, child_processes_inherit));
+ new SocketType(child_processes_inherit, error));
EXPECT_FALSE(error.Fail());
error = listen_socket_up->Listen(listen_remote_address, 5);
EXPECT_FALSE(error.Fail());
std::string connect_remote_address = get_connect_addr(*listen_socket_up);
std::unique_ptr<SocketType> connect_socket_up(
- new SocketType(true, child_processes_inherit));
+ new SocketType(child_processes_inherit, error));
EXPECT_FALSE(error.Fail());
error = connect_socket_up->Connect(connect_remote_address);
EXPECT_FALSE(error.Fail());
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
void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) {
bool child_processes_inherit = false;
Error error;
- TCPSocket listen_socket(true, child_processes_inherit);
+ TCPSocket listen_socket(child_processes_inherit, error);
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(accept_socket);
+ return listen_socket.Accept("127.0.0.1:0", child_processes_inherit,
+ accept_socket);
});
char connect_remote_address[64];
}
void TestSocketListen(const char *addr) {
- // Skip IPv6 tests if there isn't a valid interafce
- auto addresses = lldb_private::SocketAddress::GetAddressInfo(addr, NULL);
- 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_wrap);
+ server_socket.Listen(addr, 0, ServerCallbackv4, (const void *)addr);
ASSERT_TRUE(result == rnb_success);
result = server_socket.Write(hello.c_str(), hello.length());
ASSERT_TRUE(result == rnb_success);
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);
- if (addresses.size() == 0)
- return;
-
char addr_wrap[256];
- if (addresses.front().GetFamily() == AF_INET6)
- sprintf(addr_wrap, "[%s]:0", addr);
- else
- sprintf(addr_wrap, "%s:0", addr);
+ sprintf(addr_wrap, "%s:0", addr);
Socket *server_socket;
Predicate<uint16_t> port_predicate;
ASSERT_EQ(bye, goodbye);
} else {
Socket *connected_socket;
- err = server_socket->Accept(connected_socket);
+ err = server_socket->Accept(addr_wrap, false, connected_socket);
if (err.Fail()) {
llvm::errs() << err.AsCString();
abort();
}
TEST(RNBSocket, LoopBackConnectIPv4) { TestSocketConnect("127.0.0.1"); }
-
-TEST(RNBSocket, LoopBackConnectIPv6) { TestSocketConnect("::1"); }