Added some basic HTTP and ip address parsing.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user