Implementation:ClickHouse ClickHouse Poco NetworkInterface Impl
base/poco/Net/src/NetworkInterface.cpp:1-1362
ClickHouse_ClickHouse
ClickHouse_ClickHouse_Network_Interface_Enumeration
This page documents the implementation details of the `NetworkInterface` class. The corresponding header is already documented under the ClickHouse_ClickHouse_Network_Interface_Enumeration principle.
Purpose
Implements the `Poco::Net::NetworkInterface` class and its internal `NetworkInterfaceImpl` pImpl class, providing cross-platform enumeration and querying of network interfaces. The implementation covers interface properties (name, index, addresses, subnet masks, broadcast addresses, MAC address, MTU, type), capability flags (broadcast, multicast, loopback, point-to-point, running, up), and platform-specific enumeration for BSD, Linux, and Android systems.
Code Reference
NetworkInterfaceImpl -- Internal State
The private implementation class stores all interface state and is reference-counted via `Poco::RefCountedObject`:
class NetworkInterfaceImpl: public Poco::RefCountedObject
{
private:
std::string _name;
std::string _displayName;
std::string _adapterName;
AddressList _addressList;
unsigned _index;
bool _broadcast;
bool _loopback;
bool _multicast;
bool _pointToPoint;
bool _up;
bool _running;
unsigned _mtu;
Type _type;
NetworkInterface::MACAddress _macAddress;
};
Physical Parameter Discovery (setPhyParams)
On Unix, uses `ioctl` to read interface flags and MTU:
void NetworkInterfaceImpl::setPhyParams()
{
struct ifreq ifr;
std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
DatagramSocket ds(SocketAddress::IPv4);
ds.impl()->ioctl(SIOCGIFFLAGS, &ifr);
setFlags(ifr.ifr_flags);
ds.impl()->ioctl(SIOCGIFMTU, &ifr);
setMTU(ifr.ifr_mtu);
}
Flag Interpretation
void NetworkInterfaceImpl::setFlags(short flags)
{
_broadcast = ((flags & IFF_BROADCAST) != 0);
_loopback = ((flags & IFF_LOOPBACK) != 0);
_multicast = ((flags & IFF_MULTICAST) != 0);
_pointToPoint = ((flags & IFF_POINTOPOINT) != 0);
_running = ((flags & IFF_RUNNING) != 0);
_up = ((flags & IFF_UP) != 0);
}
Linux Interface Enumeration (map)
Uses `getifaddrs` to enumerate all interfaces. Handles `AF_PACKET` (link layer), `AF_INET`, and `AF_INET6` address families:
NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
{
FastMutex::ScopedLock lock(_mutex);
Map result;
struct ifaddrs* ifaces = 0;
if (getifaddrs(&ifaces) < 0)
throw NetException("cannot get network adapter list");
for (iface = ifaces; iface; iface = iface->ifa_next)
{
if (!iface->ifa_addr) continue;
unsigned family = iface->ifa_addr->sa_family;
switch (family)
{
case AF_PACKET:
// Extract MAC address and interface type from sockaddr_ll
break;
case AF_INET:
// Extract IPv4 address, subnet mask, broadcast/destination address
break;
case AF_INET6:
// Extract IPv6 address with scope ID
break;
}
}
freeifaddrs(ifaces);
// Optionally filter out non-IP or non-up interfaces
return result;
}
Interface Type Mapping (Linux)
static NetworkInterface::Type fromNative(unsigned arphrd)
{
switch (arphrd)
{
case ARPHRD_ETHER: return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
case ARPHRD_PPP: return NetworkInterface::NI_TYPE_PPP;
case ARPHRD_LOOPBACK: return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
case ARPHRD_IEEE80211: return NetworkInterface::NI_TYPE_IEEE80211;
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6: return NetworkInterface::NI_TYPE_TUNNEL;
// ...
default: return NetworkInterface::NI_TYPE_OTHER;
}
}
MAC Address Formatting
std::ostream& operator << (std::ostream& os, const NetworkInterface::MACAddress& mac)
{
for (unsigned i = 0; i < mac.size(); ++i)
{
if (i > 0) os << NetworkInterface::MAC_SEPARATOR;
os << std::hex << std::setw(2) << std::setfill('0') << (unsigned) mac[i];
}
return os;
}
I/O Contract
| Input | Output | Side Effects |
|---|---|---|
| `map(bool ipOnly, bool upOnly)` | `Map` (index to `NetworkInterface`) | Calls `getifaddrs`; acquires mutex; uses `ioctl` for flags/MTU |
| `list(bool ipOnly, bool upOnly)` | `List` of `NetworkInterface` (one per address) | Calls `map` internally; expands multi-address interfaces |
| `forName(std::string, IPVersion)` | `NetworkInterface` | Throws `InterfaceNotFoundException` if not found |
| `forAddress(IPAddress)` | `NetworkInterface` | Throws `InterfaceNotFoundException` if not found |
| `forIndex(unsigned)` | `NetworkInterface` | Throws `InterfaceNotFoundException` if not found |
| Interface property accessors | Name, index, addresses, MAC, MTU, type, flags | None |
Usage Examples
// Enumerate all up interfaces with IP addresses
Poco::Net::NetworkInterface::Map ifMap = Poco::Net::NetworkInterface::map(true, true);
for (auto& entry : ifMap)
{
const Poco::Net::NetworkInterface& iface = entry.second;
std::cout << iface.name() << " [" << iface.index() << "]"
<< " MTU=" << iface.mtu()
<< " MAC=" << iface.macAddress() << std::endl;
for (const auto& addrTuple : iface.addressList())
{
std::cout << " " << addrTuple.get<Poco::Net::NetworkInterface::IP_ADDRESS>().toString()
<< "/" << addrTuple.get<Poco::Net::NetworkInterface::SUBNET_MASK>().toString()
<< std::endl;
}
}
// Look up by name
Poco::Net::NetworkInterface eth0 = Poco::Net::NetworkInterface::forName("eth0");
// Look up by address
Poco::Net::NetworkInterface loopback = Poco::Net::NetworkInterface::forAddress(
Poco::Net::IPAddress("127.0.0.1"));
Internal Details
- The implementation is split into three platform-specific sections using preprocessor conditionals: BSD/QNX/Solaris, Linux/Android, and a fallback (currently unimplemented with `#error`).
- On Linux, `AF_PACKET` addresses provide the link-layer MAC address and hardware type via `struct sockaddr_ll`.
- On BSD, `AF_LINK` addresses provide equivalent information via `struct sockaddr_dl`.
- When `POCO_NO_LINUX_IF_PACKET_H` is defined, MAC addresses are read from `/sys/class/net/<name>/address` and types from `/sys/class/net/<name>/type`.
- The `list` method flattens the `map` result, creating a separate `NetworkInterface` entry for each address on multi-homed interfaces, copying all physical properties from the original entry.
- A static `FastMutex` protects the `map` method, making interface enumeration thread-safe.
- The `NetworkInterfaceImpl` is reference-counted: the `NetworkInterface` copy constructor calls `duplicate`, and the destructor calls `release`.
- Android lacks `<ifaddrs.h>`, so `map` throws `Poco::NotImplementedException` on that platform.
- The `destAddress` method is only valid for point-to-point interfaces; it throws `InvalidAccessException` otherwise.