25 addr->sin_len =
sizeof(T);
30Set_Sockaddr_Len(T *addr) {
31 Set_Sockaddr_Len_Case(addr, swoc::meta::CaseArg);
36namespace swoc {
inline namespace SWOC_VERSION_NS {
38IPAddr
const IPAddr::INVALID;
39IP4Addr
const IP4Addr::MIN{INADDR_ANY};
40IP4Addr
const IP4Addr::MAX{INADDR_BROADCAST};
41IP6Addr
const IP6Addr::MIN{0, 0};
42IP6Addr
const IP6Addr::MAX{std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max()};
54 switch (src->sa_family) {
56 n =
sizeof(sockaddr_in);
59 n =
sizeof(sockaddr_in6);
72 sa4.sin_family = AF_INET;
74 Set_Sockaddr_Len(&
sa4);
81 sa6.sin6_family = AF_INET6;
83 Set_Sockaddr_Len(&
sa6);
92 sa4.sin_family = AF_INET;
94 Set_Sockaddr_Len(&
sa4);
98 sa6.sin6_family = AF_INET6;
100 Set_Sockaddr_Len(&
sa6);
110 }
else if (addr.
is_ip6()) {
119 sa4.sin_family = AF_INET;
122 Set_Sockaddr_Len(&
sa4);
129 sa6.sin6_family = AF_INET6;
132 Set_Sockaddr_Len(&
sa6);
140 }
else if (srv.
is_ip6()) {
151 std::string_view local;
162 *addr = std::string_view{};
163 *
port = std::string_view{};
164 *rest = std::string_view{};
168 bool colon_p =
false;
179 TextView::size_type last = src.rfind(
':');
180 if (last != TextView::npos && last == src.find(
':')) {
193 if (tmp.data() == src.
data()) {
194 src.
assign(tmp.data() - 1, tmp.size() + 1);
196 *
port = std::string_view(tmp.data(), src.
data() - tmp.data());
201 return !addr->empty();
215 switch (
sa.sa_family) {
217 return sizeof(sockaddr_in);
219 return sizeof(sockaddr_in6);
221 return sizeof(sockaddr);
242 memset(
this, 0,
sizeof(*
this));
245 sa4.sin_addr.s_addr = INADDR_ANY;
246 Set_Sockaddr_Len(&
sa4);
247 }
else if (AF_INET6 ==
family) {
249 sa6.sin6_addr = in6addr_any;
250 Set_Sockaddr_Len(&
sa6);
260 zret =
sa4.sin_addr.s_addr == INADDR_ANY;
263 zret = IN6_IS_ADDR_UNSPECIFIED(&
sa6.sin6_addr);
271 memset(
this, 0,
sizeof(*
this));
274 sa4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
275 Set_Sockaddr_Len(&
sa4);
276 }
else if (AF_INET6 ==
family) {
278 sa6.sin6_addr = in6addr_loopback;
279 Set_Sockaddr_Len(&
sa6);
289 zret = ((ntohl(
sa4.sin_addr.s_addr) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET;
292 zret = IN6_IS_ADDR_LOOPBACK(&
sa6.sin6_addr);
306 src.trim_if(&isspace);
307 if (src.empty() || src.back() ==
'.' || (
'[' == *src && ((++src).empty() || src.back() !=
']'))) {
311 in_addr_t max = std::numeric_limits<in_addr_t>::max();
315 auto v =
svtou(token, &parsed);
316 if (parsed.size() != token.size()) {
325 }
else if (v <= std::numeric_limits<uint8_t>::max()) {
326 _addr += v << (--n * 8);
334 if (!src.empty() || n != 0) {
352 sin->sin_family = AF_INET;
354 Set_Sockaddr_Len(sin);
362 sin6->sin6_family = AF_INET6;
364 Set_Sockaddr_Len(sin6);
370 return *
this < that ? -1 : *
this > that ? 1 : 0;
377 _addr._store[
MSW] <<= n;
378 _addr._store[
MSW] |= (_addr._store[
LSW] >> (
WORD_WIDTH - n)) & ~(MASK << n);
379 _addr._store[
LSW] <<= n;
382 _addr._store[
MSW] = _addr._store[
LSW] << n;
383 _addr._store[
LSW] = 0;
392 _addr._store[
LSW] >>= n;
393 _addr._store[
LSW] |= (_addr._store[
MSW] & ~(MASK << n)) << (
WORD_WIDTH - n);
394 _addr._store[
MSW] >>= n;
397 _addr._store[
LSW] = _addr._store[
MSW] >> n;
398 _addr._store[
MSW] = 0;
422 auto quad = _addr._quad.
data();
424 src.trim_if(&isspace);
425 if (src &&
'[' == *src) {
427 if (src.empty() || src.back() !=
']') {
430 src.remove_suffix(1);
433 if (src.size() < 2) {
441 if (src.size() == 2) {
444 }
else if (src.size() == 3 && src[2] ==
'1') {
450 src.remove_prefix(2);
459 while (n <
static_cast<int>(
N_QUADS) && !src.empty()) {
460 TextView token{src.take_prefix_at(
':')};
462 if (empty_idx >= 0) {
468 auto x =
svtoi(token, &r, 16);
469 if (r.size() == token.size()) {
478 if (empty_idx >= 0) {
479 if (n <
static_cast<int>(
N_QUADS)) {
480 int nil_idx =
N_QUADS - (n - empty_idx);
482 for (
int k =
N_QUADS - 1; k >= empty_idx; --k) {
491 if (n ==
N_QUADS && src.empty()) {
525 _addr._ip4.copy_to(sa);
526 }
else if (this->
is_ip6()) {
527 _addr._ip6.copy_to(sa);
537 if (TextView::npos != src.prefix(5).find_first_of(
'.')) {
539 }
else if (TextView::npos != src.prefix(6).find_first_of(
':')) {
548 if (!_addr._ip4.load(src)) {
553 if (!_addr._ip6.load(src)) {
564 switch (addr->sa_family) {
566 return this->
assign(
reinterpret_cast<sockaddr_in
const *
>(addr));
568 return this->
assign(
reinterpret_cast<sockaddr_in6
const *
>(addr));
578IPAddr::operator<(self_type
const &that)
const {
580 switch (that._family) {
588 }
else if (AF_INET6 ==
_family) {
589 switch (that._family) {
593 return _addr._ip6 < that._addr._ip6;
598 return that.is_valid();
606 return _addr._ip4.cmp(that._addr.
_ip4);
612 }
else if (AF_INET6 ==
_family) {
617 return _addr._ip6.cmp(that._addr.
_ip6);
626IPAddr::operator&=(
IPMask const &mask) {
629 }
else if (
_family == AF_INET6) {
636IPAddr::operator|=(
IPMask const &mask) {
639 }
else if (
_family == AF_INET6) {
647 return (AF_INET ==
_family && _addr._ip4.is_multicast()) || (AF_INET6 ==
_family && _addr._ip6.is_multicast());
651 using sa4 = sockaddr_in
const *;
652 using sa6 = sockaddr_in6
const *;
654 if (lhs.
family() != sa->sa_family) {
657 return lhs.
family() == AF_UNSPEC ||
666 if (parsed.size() != text.size()) {
677 }
else if (addr.
is_ip6()) {
691 }
while ((q & mask) == q);
706 return self_type(cidr);
720 return self_type(cidr);
725 static constexpr auto MASK = ~IP6Addr::word_type{0};
744 TextView addr_text, port_text, rest;
748 if (!port_text.empty()) {
750 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
755 if (
addr.load(addr_text)) {
770 TextView addr_text, port_text, rest;
774 if (!port_text.empty()) {
776 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
781 if (
addr.load(addr_text)) {
796 TextView addr_text, port_text, rest;
800 if (!port_text.empty()) {
802 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
807 if (
addr.load(addr_text)) {
818 _srv._ip4.assign(addr.ip4(), port);
819 }
else if (
addr.is_ip6()) {
820 _srv._ip6.assign(addr.ip6(), port);
829 _srv._ip4.assign(&ep.
sa4);
832 _srv._ip6.assign(&ep.
sa6);
838 if (AF_INET == sa->sa_family) {
840 _srv._ip4.assign(
reinterpret_cast<sockaddr_in
const *
>(sa));
841 }
else if (AF_INET6 == sa->sa_family) {
843 _srv._ip6.assign(
reinterpret_cast<sockaddr_in6
const *
>(sa));
854 bool mask_p =
mask.load(mask_text);
859 mask_p = (m ==
mask.as_ip4());
877 bool mask_p =
mask.load(mask_text);
882 mask_p = (m ==
mask.as_ip6());
900 bool mask_p =
mask.load(mask_text);
906 mask_p = (m ==
mask.as_ip6());
917 mask_p = (m ==
mask.as_ip4());
939 if (0 == mask.
width()) {
944 if (mask.
width() < 32) {
945 in_addr_t bits = INADDR_BROADCAST << (32 - mask.
width());
955 static const string_view SEPARATORS(
"/-");
956 auto idx = text.find_first_of(SEPARATORS);
957 if (idx != text.npos) {
958 if (idx + 1 < text.size()) {
959 if (
'/' == text[idx]) {
961 if (addr.
load(text.substr(0, idx))) {
963 text.remove_prefix(idx + 1);
964 if (mask.
load(text)) {
969 }
else if (
_min.load(text.substr(0, idx)) &&
_max.load(text.substr(idx + 1))) {
973 }
else if (
_min.load(text)) {
985 if (!nets.empty() && (*nets).as_range() == *
this) {
993 this->search_wider();
1000 if (upper >=
_range.max()) {
1003 _range.assign_min(++upper);
1005 if (this->is_valid(
_mask)) {
1006 this->search_wider();
1008 this->search_narrower();
1022IP4Range::NetSource::search_wider() {
1026 if (this->is_valid(m)) {
1036IP4Range::NetSource::search_narrower() {
1037 while (!this->is_valid(_mask)) {
1048 static constexpr auto FULL_MASK{std::numeric_limits<uint64_t>::max()};
1049 auto cidr = mask.
width();
1053 }
else if (cidr < 64) {
1054 auto bits = FULL_MASK << (64 - cidr);
1055 _min._addr._store[0] = addr._addr.
_store[0] & bits;
1056 _min._addr._store[1] = 0;
1057 _max._addr._store[0] = addr._addr.
_store[0] | ~bits;
1058 _max._addr._store[1] = FULL_MASK;
1059 }
else if (cidr == 64) {
1060 _min._addr._store[0] =
_max._addr._store[0] = addr._addr.
_store[0];
1061 _min._addr._store[1] = 0;
1062 _max._addr._store[1] = FULL_MASK;
1063 }
else if (cidr <= 128) {
1066 auto bits = FULL_MASK << (128 - cidr);
1067 _min._addr._store[1] &= bits;
1068 _max._addr._store[1] |= ~bits;
1076 static const string_view SEPARATORS(
"/-");
1077 auto idx = text.find_first_of(SEPARATORS);
1078 if (idx != text.npos) {
1079 if (idx + 1 < text.size()) {
1080 if (
'/' == text[idx]) {
1082 if (addr.
load(text.substr(0, idx))) {
1084 text.remove_prefix(idx + 1);
1085 if (mask.
load(text)) {
1086 this->
assign(addr, mask);
1090 }
else if (
_min.load(text.substr(0, idx)) &&
_max.load(text.substr(idx + 1))) {
1094 }
else if (
_min.load(text)) {
1103 if (
min.is_ip4() &&
max.is_ip4()) {
1105 }
else if (
min.is_ip6() &&
max.is_ip6()) {
1112 if (
auto idx = text.find_first_of(
':'); idx != text.npos) {
1113 if (_range._ip6.load(text)) {
1117 }
else if (_range._ip4.load(text)) {
1129 return _range._ip4.min();
1131 return _range._ip6.min();
1142 return _range._ip4.max();
1144 return _range._ip6.max();
1155 return _range._ip4.empty();
1157 return _range._ip6.empty();
1168 return _range._ip4.network_mask();
1170 return _range._ip6.network_mask();
1183 return _range._ip4 == that._range.
_ip4;
1186 return _range._ip6 == that._range.
_ip6;
1194 if (!nets.empty() && (*nets).as_range() == *
this) {
1195 return nets->mask();
1202 this->search_wider();
1209 if (upper >=
_range.max()) {
1212 _range.assign_min(++upper);
1214 if (this->is_valid(
_mask)) {
1215 this->search_wider();
1217 this->search_narrower();
1224IP6Range::NetSource::search_wider() {
1225 while (_mask.width() > 0) {
1228 if (this->is_valid(m)) {
1237IP6Range::NetSource::search_narrower() {
1238 while (!this->is_valid(_mask)) {
1248 }
else if (AF_INET6 ==
_family) {
1261 }
else if (AF_INET6 ==
_family) {
static constexpr in_addr_t reorder(in_addr_t src)
in_addr_t network_order() const
in_addr_t host_order() const
static const self_type MIN
Minimum value.
static constexpr size_t SIZE
Size of IPv4 address in bytes.
static constexpr size_t WIDTH
sockaddr * copy_to(sockaddr *sa) const
in_addr_t _addr
Address in host order.
static const self_type MAX
Maximum value.
self_type & operator=(self_type const &that)=default
Self assignment.
bool load(string_view const &text)
constexpr IP4Addr()=default
Default constructor - ANY address.
self_type & clear()
Reset network to invalid state.
self_type & assign(IP4Addr const &addr, IPMask const &mask)
bool load(swoc::TextView text)
IPMask const & mask() const
IP4Addr _mask
Mask for current network.
self_type & operator++()
Move to next network.
IP4Range range_type
Import base range type.
NetSource(range_type const &range)
Construct from range.
bool load(string_view text)
< Import assign methods.
self_type & assign(IP4Addr const &addr, IPMask const &mask)
< Import super class constructors.
constexpr IP4Range()=default
Default constructor, invalid range.
IPMask network_mask() const
An IPv4 address and host_order_port, modeled on an SRV type for DNS.
constexpr IP4Addr const & addr() const
in_port_t network_order_port() const
bool load(swoc::TextView text)
constexpr IP4Srv()=default
Default constructor.
self_type & assign(IP4Addr const &addr)
static void reorder(in6_addr &dst, raw_type const &src)
int cmp(self_type const &that) const
Generic three value compare.
uint16_t quad_type
Size of one segment of an IPv6 address.
self_type & operator<<=(unsigned n)
static constexpr unsigned MSW
Most significant word index.
static const self_type MIN
Minimum value of an address.
static constexpr size_t QUAD_WIDTH
Number of bits per quad.
static constexpr quad_type QUAD_MASK
A bit mask of all 1 bits the size of a quad.
self_type & operator>>=(unsigned n)
uint64_t word_type
Type used as a "word", the natural working unit of the address.
bool load(string_view const &str)
static const self_type MAX
Maximum value of an address.
static constexpr std::array< unsigned, N_QUADS > QUAD_IDX
static constexpr unsigned LSW
Least significant word index.
static constexpr size_t N_QUADS
in6_addr network_order() const
Return the address in network order.
self_type & operator|=(self_type const &that)
sockaddr_in6 * copy_to(sockaddr_in6 *sin6) const
static constexpr size_t WIDTH
Number of bits in the address.
std::array< uint8_t, SIZE > raw_type
self_type & operator&=(self_type const &that)
IP6Addr()=default
Default constructor - ANY address.
static constexpr size_t WORD_WIDTH
Number of bits per word.
self_type & assign(IP6Addr const &addr, IPMask const &mask)
IPMask const & mask() const
self_type & clear()
Reset network to invalid state.
bool load(swoc::TextView text)
IPMask _mask
Current CIDR value.
IP6Range _range
Remaining range.
NetSource(range_type const &range)
Construct from range.
self_type & operator++()
Move to next network.
IP6Range range_type
Import base range type.
bool load(string_view text)
< Import assign methods.
IPMask network_mask() const
self_type & assign(IP6Addr const &addr, IPMask const &mask)
< Import super class constructors.
An IPv6 address and host_order_port, modeled on an SRV type for DNS.
self_type & assign(IP6Addr const &addr)
bool load(swoc::TextView text)
IP6Srv()=default
Default constructor.
in_port_t network_order_port() const
constexpr IP6Addr const & addr() const
self_type & operator=(self_type const &that)=default
Copy assignment.
bool is_valid() const
Test for validity.
bool is_ip6() const
Test for IPv6.
bool is_multicast() const
Test for multicast.
bool is_ip4() const
Test for IPv4.
IPAddr()=default
Default constructor - invalid result.
int cmp(self_type const &that) const
Generic compare.
IP6Addr const & ip6() const
sockaddr * copy_to(sockaddr *sa) const
bool load(string_view const &text)
IP4Addr const & ip4() const
sa_family_t _family
Protocol family.
self_type & assign(sockaddr const *addr)
Set to the address in addr.
sa_family_t family() const
bool load(string_view const &text)
uint8_t raw_type
Storage for mask width.
raw_type _cidr
Mask width in bits.
raw_type width() const
The width of the mask.
static self_type mask_for(IPAddr const &addr)
static raw_type mask_for_quad(IP6Addr::quad_type q)
Compute a partial IPv6 mask, sized for the basic storage type.
self_type & assign(IPAddr const &addr, IPMask const &mask)
bool load(swoc::TextView text)
IPMask const & mask() const
self_type & clear()
Reset network to invalid state.
bool operator==(IPRange const &r) const
Compare to a range.
storage_type _raw
Storage for the view pointer.
sa_family_t _family
Range address family.
bool load(std::string_view const &text)
IP4Range const & ip4() const
sa_family_t family() const
bool operator==(self_type const &that) const
Equality.
sa_family_t _family
Family of _range.
IP6Range const & ip6() const
IPRange()=default
Default constructor - construct invalid range.
IPMask network_mask() const
An IP address and host_order_port, modeled on an SRV type for DNS.
IP4Srv const & ip4() const
IP6Srv const & ip6() const
sa_family_t _family
Protocol family.
IPSrv()=default
Default constructor.
constexpr sa_family_t family() const
self_type & assign(IP4Addr const &addr)
bool load(swoc::TextView text)
self_type & clear()
Clear the view (become an empty view).
self_type & assign(char *&c_str)
self_type & ltrim_if(F const &pred)
self_type take_prefix_at(char c)
self_type split_suffix_at(char c)
self_type take_prefix(size_t n)
constexpr value_type const * data() const noexcept
For template deduction guides.
uintmax_t svtou(TextView src, TextView *out, int base)
intmax_t svtoi(TextView src, TextView *out, int base)
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
MemSpan< T > const & memset(MemSpan< T > const &dst, T const &value)
void * memcpy(void *dst, const std::string_view &src)
uintmax_t svtou(TextView src, TextView *out, int base)
quad_store_type _quad
By quad.
word_store_type _store
0 is MSW, 1 is LSW.
IP4Addr _ip4
IPv4 address (host)
IP6Addr _ip6
IPv6 address (host)
bool parse(string_view const &str)
struct sockaddr_in sa4
IPv4.
bool is_ip6() const
Test for IPv6.
static in_port_t & port(sockaddr *sa)
self_type & set_to_loopback(int family)
self_type & set_to_any(int family)
static bool tokenize(string_view src, string_view *host=nullptr, string_view *port=nullptr, string_view *rest=nullptr)
static bool assign(sockaddr *dst, sockaddr const *src)
static void invalidate(sockaddr *addr)
Invalidate a sockaddr.
sa_family_t family() const
bool is_ip4() const
Test for IPv4.
struct sockaddr sa
Generic address.
static string_view family_name(sa_family_t family)
The string name of the address family.
struct sockaddr_in6 sa6
IPv6.
IPEndpoint()
Default construct invalid instance.