Files
llvm/lldb/source/Host/common/UDPSocket.cpp
Jim Ingham 59dd7fd153 We try to avoid static objects. These are on the error path for unsupported features
in the socket, so just returning freshly constructed objects is fine.

llvm-svn: 259443
2016-02-02 00:21:39 +00:00

159 lines
4.5 KiB
C++

//===-- UdpSocket.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/common/UDPSocket.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
#ifndef LLDB_DISABLE_POSIX
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#include <memory>
using namespace lldb;
using namespace lldb_private;
namespace {
const int kDomain = AF_INET;
const int kType = SOCK_DGRAM;
static const char *g_not_supported_error = "Not supported";
}
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_send_sockaddr,
m_send_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 *&send_socket, Socket *&recv_socket)
{
std::unique_ptr<UDPSocket> final_send_socket;
std::unique_ptr<UDPSocket> final_recv_socket;
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf ("UDPSocket::%s (host/port = %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;
// Setup the receiving end of the UDP connection on this localhost
// on port zero. After we bind to port zero we can read the port.
final_recv_socket.reset(new UDPSocket(child_processes_inherit, error));
if (error.Success())
{
// Socket was created, now lets bind to the requested port
SocketAddress addr;
addr.SetToAnyAddress (AF_INET, 0);
if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1)
{
// Bind failed...
SetLastError (error);
}
}
assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid()));
if (error.Fail())
return error;
// 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_str.c_str(), port_str.c_str(), &hints, &service_info_list);
if (err != 0)
{
error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
host_str.c_str(),
port_str.c_str(),
err,
gai_strerror(err));
return error;
}
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())
{
final_send_socket.reset(new UDPSocket(send_fd));
final_send_socket->m_send_sockaddr = service_info_ptr;
break;
}
else
continue;
}
:: freeaddrinfo (service_info_list);
if (!final_send_socket)
return error;
send_socket = final_send_socket.release();
recv_socket = final_recv_socket.release();
error.Clear();
return error;
}