Added name resolution code for linux.
This commit is contained in:
parent
a755de5c5f
commit
04a28e220c
1
SModule
1
SModule
@ -11,6 +11,7 @@ mijin_sources = Split("""
|
||||
source/mijin/io/process.cpp
|
||||
source/mijin/io/stream.cpp
|
||||
source/mijin/net/http.cpp
|
||||
source/mijin/net/ip.cpp
|
||||
source/mijin/net/socket.cpp
|
||||
source/mijin/util/os.cpp
|
||||
source/mijin/types/name.cpp
|
||||
|
@ -1,14 +1,105 @@
|
||||
|
||||
#include "./ip.hpp"
|
||||
|
||||
#include <format>
|
||||
|
||||
#include "../detect.hpp"
|
||||
#include "../util/string.hpp"
|
||||
#include "./detail/net_common.hpp"
|
||||
|
||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||
#if !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
|
||||
struct AddrInfoContext
|
||||
{
|
||||
gaicb item;
|
||||
gaicb* list = &item;
|
||||
};
|
||||
using os_resolve_handle_t = AddrInfoContext;
|
||||
|
||||
StreamError translateGAIError(int error)
|
||||
{
|
||||
(void) error; // TODO
|
||||
return StreamError::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
StreamError osBeginResolve(const std::string& hostname, os_resolve_handle_t& handle) noexcept
|
||||
{
|
||||
handle.item = {.ar_name = hostname.c_str()};
|
||||
|
||||
const int result = getaddrinfo_a(GAI_NOWAIT, &handle.list, 1, nullptr);
|
||||
if (result != 0)
|
||||
{
|
||||
return StreamError::UNKNOWN_ERROR;
|
||||
}
|
||||
return StreamError::SUCCESS;
|
||||
}
|
||||
|
||||
bool osResolveDone(os_resolve_handle_t& handle) noexcept
|
||||
{
|
||||
return gai_error(&handle.item) != EAI_INPROGRESS;
|
||||
}
|
||||
|
||||
StreamResult<std::vector<ip_address_t>> osResolveResult(os_resolve_handle_t& handle) noexcept
|
||||
{
|
||||
if (const int error = gai_error(&handle.item); error != 0)
|
||||
{
|
||||
if (handle.item.ar_result != nullptr)
|
||||
{
|
||||
freeaddrinfo(handle.item.ar_result);
|
||||
}
|
||||
return translateGAIError(error);
|
||||
}
|
||||
if (handle.item.ar_result == nullptr)
|
||||
{
|
||||
return StreamError::UNKNOWN_ERROR;
|
||||
}
|
||||
std::vector<ip_address_t> resultAddresses;
|
||||
for (addrinfo* result = handle.item.ar_result; result != nullptr; result = result->ai_next)
|
||||
{
|
||||
if (result->ai_protocol != IPPROTO_TCP)
|
||||
{
|
||||
// we actually just care about TCP, right?
|
||||
continue;
|
||||
}
|
||||
switch (result->ai_family)
|
||||
{
|
||||
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
||||
#error "TODO: swap byte order of the address"
|
||||
#endif
|
||||
case AF_INET:
|
||||
{
|
||||
sockaddr_in& addr = *reinterpret_cast<sockaddr_in*>(result->ai_addr);
|
||||
resultAddresses.emplace_back(std::bit_cast<IPv4Address>(addr.sin_addr));
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
sockaddr_in6& addr = *reinterpret_cast<sockaddr_in6*>(result->ai_addr);
|
||||
IPv6Address addr6 = std::bit_cast<IPv6Address>(addr.sin6_addr);
|
||||
for (std::uint16_t& hextet : addr6.hextets)
|
||||
{
|
||||
hextet = ntohs(hextet);
|
||||
}
|
||||
resultAddresses.emplace_back(addr6);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(handle.item.ar_result);
|
||||
return resultAddresses;
|
||||
}
|
||||
#elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||
struct WSAQueryContext
|
||||
{
|
||||
// WSA stuff
|
||||
@ -100,6 +191,88 @@ StreamResult<std::vector<ip_address_t>> osResolveResult(os_resolve_handle_t& que
|
||||
#endif // MIJIN_TARGET_OS
|
||||
}
|
||||
|
||||
std::string IPv4Address::toString() const
|
||||
{
|
||||
return std::format("{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]);
|
||||
}
|
||||
|
||||
std::string IPv6Address::toString() const
|
||||
{
|
||||
return std::format("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", hextets[0], hextets[1], hextets[2], hextets[3], hextets[4],
|
||||
hextets[5], hextets[6], hextets[7]);
|
||||
}
|
||||
|
||||
Optional<IPv4Address> IPv4Address::fromString(std::string_view stringView) noexcept
|
||||
{
|
||||
std::vector<std::string_view> parts = split(stringView, ".", {.limitParts = 4});
|
||||
if (parts.size() != 4) {
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
IPv4Address address;
|
||||
for (int idx = 0; idx < 4; ++idx)
|
||||
{
|
||||
if (!toNumber(parts[idx], address.octets[idx]))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
Optional<IPv6Address> IPv6Address::fromString(std::string_view stringView) noexcept
|
||||
{
|
||||
// very specific edge case
|
||||
if (stringView.contains(":::"))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> parts = split(stringView, "::", {.ignoreEmpty = false});
|
||||
if (parts.size() > 2)
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
if (parts.size() == 1)
|
||||
{
|
||||
parts.emplace_back("");
|
||||
}
|
||||
|
||||
std::vector<std::string_view> partsLeft = split(parts[0], ":");
|
||||
std::vector<std::string_view> partsRight = split(parts[1], ":");
|
||||
|
||||
std::erase_if(partsLeft, std::mem_fn(&std::string_view::empty));
|
||||
std::erase_if(partsRight, std::mem_fn(&std::string_view::empty));
|
||||
|
||||
if (partsLeft.size() + partsRight.size() > 8)
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
|
||||
IPv6Address address = {};
|
||||
unsigned hextet = 0;
|
||||
for (std::string_view part : partsLeft)
|
||||
{
|
||||
if (!toNumber(part, address.hextets[hextet], /* base = */ 16))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
++hextet;
|
||||
}
|
||||
for (; hextet < (8 - partsRight.size()); ++hextet)
|
||||
{
|
||||
address.hextets[hextet] = 0;
|
||||
}
|
||||
for (std::string_view part : partsRight)
|
||||
{
|
||||
if (!toNumber(part, address.hextets[hextet], /* base = */ 16))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
++hextet;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
Task<StreamResult<std::vector<ip_address_t>>> c_resolveHostname(std::string hostname) noexcept
|
||||
{
|
||||
os_resolve_handle_t resolveHandle;
|
||||
|
@ -17,6 +17,8 @@ struct IPv4Address
|
||||
|
||||
auto operator<=>(const IPv4Address&) const noexcept = default;
|
||||
|
||||
[[nodiscard]] std::string toString() const;
|
||||
|
||||
[[nodiscard]]
|
||||
static Optional<IPv4Address> fromString(std::string_view stringView) noexcept;
|
||||
};
|
||||
@ -27,11 +29,23 @@ struct IPv6Address
|
||||
|
||||
auto operator<=>(const IPv6Address&) const noexcept = default;
|
||||
|
||||
[[nodiscard]] std::string toString() const;
|
||||
|
||||
[[nodiscard]]
|
||||
static Optional<IPv6Address> fromString(std::string_view stringView) noexcept;
|
||||
};
|
||||
using ip_address_t = std::variant<IPv4Address, IPv6Address>;
|
||||
|
||||
[[nodiscard]]
|
||||
inline std::string ipAddressToString(const ip_address_t& address) noexcept
|
||||
{
|
||||
if (address.valueless_by_exception())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return std::visit([](const auto& addr) { return addr.toString(); }, address);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline Optional<ip_address_t> ipAddressFromString(std::string_view stringView) noexcept
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "./detail/net_common.hpp"
|
||||
#include "../detect.hpp"
|
||||
#include "../util/string.hpp"
|
||||
#include "../util/variant.hpp"
|
||||
|
||||
namespace mijin
|
||||
@ -181,77 +180,6 @@ StreamError translateWinError() noexcept
|
||||
#endif // MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||
}// namespace impl
|
||||
|
||||
Optional<IPv4Address> IPv4Address::fromString(std::string_view stringView) noexcept
|
||||
{
|
||||
std::vector<std::string_view> parts = split(stringView, ".", {.limitParts = 4});
|
||||
if (parts.size() != 4) {
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
IPv4Address address;
|
||||
for (int idx = 0; idx < 4; ++idx)
|
||||
{
|
||||
if (!toNumber(parts[idx], address.octets[idx]))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
Optional<IPv6Address> IPv6Address::fromString(std::string_view stringView) noexcept
|
||||
{
|
||||
// very specific edge case
|
||||
if (stringView.contains(":::"))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> parts = split(stringView, "::", {.ignoreEmpty = false});
|
||||
if (parts.size() > 2)
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
if (parts.size() == 1)
|
||||
{
|
||||
parts.emplace_back("");
|
||||
}
|
||||
|
||||
std::vector<std::string_view> partsLeft = split(parts[0], ":");
|
||||
std::vector<std::string_view> partsRight = split(parts[1], ":");
|
||||
|
||||
std::erase_if(partsLeft, std::mem_fn(&std::string_view::empty));
|
||||
std::erase_if(partsRight, std::mem_fn(&std::string_view::empty));
|
||||
|
||||
if (partsLeft.size() + partsRight.size() > 8)
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
|
||||
IPv6Address address = {};
|
||||
unsigned hextet = 0;
|
||||
for (std::string_view part : partsLeft)
|
||||
{
|
||||
if (!toNumber(part, address.hextets[hextet], /* base = */ 16))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
++hextet;
|
||||
}
|
||||
for (; hextet < (8 - partsRight.size()); ++hextet)
|
||||
{
|
||||
address.hextets[hextet] = 0;
|
||||
}
|
||||
for (std::string_view part : partsRight)
|
||||
{
|
||||
if (!toNumber(part, address.hextets[hextet], /* base = */ 16))
|
||||
{
|
||||
return NULL_OPTIONAL;
|
||||
}
|
||||
++hextet;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
StreamError TCPStream::readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options, std::size_t* outBytesRead)
|
||||
{
|
||||
MIJIN_ASSERT(isOpen(), "Socket is not open.");
|
||||
@ -412,8 +340,11 @@ StreamError TCPStream::open(ip_address_t address, std::uint16_t port) noexcept
|
||||
};
|
||||
return connect(handle_, reinterpret_cast<sockaddr*>(&connectAddress), sizeof(sockaddr_in)) == 0;
|
||||
},
|
||||
[&](const IPv6Address& address6)
|
||||
[&](IPv6Address address6)
|
||||
{
|
||||
for (std::uint16_t& hextet : address6.hextets) {
|
||||
hextet = htons(hextet);
|
||||
}
|
||||
sockaddr_in6 connectAddress =
|
||||
{
|
||||
.sin6_family = AF_INET6,
|
||||
@ -474,8 +405,11 @@ StreamError TCPServerSocket::setup(ip_address_t address, std::uint16_t port) noe
|
||||
};
|
||||
return bind(handle_, reinterpret_cast<sockaddr*>(&bindAddress), sizeof(sockaddr_in)) == 0;
|
||||
},
|
||||
[&](const IPv6Address& address6)
|
||||
[&](IPv6Address address6)
|
||||
{
|
||||
for (std::uint16_t& hextet : address6.hextets) {
|
||||
hextet = htons(hextet);
|
||||
}
|
||||
sockaddr_in6 bindAddress =
|
||||
{
|
||||
.sin6_family = AF_INET6,
|
||||
|
Loading…
x
Reference in New Issue
Block a user