Implementation:ClickHouse ClickHouse Poco SocketAddress Impl
base/poco/Net/src/SocketAddress.cpp:1-429
ClickHouse_ClickHouse
ClickHouse_ClickHouse_Network_Address_Representation
| Source File | base/poco/Net/src/SocketAddress.cpp |
|---|---|
| Lines of Code | 429 |
| Principle | Principle:ClickHouse_ClickHouse_Network_Address_Representation |
| Domain | Networking, Sockets |
| Language | C++ |
| Last Updated | 2026-02-08 00:00 GMT |
Purpose
Implements the `SocketAddress` class, which represents a network endpoint as a combination of IP address and port number. Provides extensive construction from various input forms (host+port, host:port strings, IPv6 bracket notation, Unix domain paths, raw `sockaddr` structs) and supports DNS resolution, service name resolution, IPv4/IPv6/Unix address families, and binary serialization.
Code Reference
Constructors
SocketAddress::SocketAddress() { newIPv4(); }
SocketAddress::SocketAddress(Family fam) { init(IPAddress(fam), 0); }
SocketAddress::SocketAddress(const IPAddress& host, Poco::UInt16 port) { init(host, port); }
SocketAddress::SocketAddress(Poco::UInt16 port) { init(IPAddress(), port); }
SocketAddress::SocketAddress(const std::string& host, Poco::UInt16 port) { init(host, port); }
SocketAddress::SocketAddress(const std::string& hostAndPort) { init(hostAndPort); }
// From raw sockaddr (dispatches by sa_family)
SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length)
{
if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET)
newIPv4(reinterpret_cast<const struct sockaddr_in*>(sockAddr));
#if defined(POCO_HAVE_IPv6)
else if (length == sizeof(struct sockaddr_in6) && sockAddr->sa_family == AF_INET6)
newIPv6(reinterpret_cast<const struct sockaddr_in6*>(sockAddr));
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX)
newLocal(reinterpret_cast<const sockaddr_un*>(sockAddr));
#endif
else throw Poco::InvalidArgumentException("Invalid address length or family");
}
String Parsing (host:port)
void SocketAddress::init(const std::string& hostAndPort)
{
std::string host;
std::string port;
auto it = hostAndPort.begin();
auto end = hostAndPort.end();
#if defined(POCO_OS_FAMILY_UNIX)
if (*it == '/') { newLocal(hostAndPort); return; }
#endif
if (*it == '[')
{
++it;
while (it != end && *it != ']') host += *it++;
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
++it;
}
else
{
while (it != end && *it != ':') host += *it++;
}
if (it != end && *it == ':')
{
++it;
while (it != end) port += *it++;
}
else throw InvalidArgumentException("Missing port number");
init(host, resolveService(port));
}
DNS Resolution in init
void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber)
{
IPAddress ip;
if (IPAddress::tryParse(hostAddress, ip))
{
init(ip, portNumber);
}
else
{
HostEntry he = DNS::hostByName(hostAddress);
HostEntry::AddressList addresses = he.addresses();
if (addresses.size() > 0)
{
#if defined(POCO_HAVE_IPv6) && defined(POCO_SOCKETADDRESS_PREFER_IPv4)
std::stable_sort(addresses.begin(), addresses.end(), AFLT());
#endif
init(addresses[0], portNumber);
}
else throw HostNotFoundException("No address found for host", hostAddress);
}
}
Service Name Resolution
Poco::UInt16 SocketAddress::resolveService(const std::string& service)
{
unsigned port;
if (NumberParser::tryParseUnsigned(service, port) && port <= 0xFFFF)
return (UInt16) port;
else
{
struct servent* se = getservbyname(service.c_str(), NULL);
if (se) return ntohs(se->s_port);
else throw ServiceNotFoundException(service);
}
}
Binary Serialization
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const SocketAddress& value)
{
writer << value.host();
writer << value.port();
return writer;
}
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, SocketAddress& value)
{
Poco::Net::IPAddress host;
reader >> host;
Poco::UInt16 port;
reader >> port;
value = Poco::Net::SocketAddress(host, port);
return reader;
}
I/O Contract
| Input | Output | Side Effects |
|---|---|---|
| `SocketAddress("host:port")` string | Constructed SocketAddress | DNS lookup if host is not a numeric IP; `getservbyname` if port is a service name |
| `SocketAddress("[::1]:8080")` IPv6 bracket notation | Constructed SocketAddress with IPv6 | Parses bracket-enclosed IPv6 address |
| `SocketAddress("/var/run/sock")` Unix path (starts with `/`) | Constructed local SocketAddress | Creates `LocalSocketAddressImpl` (Unix only) |
| `SocketAddress(sockaddr*, len)` raw struct | Constructed SocketAddress | Dispatches to IPv4/IPv6/Unix based on `sa_family` and length |
| `host()`, `port()`, `af()`, `family()`, `toString()` | Respective values | Delegates to the internal `SocketAddressImpl` pimpl |
| `operator<` | Boolean comparison | Compares by family, then host, then port; used for ordered containers |
| `operator<<(BinaryWriter)` / `operator>>(BinaryReader)` | Serialized/deserialized SocketAddress | Writes/reads host and port in binary format |
Usage Examples
// From string with DNS resolution
SocketAddress addr1("www.example.com:80");
// From explicit IP and port
SocketAddress addr2(IPAddress("192.168.1.1"), 8123);
// IPv6 bracket notation
SocketAddress addr3("[::1]:9000");
// From port number only (binds to all interfaces)
SocketAddress addr4(8080);
// Service name resolution
SocketAddress addr5("localhost", "http"); // resolves "http" to port 80
// Unix domain socket (Linux/macOS)
SocketAddress addr6("/var/run/clickhouse.sock");
// Binary serialization
Poco::BinaryWriter writer(stream);
writer << addr1;
// Comparison (for use in std::map etc.)
if (addr1 < addr2) { /* ... */ }
// String representation
std::cout << addr1.toString(); // "93.184.216.34:80"
Internal Details
Address Family Dispatch
`SocketAddress` uses a pimpl pattern with family-specific implementations:
- `IPv4SocketAddressImpl` wrapping `sockaddr_in`
- `IPv6SocketAddressImpl` wrapping `sockaddr_in6` (when `POCO_HAVE_IPv6` is defined)
- `LocalSocketAddressImpl` wrapping `sockaddr_un` (when `POCO_OS_FAMILY_UNIX` is defined)
The appropriate implementation is selected in `init` based on the `IPAddress` family, or in constructors accepting raw `sockaddr` based on `sa_family`.
IPv4 Preference
When `POCO_SOCKETADDRESS_PREFER_IPv4` is defined and both IPv4 and IPv6 addresses are returned from DNS, the address list is stable-sorted to prefer IPv4 addresses using the `AFLT` comparator functor.
Port Byte Order
The `port` accessor calls `ntohs` on the network-byte-order port stored in the underlying `sockaddr_in`/`sockaddr_in6`.