1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved. 2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be 3*3f982cf4SFabien Sanglard // found in the LICENSE file. 4*3f982cf4SFabien Sanglard 5*3f982cf4SFabien Sanglard #ifndef PLATFORM_BASE_IP_ADDRESS_H_ 6*3f982cf4SFabien Sanglard #define PLATFORM_BASE_IP_ADDRESS_H_ 7*3f982cf4SFabien Sanglard 8*3f982cf4SFabien Sanglard #include <array> 9*3f982cf4SFabien Sanglard #include <cstdint> 10*3f982cf4SFabien Sanglard #include <ostream> 11*3f982cf4SFabien Sanglard #include <string> 12*3f982cf4SFabien Sanglard #include <type_traits> 13*3f982cf4SFabien Sanglard 14*3f982cf4SFabien Sanglard #include "platform/base/error.h" 15*3f982cf4SFabien Sanglard 16*3f982cf4SFabien Sanglard namespace openscreen { 17*3f982cf4SFabien Sanglard 18*3f982cf4SFabien Sanglard class IPAddress { 19*3f982cf4SFabien Sanglard public: 20*3f982cf4SFabien Sanglard enum class Version { 21*3f982cf4SFabien Sanglard kV4, 22*3f982cf4SFabien Sanglard kV6, 23*3f982cf4SFabien Sanglard }; 24*3f982cf4SFabien Sanglard kAnyV4()25*3f982cf4SFabien Sanglard static constexpr IPAddress kAnyV4() { return IPAddress{0, 0, 0, 0}; } kAnyV6()26*3f982cf4SFabien Sanglard static constexpr IPAddress kAnyV6() { 27*3f982cf4SFabien Sanglard return IPAddress{0, 0, 0, 0, 0, 0, 0, 0}; 28*3f982cf4SFabien Sanglard } kV4LoopbackAddress()29*3f982cf4SFabien Sanglard static constexpr IPAddress kV4LoopbackAddress() { 30*3f982cf4SFabien Sanglard return IPAddress{127, 0, 0, 1}; 31*3f982cf4SFabien Sanglard } kV6LoopbackAddress()32*3f982cf4SFabien Sanglard static constexpr IPAddress kV6LoopbackAddress() { 33*3f982cf4SFabien Sanglard return IPAddress{0, 0, 0, 0, 0, 0, 0, 1}; 34*3f982cf4SFabien Sanglard } 35*3f982cf4SFabien Sanglard static constexpr size_t kV4Size = 4; 36*3f982cf4SFabien Sanglard static constexpr size_t kV6Size = 16; 37*3f982cf4SFabien Sanglard IPAddress()38*3f982cf4SFabien Sanglard constexpr IPAddress() : version_(Version::kV4), bytes_({}) {} 39*3f982cf4SFabien Sanglard 40*3f982cf4SFabien Sanglard // |bytes| contains 4 octets for IPv4, or 8 hextets (16 bytes of big-endian 41*3f982cf4SFabien Sanglard // shorts) for IPv6. 42*3f982cf4SFabien Sanglard IPAddress(Version version, const uint8_t* bytes); 43*3f982cf4SFabien Sanglard 44*3f982cf4SFabien Sanglard // IPv4 constructors (IPAddress from 4 octets). IPAddress(const std::array<uint8_t,4> & bytes)45*3f982cf4SFabien Sanglard explicit constexpr IPAddress(const std::array<uint8_t, 4>& bytes) 46*3f982cf4SFabien Sanglard : version_(Version::kV4), 47*3f982cf4SFabien Sanglard bytes_{{bytes[0], bytes[1], bytes[2], bytes[3]}} {} 48*3f982cf4SFabien Sanglard IPAddress(const uint8_t (& b)[4])49*3f982cf4SFabien Sanglard explicit constexpr IPAddress(const uint8_t (&b)[4]) 50*3f982cf4SFabien Sanglard : version_(Version::kV4), bytes_{{b[0], b[1], b[2], b[3]}} {} 51*3f982cf4SFabien Sanglard IPAddress(uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4)52*3f982cf4SFabien Sanglard constexpr IPAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) 53*3f982cf4SFabien Sanglard : version_(Version::kV4), bytes_{{b1, b2, b3, b4}} {} 54*3f982cf4SFabien Sanglard 55*3f982cf4SFabien Sanglard // IPv6 constructors (IPAddress from 8 hextets). IPAddress(const std::array<uint16_t,8> & hextets)56*3f982cf4SFabien Sanglard explicit constexpr IPAddress(const std::array<uint16_t, 8>& hextets) 57*3f982cf4SFabien Sanglard : IPAddress(hextets[0], 58*3f982cf4SFabien Sanglard hextets[1], 59*3f982cf4SFabien Sanglard hextets[2], 60*3f982cf4SFabien Sanglard hextets[3], 61*3f982cf4SFabien Sanglard hextets[4], 62*3f982cf4SFabien Sanglard hextets[5], 63*3f982cf4SFabien Sanglard hextets[6], 64*3f982cf4SFabien Sanglard hextets[7]) {} 65*3f982cf4SFabien Sanglard IPAddress(const uint16_t (& hextets)[8])66*3f982cf4SFabien Sanglard explicit constexpr IPAddress(const uint16_t (&hextets)[8]) 67*3f982cf4SFabien Sanglard : IPAddress(hextets[0], 68*3f982cf4SFabien Sanglard hextets[1], 69*3f982cf4SFabien Sanglard hextets[2], 70*3f982cf4SFabien Sanglard hextets[3], 71*3f982cf4SFabien Sanglard hextets[4], 72*3f982cf4SFabien Sanglard hextets[5], 73*3f982cf4SFabien Sanglard hextets[6], 74*3f982cf4SFabien Sanglard hextets[7]) {} 75*3f982cf4SFabien Sanglard IPAddress(uint16_t h0,uint16_t h1,uint16_t h2,uint16_t h3,uint16_t h4,uint16_t h5,uint16_t h6,uint16_t h7)76*3f982cf4SFabien Sanglard constexpr IPAddress(uint16_t h0, 77*3f982cf4SFabien Sanglard uint16_t h1, 78*3f982cf4SFabien Sanglard uint16_t h2, 79*3f982cf4SFabien Sanglard uint16_t h3, 80*3f982cf4SFabien Sanglard uint16_t h4, 81*3f982cf4SFabien Sanglard uint16_t h5, 82*3f982cf4SFabien Sanglard uint16_t h6, 83*3f982cf4SFabien Sanglard uint16_t h7) 84*3f982cf4SFabien Sanglard : version_(Version::kV6), 85*3f982cf4SFabien Sanglard bytes_{{ 86*3f982cf4SFabien Sanglard static_cast<uint8_t>(h0 >> 8), 87*3f982cf4SFabien Sanglard static_cast<uint8_t>(h0), 88*3f982cf4SFabien Sanglard static_cast<uint8_t>(h1 >> 8), 89*3f982cf4SFabien Sanglard static_cast<uint8_t>(h1), 90*3f982cf4SFabien Sanglard static_cast<uint8_t>(h2 >> 8), 91*3f982cf4SFabien Sanglard static_cast<uint8_t>(h2), 92*3f982cf4SFabien Sanglard static_cast<uint8_t>(h3 >> 8), 93*3f982cf4SFabien Sanglard static_cast<uint8_t>(h3), 94*3f982cf4SFabien Sanglard static_cast<uint8_t>(h4 >> 8), 95*3f982cf4SFabien Sanglard static_cast<uint8_t>(h4), 96*3f982cf4SFabien Sanglard static_cast<uint8_t>(h5 >> 8), 97*3f982cf4SFabien Sanglard static_cast<uint8_t>(h5), 98*3f982cf4SFabien Sanglard static_cast<uint8_t>(h6 >> 8), 99*3f982cf4SFabien Sanglard static_cast<uint8_t>(h6), 100*3f982cf4SFabien Sanglard static_cast<uint8_t>(h7 >> 8), 101*3f982cf4SFabien Sanglard static_cast<uint8_t>(h7), 102*3f982cf4SFabien Sanglard }} {} 103*3f982cf4SFabien Sanglard 104*3f982cf4SFabien Sanglard constexpr IPAddress(const IPAddress& o) noexcept = default; 105*3f982cf4SFabien Sanglard constexpr IPAddress(IPAddress&& o) noexcept = default; 106*3f982cf4SFabien Sanglard ~IPAddress() = default; 107*3f982cf4SFabien Sanglard 108*3f982cf4SFabien Sanglard constexpr IPAddress& operator=(const IPAddress& o) noexcept = default; 109*3f982cf4SFabien Sanglard constexpr IPAddress& operator=(IPAddress&& o) noexcept = default; 110*3f982cf4SFabien Sanglard 111*3f982cf4SFabien Sanglard bool operator==(const IPAddress& o) const; 112*3f982cf4SFabien Sanglard bool operator!=(const IPAddress& o) const; 113*3f982cf4SFabien Sanglard 114*3f982cf4SFabien Sanglard // IP address comparison rules are based on the following two principles: 115*3f982cf4SFabien Sanglard // 1. newer versions are greater, e.g. IPv6 > IPv4 116*3f982cf4SFabien Sanglard // 2. higher numerical values are greater, e.g. 192.168.0.1 > 10.0.0.1 117*3f982cf4SFabien Sanglard bool operator<(const IPAddress& other) const; 118*3f982cf4SFabien Sanglard bool operator>(const IPAddress& other) const { return other < *this; } 119*3f982cf4SFabien Sanglard bool operator<=(const IPAddress& other) const { return !(other < *this); } 120*3f982cf4SFabien Sanglard bool operator>=(const IPAddress& other) const { return !(*this < other); } 121*3f982cf4SFabien Sanglard explicit operator bool() const; 122*3f982cf4SFabien Sanglard version()123*3f982cf4SFabien Sanglard Version version() const { return version_; } IsV4()124*3f982cf4SFabien Sanglard bool IsV4() const { return version_ == Version::kV4; } IsV6()125*3f982cf4SFabien Sanglard bool IsV6() const { return version_ == Version::kV6; } 126*3f982cf4SFabien Sanglard 127*3f982cf4SFabien Sanglard // These methods assume |x| is the appropriate size, but due to various 128*3f982cf4SFabien Sanglard // callers' casting needs we can't check them like the constructors above. 129*3f982cf4SFabien Sanglard // Callers should instead make any necessary checks themselves. 130*3f982cf4SFabien Sanglard void CopyToV4(uint8_t* x) const; 131*3f982cf4SFabien Sanglard void CopyToV6(uint8_t* x) const; 132*3f982cf4SFabien Sanglard 133*3f982cf4SFabien Sanglard // In some instances, we want direct access to the underlying byte storage, 134*3f982cf4SFabien Sanglard // in order to avoid making multiple copies. bytes()135*3f982cf4SFabien Sanglard const uint8_t* bytes() const { return bytes_.data(); } 136*3f982cf4SFabien Sanglard 137*3f982cf4SFabien Sanglard // Parses a text representation of an IPv4 address (e.g. "192.168.0.1") or an 138*3f982cf4SFabien Sanglard // IPv6 address (e.g. "abcd::1234"). 139*3f982cf4SFabien Sanglard static ErrorOr<IPAddress> Parse(const std::string& s); 140*3f982cf4SFabien Sanglard 141*3f982cf4SFabien Sanglard private: 142*3f982cf4SFabien Sanglard Version version_; 143*3f982cf4SFabien Sanglard std::array<uint8_t, 16> bytes_; 144*3f982cf4SFabien Sanglard }; 145*3f982cf4SFabien Sanglard 146*3f982cf4SFabien Sanglard struct IPEndpoint { 147*3f982cf4SFabien Sanglard public: 148*3f982cf4SFabien Sanglard IPAddress address; 149*3f982cf4SFabien Sanglard uint16_t port = 0; 150*3f982cf4SFabien Sanglard 151*3f982cf4SFabien Sanglard // Used with various socket types to indicate "any" address. 152*3f982cf4SFabien Sanglard static const IPEndpoint kAnyV4(); 153*3f982cf4SFabien Sanglard static const IPEndpoint kAnyV6(); 154*3f982cf4SFabien Sanglard explicit operator bool() const; 155*3f982cf4SFabien Sanglard 156*3f982cf4SFabien Sanglard // Parses a text representation of an IPv4/IPv6 address and port (e.g. 157*3f982cf4SFabien Sanglard // "192.168.0.1:8080" or "[abcd::1234]:8080"). 158*3f982cf4SFabien Sanglard static ErrorOr<IPEndpoint> Parse(const std::string& s); 159*3f982cf4SFabien Sanglard 160*3f982cf4SFabien Sanglard std::string ToString() const; 161*3f982cf4SFabien Sanglard }; 162*3f982cf4SFabien Sanglard 163*3f982cf4SFabien Sanglard bool operator==(const IPEndpoint& a, const IPEndpoint& b); 164*3f982cf4SFabien Sanglard bool operator!=(const IPEndpoint& a, const IPEndpoint& b); 165*3f982cf4SFabien Sanglard 166*3f982cf4SFabien Sanglard bool operator<(const IPEndpoint& a, const IPEndpoint& b); 167*3f982cf4SFabien Sanglard inline bool operator>(const IPEndpoint& a, const IPEndpoint& b) { 168*3f982cf4SFabien Sanglard return b < a; 169*3f982cf4SFabien Sanglard } 170*3f982cf4SFabien Sanglard inline bool operator<=(const IPEndpoint& a, const IPEndpoint& b) { 171*3f982cf4SFabien Sanglard return !(a > b); 172*3f982cf4SFabien Sanglard } 173*3f982cf4SFabien Sanglard inline bool operator>=(const IPEndpoint& a, const IPEndpoint& b) { 174*3f982cf4SFabien Sanglard return !(a < b); 175*3f982cf4SFabien Sanglard } 176*3f982cf4SFabien Sanglard 177*3f982cf4SFabien Sanglard // Outputs a string of the form: 178*3f982cf4SFabien Sanglard // 123.234.34.56 179*3f982cf4SFabien Sanglard // or fe80:0000:0000:0000:1234:5678:9abc:def0 180*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& out, const IPAddress& address); 181*3f982cf4SFabien Sanglard 182*3f982cf4SFabien Sanglard // Outputs a string of the form: 183*3f982cf4SFabien Sanglard // 123.234.34.56:443 184*3f982cf4SFabien Sanglard // or [fe80:0000:0000:0000:1234:5678:9abc:def0]:8080 185*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& out, const IPEndpoint& endpoint); 186*3f982cf4SFabien Sanglard 187*3f982cf4SFabien Sanglard } // namespace openscreen 188*3f982cf4SFabien Sanglard 189*3f982cf4SFabien Sanglard #endif // PLATFORM_BASE_IP_ADDRESS_H_ 190