#3 - DNS support + IPv6
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#include "ClientArgs.hpp"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <charconv>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -25,12 +24,6 @@ std::string_view trim(std::string_view str) {
|
||||
return str.substr(start, end - start);
|
||||
}
|
||||
|
||||
bool is_valid_ipv4(std::string_view ip_str) {
|
||||
// Use inet_pton to validate IPv4 format
|
||||
struct in_addr addr;
|
||||
return inet_pton(AF_INET, std::string(ip_str).c_str(), &addr) == 1;
|
||||
}
|
||||
|
||||
tl::expected<int, std::string> parse_port(std::string_view port_str) {
|
||||
if(port_str.empty()) {
|
||||
return 8080; // Default port
|
||||
@@ -63,15 +56,27 @@ tl::expected<net::Address, std::string> parse_address(std::string_view text) {
|
||||
return tl::make_unexpected("address cannot be empty");
|
||||
}
|
||||
|
||||
// Find the colon to split host and port
|
||||
size_t colon_pos = text.rfind(':');
|
||||
|
||||
std::string_view host;
|
||||
std::string_view port_str;
|
||||
|
||||
if(colon_pos == std::string_view::npos) {
|
||||
// No colon found: treat entire string as port or host
|
||||
// If it's all digits, treat as port; otherwise as host (will fail validation)
|
||||
// An IPv6 literal carries colons of its own, so the brackets it is written
|
||||
// in are what says where the host ends. This is the form to_string() emits.
|
||||
if(text.front() == '[') {
|
||||
size_t closing = text.find(']');
|
||||
if(closing == std::string_view::npos) {
|
||||
return tl::make_unexpected("address is missing a closing bracket");
|
||||
}
|
||||
|
||||
host = text.substr(1, closing - 1);
|
||||
port_str = text.substr(closing + 1);
|
||||
|
||||
if(!port_str.empty()) {
|
||||
if(port_str.front() != ':') {
|
||||
return tl::make_unexpected("expected a port after the closing bracket");
|
||||
}
|
||||
port_str.remove_prefix(1);
|
||||
}
|
||||
} else if(size_t colon_pos = text.rfind(':'); colon_pos == std::string_view::npos) {
|
||||
bool all_digits = !text.empty() && std::all_of(text.begin(), text.end(),
|
||||
[](unsigned char c) { return std::isdigit(c); });
|
||||
|
||||
@@ -79,7 +84,6 @@ tl::expected<net::Address, std::string> parse_address(std::string_view text) {
|
||||
host = "127.0.0.1";
|
||||
port_str = text;
|
||||
} else {
|
||||
// Treat as host with no port
|
||||
host = text;
|
||||
port_str = "";
|
||||
}
|
||||
@@ -93,10 +97,6 @@ tl::expected<net::Address, std::string> parse_address(std::string_view text) {
|
||||
return tl::make_unexpected("host cannot be empty");
|
||||
}
|
||||
|
||||
if(!is_valid_ipv4(host)) {
|
||||
return tl::make_unexpected("not a valid IPv4 address");
|
||||
}
|
||||
|
||||
// Parse port
|
||||
auto port_result = parse_port(port_str);
|
||||
if(!port_result) {
|
||||
@@ -104,7 +104,13 @@ tl::expected<net::Address, std::string> parse_address(std::string_view text) {
|
||||
}
|
||||
|
||||
int port = port_result.value();
|
||||
return net::Address(std::optional<std::string>(std::string(host)), port);
|
||||
|
||||
auto address_r = net::Address::resolve(std::string(host), port);
|
||||
if(!address_r) {
|
||||
return tl::make_unexpected(address_r.error().message());
|
||||
}
|
||||
|
||||
return address_r.value();
|
||||
}
|
||||
|
||||
std::optional<std::string> server_arg(int argc, char** argv) {
|
||||
|
||||
@@ -12,10 +12,13 @@ namespace tw::app {
|
||||
/**
|
||||
* Parse an address string into a network address.
|
||||
*
|
||||
* Accepts "host:port" or a bare port number. Bare port uses 127.0.0.1.
|
||||
* Missing port defaults to 8080. Trims surrounding whitespace.
|
||||
* Validates the host with inet_pton and returns an error string
|
||||
* for non-IPv4 addresses or invalid ports.
|
||||
* Accepts "host:port" or a bare port number, where the host may be a name as
|
||||
* well as an address literal; an IPv6 literal has to be bracketed, as
|
||||
* "[::1]:8080". Bare port uses 127.0.0.1. Missing port defaults to 8080.
|
||||
* Trims surrounding whitespace.
|
||||
*
|
||||
* Looks the host up, so it blocks for as long as that takes, and returns an
|
||||
* error string for a host that does not resolve or an invalid port.
|
||||
*/
|
||||
tl::expected<net::Address, std::string> parse_address(std::string_view text);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user