SocketAddr
Description
Wraps struct sockaddr_storage. raw[0..length] carries the actual address bytes; family records the address family so callers do not have to peek into raw. The byte layout of sockaddr_in / sockaddr_in6 is identical on Linux, macOS, and Windows, so SocketAddr is platform-portable as a value.
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Socket.h:74:
u32 length;
SocketFamily family;
} SocketAddr;
///
- In
Socket.h:88:
SockFd fd;
SocketKind kind;
SocketAddr bound;
} Listener;- In
Socket.h:100:
SockFd fd;
SocketKind kind;
SocketAddr peer;
} Socket;- In
Socket.h:143:
/// TAGS: Socket, Address
///
bool socket_addr_parse_zstr(SocketAddr *out, Zstr spec, SocketKind kind);
///
- In
Socket.h:157:
/// TAGS: Socket, Parse, Address
///
bool socket_addr_parse_str(SocketAddr *out, const Str *spec, SocketKind kind);
#define SocketAddrParse(out, spec, kind) \
_Generic( \- In
Socket.h:181:
/// TAGS: Socket, Address, Format
///
Str socket_addr_format(const SocketAddr *addr, Allocator *alloc);
#define SocketAddrFormat(...) OVERLOAD(SocketAddrFormat, __VA_ARGS__)
#define SocketAddrFormat_1(addr) socket_addr_format((addr), MisraScope)- In
Socket.h:203:
/// TAGS: Socket, Listener, Bind
///
bool ListenerOpen(Listener *out, SocketKind kind, const SocketAddr *addr, i32 backlog);
///
- In
Socket.h:218:
/// TAGS: Socket, Listener, Address
///
bool ListenerLocalAddr(const Listener *self, SocketAddr *out);
///
- In
Socket.h:259:
/// TAGS: Socket, Connect
///
bool SocketConnect(Socket *out, SocketKind kind, const SocketAddr *target);
///
- In
Dns.h:53:
typedef Vec(HostsEntry) HostsTable;
typedef Vec(SocketAddr) DnsAddrs;
///
- In
Dns.h:152:
/// TAGS: Dns, Resolve, Init
///
bool dns_resolver_add_nameserver(DnsResolver *self, SocketAddr ns);
#define DnsResolverAddNameserver(self, ns) dns_resolver_add_nameserver((self), (ns))- In
Dns.h:239:
/// TAGS: Dns, Resolve, API
///
bool dns_resolve_4_one_zstr(DnsResolver *self, Zstr spec, SocketKind kind, SocketAddr *out);
bool dns_resolve_4_one_str(DnsResolver *self, const Str *spec, SocketKind kind, SocketAddr *out);- In
Dns.h:240:
///
bool dns_resolve_4_one_zstr(DnsResolver *self, Zstr spec, SocketKind kind, SocketAddr *out);
bool dns_resolve_4_one_str(DnsResolver *self, const Str *spec, SocketKind kind, SocketAddr *out);
///
- In
Dns.h:260:
char *: dns_resolve_4_vec_zstr((self), (Zstr)(spec), (kind), (DnsAddrs *)(out)) \
), \
SocketAddr *: _Generic( \
(spec), \
Str *: dns_resolve_4_one_str((self), (const Str *)(spec), (kind), (SocketAddr *)(out)), \
- In
Dns.h:262:
SocketAddr *: _Generic( \
(spec), \
Str *: dns_resolve_4_one_str((self), (const Str *)(spec), (kind), (SocketAddr *)(out)), \
Zstr: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)), \
char *: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)) \
- In
Dns.h:263:
(spec), \
Str *: dns_resolve_4_one_str((self), (const Str *)(spec), (kind), (SocketAddr *)(out)), \
Zstr: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)), \
char *: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)) \
) \
- In
Dns.h:264:
Str *: dns_resolve_4_one_str((self), (const Str *)(spec), (kind), (SocketAddr *)(out)), \
Zstr: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)), \
char *: dns_resolve_4_one_zstr((self), (Zstr)(spec), (kind), (SocketAddr *)(out)) \
) \
)- In
Dns.c:58:
// ---------------------------------------------------------------------------
static SocketAddr sockaddr_v4(const u8 ip[4], u16 port) {
SocketAddr a = {0};
struct sockaddr_in *sa = (struct sockaddr_in *)a.raw;- In
Dns.c:59:
static SocketAddr sockaddr_v4(const u8 ip[4], u16 port) {
SocketAddr a = {0};
struct sockaddr_in *sa = (struct sockaddr_in *)a.raw;
sa->sin_family = AF_INET;- In
Dns.c:69:
}
static SocketAddr sockaddr_v6(const u8 ip[16], u16 port) {
SocketAddr a = {0};
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a.raw;- In
Dns.c:70:
static SocketAddr sockaddr_v6(const u8 ip[16], u16 port) {
SocketAddr a = {0};
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a.raw;
sa->sin6_family = AF_INET6;- In
Dns.c:290:
u8 v6[16] = {0};
if (parse_ipv4(StrBegin(&ip_buf), v4)) {
SocketAddr a = sockaddr_v4(v4, 53);
VecPushBackR(out, a);
} else if (parse_ipv6(StrBegin(&ip_buf), v6)) {- In
Dns.c:293:
VecPushBackR(out, a);
} else if (parse_ipv6(StrBegin(&ip_buf), v6)) {
SocketAddr a = sockaddr_v6(v6, 53);
VecPushBackR(out, a);
}- In
Dns.c:401:
}
bool dns_resolver_add_nameserver(DnsResolver *self, SocketAddr ns) {
if (!self)
return false;- In
Dns.c:488:
// land bytes in `resp_buf[0 .. resp_cap)`. Returns the response length
// on success or -1 on failure.
static i64 udp_round_trip(const SocketAddr *ns, const u8 *query, u64 qlen, u8 *resp_buf, u64 resp_cap, u32 timeout_ms) {
Socket sock = {0};
if (!SocketConnect(&sock, SOCKET_KIND_UDP, ns)) {- In
Dns.c:513:
// response's id is checked to match before the records are extracted.
static bool
try_one_query(DnsResolver *self, const SocketAddr *ns, Zstr hostname, DnsType qtype, u16 port, DnsAddrs *out) {
// Per-call scratch: one DNS query buffer (<= 1232 B) plus the parsed
// response with its records vector. Everything is dropped at function
- In
Dns.c:550:
VecForeachPtr(&resp.answers, rec) {
if (rec->type == qtype) {
SocketAddr a = qtype == DNS_TYPE_A ? sockaddr_v4(rec->ipv4, port) : sockaddr_v6(rec->ipv6, port);
VecPushBackR(out, a);
found = true;- In
Dns.c:585:
VecForeachPtr(&self->hosts, e) {
if (StrLen(&e->name) > 0 && ZstrCompare(StrBegin(&e->name), nq) == 0) {
SocketAddr a = e->is_ipv6 ? sockaddr_v6(e->ip, port) : sockaddr_v4(e->ip, port);
VecPushBackR(out, a);
found = true;- In
Dns.c:632:
// setting up a DnsResolver still expect numeric addresses to skip
// the network.
SocketAddr direct;
if (SocketAddrParse(&direct, spec, kind)) {
VecPushBackR(out, direct);- In
Dns.c:704:
}
bool dns_resolve_4_one_zstr(DnsResolver *self, Zstr spec, SocketKind kind, SocketAddr *out) {
if (!self || !spec || !out) {
return false;- In
Dns.c:718:
}
bool dns_resolve_4_one_str(DnsResolver *self, const Str *spec, SocketKind kind, SocketAddr *out) {
if (!self || !spec || !out) {
return false;- In
Socket.c:367:
// Reading through `struct sockaddr->sa_family` lets the compiler pick
// the right field for each platform.
static void fill_socket_addr_from_sockaddr(SocketAddr *out, const struct sockaddr *sa, u32 len) {
MemSet(out, 0, sizeof(*out));
if (len > (u32)SOCKET_ADDR_MAX_SIZE) {- In
Socket.c:381:
// ---------------------------------------------------------------------------
bool socket_addr_parse_zstr(SocketAddr *out, Zstr spec, SocketKind kind) {
if (!out) {
LOG_FATAL("SocketAddrParse: out is NULL");- In
Socket.c:440:
}
bool socket_addr_parse_str(SocketAddr *out, const Str *spec, SocketKind kind) {
if (!out) {
LOG_FATAL("SocketAddrParse: out is NULL");- In
Socket.c:458:
}
Str socket_addr_format(const SocketAddr *addr, Allocator *alloc) {
Str out = StrInit(alloc);
if (!addr || addr->length == 0) {- In
Socket.c:743:
// ---------------------------------------------------------------------------
bool ListenerOpen(Listener *out, SocketKind kind, const SocketAddr *addr, i32 backlog) {
if (!out || !addr) {
LOG_FATAL("ListenerOpen: NULL argument");- In
Socket.c:800:
}
bool ListenerLocalAddr(const Listener *self, SocketAddr *out) {
if (!self || !out) {
LOG_FATAL("ListenerLocalAddr: NULL argument");- In
Socket.c:849:
// ---------------------------------------------------------------------------
bool SocketConnect(Socket *out, SocketKind kind, const SocketAddr *target) {
if (!out || !target) {
LOG_FATAL("SocketConnect: NULL argument");- In
Beam.c:345:
}
static void handle_connection(Allocator *alloc, Socket *client, const SocketAddr *upstream_addr) {
Str peer_str = SocketAddrFormat(&client->peer, alloc);- In
Beam.c:405:
}
SocketAddr listen_addr;
if (!DnsResolve(&resolver, listen_spec, SOCKET_KIND_TCP, &listen_addr)) {
LOG_ERROR("invalid --listen address: {}", listen_spec);- In
Beam.c:412:
}
SocketAddr upstream_addr;
if (!DnsResolve(&resolver, upstream_spec, SOCKET_KIND_TCP, &upstream_addr)) {
LOG_ERROR("invalid --upstream address: {}", upstream_spec);- In
SysDns.c:76:
}
static bool v4_is(const SocketAddr *ad, Allocator *a, Zstr expect) {
if (ad->family != SOCKET_FAMILY_INET) {
return false;- In
SysDns.c:86:
}
static bool v6_is(const SocketAddr *ad, Allocator *a, Zstr expect) {
if (ad->family != SOCKET_FAMILY_INET6) {
return false;- In
SysDns.c:294:
DnsResolverInit(&r, a);
SocketAddr one;
bool got = DnsResolve(&r, "127.0.0.1:80", SOCKET_KIND_TCP, &one);- In
SysDns.c:1117:
bool ok = got && VecLen(&out) == 1;
if (ok) {
const SocketAddr *ad = VecPtrAt(&out, 0);
ok = ad->family == SOCKET_FAMILY_INET && ad->length == 16u;
// Network byte order: port bytes are 0x12 then 0x34 at raw[2..4].
- In
SysDns.c:1152:
bool ok = got && VecLen(&out) == 1;
if (ok) {
const SocketAddr *ad = VecPtrAt(&out, 0);
ok = ad->family == SOCKET_FAMILY_INET6 && ad->length == 28u;
// sin6_port at raw[2..4], network order.
- In
SysDns.c:1189:
resolver_init_empty(&r, a);
SocketAddr ns;
bool parsed = SocketAddrParse(&ns, "127.0.0.1:5353", SOCKET_KIND_UDP);- In
SysDns.c:1204:
// A NULL resolver is rejected.
static bool test_ns_add_nameserver_null(void) {
SocketAddr ns = {0};
bool refused = !dns_resolver_add_nameserver(NULL, ns);
return refused;- In
SysDns.c:1917:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "single:80", SOCKET_KIND_TCP, &one);- In
SysDns.c:1934:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "multi:80", SOCKET_KIND_TCP, &one);- In
SysDns.c:1951:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "absent:80", SOCKET_KIND_TCP, &one);- In
SysDns.c:1969:
Str spec = StrInitFromZstr("multi:80", a);
SocketAddr one;
bool got = dns_resolve_4_one_str(&r, &spec, SOCKET_KIND_TCP, &one);- In
Socket.c:26:
Socket server = {0};
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:40:
// host:port string and re-parse so the test only ever talks to the
// public API.
SocketAddr local;
if (!ListenerLocalAddr(&listener, &local)) {
ListenerClose(&listener);- In
Socket.c:47:
}
Str local_str = SocketAddrFormat(&local, a);
SocketAddr connect_addr;
bool parsed = SocketAddrParse(&connect_addr, (Zstr)StrBegin(&local_str), SOCKET_KIND_TCP);
StrDeinit(&local_str);- In
Socket.c:97:
{
SocketAddr addr;
if (!SocketAddrParse(&addr, "127.0.0.1:8080", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:108:
{
SocketAddr addr;
if (!SocketAddrParse(&addr, "[::1]:8080", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:151:
Pair p = {0};
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP))
return p;- In
Socket.c:158:
return p;
SocketAddr local;
if (!ListenerLocalAddr(&p.listener, &local)) {
ListenerClose(&p.listener);- In
Socket.c:165:
Str local_str = SocketAddrFormat(&local, a);
SocketAddr connect_addr;
bool parsed = SocketAddrParse(&connect_addr, (Zstr)StrBegin(&local_str), SOCKET_KIND_TCP);
StrDeinit(&local_str);- In
Socket.c:643:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, spec, SOCKET_KIND_TCP);
if (ok) {- In
Socket.c:779:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, "1.2.3.4:80", SOCKET_KIND_TCP);
ok = ok && addr.family == SOCKET_FAMILY_INET;- In
Socket.c:799:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, "10.0.0.1:4660", SOCKET_KIND_TCP);- In
Socket.c:817:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, "[2001:db8::1]:443", SOCKET_KIND_TCP);
ok = ok && addr.family == SOCKET_FAMILY_INET6;- In
Socket.c:844:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, "[::1]:8080", SOCKET_KIND_TCP);
ok = ok && addr.family == SOCKET_FAMILY_INET6;- In
Socket.c:860:
// mutation would return true here.
bool test_sk3_parse_no_port_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "127.0.0.1", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:867:
// Port overflow ">65535" rejected.
bool test_sk3_parse_port_overflow_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "1.2.3.4:99999", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:874:
// Empty port "1.2.3.4:" rejected (parse_port empty -> false).
bool test_sk3_parse_empty_port_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "1.2.3.4:", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:881:
// Unmatched '[' bracket "[::1" rejected (split_host_port: no ']' -> false).
bool test_sk3_parse_unmatched_bracket_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "[::1", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:888:
// Empty spec "" rejected.
bool test_sk3_parse_empty_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:896:
// close[1] != ':' branch in split_host_port.
bool test_sk3_parse_bracket_missing_colon_rejected(void) {
SocketAddr addr;
bool parsed = SocketAddrParse(&addr, "[::1]8080", SOCKET_KIND_TCP);
return parsed == false;- In
Socket.c:914:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:4660", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:928:
}
SocketAddr local;
bool ok = ListenerLocalAddr(&listener, &local);
// family + length come straight from fill_socket_addr_from_sockaddr.
- In
Socket.c:950:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:962:
}
SocketAddr local;
bool ok = ListenerLocalAddr(&listener, &local);
ok = ok && local.family == SOCKET_FAMILY_INET;- In
Socket.c:990:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:1002:
}
SocketAddr local;
if (!ListenerLocalAddr(&listener, &local)) {
ListenerClose(&listener);- In
Socket.c:1009:
}
Str local_str = SocketAddrFormat(&local, a);
SocketAddr connect_addr;
bool parsed = SocketAddrParse(&connect_addr, (Zstr)StrBegin(&local_str), SOCKET_KIND_TCP);
StrDeinit(&local_str);- In
Socket.c:1040:
// Guards the af == AF_UNSPEC rejection at ListenerOpen:751.
bool test_sk3_listener_unspec_family_fails(void) {
SocketAddr bad;
MemSet(&bad, 0, sizeof(bad)); // family = SOCKET_FAMILY_UNSPEC
- In
Socket.c:1065:
// flipped success test would make the call return false.
bool test_sk3_nonblocking_set_true_returns_true(void) {
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
return false;- In
Socket.c:1097:
// failure everything opened so far is torn down and false is returned.
// ---------------------------------------------------------------------------
static bool sk4_make_pair(Allocator *a, Listener *listener, Socket *client, Socket *server, SocketAddr *local_out) {
*client = (Socket) {0};
*server = (Socket) {0};- In
Socket.c:1101:
*server = (Socket) {0};
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP))
return false;- In
Socket.c:1108:
return false;
SocketAddr local;
if (!ListenerLocalAddr(listener, &local)) {
ListenerClose(listener);- In
Socket.c:1117:
Str local_str = SocketAddrFormat(&local, a);
SocketAddr connect_addr;
bool parsed = SocketAddrParse(&connect_addr, (Zstr)StrBegin(&local_str), SOCKET_KIND_TCP);
StrDeinit(&local_str);- In
Socket.c:1255:
Socket client;
Socket server;
SocketAddr local;
if (!sk4_make_pair(a, &listener, &client, &server, &local)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:1479:
// 65535 accepted and round-trips to the exact value.
{
SocketAddr addr;
bool p = SocketAddrParse(&addr, "127.0.0.1:65535", SOCKET_KIND_TCP);
ok = ok && p;- In
Socket.c:1491:
// 0 accepted and round-trips.
{
SocketAddr addr;
bool p = SocketAddrParse(&addr, "127.0.0.1:0", SOCKET_KIND_TCP);
ok = ok && p;- In
Socket.c:1503:
// 4660 (0x1234) accepted -- non-boundary middle value, exact port.
{
SocketAddr addr;
bool p = SocketAddrParse(&addr, "1.2.3.4:4660", SOCKET_KIND_TCP);
ok = ok && p;- In
Socket.c:1515:
// Overflow / junk -> rejected.
{
SocketAddr addr;
ok = ok && !SocketAddrParse(&addr, "127.0.0.1:65536", SOCKET_KIND_TCP);
ok = ok && !SocketAddrParse(&addr, "127.0.0.1:99999", SOCKET_KIND_TCP);- In
Socket.c:1543:
StrAppendFmt(&spec, "{}", (Zstr) "1.2.3.4:4660");
SocketAddr addr;
bool p = socket_addr_parse_str(&addr, &spec, SOCKET_KIND_TCP);
ok = ok && p;- In
Socket.c:1554:
// NULL spec -> rejected, out zeroed.
SocketAddr addr2;
ok = ok && !socket_addr_parse_str(&addr2, NULL, SOCKET_KIND_TCP);- In
Socket.c:1576:
// Empty address -> empty string.
{
SocketAddr empty = {0};
Str r = SocketAddrFormat(&empty, a);
ok = ok && StrLen(&r) == 0;- In
Socket.c:1584:
// IPv6 round-trip with brackets + exact port.
{
SocketAddr addr;
bool p = SocketAddrParse(&addr, "[::1]:4660", SOCKET_KIND_TCP);
ok = ok && p;- In
Socket.c:1612:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, spec, SOCKET_KIND_TCP);
if (ok) {- In
Socket.c:1657:
Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc);- In
Socket.c:1669:
}
SocketAddr local;
bool ok = ListenerLocalAddr(&listener, &local);
ok = ok && local.family == SOCKET_FAMILY_INET;
Last updated on