Network Endpoints#

Join provides endpoint classes that encapsulate network addresses. Endpoints combine an address with protocol-specific information (port, device, PID, etc.).

Endpoint features:

  • protocol-aware — each protocol has its endpoint type
  • type-safe — compile-time endpoint validation
  • URL parsing — automatic hostname resolution
  • comparison — sortable for use in maps/sets

Endpoint types#

Internet endpoints#

IP address + port:

Tcp::Endpoint tcpEndpoint("192.168.1.1", 8080);
Udp::Endpoint udpEndpoint("2001:db8::1", 53);

Unix endpoints#

Filesystem path:

UnixStream::Endpoint unixEndpoint("/tmp/socket");
UnixDgram::Endpoint dgramEndpoint("/var/run/app.sock");

Process ID + multicast groups:

Netlink::Endpoint nlEndpoint(getpid(), RTMGRP_LINK);

Network interface:

Raw::Endpoint rawEndpoint("eth0");

Creating internet endpoints#

From IP and port#

IpAddress ip("10.0.0.1");
Tcp::Endpoint endpoint1(ip, 8080);

// Or directly
Tcp::Endpoint endpoint2("10.0.0.1", 8080);

From protocol and port#

// Wildcard address for listening
Tcp::Endpoint listen(Tcp::v6(), 8080);  // [::]:8080

Internet endpoint properties#

Tcp::Endpoint endpoint("192.168.1.100", 8080);

// IP address
IpAddress ip = endpoint.ip();
endpoint.ip(IpAddress("10.0.0.1"));

// Port
uint16_t port = endpoint.port();
endpoint.port(9090);

// Hostname (if created from URL)
std::string host = endpoint.hostname();
endpoint.hostname("example.com");

// Protocol
Tcp protocol = endpoint.protocol();  // v4() or v6()

// Device (IPv6 only, for link-local)
endpoint.device("eth0");
std::string dev = endpoint.device();

Unix endpoints#

Filesystem paths for local IPC:

UnixStream::Endpoint server("/tmp/server.sock");
UnixDgram::Endpoint client("/tmp/client.sock");

// Get/set path
std::string path = server.device();
server.device("/var/run/new.sock");

// Protocol and length
UnixStream protocol = server.protocol();
socklen_t len = server.length();

Kernel communication endpoints:

// Process ID and multicast groups
Netlink::Endpoint route(Netlink::rt(), RTMGRP_LINK | RTMGRP_IPV4_IFADDR);

// Get/set properties
uint32_t pid = route.pid();
route.pid(getpid());

uint32_t groups = route.groups();
route.groups(RTMGRP_LINK);

// Protocol
Netlink protocol = route.protocol();  // rt() or nf()

Network interface access:

Raw::Endpoint eth("eth0");

// Get/set interface
std::string iface = eth.device();
eth.device("wlan0");

// Protocol
Raw protocol = eth.protocol();
socklen_t len = eth.length();

Comparison#

Endpoints are comparable and sortable:

Tcp::Endpoint a("10.0.0.1", 80);
Tcp::Endpoint b("10.0.0.1", 443);
Tcp::Endpoint c("10.0.0.2", 80);

bool equal = (a == b);     // false (different ports)
bool less = (a < b);       // true (lower port)
bool less2 = (a < c);      // true (lower IP)

// Use in sorted containers
std::set<Tcp::Endpoint> endpoints;
std::map<Tcp::Endpoint, Connection> connections;

Stream output#

Tcp::Endpoint endpoint("192.168.1.1", 8080);
std::cout << endpoint << "\n";  // "192.168.1.1:8080"

Tcp::Endpoint ipv6("[2001:db8::1]:443");
std::cout << ipv6 << "\n";      // "[2001:db8::1]:443"

UnixStream::Endpoint unix("/tmp/socket");
std::cout << unix << "\n";      // "/tmp/socket"

Netlink::Endpoint nl(1234, RTMGRP_LINK);
std::cout << nl << "\n";        // "pid=1234,groups=1"

Usage patterns#

Server binding#

// Bind to specific address
Tcp::Endpoint specific("192.168.1.10", 8080);
acceptor.bind(specific);

// Bind to wildcard (all interfaces)
Tcp::Endpoint wildcard(Tcp::v4(), 8080);
acceptor.bind(wildcard);

Client connection#

// Connect by hostname
Tcp::Socket socket;
Tcp::Endpoint endpoint("example.com", 80);
socket.connect(endpoint);

// Connect by IP
Tcp::Endpoint direct("93.184.216.34", 80);
socket.connect(direct);

UDP sendto/recvfrom#

Udp::Socket socket;
Udp::Endpoint remote("8.8.8.8", 53);

// Send to endpoint
socket.sendTo("DNS query", remote);

// Receive from endpoint
Udp::Endpoint sender;
std::string data = socket.receiveFrom(sender);
std::cout << "From: " << sender << "\n";
// Link-local addresses require interface specification
IpAddress linkLocal("fe80::1");
Tcp::Endpoint endpoint(linkLocal, 8080);
endpoint.device("eth0");  // Specify interface

Low-level access#

Get underlying sockaddr:

Tcp::Endpoint endpoint("10.0.0.1", 8080);

// Mutable access
struct sockaddr* addr = endpoint.addr();
socklen_t len = endpoint.length();

// Const access
const struct sockaddr* caddr = endpoint.addr();

// Use with system calls
::connect(sockfd, endpoint.addr(), endpoint.length());

Best practices#

  • Use URLs — simplifies hostname resolution
  • Wildcard for servers — bind to all interfaces with Protocol(family, port)
  • Check resolved IPs — verify hostname resolution succeeded
  • Specify device — for link-local IPv6 addresses
  • Store in containers — endpoints are comparable and copyable

Summary#

Endpoint TypeAddress TypeAdditional Data
BasicUnixEndpointFilesystem path-
BasicNetlinkEndpointPID + GroupsProtocol type
BasicLinkLayerEndpointInterface-
BasicInternetEndpointIP + PortHostname, device

All endpoints provide:

  • protocol() — get associated protocol
  • length() — get sockaddr size
  • addr() — get underlying sockaddr
  • Comparison operators
  • Stream insertion