Commit 3366df11 authored by hydratim's avatar hydratim

Added IPv6 support

parent ca1e564e
...@@ -815,15 +815,8 @@ namespace helpers ...@@ -815,15 +815,8 @@ namespace helpers
{ {
inline Address httpAddr(const StringView& view) { inline Address httpAddr(const StringView& view) {
auto const str = view.toString(); auto const str = view.toString();
auto const pos = str.find(':'); return Address(str);
if (pos == std::string::npos) {
return Address(std::move(str), HTTP_STANDARD_PORT);
} }
auto const host = str.substr(0, pos);
auto const port = std::stoi(str.substr(pos + 1));
return Address(std::move(host), port);
}
} // namespace helpers } // namespace helpers
} // namespace Http } // namespace Http
} // namespace Pistache } // namespace Pistache
...@@ -53,6 +53,7 @@ public: ...@@ -53,6 +53,7 @@ public:
static Ipv4 any(); static Ipv4 any();
std::string toString() const; std::string toString() const;
void toNetwork(in_addr_t*) const;
private: private:
uint8_t a; uint8_t a;
...@@ -61,6 +62,25 @@ private: ...@@ -61,6 +62,25 @@ private:
uint8_t d; uint8_t d;
}; };
class Ipv6 {
public:
Ipv6(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h);
static Ipv6 any();
std::string toString() const;
void toNetwork(in6_addr*) const;
private:
uint16_t a;
uint16_t b;
uint16_t c;
uint16_t d;
uint16_t e;
uint16_t f;
uint16_t g;
uint16_t h;
};
class Address { class Address {
public: public:
Address(); Address();
...@@ -68,6 +88,7 @@ public: ...@@ -68,6 +88,7 @@ public:
Address(std::string addr); Address(std::string addr);
Address(const char* addr); Address(const char* addr);
Address(Ipv4 ip, Port port); Address(Ipv4 ip, Port port);
Address(Ipv6 ip, Port port);
Address(const Address& other) = default; Address(const Address& other) = default;
Address(Address&& other) = default; Address(Address&& other) = default;
...@@ -79,11 +100,13 @@ public: ...@@ -79,11 +100,13 @@ public:
std::string host() const; std::string host() const;
Port port() const; Port port() const;
int family() const;
private: private:
void init(const std::string& addr); void init(const std::string& addr);
std::string host_; std::string host_;
Port port_; Port port_;
int family_;
}; };
class Error : public std::runtime_error { class Error : public std::runtime_error {
......
...@@ -340,17 +340,32 @@ Host::Host(const std::string& data) ...@@ -340,17 +340,32 @@ Host::Host(const std::string& data)
void void
Host::parse(const std::string& data) { Host::parse(const std::string& data) {
auto pos = data.find(':'); unsigned long pos = data.find(']');
if (pos != std::string::npos) { unsigned long s_pos = data.find('[');
std::string h = data.substr(0, pos); if (pos != std::string::npos && s_pos != std::string::npos) {
int16_t p = std::stoi(data.substr(pos + 1)); //IPv6 address
host_ = data.substr(s_pos+1, pos-1);
host_ = h; pos++;
port_ = p;
} else { } else {
host_ = data; //IPv4 address
port_ = HTTP_STANDARD_PORT; pos = data.find(':');
if (pos == std::string::npos) {
host_ = data;
port_ = HTTP_STANDARD_PORT;
}
host_ = data.substr(0, pos);
if (host_ == "*") {
host_ = "0.0.0.0";
}
} }
char *end;
const std::string portPart = data.substr(pos + 1);
if (portPart.empty())
throw std::invalid_argument("Invalid port");
long port = strtol(portPart.c_str(), &end, 10);
if (*end != 0 || port < Port::min() || port > Port::max())
throw std::invalid_argument("Invalid port");
port_ = static_cast<uint16_t>(port);
} }
void void
......
...@@ -52,12 +52,71 @@ Ipv4::any() { ...@@ -52,12 +52,71 @@ Ipv4::any() {
std::string std::string
Ipv4::toString() const { Ipv4::toString() const {
static constexpr size_t MaxSize = sizeof("255") * 4 + 3 + 1; /* 4 * 255 + 3 * dot + \0 */
// Use the built-in ipv4 string length from arpa/inet.h
char buff[INET_ADDRSTRLEN+1];
in_addr_t addr;
toNetwork(&addr);
// Convert the network format address into display format
inet_ntop(AF_INET, &addr, buff, INET_ADDRSTRLEN);
return std::string(buff);
}
char buff[MaxSize]; void Ipv4::toNetwork(in_addr_t *addr) const {
snprintf(buff, MaxSize, "%d.%d.%d.%d", a, b, c, d); // Bitshift the bytes into an in_addr_t (a single 32bit unsigned int);
*addr = (uint32_t)(d<<24) | (uint32_t)(c<<16) | (uint32_t)(b<<8) | (uint32_t)a;
}
return std::string(buff); Ipv6::Ipv6(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
: a(a)
, b(b)
, c(c)
, d(d)
, e(e)
, f(f)
, g(g)
, h(h)
{ }
Ipv6
Ipv6::any() {
return Ipv6(0, 0, 0, 0, 0, 0, 0, 0);
}
std::string
Ipv6::toString() const {
// Use the built-in ipv6 string length from arpa/inet.h
char buff6[INET6_ADDRSTRLEN+1];
in6_addr addr;
toNetwork(&addr);
inet_ntop(AF_INET6, &addr, buff6, INET6_ADDRSTRLEN);
return std::string(buff6);
}
void Ipv6::toNetwork(in6_addr *addr6) const {
uint16_t temp_ip6[8] = {a, b, c, d, e, f, g, h};
uint16_t remap_ip6[8] = {0};
uint16_t x, y;
// If native endianness is little-endian swap the bytes, otherwise just copy them into the new array
if ( htonl(1) != 1 ) {
for (uint16_t i = 0; i<8; i++) {
x = temp_ip6[i];
y = __builtin_bswap16 (x);
remap_ip6[i] = y;
}
} else {
memcpy(remap_ip6, temp_ip6, 16);
}
// Copy the bytes into the in6_addr struct
memcpy(addr6->s6_addr16, remap_ip6, 16);
} }
Address::Address() Address::Address()
...@@ -86,16 +145,31 @@ Address::Address(Ipv4 ip, Port port) ...@@ -86,16 +145,31 @@ Address::Address(Ipv4 ip, Port port)
, port_(port) , port_(port)
{ } { }
Address::Address(Ipv6 ip, Port port)
: host_(ip.toString())
, port_(port)
{ }
Address Address
Address::fromUnix(struct sockaddr* addr) { Address::fromUnix(struct sockaddr* addr) {
struct sockaddr_in *in_addr = reinterpret_cast<struct sockaddr_in *>(addr); if (addr->sa_family == AF_INET) {
struct sockaddr_in *in_addr = reinterpret_cast<struct sockaddr_in *>(addr);
char *host = inet_ntoa(in_addr->sin_addr); char host[INET_ADDRSTRLEN+1];
assert(addr); inet_ntop(AF_INET, &(in_addr->sin_addr), host, INET_ADDRSTRLEN);
int port = ntohs(in_addr->sin_port);
int port = ntohs(in_addr->sin_port); assert(addr);
return Address(host, port);
} else if (addr->sa_family == AF_INET6) {
struct sockaddr_in6 *in_addr = reinterpret_cast<struct sockaddr_in6 *>(addr);
char host[INET6_ADDRSTRLEN+1];
inet_ntop(AF_INET6, &(in_addr->sin6_addr), host, INET6_ADDRSTRLEN);
int port = ntohs(in_addr->sin6_port);
assert(addr);
return Address(host, port);
}
throw Error("Not an IP socket");
return Address(host, port);
} }
std::string std::string
...@@ -108,18 +182,30 @@ Address::port() const { ...@@ -108,18 +182,30 @@ Address::port() const {
return port_; return port_;
} }
int
Address::family() const {
return family_;
}
void void
Address::init(const std::string& addr) { Address::init(const std::string& addr) {
const auto pos = addr.find(':'); unsigned long pos = addr.find(']');
unsigned long s_pos = addr.find('[');
if (pos == std::string::npos) if (pos != std::string::npos && s_pos != std::string::npos) {
throw std::invalid_argument("Invalid address"); //IPv6 address
host_ = addr.substr(s_pos+1, pos-1);
host_ = addr.substr(0, pos); pos++;
if (host_ == "*") { } else {
host_ = "0.0.0.0"; //IPv4 address
pos = addr.find(':');
if (pos == std::string::npos)
throw std::invalid_argument("Invalid address");
host_ = addr.substr(0, pos);
if (host_ == "*") {
host_ = "0.0.0.0";
}
} }
char *end; char *end;
const std::string portPart = addr.substr(pos + 1); const std::string portPart = addr.substr(pos + 1);
if (portPart.empty()) if (portPart.empty())
......
...@@ -157,7 +157,7 @@ Listener::bind(const Address& address) { ...@@ -157,7 +157,7 @@ Listener::bind(const Address& address) {
addr_ = address; addr_ = address;
struct addrinfo hints; struct addrinfo hints;
hints.ai_family = AF_INET; hints.ai_family = address.family();
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0; hints.ai_protocol = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment