summaryrefslogtreecommitdiff
path: root/tools/debugserver/source
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-02 18:31:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-02 18:31:19 +0000
commit773dd0e6e632d48d7123a321ba86f50847b9afc0 (patch)
treec6bd992bb1963df11f8de346d12a5a70c2e4deb2 /tools/debugserver/source
parent5060b64b7d79491d507a75201be161fd0c38fcbb (diff)
Notes
Diffstat (limited to 'tools/debugserver/source')
-rw-r--r--tools/debugserver/source/CMakeLists.txt1
-rw-r--r--tools/debugserver/source/RNBSocket.cpp246
-rw-r--r--tools/debugserver/source/debugserver.cpp16
3 files changed, 131 insertions, 132 deletions
diff --git a/tools/debugserver/source/CMakeLists.txt b/tools/debugserver/source/CMakeLists.txt
index 782c946f702fe..775a1a127b6fe 100644
--- a/tools/debugserver/source/CMakeLists.txt
+++ b/tools/debugserver/source/CMakeLists.txt
@@ -62,6 +62,7 @@ set(lldbDebugserverCommonSources
StdStringExtractor.cpp
# JSON reader depends on the following LLDB-common files
${LLDB_SOURCE_DIR}/source/Host/common/StringConvert.cpp
+ ${LLDB_SOURCE_DIR}/source/Host/common/SocketAddress.cpp
# end JSON reader dependencies
libdebugserver.cpp
PseudoTerminal.cpp
diff --git a/tools/debugserver/source/RNBSocket.cpp b/tools/debugserver/source/RNBSocket.cpp
index a8d119e455fa5..62a3e4f9adf53 100644
--- a/tools/debugserver/source/RNBSocket.cpp
+++ b/tools/debugserver/source/RNBSocket.cpp
@@ -17,10 +17,15 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
+#include <map>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <sys/event.h>
#include <termios.h>
+#include <vector>
+
+#include "lldb/Host/SocketAddress.h"
#ifdef WITH_LOCKDOWN
#include "lockdown.h"
@@ -66,176 +71,161 @@ rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port,
// Disconnect without saving errno
Disconnect(false);
- // Now figure out the hostname that will be attaching and palce it into
- struct sockaddr_in listen_addr;
- ::memset(&listen_addr, 0, sizeof listen_addr);
- listen_addr.sin_len = sizeof listen_addr;
- listen_addr.sin_family = AF_INET;
- listen_addr.sin_port = htons(port);
- listen_addr.sin_addr.s_addr = INADDR_ANY;
-
- if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr)) {
- DNBLogThreaded("error: failed to resolve connecting host '%s'",
- listen_host);
+ DNBError err;
+ int queue_id = kqueue();
+ if (queue_id < 0) {
+ err.SetError(errno, DNBError::MachKernel);
+ err.LogThreaded("error: failed to create kqueue.");
return rnb_err;
}
- DNBError err;
- int listen_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (listen_fd == -1)
- err.SetError(errno, DNBError::POSIX);
+ std::map<int, lldb_private::SocketAddress> sockets;
+ auto addresses = lldb_private::SocketAddress::GetAddressInfo(
+ listen_host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
- if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
- err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol "
- "= IPPROTO_TCP ) => socket = %i",
- listen_fd);
+ for (auto address : addresses) {
+ int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
+ if (sock_fd == -1)
+ continue;
- if (err.Fail())
- return rnb_err;
+ SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
- // enable local address reuse
- SetSocketOption(listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
-
- struct sockaddr_in sa;
- ::memset(&sa, 0, sizeof sa);
- sa.sin_len = sizeof sa;
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
- sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host
- // network interface (this is NOT who can
- // connect to us)
- int error = ::bind(listen_fd, (struct sockaddr *)&sa, sizeof(sa));
- if (error == -1)
- err.SetError(errno, DNBError::POSIX);
+ address.SetPort(port);
- if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
- err.LogThreaded(
- "::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )",
- listen_fd);
+ int error = ::bind(sock_fd, &address.sockaddr(), address.GetLength());
+ if (error == -1) {
+ ClosePort(sock_fd, false);
+ continue;
+ }
- if (err.Fail()) {
- ClosePort(listen_fd, false);
- return rnb_err;
- }
+ error = ::listen(sock_fd, 5);
+ if (error == -1) {
+ ClosePort(sock_fd, false);
+ continue;
+ }
- error = ::listen(listen_fd, 5);
- if (error == -1)
- err.SetError(errno, DNBError::POSIX);
+ // We were asked to listen on port zero which means we must now read the
+ // actual port that was given to us as port zero is a special code for "find
+ // an open port for me". This will only execute on the first socket created,
+ // subesquent sockets will reuse this port number.
+ if (port == 0) {
+ socklen_t sa_len = address.GetLength();
+ if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
+ port = address.GetPort();
+ }
- if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
- err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd);
+ sockets[sock_fd] = address;
+ }
- if (err.Fail()) {
- ClosePort(listen_fd, false);
+ if (sockets.size() == 0) {
+ err.SetError(errno, DNBError::POSIX);
+ err.LogThreaded("::listen or ::bind failed");
return rnb_err;
}
- if (callback) {
- // We were asked to listen on port zero which means we
- // must now read the actual port that was given to us
- // as port zero is a special code for "find an open port
- // for me".
- if (port == 0) {
- socklen_t sa_len = sizeof(sa);
- if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) {
- port = ntohs(sa.sin_port);
- callback(callback_baton, port);
- }
- } else {
- callback(callback_baton, port);
- }
- }
+ if (callback)
+ callback(callback_baton, port);
- struct sockaddr_in accept_addr;
- ::memset(&accept_addr, 0, sizeof accept_addr);
- accept_addr.sin_len = sizeof accept_addr;
+ std::vector<struct kevent> events;
+ events.resize(sockets.size());
+ int i = 0;
+ for (auto socket : sockets) {
+ EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0);
+ }
bool accept_connection = false;
// Loop until we are happy with our connection
while (!accept_connection) {
- socklen_t accept_addr_len = sizeof accept_addr;
- m_fd =
- ::accept(listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
- if (m_fd == -1)
- err.SetError(errno, DNBError::POSIX);
+ struct kevent event_list[4];
+ int num_events =
+ kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
- if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
- err.LogThreaded(
- "::accept ( socket = %i, address = %p, address_len = %u )", listen_fd,
- &accept_addr, accept_addr_len);
+ if (num_events < 0) {
+ err.SetError(errno, DNBError::MachKernel);
+ err.LogThreaded("error: kevent() failed.");
+ }
- if (err.Fail())
- break;
+ for (int i = 0; i < num_events; ++i) {
+ auto sock_fd = event_list[i].ident;
+ auto socket_pair = sockets.find(sock_fd);
+ if (socket_pair == sockets.end())
+ continue;
- if (listen_addr.sin_addr.s_addr == INADDR_ANY)
- accept_connection = true;
- else {
- if (accept_addr_len == listen_addr.sin_len &&
- accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr) {
+ lldb_private::SocketAddress &addr_in = socket_pair->second;
+ lldb_private::SocketAddress accept_addr;
+ socklen_t sa_len = accept_addr.GetMaxLength();
+ m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len);
+
+ if (m_fd == -1) {
+ err.SetError(errno, DNBError::POSIX);
+ err.LogThreaded("error: Socket accept failed.");
+ }
+
+ if (addr_in.IsAnyAddr())
accept_connection = true;
- } else {
- ::close(m_fd);
- m_fd = -1;
- const uint8_t *accept_ip =
- (const uint8_t *)&accept_addr.sin_addr.s_addr;
- const uint8_t *listen_ip =
- (const uint8_t *)&listen_addr.sin_addr.s_addr;
- ::fprintf(stderr, "error: rejecting incoming connection from "
- "%u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
- accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
- listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
- DNBLogThreaded("error: rejecting connection from %u.%u.%u.%u "
- "(expecting %u.%u.%u.%u)",
- accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
- listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
+ else {
+ if (accept_addr == addr_in)
+ accept_connection = true;
+ else {
+ ::close(m_fd);
+ m_fd = -1;
+ ::fprintf(
+ stderr,
+ "error: rejecting incoming connection from %s (expecting %s)\n",
+ accept_addr.GetIPAddress().c_str(),
+ addr_in.GetIPAddress().c_str());
+ DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
+ accept_addr.GetIPAddress().c_str(),
+ addr_in.GetIPAddress().c_str());
+ }
}
}
+ if (err.Fail())
+ break;
+ }
+ for (auto socket : sockets) {
+ int ListenFd = socket.first;
+ ClosePort(ListenFd, false);
}
- ClosePort(listen_fd, false);
-
- if (err.Fail()) {
+ if (err.Fail())
return rnb_err;
- } else {
- // Keep our TCP packets coming without any delays.
- SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
- }
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
return rnb_success;
}
rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
+ auto result = rnb_err;
Disconnect(false);
- // Create the socket
- m_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_fd == -1)
- return rnb_err;
+ auto addresses = lldb_private::SocketAddress::GetAddressInfo(
+ host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
- // Enable local address reuse
- SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+ for (auto address : addresses) {
+ m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd == -1)
+ continue;
- struct sockaddr_in sa;
- ::memset(&sa, 0, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
+ // Enable local address reuse
+ SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
- if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr)) {
- DNBLogThreaded("error: failed to resolve host '%s'", host);
- Disconnect(false);
- return rnb_err;
- }
+ address.SetPort(port);
- if (-1 == ::connect(m_fd, (const struct sockaddr *)&sa, sizeof(sa))) {
- Disconnect(false);
- return rnb_err;
- }
+ if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
+ Disconnect(false);
+ continue;
+ }
+ SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
- // Keep our TCP packets coming without any delays.
- SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
- return rnb_success;
+ result = rnb_success;
+ break;
+ }
+ return result;
}
rnb_err_t RNBSocket::useFD(int fd) {
diff --git a/tools/debugserver/source/debugserver.cpp b/tools/debugserver/source/debugserver.cpp
index 0cb72f4ece459..bc1954de334a2 100644
--- a/tools/debugserver/source/debugserver.cpp
+++ b/tools/debugserver/source/debugserver.cpp
@@ -1345,10 +1345,18 @@ int main(int argc, char *argv[]) {
show_usage_and_exit(1);
}
// accept 'localhost:' prefix on port number
-
- int items_scanned = ::sscanf(argv[0], "%[^:]:%i", str, &port);
- if (items_scanned == 2) {
- host = str;
+ std::string host_specifier = argv[0];
+ auto colon_location = host_specifier.rfind(':');
+ if (colon_location != std::string::npos) {
+ host = host_specifier.substr(0, colon_location);
+ std::string port_str =
+ host_specifier.substr(colon_location + 1, std::string::npos);
+ char *end_ptr;
+ port = strtoul(port_str.c_str(), &end_ptr, 0);
+ if (end_ptr < port_str.c_str() + port_str.size())
+ show_usage_and_exit(2);
+ if (host.front() == '[' && host.back() == ']')
+ host = host.substr(1, host.size() - 2);
DNBLogDebug("host = '%s' port = %i", host.c_str(), port);
} else {
// No hostname means "localhost"