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

Merge pull request #542 from hydratim/hydratim-network-cleanup1

Some clean-up of the net primitives
parents 47037a2a e65daea3
...@@ -83,45 +83,35 @@ private: ...@@ -83,45 +83,35 @@ private:
uint16_t port; uint16_t port;
}; };
class Ipv4 {
public:
Ipv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
static Ipv4 any();
static Ipv4 loopback();
std::string toString() const;
void toNetwork(in_addr_t*) const;
class IP {
private: private:
uint8_t a; int port;
uint8_t b; int family;
uint8_t c; union {
uint8_t d; struct sockaddr_in addr;
}; struct sockaddr_in6 addr6;
};
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); IP();
IP(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
static Ipv6 any(); IP(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 loopback(); IP(struct sockaddr *);
static IP any();
static IP loopback();
static IP any(bool ipv6);
static IP loopback(bool ipv6);
int getFamily() const;
int getPort() const;
std::string toString() const; std::string toString() const;
void toNetwork(in6_addr*) const; void toNetwork(in_addr_t*) const;
void toNetwork(struct in6_addr*) const;
// Returns 'true' if the kernel/libc support IPV6, false if not. // Returns 'true' if the system has IPV6 support, false if not.
static bool supported(); static bool supported();
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;
}; };
using Ipv4 = IP;
using Ipv6 = IP;
class AddressParser { class AddressParser {
public: public:
...@@ -131,20 +121,21 @@ public: ...@@ -131,20 +121,21 @@ public:
bool hasColon() const; bool hasColon() const;
int family() const; int family() const;
private: private:
std::string host_; std::string host_;
std::string port_; std::string port_;
bool hasColon_ = false; bool hasColon_ = false;
int family_ = 0; int family_ = 0;
}; };
class Address { class Address {
public: public:
Address(); Address();
Address(std::string host, Port port); Address(std::string host, Port port);
Address(std::string addr); Address(std::string addr);
Address(const char* addr); Address(const char* addr);
Address(Ipv4 ip, Port port); Address(IP 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;
...@@ -160,9 +151,8 @@ public: ...@@ -160,9 +151,8 @@ public:
private: private:
void init(const std::string& addr); void init(const std::string& addr);
std::string host_; IP ip_;
Port port_; Port port_;
int family_ = AF_INET;
}; };
class Error : public std::runtime_error { class Error : public std::runtime_error {
......
...@@ -70,101 +70,117 @@ Port::toString() const { ...@@ -70,101 +70,117 @@ Port::toString() const {
return std::to_string(port); return std::to_string(port);
} }
Ipv4::Ipv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d) IP::IP() {
: a(a) family = AF_INET;
, b(b) addr = {0};
, c(c) addr.sin_family = AF_INET;
, d(d) uint8_t buff[INET_ADDRSTRLEN+1] = {0,0,0,0};
{ } memcpy(&addr.sin_addr.s_addr, buff, INET_ADDRSTRLEN);
Ipv4
Ipv4::any() {
return Ipv4(0, 0, 0, 0);
} }
Ipv4 IP::IP(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
Ipv4::loopback() { family = AF_INET;
return Ipv4(127, 0, 0, 1); addr = {0};
addr.sin_family = AF_INET;
uint8_t buff[INET_ADDRSTRLEN+1] = {a,b,c,d};
memcpy(&addr.sin_addr.s_addr, buff, INET_ADDRSTRLEN);
} }
IP::IP(uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h){
family = AF_INET6;
addr6 = { 0 };
addr6.sin6_family = AF_INET6;
uint16_t buff[9] {a,b,c,d,e,f,g,h, '\0'};
uint16_t remap[9] = {0,0,0,0,0,0,0,0, '\0'};
if ( htonl(1) != 1 ) {
for (int i = 0; i<8; i++) {
uint16_t x = buff[i];
uint16_t y = htons(x);
remap[i] = y;
}
} else {
memcpy(&remap, &buff, sizeof(remap));
}
memcpy(&addr6.sin6_addr.s6_addr16, &remap, 8*sizeof(uint16_t));
}
std::string IP::IP(struct sockaddr* _addr) {
Ipv4::toString() const { if (_addr->sa_family == AF_INET) {
struct sockaddr_in *in_addr = reinterpret_cast<struct sockaddr_in *>(_addr);
// Use the built-in ipv4 string length from arpa/inet.h family = AF_INET;
char buff[INET_ADDRSTRLEN+1]; port = in_addr->sin_port;
memcpy(&(addr.sin_addr.s_addr), &(in_addr->sin_addr.s_addr), sizeof(in_addr_t));
in_addr_t addr; } else if (_addr->sa_family == AF_INET6) {
toNetwork(&addr); struct sockaddr_in6 *in_addr = reinterpret_cast<struct sockaddr_in6 *>(_addr);
family = AF_INET6;
port = in_addr->sin6_port;
memcpy(&(addr6.sin6_addr.s6_addr16), &(in_addr->sin6_addr.s6_addr16), 8*sizeof(uint16_t));
}
}
// Convert the network format address into display format IP
inet_ntop(AF_INET, &addr, buff, INET_ADDRSTRLEN); IP::any() {
return IP(0, 0, 0, 0);
}
return std::string(buff); IP
IP::any(bool is_ipv6) {
if (is_ipv6) {
return IP(0, 0, 0, 0, 0, 0, 0, 0);
} else {
return IP(0, 0, 0, 0);
}
} }
void Ipv4::toNetwork(in_addr_t *addr) const { IP
// Bitshift the bytes into an in_addr_t (a single 32bit unsigned int); IP::loopback(){
*addr = htonl( (uint32_t)(a<<24) | (uint32_t)(b<<16) | (uint32_t)(c<<8) | (uint32_t)d );; return IP(127, 0, 0, 1);
} }
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) IP
: a(a) IP::loopback(bool is_ipv6) {
, b(b) if (is_ipv6) {
, c(c) return IP(0, 0, 0, 0, 0, 0, 0, 1);
, d(d) } else {
, e(e) return IP(127, 0, 0, 1);
, f(f) }
, g(g) }
, h(h)
{ }
Ipv6 int IP::getFamily() const {
Ipv6::any() { return family;
return Ipv6(0, 0, 0, 0, 0, 0, 0, 0);
} }
Ipv6 int IP::getPort() const {
Ipv6::loopback() { return port;
return Ipv6(0, 0, 0, 0, 0, 0, 0, 1);
} }
std::string std::string
Ipv6::toString() const { IP::toString() const {
char buff[INET6_ADDRSTRLEN+1];
// Use the built-in ipv6 string length from arpa/inet.h if (family == AF_INET) {
char buff6[INET6_ADDRSTRLEN+1]; in_addr_t addr_;
toNetwork(&addr_);
in6_addr addr; inet_ntop(AF_INET, &addr_, buff, INET_ADDRSTRLEN);
toNetwork(&addr); } else if (family == AF_INET6) {
struct in6_addr addr_ = in6addr_any;
inet_ntop(AF_INET6, &addr, buff6, INET6_ADDRSTRLEN); toNetwork(&addr_);
inet_ntop(AF_INET6, &addr_, buff, INET6_ADDRSTRLEN);
return std::string(buff6); }
return std::string(buff);
} }
void Ipv6::toNetwork(in6_addr *addr6) const { void IP::toNetwork(in_addr_t *_addr) const {
uint16_t temp_ip6[8] = {a, b, c, d, e, f, g, h}; memcpy(_addr, &addr.sin_addr.s_addr, sizeof(uint32_t));
uint16_t remap_ip6[8] = {0}; }
// If native endianness is little-endian swap the bytes, otherwise just copy them into the new array void IP::toNetwork(struct in6_addr *out) const {
if ( htonl(1) != 1 ) { memcpy(&out->s6_addr16, &(addr6.sin6_addr.s6_addr16), 8*sizeof(uint16_t));
for (uint16_t i = 0; i<8; i++) {
uint16_t x = temp_ip6[i];
uint16_t y = htons(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);
} }
bool Ipv6::supported() { bool IP::supported() {
struct ifaddrs *ifaddr = nullptr; struct ifaddrs *ifaddr = nullptr;
struct ifaddrs *ifa = nullptr; struct ifaddrs *ifa = nullptr;
int family, n; int addr_family, n;
bool supportsIpv6 = false; bool supportsIpv6 = false;
if (getifaddrs(&ifaddr) == -1) { if (getifaddrs(&ifaddr) == -1) {
...@@ -176,8 +192,8 @@ bool Ipv6::supported() { ...@@ -176,8 +192,8 @@ bool Ipv6::supported() {
continue; continue;
} }
family = ifa->ifa_addr->sa_family; addr_family = ifa->ifa_addr->sa_family;
if (family == AF_INET6) { if (addr_family == AF_INET6) {
supportsIpv6 = true; supportsIpv6 = true;
continue; continue;
} }
...@@ -187,6 +203,7 @@ bool Ipv6::supported() { ...@@ -187,6 +203,7 @@ bool Ipv6::supported() {
return supportsIpv6; return supportsIpv6;
} }
AddressParser::AddressParser(const std::string& data) AddressParser::AddressParser(const std::string& data)
{ {
std::size_t end_pos = data.find(']'); std::size_t end_pos = data.find(']');
...@@ -245,9 +262,11 @@ int AddressParser::family() const ...@@ -245,9 +262,11 @@ int AddressParser::family() const
} }
Address::Address() Address::Address()
: host_("") {
, port_(0) port_ = Port(0);
{ } ip_ = IP::any();
}
Address::Address(std::string host, Port port) Address::Address(std::string host, Port port)
{ {
...@@ -268,41 +287,25 @@ Address::Address(const char* addr) ...@@ -268,41 +287,25 @@ Address::Address(const char* addr)
init(std::string(addr)); init(std::string(addr));
} }
Address::Address(Ipv4 ip, Port port) Address::Address(IP ip, Port port)
: host_(ip.toString()) : ip_(ip)
, port_(port) , port_(port)
, family_(AF_INET)
{ }
Address::Address(Ipv6 ip, Port port)
: host_(ip.toString())
, port_(port)
, family_(AF_INET6)
{ } { }
Address Address
Address::fromUnix(struct sockaddr* addr) { Address::fromUnix(struct sockaddr* addr) {
if (addr->sa_family == AF_INET) { if ((addr->sa_family==AF_INET) or (addr->sa_family==AF_INET6)) {
struct sockaddr_in *in_addr = reinterpret_cast<struct sockaddr_in *>(addr); IP ip = IP(addr);
char host[INET_ADDRSTRLEN+1]; Port port = Port(ip.getPort());
inet_ntop(AF_INET, &(in_addr->sin_addr), host, INET_ADDRSTRLEN);
int port = ntohs(in_addr->sin_port);
assert(addr); assert(addr);
return Address(host, port); return Address(ip, 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"); throw Error("Not an IP socket");
} }
std::string std::string
Address::host() const { Address::host() const {
return host_; return ip_.toString();
} }
Port Port
...@@ -312,13 +315,16 @@ Address::port() const { ...@@ -312,13 +315,16 @@ Address::port() const {
int int
Address::family() const { Address::family() const {
return family_; return ip_.getFamily();
} }
void Address::init(const std::string& addr) void Address::init(const std::string& addr)
{ {
AddressParser parser(addr); AddressParser parser(addr);
family_ = parser.family(); int family_ = parser.family();
std::string host_;
if (family_ == AF_INET6) if (family_ == AF_INET6)
{ {
const std::string& raw_host = parser.rawHost(); const std::string& raw_host = parser.rawHost();
...@@ -329,10 +335,20 @@ void Address::init(const std::string& addr) ...@@ -329,10 +335,20 @@ void Address::init(const std::string& addr)
{ {
throw std::invalid_argument("Invalid IPv6 address"); throw std::invalid_argument("Invalid IPv6 address");
} }
char buff[INET6_ADDRSTRLEN+1] = {};
memcpy(buff, host_.c_str(), INET6_ADDRSTRLEN);
struct in6_addr addr;
inet_pton(AF_INET6, buff, &addr);
struct sockaddr_in6 s_addr = {0};
s_addr.sin6_family = AF_INET6;
memcpy(&(s_addr.sin6_addr.s6_addr16), &addr.s6_addr16, 8*sizeof(uint16_t));
ip_ = IP(reinterpret_cast<struct sockaddr *>(&s_addr));
} }
else if (family_ == AF_INET) else if (family_ == AF_INET)
{ {
host_ = parser.rawHost(); host_ = parser.rawHost();
if (host_ == "*") if (host_ == "*")
{ {
host_ = "0.0.0.0"; host_ = "0.0.0.0";
...@@ -343,6 +359,7 @@ void Address::init(const std::string& addr) ...@@ -343,6 +359,7 @@ void Address::init(const std::string& addr)
} }
struct hostent *hp = ::gethostbyname(host_.c_str()); struct hostent *hp = ::gethostbyname(host_.c_str());
if (hp) if (hp)
{ {
struct in_addr **addr_list; struct in_addr **addr_list;
...@@ -359,6 +376,15 @@ void Address::init(const std::string& addr) ...@@ -359,6 +376,15 @@ void Address::init(const std::string& addr)
{ {
throw std::invalid_argument("Invalid IPv4 address"); throw std::invalid_argument("Invalid IPv4 address");
} }
char buff[INET_ADDRSTRLEN+1] = {};
memcpy(buff, host_.c_str(), INET_ADDRSTRLEN);
struct in_addr addr;
inet_pton(AF_INET, buff, &addr);
struct sockaddr_in s_addr = {0};
s_addr.sin_family = AF_INET;
memcpy(&(s_addr.sin_addr.s_addr), &addr.s_addr, sizeof(uint32_t));
ip_ = IP(reinterpret_cast<struct sockaddr *>(&s_addr));
} }
else else
{ assert(false); } { assert(false); }
......
...@@ -30,65 +30,111 @@ TEST(net_test, address_creation) ...@@ -30,65 +30,111 @@ TEST(net_test, address_creation)
{ {
Address address1("127.0.0.1:8080"); Address address1("127.0.0.1:8080");
ASSERT_EQ(address1.host(), "127.0.0.1"); ASSERT_EQ(address1.host(), "127.0.0.1");
ASSERT_EQ(address1.family(), AF_INET);
ASSERT_EQ(address1.port(), 8080); ASSERT_EQ(address1.port(), 8080);
std::string addr = "127.0.0.1"; std::string addr = "127.0.0.1";
Address address2(addr, Port(8080)); Address address2(addr, Port(8080));
ASSERT_EQ(address2.host(), "127.0.0.1"); ASSERT_EQ(address2.host(), "127.0.0.1");
ASSERT_EQ(address2.family(), AF_INET);
ASSERT_EQ(address2.port(), 8080); ASSERT_EQ(address2.port(), 8080);
Address address3(Ipv4(127, 0, 0, 1), Port(8080)); Address address3(Ipv4(127, 0, 0, 1), Port(8080));
ASSERT_EQ(address3.host(), "127.0.0.1"); ASSERT_EQ(address3.host(), "127.0.0.1");
ASSERT_EQ(address3.family(), AF_INET);
ASSERT_EQ(address3.port(), 8080); ASSERT_EQ(address3.port(), 8080);
Address address4(Ipv4::any(), Port(8080)); Address address4(Ipv4::any(), Port(8080));
ASSERT_EQ(address4.host(), "0.0.0.0"); ASSERT_EQ(address4.host(), "0.0.0.0");
ASSERT_EQ(address4.family(), AF_INET);
ASSERT_EQ(address4.port(), 8080); ASSERT_EQ(address4.port(), 8080);
Address address5("*:8080"); Address address5("*:8080");
ASSERT_EQ(address5.host(), "0.0.0.0"); ASSERT_EQ(address5.host(), "0.0.0.0");
ASSERT_EQ(address5.family(), AF_INET);
ASSERT_EQ(address5.port(), 8080); ASSERT_EQ(address5.port(), 8080);
Address address6("[::1]:8080"); Address address6("[::1]:8080");
ASSERT_EQ(address6.host(), "::1"); ASSERT_EQ(address6.host(), "::1");
ASSERT_EQ(address6.family(), AF_INET6);
ASSERT_EQ(address6.port(), 8080); ASSERT_EQ(address6.port(), 8080);
std::string addr2 = "[::1]"; std::string addr2 = "[::1]";
Address address7(addr2, Port(8080)); Address address7(addr2, Port(8080));
ASSERT_EQ(address7.host(), "::1"); ASSERT_EQ(address7.host(), "::1");
ASSERT_EQ(address7.family(), AF_INET6);
ASSERT_EQ(address7.port(), 8080); ASSERT_EQ(address7.port(), 8080);
Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080)); Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080));
ASSERT_EQ(address8.host(), "::1"); ASSERT_EQ(address8.host(), "::1");
ASSERT_EQ(address8.family(), AF_INET6);
ASSERT_EQ(address8.port(), 8080); ASSERT_EQ(address8.port(), 8080);
Address address9(Ipv6::any(), Port(8080)); Address address9(Ipv6::any(true), Port(8080));
ASSERT_EQ(address9.host(), "::"); ASSERT_EQ(address9.host(), "::");
ASSERT_EQ(address9.family(), AF_INET6);
ASSERT_EQ(address9.port(), 8080); ASSERT_EQ(address9.port(), 8080);
Address address10("[::]:8080"); Address address10("[::]:8080");
ASSERT_EQ(address10.host(), "::"); ASSERT_EQ(address10.host(), "::");
ASSERT_EQ(address10.family(), AF_INET6);
ASSERT_EQ(address10.port(), 8080); ASSERT_EQ(address10.port(), 8080);
Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080"); Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
ASSERT_EQ(address11.host(), "2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455"); ASSERT_EQ(address11.host(), "2001:db8:aabb:ccdd:eeff:11:2233:4455");
ASSERT_EQ(address11.family(), AF_INET6);
ASSERT_EQ(address11.port(), 8080); ASSERT_EQ(address11.port(), 8080);
Address address12(Ipv4::loopback(), Port(8080)); Address address12(Ipv4::loopback(), Port(8080));
ASSERT_EQ(address12.host(), "127.0.0.1"); ASSERT_EQ(address12.host(), "127.0.0.1");
ASSERT_EQ(address12.family(), AF_INET);
ASSERT_EQ(address12.port(), 8080); ASSERT_EQ(address12.port(), 8080);
Address address13(Ipv6::loopback(), Port(8080)); Address address13(Ipv6::loopback(true), Port(8080));
ASSERT_EQ(address13.host(), "::1"); ASSERT_EQ(address13.host(), "::1");
ASSERT_EQ(address13.family(), AF_INET6);
ASSERT_EQ(address13.port(), 8080); ASSERT_EQ(address13.port(), 8080);
Address address14("127.0.0.1"); Address address14("127.0.0.1");
ASSERT_EQ(address14.host(), "127.0.0.1"); ASSERT_EQ(address14.host(), "127.0.0.1");
ASSERT_EQ(address14.family(), AF_INET);
ASSERT_EQ(address14.port(), 80); ASSERT_EQ(address14.port(), 80);
Address address15("www.example.com"); Address address15("www.example.com");
ASSERT_EQ(address15.host(), "93.184.216.34"); ASSERT_EQ(address15.host(), "93.184.216.34");
ASSERT_EQ(address15.family(), AF_INET);
ASSERT_EQ(address15.port(), 80); ASSERT_EQ(address15.port(), 80);
Address address16(IP(127, 0, 0, 1), Port(8080));
ASSERT_EQ(address16.host(), "127.0.0.1");
ASSERT_EQ(address16.family(), AF_INET);
ASSERT_EQ(address16.port(), 8080);
Address address17(IP::any(), Port(8080));
ASSERT_EQ(address17.host(), "0.0.0.0");
ASSERT_EQ(address17.family(), AF_INET);
ASSERT_EQ(address17.port(), 8080);
Address address18(IP(2, 0, 0, 0, 0, 0, 0, 1), Port(8080));
ASSERT_EQ(address18.host(), "2::1");
ASSERT_EQ(address18.family(), AF_INET6);
ASSERT_EQ(address18.port(), 8080);
Address address19(IP::any(true), Port(8080));
ASSERT_EQ(address19.host(), "::");
ASSERT_EQ(address19.family(), AF_INET6);
ASSERT_EQ(address19.port(), 8080);
Address address20(IP::loopback(true), Port(8080));
ASSERT_EQ(address20.host(), "::1");
ASSERT_EQ(address20.family(), AF_INET6);
ASSERT_EQ(address20.port(), 8080);
Address address21(IP::loopback(), Port(8080));
ASSERT_EQ(address21.host(), "127.0.0.1");
ASSERT_EQ(address21.family(), AF_INET);
ASSERT_EQ(address21.port(), 8080);
} }
TEST(net_test, invalid_address) TEST(net_test, invalid_address)
......
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