Unverified Commit e879b36f authored by Dennis Jenkins's avatar Dennis Jenkins Committed by GitHub

Merge pull request #403 from dennisjenkins75/ipv6_support

Ipv6 support
parents fcf8f910 714c13d8
...@@ -48,8 +48,6 @@ public: ...@@ -48,8 +48,6 @@ public:
Flags<Options> options = Options::None, Flags<Options> options = Options::None,
int backlog = Const::MaxBacklog); int backlog = Const::MaxBacklog);
void setHandler(const std::shared_ptr<Handler>& handler); void setHandler(const std::shared_ptr<Handler>& handler);
static bool systemSupportsIpv6();
void bind(); void bind();
void bind(const Address& address); void bind(const Address& address);
......
...@@ -26,6 +26,42 @@ ...@@ -26,6 +26,42 @@
namespace Pistache { namespace Pistache {
// Wrapper around 'getaddrinfo()' that handles cleanup on destruction.
class AddrInfo {
public:
// Disable copy and assign.
AddrInfo(const AddrInfo &) = delete;
AddrInfo& operator=(const AddrInfo &) = delete;
// Default construction: do nothing.
AddrInfo() : addrs(nullptr) {}
~AddrInfo() {
if (addrs) {
::freeaddrinfo(addrs);
}
}
// Call "::getaddrinfo()", but stash result locally. Takes the same args
// as the first 3 args to "::getaddrinfo()" and returns the same result.
int invoke(const char *node, const char *service,
const struct addrinfo *hints) {
if (addrs) {
::freeaddrinfo(addrs);
addrs = nullptr;
}
return ::getaddrinfo(node, service, hints, &addrs);
}
const struct addrinfo *get_info_ptr() const {
return addrs;
}
private:
struct addrinfo *addrs;
};
class Port { class Port {
public: public:
Port(uint16_t port = 0); Port(uint16_t port = 0);
...@@ -66,13 +102,16 @@ private: ...@@ -66,13 +102,16 @@ private:
class Ipv6 { class Ipv6 {
public: 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); 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(); static Ipv6 any();
static Ipv6 loopback(); static Ipv6 loopback();
std::string toString() const; std::string toString() const;
void toNetwork(in6_addr*) const; void toNetwork(in6_addr*) const;
// Returns 'true' if the kernel/libc support IPV6, false if not.
static bool supported();
private: private:
uint16_t a; uint16_t a;
uint16_t b; uint16_t b;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ifaddrs.h>
#include <iostream> #include <iostream>
#include <pistache/net.h> #include <pistache/net.h>
...@@ -130,6 +131,32 @@ void Ipv6::toNetwork(in6_addr *addr6) const { ...@@ -130,6 +131,32 @@ void Ipv6::toNetwork(in6_addr *addr6) const {
memcpy(addr6->s6_addr16, remap_ip6, 16); memcpy(addr6->s6_addr16, remap_ip6, 16);
} }
bool Ipv6::supported() {
struct ifaddrs *ifaddr = nullptr;
struct ifaddrs *ifa = nullptr;
int family, n;
bool supportsIpv6 = false;
if (getifaddrs(&ifaddr) == -1) {
throw std::runtime_error("Call to getifaddrs() failed");
}
for (ifa = ifaddr, n = 0; ifa != nullptr; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == nullptr) {
continue;
}
family = ifa->ifa_addr->sa_family;
if (family == AF_INET6) {
supportsIpv6 = true;
continue;
}
}
freeifaddrs(ifaddr);
return supportsIpv6;
}
Address::Address() Address::Address()
: host_("") : host_("")
, port_(0) , port_(0)
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include <ifaddrs.h>
#include <netdb.h> #include <netdb.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/timerfd.h> #include <sys/timerfd.h>
...@@ -147,29 +146,6 @@ Listener::pinWorker(size_t worker, const CpuSet& set) ...@@ -147,29 +146,6 @@ Listener::pinWorker(size_t worker, const CpuSet& set)
#endif #endif
} }
bool
Listener::systemSupportsIpv6(){
struct ifaddrs *ifaddr, *ifa;
int family, n;
bool supportsIpv6 = false;
if (getifaddrs(&ifaddr) == -1) {
throw std::runtime_error("Call to getifaddrs() failed");
}
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
if (family == AF_INET6) {
supportsIpv6 = true;
continue;
}
}
freeifaddrs(ifaddr);
return supportsIpv6;
}
void void
Listener::bind() { Listener::bind() {
bind(addr_); bind(addr_);
...@@ -189,13 +165,14 @@ Listener::bind(const Address& address) { ...@@ -189,13 +165,14 @@ Listener::bind(const Address& address) {
const auto& host = addr_.host(); const auto& host = addr_.host();
const auto& port = addr_.port().toString(); const auto& port = addr_.port().toString();
struct addrinfo *addrs; AddrInfo addr_info;
TRY(::getaddrinfo(host.c_str(), port.c_str(), &hints, &addrs));
TRY(addr_info.invoke(host.c_str(), port.c_str(), &hints));
int fd = -1; int fd = -1;
addrinfo *addr; const addrinfo * addr = nullptr;
for (addr = addrs; addr; addr = addr->ai_next) { for (addr = addr_info.get_info_ptr(); addr; addr = addr->ai_next) {
fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (fd < 0) continue; if (fd < 0) continue;
......
...@@ -198,7 +198,7 @@ TEST(listener_test, listener_bind_ephemeral_v4_port) { ...@@ -198,7 +198,7 @@ TEST(listener_test, listener_bind_ephemeral_v4_port) {
TEST(listener_test, listener_bind_ephemeral_v6_port) { TEST(listener_test, listener_bind_ephemeral_v6_port) {
Pistache::Tcp::Listener listener; Pistache::Tcp::Listener listener;
if (listener.systemSupportsIpv6()) { if (Pistache::Ipv6::supported()) {
Pistache::Port port(0); Pistache::Port port(0);
Pistache::Address address(Pistache::Ipv6::any(), port); Pistache::Address address(Pistache::Ipv6::any(), port);
......
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