Added some basic HTTP and ip address parsing.

This commit is contained in:
2024-08-18 23:06:09 +02:00
parent 03c899f17e
commit 35e7131780
9 changed files with 497 additions and 35 deletions

View File

@@ -1,13 +1,17 @@
#include "./socket.hpp"
#include <iostream>
#include "../detect.hpp"
#include "../util/string.hpp"
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "../util/variant.hpp"
#endif
namespace mijin
@@ -51,6 +55,77 @@ int readFlags(const ReadOptions& options)
}
}
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.");
@@ -174,7 +249,7 @@ StreamFeatures TCPStream::getFeatures()
};
}
StreamError TCPStream::open(const char* address, std::uint16_t port) noexcept
StreamError TCPStream::open(ip_address_t address, std::uint16_t port) noexcept
{
MIJIN_ASSERT(!isOpen(), "Socket is already open.");
@@ -183,13 +258,31 @@ StreamError TCPStream::open(const char* address, std::uint16_t port) noexcept
{
return translateErrno();
}
sockaddr_in connectAddress =
{
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr = {inet_addr(address)}
};
if (connect(handle_, reinterpret_cast<sockaddr*>(&connectAddress), sizeof(sockaddr_in)) < 0)
const bool connected = std::visit(Visitor{
[&](const IPv4Address& address4)
{
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#error "TODO: swap byte orderof thre address"
#endif
sockaddr_in connectAddress =
{
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr = {.s_addr = std::bit_cast<in_addr_t>(address4)}
};
return connect(handle_, reinterpret_cast<sockaddr*>(&connectAddress), sizeof(sockaddr_in)) == 0;
},
[&](const IPv6Address& address6) {
sockaddr_in6 connectAddress =
{
.sin6_family = AF_INET,
.sin6_port = htons(port),
.sin6_addr = std::bit_cast<in6_addr>(address6)
};
return connect(handle_, reinterpret_cast<sockaddr*>(&connectAddress), sizeof(sockaddr_in6)) == 0;}
}, address);
if (!connected)
{
::close(handle_);
handle_ = -1;