| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GARNET_LIB_INET_IP_ADDRESS_H_ |
| #define GARNET_LIB_INET_IP_ADDRESS_H_ |
| |
| #include <arpa/inet.h> |
| |
| #include "lib/fxl/logging.h" |
| |
| #include <fuchsia/net/cpp/fidl.h> |
| |
| namespace inet { |
| |
| // Represents a V4 or V6 IP address. |
| class IpAddress { |
| public: |
| static const IpAddress kInvalid; |
| static const IpAddress kV4Loopback; |
| static const IpAddress kV6Loopback; |
| |
| // Creates an IpAddress from a string containing a numeric IP address. Returns |
| // |kInvalid| if |address_string| cannot be converted into a valid IP address. |
| static IpAddress FromString(const std::string address_string, |
| sa_family_t family = AF_UNSPEC); |
| |
| // Creates an invalid IP address. |
| IpAddress(); |
| |
| // Creates an IPV4 address from four address bytes. |
| IpAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3); |
| |
| // Creates an IPV4 address from an in_addr_t. |
| explicit IpAddress(in_addr_t addr); |
| |
| // Creates an IPV4 address from an in_addr struct. |
| explicit IpAddress(const in_addr& addr); |
| |
| // Creates an IPV6 address from eight address words. |
| IpAddress(uint16_t w0, uint16_t w1, uint16_t w2, uint16_t w3, uint16_t w4, |
| uint16_t w5, uint16_t w6, uint16_t w7); |
| |
| // Creates an IPV6 address from two address words (first and last). |
| IpAddress(uint16_t w0, uint16_t w7); |
| |
| // Creates an IPV6 address from an in6_addr struct. |
| explicit IpAddress(const in6_addr& addr); |
| |
| // Creates an address from a sockaddr struct. |
| explicit IpAddress(const sockaddr* addr); |
| |
| // Creates an address from a sockaddr_storage struct. |
| explicit IpAddress(const sockaddr_storage& addr); |
| |
| // Creates an address from an IpAddress struct. |
| explicit IpAddress(const fuchsia::net::IpAddress* addr); |
| |
| bool is_valid() const { return family_ != AF_UNSPEC; } |
| |
| sa_family_t family() const { return family_; } |
| |
| bool is_v4() const { return family() == AF_INET; } |
| |
| bool is_v6() const { return family() == AF_INET6; } |
| |
| bool is_loopback() const; |
| |
| const in_addr& as_in_addr() const { |
| FXL_DCHECK(is_v4()); |
| return v4_; |
| } |
| |
| in_addr_t as_in_addr_t() const { |
| FXL_DCHECK(is_v4()); |
| return v4_.s_addr; |
| } |
| |
| const in6_addr& as_in6_addr() const { |
| FXL_DCHECK(is_v6()); |
| return v6_; |
| } |
| |
| const uint8_t* as_bytes() const { return v6_.s6_addr; } |
| |
| const uint16_t* as_words() const { return v6_.s6_addr16; } |
| |
| size_t byte_count() const { |
| return is_v4() ? sizeof(in_addr) : sizeof(in6_addr); |
| } |
| |
| size_t word_count() const { return byte_count() / sizeof(uint16_t); } |
| |
| std::string ToString() const; |
| |
| explicit operator bool() const { return is_valid(); } |
| |
| bool operator==(const IpAddress& other) const { |
| return is_v4() == other.is_v4() && |
| std::memcmp(as_bytes(), other.as_bytes(), byte_count()) == 0; |
| } |
| |
| bool operator!=(const IpAddress& other) const { return !(*this == other); } |
| |
| private: |
| sa_family_t family_; |
| union { |
| in_addr v4_; |
| in6_addr v6_; |
| }; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const IpAddress& value); |
| |
| } // namespace inet |
| |
| template <> |
| struct std::hash<inet::IpAddress> { |
| std::size_t operator()(const inet::IpAddress& address) const noexcept { |
| size_t hash = 0; |
| |
| auto byte_ptr = address.as_bytes(); |
| for (size_t i = 0; i < address.byte_count(); ++i) { |
| hash = (hash << 1) ^ *byte_ptr; |
| ++byte_ptr; |
| } |
| |
| return hash; |
| } |
| }; |
| |
| #endif // GARNET_LIB_INET_IP_ADDRESS_H_ |