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:172:
/// 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:173:
///
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:193:
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:195:
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:196:
(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:197:
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:407:
// 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:432:
// 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:469:
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:504:
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:551:
// 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:623:
}
bool dns_resolve_4_one_zstr(DnsResolver *self, Zstr spec, SocketKind kind, SocketAddr *out) {
if (!self || !spec || !out) {
return false;- In
Dns.c:637:
}
bool dns_resolve_4_one_str(DnsResolver *self, const Str *spec, SocketKind kind, SocketAddr *out) {
if (!self || !spec || !out) {
return false;- In
Socket.c:366:
// 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:380:
// ---------------------------------------------------------------------------
bool socket_addr_parse_zstr(SocketAddr *out, Zstr spec, SocketKind kind) {
if (!out) {
LOG_FATAL("SocketAddrParse: out is NULL");- In
Socket.c:439:
}
bool socket_addr_parse_str(SocketAddr *out, const Str *spec, SocketKind kind) {
if (!out) {
LOG_FATAL("SocketAddrParse: out is NULL");- In
Socket.c:457:
}
Str socket_addr_format(const SocketAddr *addr, Allocator *alloc) {
Str out = StrInit(alloc);
if (!addr || addr->length == 0) {- In
Socket.c:742:
// ---------------------------------------------------------------------------
bool ListenerOpen(Listener *out, SocketKind kind, const SocketAddr *addr, i32 backlog) {
if (!out || !addr) {
LOG_FATAL("ListenerOpen: NULL argument");- In
Socket.c:799:
}
bool ListenerLocalAddr(const Listener *self, SocketAddr *out) {
if (!self || !out) {
LOG_FATAL("ListenerLocalAddr: NULL argument");- In
Socket.c:848:
// ---------------------------------------------------------------------------
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.Api.c:91:
// Compare a resolved IPv4 SocketAddr against expected dotted-decimal
// + port via SocketAddrFormat (exact-byte check without poking raw[]).
static bool v4_is(const SocketAddr *ad, Allocator *a, Zstr expect) {
if (ad->family != SOCKET_FAMILY_INET) {
return false;- In
SysDns.Api.c:101:
}
static bool v6_is(const SocketAddr *ad, Allocator *a, Zstr expect) {
if (ad->family != SOCKET_FAMILY_INET6) {
return false;- In
SysDns.Api.c:618:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "single:80", SOCKET_KIND_TCP, &one);- In
SysDns.Api.c:637:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "multi:80", SOCKET_KIND_TCP, &one);- In
SysDns.Api.c:655:
resolver_init_crafted(&r, a);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "absent:80", SOCKET_KIND_TCP, &one);- In
SysDns.Api.c:677:
Str spec = StrInitFromZstr("multi:80", a);
SocketAddr one;
bool got = dns_resolve_4_one_str(&r, &spec, SOCKET_KIND_TCP, &one); Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr addr;
bool ok = SocketAddrParse(&addr, spec, SOCKET_KIND_TCP);
if (ok) { Allocator *a = ALLOCATOR_OF(&alloc);
SocketAddr bind_addr;
if (!SocketAddrParse(&bind_addr, "127.0.0.1:0", SOCKET_KIND_TCP)) {
DefaultAllocatorDeinit(&alloc); }
SocketAddr local;
bool ok = ListenerLocalAddr(&listener, &local);
ok = ok && local.family == SOCKET_FAMILY_INET;- In
SysDns.c:168:
DnsResolverInit(&r, a);
SocketAddr one;
bool got = DnsResolve(&r, "127.0.0.1:80", 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
SysDns.Wire.c:34:
static bool test_sd3_sockaddr_v4_fields(void) {
const u8 ip[4] = {1, 2, 3, 4};
SocketAddr a = sockaddr_v4(ip, 0x1234);
// Wrapper-level invariants (line 64/65 -> a.length, a.family).
- In
SysDns.Wire.c:76:
static bool test_sd3_sockaddr_v4_port_swap(void) {
const u8 ip[4] = {10, 0, 0, 1};
SocketAddr a = sockaddr_v4(ip, 0xABCD);
const struct sockaddr_in *sa = (const struct sockaddr_in *)a.raw;- In
SysDns.Wire.c:95:
static bool test_sd3_sockaddr_v6_fields(void) {
const u8 ip[16] = {0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34};
SocketAddr a = sockaddr_v6(ip, 0x1234);
// Wrapper-level invariants (line 75/76).
static bool test_sd3_sockaddr_v6_port_swap(void) {
const u8 ip[16] = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
SocketAddr a = sockaddr_v6(ip, 0xABCD);
const struct sockaddr_in6 *sa = (const struct sockaddr_in6 *)a.raw;- In
SysDns.Mut.c:242:
}
static bool v4_is(const SocketAddr *ad, Allocator *a, Zstr expect) {
if (ad->family != SOCKET_FAMILY_INET) {
return false;- In
SysDns.Mut.c:271:
hosts_push_v4(&r, "pick", 9, 8, 7, 6);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "pick:443", SOCKET_KIND_TCP, &one);
bool ok = got && v4_is(&one, a, "9.8.7.6:443");- In
SysDns.Mut.c:288:
hosts_push_v4(&r, "pick", 9, 8, 7, 6);
SocketAddr one;
bool got = dns_resolve_4_one_zstr(&r, "absent:443", SOCKET_KIND_TCP, &one);
Last updated on