Implementation:ClickHouse ClickHouse Poco IPAddress Impl
base/poco/Net/src/IPAddress.cpp:1-584
ClickHouse_ClickHouse
ClickHouse_ClickHouse_Network_Address_Representation
This page documents the implementation details of the `IPAddress` class. The corresponding header is already documented under the ClickHouse_ClickHouse_Network_Address_Representation principle.
Purpose
Implements the `Poco::Net::IPAddress` class, which provides a high-level representation of IPv4 and IPv6 network addresses. The implementation delegates to internal `IPv4AddressImpl` and `IPv6AddressImpl` objects (via the pImpl idiom) while offering a unified public API for address construction, parsing, comparison, bitwise operations, classification, masking, and binary serialization.
Code Reference
Construction from String
The constructor attempts to parse the string first as IPv4, then falls back to IPv6:
IPAddress::IPAddress(const std::string& addr)
{
IPv4AddressImpl empty4 = IPv4AddressImpl();
if (addr.empty() || trim(addr) == "0.0.0.0")
{
newIPv4(empty4.addr());
return;
}
IPv4AddressImpl addr4(IPv4AddressImpl::parse(addr));
if (addr4 != empty4)
{
newIPv4(addr4.addr());
return;
}
#if defined(POCO_HAVE_IPv6)
IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr));
if (addr6 != IPv6AddressImpl())
{
newIPv6(addr6.addr(), addr6.scope());
return;
}
#endif
throw InvalidAddressException(addr);
}
Bitwise Operators
Bitwise AND, OR, XOR, and complement are implemented for subnet masking and address arithmetic. Each operator delegates to the appropriate `IPv4AddressImpl` or `IPv6AddressImpl` operator:
IPAddress IPAddress::operator & (const IPAddress& other) const
{
if (family() == other.family())
{
if (family() == IPv4)
{
IPv4AddressImpl t(pImpl()->addr());
IPv4AddressImpl o(other.pImpl()->addr());
return IPAddress((t & o).addr(), sizeof(struct in_addr));
}
#if defined(POCO_HAVE_IPv6)
else if (family() == IPv6)
{
const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
const IPv6AddressImpl r = t & o;
return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
}
#endif
}
// throws on family mismatch
}
Binary Serialization
Free operators provide `BinaryWriter`/`BinaryReader` support:
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value)
{
writer << static_cast<Poco::UInt8>(value.length());
writer.writeRaw(reinterpret_cast<const char*>(value.addr()), value.length());
return writer;
}
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value)
{
char buf[Poco::Net::IPAddress::MAX_ADDRESS_LENGTH];
Poco::UInt8 length;
reader >> length;
reader.readRaw(buf, length);
value = Poco::Net::IPAddress(buf, length);
return reader;
}
I/O Contract
| Input | Output | Side Effects |
|---|---|---|
| `std::string` (address string) | `IPAddress` object (IPv4 or IPv6) | Throws `InvalidAddressException` if unparseable |
| `const void*` + `poco_socklen_t` (raw bytes) | `IPAddress` object | Throws `InvalidArgumentException` if length invalid |
| `IPAddress` + `IPAddress` via `operator &` | Masked `IPAddress` | Throws on family mismatch |
| `IPAddress` via `BinaryWriter <<` | Serialized length byte + raw address bytes | Writes to binary stream |
| `BinaryReader >>` | Deserialized `IPAddress` | Reads from binary stream |
| `std::string` via `tryParse` | `bool` success + populated `IPAddress& result` | Non-throwing parse attempt |
Usage Examples
// Parse from string
Poco::Net::IPAddress addr("192.168.1.1");
Poco::Net::IPAddress addr6("::1");
// Subnet masking
Poco::Net::IPAddress network = addr & Poco::Net::IPAddress("255.255.255.0");
// Classification
bool isLocal = addr.isLoopback();
bool isMC = addr.isMulticast();
bool isUC = addr.isUnicast();
// Try-parse pattern
Poco::Net::IPAddress result;
if (Poco::Net::IPAddress::tryParse("10.0.0.1", result))
{
// use result
}
// Prefix-based mask construction
Poco::Net::IPAddress mask(24, Poco::Net::IPAddress::IPv4); // 255.255.255.0
Internal Details
- The `IPAddress` class uses an in-place storage pattern (`newIPv4` / `newIPv6`) with `pImpl` to avoid heap allocation for the common IPv4 case.
- Comparison operators (`==`, `<`) compare raw bytes via `std::memcmp` and also check scope IDs for IPv6.
- The `mask` method applies a bitmask in-place: `addr = (addr & mask) | (set & ~mask)`.
- The `tryParse` static method returns `false` instead of throwing, suitable for input validation.
- `IPAddress::broadcast` returns 255.255.255.255 (`INADDR_NONE`).
- IPv6 support is conditional on the `POCO_HAVE_IPv6` compile-time flag.