1 //===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #define _WINSOCK_DEPRECATED_NO_WARNINGS
14 #include "lldb/Host/common/TCPSocket.h"
16 #include "lldb/Host/Config.h"
17 #include "lldb/Host/MainLoop.h"
18 #include "lldb/Utility/Log.h"
20 #include "llvm/Config/llvm-config.h"
21 #include "llvm/Support/raw_ostream.h"
23 #ifndef LLDB_DISABLE_POSIX
24 #include <arpa/inet.h>
25 #include <netinet/tcp.h>
26 #include <sys/socket.h>
34 #define CLOSE_SOCKET closesocket
35 typedef const char *set_socket_option_arg_type;
38 #define CLOSE_SOCKET ::close
39 typedef const void *set_socket_option_arg_type;
43 using namespace lldb_private;
46 const int kType = SOCK_STREAM;
49 TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
50 : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
52 TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
53 : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
54 listen_socket.m_child_processes_inherit) {
58 TCPSocket::TCPSocket(NativeSocket socket, bool should_close,
59 bool child_processes_inherit)
60 : Socket(ProtocolTcp, should_close, child_processes_inherit) {
64 TCPSocket::~TCPSocket() { CloseListenSockets(); }
66 bool TCPSocket::IsValid() const {
67 return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
70 // Return the port number that is being used by the socket.
71 uint16_t TCPSocket::GetLocalPortNumber() const {
72 if (m_socket != kInvalidSocketValue) {
73 SocketAddress sock_addr;
74 socklen_t sock_addr_len = sock_addr.GetMaxLength();
75 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
76 return sock_addr.GetPort();
77 } else if (!m_listen_sockets.empty()) {
78 SocketAddress sock_addr;
79 socklen_t sock_addr_len = sock_addr.GetMaxLength();
80 if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
82 return sock_addr.GetPort();
87 std::string TCPSocket::GetLocalIPAddress() const {
88 // We bound to port zero, so we need to figure out which port we actually
90 if (m_socket != kInvalidSocketValue) {
91 SocketAddress sock_addr;
92 socklen_t sock_addr_len = sock_addr.GetMaxLength();
93 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
94 return sock_addr.GetIPAddress();
99 uint16_t TCPSocket::GetRemotePortNumber() const {
100 if (m_socket != kInvalidSocketValue) {
101 SocketAddress sock_addr;
102 socklen_t sock_addr_len = sock_addr.GetMaxLength();
103 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
104 return sock_addr.GetPort();
109 std::string TCPSocket::GetRemoteIPAddress() const {
110 // We bound to port zero, so we need to figure out which port we actually
112 if (m_socket != kInvalidSocketValue) {
113 SocketAddress sock_addr;
114 socklen_t sock_addr_len = sock_addr.GetMaxLength();
115 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
116 return sock_addr.GetIPAddress();
121 Status TCPSocket::CreateSocket(int domain) {
127 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
128 m_child_processes_inherit, error);
132 Status TCPSocket::Connect(llvm::StringRef name) {
134 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
136 log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
139 std::string host_str;
140 std::string port_str;
141 int32_t port = INT32_MIN;
142 if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
145 auto addresses = lldb_private::SocketAddress::GetAddressInfo(
146 host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
147 for (auto address : addresses) {
148 error = CreateSocket(address.GetFamily());
152 address.SetPort(port);
154 if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(),
155 address.GetLength())) {
156 CLOSE_SOCKET(GetNativeSocket());
166 error.SetErrorString("Failed to connect port");
170 Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
171 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
173 log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data());
176 std::string host_str;
177 std::string port_str;
178 int32_t port = INT32_MIN;
179 if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
183 host_str = "0.0.0.0";
184 auto addresses = lldb_private::SocketAddress::GetAddressInfo(
185 host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
186 for (auto address : addresses) {
187 int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
188 m_child_processes_inherit, error);
194 // enable local address reuse
195 int option_value = 1;
196 set_socket_option_arg_type option_value_p =
197 reinterpret_cast<set_socket_option_arg_type>(&option_value);
198 ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
199 sizeof(option_value));
201 SocketAddress listen_address = address;
202 if(!listen_address.IsLocalhost())
203 listen_address.SetToAnyAddress(address.GetFamily(), port);
205 listen_address.SetPort(port);
208 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
210 err = ::listen(fd, backlog);
218 socklen_t sa_len = address.GetLength();
219 if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
220 port = address.GetPort();
222 m_listen_sockets[fd] = address;
225 if (m_listen_sockets.size() == 0)
226 error.SetErrorString("Failed to connect port");
230 void TCPSocket::CloseListenSockets() {
231 for (auto socket : m_listen_sockets)
232 CLOSE_SOCKET(socket.first);
233 m_listen_sockets.clear();
236 Status TCPSocket::Accept(Socket *&conn_socket) {
238 if (m_listen_sockets.size() == 0) {
239 error.SetErrorString("No open listening sockets!");
244 int listen_sock = -1;
245 lldb_private::SocketAddress AcceptAddr;
246 MainLoop accept_loop;
247 std::vector<MainLoopBase::ReadHandleUP> handles;
248 for (auto socket : m_listen_sockets) {
249 auto fd = socket.first;
250 auto inherit = this->m_child_processes_inherit;
251 auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
252 handles.emplace_back(accept_loop.RegisterReadObject(
253 io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
254 &listen_sock](MainLoopBase &loop) {
255 socklen_t sa_len = AcceptAddr.GetMaxLength();
256 sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
259 loop.RequestTermination();
265 bool accept_connection = false;
266 std::unique_ptr<TCPSocket> accepted_socket;
267 // Loop until we are happy with our connection
268 while (!accept_connection) {
274 lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
275 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
277 llvm::errs() << llvm::formatv(
278 "error: rejecting incoming connection from {0} (expecting {1})",
279 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
282 accept_connection = true;
283 accepted_socket.reset(new TCPSocket(sock, *this));
286 if (!accepted_socket)
289 // Keep our TCP packets coming without any delays.
290 accepted_socket->SetOptionNoDelay();
292 conn_socket = accepted_socket.release();
296 int TCPSocket::SetOptionNoDelay() {
297 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
300 int TCPSocket::SetOptionReuseAddress() {
301 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);