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/process.cpp
|
||||||
source/mijin/io/stream.cpp
|
source/mijin/io/stream.cpp
|
||||||
source/mijin/net/http.cpp
|
source/mijin/net/http.cpp
|
||||||
|
source/mijin/net/ip.cpp
|
||||||
source/mijin/net/socket.cpp
|
source/mijin/net/socket.cpp
|
||||||
source/mijin/util/os.cpp
|
source/mijin/util/os.cpp
|
||||||
source/mijin/types/name.cpp
|
source/mijin/types/name.cpp
|
||||||
|
@ -1,14 +1,105 @@
|
|||||||
|
|
||||||
#include "./ip.hpp"
|
#include "./ip.hpp"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
#include "../detect.hpp"
|
#include "../detect.hpp"
|
||||||
|
#include "../util/string.hpp"
|
||||||
#include "./detail/net_common.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 mijin
|
||||||
{
|
{
|
||||||
namespace
|
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
|
struct WSAQueryContext
|
||||||
{
|
{
|
||||||
// WSA stuff
|
// WSA stuff
|
||||||
@ -100,6 +191,88 @@ StreamResult<std::vector<ip_address_t>> osResolveResult(os_resolve_handle_t& que
|
|||||||
#endif // MIJIN_TARGET_OS
|
#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
|
Task<StreamResult<std::vector<ip_address_t>>> c_resolveHostname(std::string hostname) noexcept
|
||||||
{
|
{
|
||||||
os_resolve_handle_t resolveHandle;
|
os_resolve_handle_t resolveHandle;
|
||||||
|
@ -17,6 +17,8 @@ struct IPv4Address
|
|||||||
|
|
||||||
auto operator<=>(const IPv4Address&) const noexcept = default;
|
auto operator<=>(const IPv4Address&) const noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string toString() const;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static Optional<IPv4Address> fromString(std::string_view stringView) noexcept;
|
static Optional<IPv4Address> fromString(std::string_view stringView) noexcept;
|
||||||
};
|
};
|
||||||
@ -27,11 +29,23 @@ struct IPv6Address
|
|||||||
|
|
||||||
auto operator<=>(const IPv6Address&) const noexcept = default;
|
auto operator<=>(const IPv6Address&) const noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string toString() const;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static Optional<IPv6Address> fromString(std::string_view stringView) noexcept;
|
static Optional<IPv6Address> fromString(std::string_view stringView) noexcept;
|
||||||
};
|
};
|
||||||
using ip_address_t = std::variant<IPv4Address, IPv6Address>;
|
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]]
|
[[nodiscard]]
|
||||||
inline Optional<ip_address_t> ipAddressFromString(std::string_view stringView) noexcept
|
inline Optional<ip_address_t> ipAddressFromString(std::string_view stringView) noexcept
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "./detail/net_common.hpp"
|
#include "./detail/net_common.hpp"
|
||||||
#include "../detect.hpp"
|
#include "../detect.hpp"
|
||||||
#include "../util/string.hpp"
|
|
||||||
#include "../util/variant.hpp"
|
#include "../util/variant.hpp"
|
||||||
|
|
||||||
namespace mijin
|
namespace mijin
|
||||||
@ -181,77 +180,6 @@ StreamError translateWinError() noexcept
|
|||||||
#endif // MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
#endif // MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
|
||||||
}// namespace impl
|
}// 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)
|
StreamError TCPStream::readRaw(std::span<std::uint8_t> buffer, const ReadOptions& options, std::size_t* outBytesRead)
|
||||||
{
|
{
|
||||||
MIJIN_ASSERT(isOpen(), "Socket is not open.");
|
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;
|
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 =
|
sockaddr_in6 connectAddress =
|
||||||
{
|
{
|
||||||
.sin6_family = AF_INET6,
|
.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;
|
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 =
|
sockaddr_in6 bindAddress =
|
||||||
{
|
{
|
||||||
.sin6_family = AF_INET6,
|
.sin6_family = AF_INET6,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user