Files
clang-p2996/lldb/source/Host/common/UDPSocket.cpp
Adrian Prantl 0642cd768b [lldb] Turn lldb_private::Status into a value type. (#106163)
This patch removes all of the Set.* methods from Status.

This cleanup is part of a series of patches that make it harder use the
anti-pattern of keeping a long-lives Status object around and updating
it while dropping any errors it contains on the floor.

This patch is largely NFC, the more interesting next steps this enables
is to:
1. remove Status.Clear()
2. assert that Status::operator=() never overwrites an error
3. remove Status::operator=()

Note that step (2) will bring 90% of the benefits for users, and step
(3) will dramatically clean up the error handling code in various
places. In the end my goal is to convert all APIs that are of the form

`    ResultTy DoFoo(Status& error)
`
to

`    llvm::Expected<ResultTy> DoFoo()
`
How to read this patch?

The interesting changes are in Status.h and Status.cpp, all other
changes are mostly

` perl -pi -e 's/\.SetErrorString/ = Status::FromErrorString/g' $(git
grep -l SetErrorString lldb/source)
`
plus the occasional manual cleanup.
2024-08-27 10:59:31 -07:00

139 lines
4.4 KiB
C++

//===-- UDPSocket.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/common/UDPSocket.h"
#include "lldb/Host/Config.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#if LLDB_ENABLE_POSIX
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#include <memory>
using namespace lldb;
using namespace lldb_private;
static const int kDomain = AF_INET;
static const int kType = SOCK_DGRAM;
static const char *g_not_supported_error = "Not supported";
UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) {
m_socket = socket;
}
UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit)
: Socket(ProtocolUdp, should_close, child_processes_inherit) {}
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());
}
Status UDPSocket::Connect(llvm::StringRef name) {
return Status::FromErrorStringWithFormat("%s", g_not_supported_error);
}
Status UDPSocket::Listen(llvm::StringRef name, int backlog) {
return Status::FromErrorStringWithFormat("%s", g_not_supported_error);
}
Status UDPSocket::Accept(Socket *&socket) {
return Status::FromErrorStringWithFormat("%s", g_not_supported_error);
}
llvm::Expected<std::unique_ptr<UDPSocket>>
UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit) {
std::unique_ptr<UDPSocket> socket;
Log *log = GetLog(LLDBLog::Connection);
LLDB_LOG(log, "host/port = {0}", name);
Status error;
llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
if (!host_port)
return host_port.takeError();
// At this point we have setup the receive port, now we need to setup the UDP
// send socket
struct addrinfo hints;
struct addrinfo *service_info_list = nullptr;
::memset(&hints, 0, sizeof(hints));
hints.ai_family = kDomain;
hints.ai_socktype = kType;
int err = ::getaddrinfo(host_port->hostname.c_str(), std::to_string(host_port->port).c_str(), &hints,
&service_info_list);
if (err != 0) {
error = Status::FromErrorStringWithFormat(
#if defined(_WIN32) && defined(UNICODE)
"getaddrinfo(%s, %d, &hints, &info) returned error %i (%S)",
#else
"getaddrinfo(%s, %d, &hints, &info) returned error %i (%s)",
#endif
host_port->hostname.c_str(), host_port->port, err, gai_strerror(err));
return error.ToError();
}
for (struct addrinfo *service_info_ptr = service_info_list;
service_info_ptr != nullptr;
service_info_ptr = service_info_ptr->ai_next) {
auto send_fd = CreateSocket(
service_info_ptr->ai_family, service_info_ptr->ai_socktype,
service_info_ptr->ai_protocol, child_processes_inherit, error);
if (error.Success()) {
socket.reset(new UDPSocket(send_fd));
socket->m_sockaddr = service_info_ptr;
break;
} else
continue;
}
::freeaddrinfo(service_info_list);
if (!socket)
return error.ToError();
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_port->hostname == "127.0.0.1" || host_port->hostname == "localhost")
? bind_addr.SetToLocalhost(kDomain, host_port->port)
: bind_addr.SetToAnyAddress(kDomain, host_port->port);
if (!bind_addr_success) {
error = Status::FromErrorString("Failed to get hostspec to bind for");
return error.ToError();
}
bind_addr.SetPort(0); // Let the source port # be determined dynamically
err = ::bind(socket->GetNativeSocket(), bind_addr, bind_addr.GetLength());
struct sockaddr_in source_info;
socklen_t address_len = sizeof (struct sockaddr_in);
err = ::getsockname(socket->GetNativeSocket(),
(struct sockaddr *)&source_info, &address_len);
return std::move(socket);
}
std::string UDPSocket::GetRemoteConnectionURI() const {
if (m_socket != kInvalidSocketValue) {
return std::string(llvm::formatv(
"udp://[{0}]:{1}", m_sockaddr.GetIPAddress(), m_sockaddr.GetPort()));
}
return "";
}