blob: 5b83d14807511935602899c3742e218956386cc8 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <functional>
#include <string>
#include <stdint.h>
namespace android {
namespace base {
// A simple structure used to encapsulate an IPv4 or IPv6 address.
// Usage is the following:
//
// 1) IPv4 addresses:
// IpAddress ip(0x7f000001); // host-order encoding.
// CHECK(ip.isIpv4());
// uint32_t address = ip.ipv4(); // read host-order 32-bit address.
//
// 2) IPv6 address:
// IpAddress ip({0,0,0,0,0,.....,0,1}); // 16-byte IPv6 address.
// CHECK(ip.isIpv6());
// const uint8_t* address = ip.ipv6Addr();
//
// 3) IPv6 address with scope id:
// IpAddress ip({....}, 1); // 16-byte address + non-0 scope-id.
// CHECK(ip.isIpv6());
// const uint8_t* address = ip.ipv6.addr;
// uint32_t scope_id = ip.ipv6ScopedId();
//
// 4) Initialize from string representation:
// IpAddress ip1("127.0.0.1");
// CHECK(ip1.isValid());
// CHECK(ip1.isIpv4());
// ASSERT_EQ(0x7f000001, ip1.ipv4());
//
// IpAddress ip2("::1");
// CHECK(ip2.isValid());
// CHECK(ip2.isIpv6());
// ASSERT_TRUE(RangesMatch(ip2.ipv6.addr, {0,0,0,....,0,1});
// ASSERT_EQ(0, ip2.ipv6ScopeId());
//
// IpAddress ip3("::2@3");
// CHECK(ip3.isValid());
// CHECK(ip3.isIpv6());
// ASSERT_TRUE(RangesMatch(ip3.ipv6Addr(), {0,0,0,....,0,2});
// ASSERT_EQ(3, ip3.ipv6ScopeId());
//
// 5) Convert to string representation:
// IpAddress ip = ...;
// std::string address = ip.toString();
//
class IpAddress {
public:
using Ipv6Address = uint8_t[16];
// Default constructor.
IpAddress() = default;
// Construct an IPv4 address instance.
// |ip| is a host-order 32-bit IP address (e.g. 0x7f000001 for 127.0.0.1).
explicit IpAddress(uint32_t ip) : mKind(Kind::Ipv4), mIpv4(ip) {}
// Construct an IPv6 address instance. |bytes| contains the address
// and |scope_id| the optional scope id, which is a system-specific
// network interface index (see if_nametoindex()).
IpAddress(const Ipv6Address bytes, uint32_t scope_id = 0);
// Construct an instance from |string| which must be either an IPv4
// dotted-decimal address, of a column-separated IPv6 address, possibly
// followed by a '%' and a scope id. Caller should later call valid()
// to ensure the input |string| was valid.
explicit IpAddress(const char* string);
// A variant of the above constructor that takes a const std::string&
// parameter instead.
explicit IpAddress(const std::string& str) : IpAddress(str.c_str()) {}
// Returns true iff this instance is valid.
bool valid() const { return mKind == Kind::Ipv4 || mKind == Kind::Ipv6; }
// Returns true iff this instance is IPv4.
bool isIpv4() const { return mKind == Kind::Ipv4; }
// Returns true iff this instance is IPv6.
bool isIpv6() const { return mKind == Kind::Ipv6; }
// Return IPv4 address as a 32-bit host-order value.
// Result is only valid iff isIpv4() is true.
uint32_t ipv4() const { return mIpv4; }
// Return the 128-bit address of an IPv6 instance.
// Result is only valid iff isIpv6() is true, and is a pointer
// to a 16-byte array of bytes.
const Ipv6Address& ipv6Addr() const { return mIpv6.mAddr; }
// Return the optional scope-id of an IPv6 instance.
// Result is only defined iff isIpv6() is true, and will be 0
// if there is no scope-id, otherwise will be the system-specific
// index of a local network interface.
uint32_t ipv6ScopeId() const { return mIpv6.mScopeId; }
// Copy and Move operations.
IpAddress(const IpAddress& other) { copyFrom(this, &other); }
IpAddress& operator=(const IpAddress& other) {
if (*this != other) {
copyFrom(this, &other);
}
return *this;
}
IpAddress(IpAddress&& other) { copyFrom(this, &other); }
IpAddress& operator=(IpAddress&& other) {
copyFrom(this, &other);
return *this;
}
// Equality comparator.
bool operator==(const IpAddress& other) const;
bool operator!=(const IpAddress& other) const { return !(*this == other); }
// Less-than operator, used for inclusion in ordered containers.
bool operator<(const IpAddress& other) const;
// Convert instance to a std::string.
std::string toString() const;
// Compute a hash for this instance.
size_t hash() const;
private:
// Type of supported IP addresses.
enum class Kind {
Invalid = -1,
Ipv4 = 4,
Ipv6 = 6,
};
static void copyFrom(IpAddress* dst, const IpAddress* src);
Kind mKind = Kind::Invalid;
union {
uint32_t mIpv4; // 32-bit IP address, host-order.
struct {
Ipv6Address mAddr; // 128-bit IPv6 address.
uint32_t
mScopeId; // 0, or system-specific network interface index.
} mIpv6;
};
};
} // namespace base
} // namespace android
// std::hash<> support for inclusion in unordered containers.
namespace std {
template <>
struct hash<android::base::IpAddress> {
typedef android::base::IpAddress argument_type;
typedef size_t result_type;
inline result_type operator()(const argument_type& a) const {
return a.hash();
}
};
} // namespace std