// Native socket address ABI smoke test. // Verifies generic IPv4/IPv6 address records and basic socket validation. #include #include #include #include // Prints one NUL-terminated string to the kernel console. static void print(const char* s) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); } // Prints one unsigned integer. static void print_u64(uint64_t v) { char buf[32]; int i = 0; if (v == 0) { print("0"); return; } while (v && i < (int)sizeof(buf)) { buf[i++] = (char)('0' + (v % 10)); v /= 10; } while (i--) { char c = buf[i]; SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) }; SysWriteConsole(&req); } } // Terminates the current process. static void exit_now(int32_t code) { while (true) SysExitProcess(code); } // Fails the test with one message. static void fail(const char* message) { print("socket_addr_smoke: "); print(message); print("\n"); exit_now(1); } // Fails the test with one status value. static void fail_status(const char* what, uint32_t status) { print("socket_addr_smoke: "); print(what); print(" status="); print_u64(status); print("\n"); exit_now(1); } // Verifies public address record shape. static void check_address_shape(void) { if (sizeof(SYS_SOCKET_ADDRESS) != SYS_SOCKET_ADDRESS_SIZE) fail("SYS_SOCKET_ADDRESS size mismatch"); } // Verifies numeric IPv4 resolution returns the generic address shape. static void check_ipv4_resolve(void) { SYS_SOCKET_ADDRESS address; size_t addressSize = sizeof(address); SYS_RESOLVE_HOST_REQUEST req; memset(&address, 0, sizeof(address)); memset(&req, 0, sizeof(req)); req.Name = SysSvFromCstr("127.0.0.1"); req.Family = SYS_AF_INET; req.AddressOut = &address; req.AddressSizeInOut = &addressSize; uint32_t status = SysResolveHost(&req); if (status != NTLSTATUS_SUCCESS) fail_status("resolve ipv4", status); if (addressSize != sizeof(address)) fail("resolve ipv4 size mismatch"); if (address.Family != SYS_AF_INET || address.Size != sizeof(address)) fail("resolve ipv4 tag mismatch"); if (address.Address[0] != 127 || address.Address[1] != 0 || address.Address[2] != 0 || address.Address[3] != 1) fail("resolve ipv4 bytes mismatch"); } // Verifies numeric IPv6 resolution returns the generic address shape. static void check_ipv6_resolve(void) { SYS_SOCKET_ADDRESS address; size_t addressSize = sizeof(address); SYS_RESOLVE_HOST_REQUEST req; memset(&address, 0, sizeof(address)); memset(&req, 0, sizeof(req)); req.Name = SysSvFromCstr("::1"); req.Family = SYS_AF_INET6; req.AddressOut = &address; req.AddressSizeInOut = &addressSize; uint32_t status = SysResolveHost(&req); if (status != NTLSTATUS_SUCCESS) fail_status("resolve ipv6", status); if (addressSize != sizeof(address)) fail("resolve ipv6 size mismatch"); if (address.Family != SYS_AF_INET6 || address.Size != sizeof(address)) fail("resolve ipv6 tag mismatch"); for (int i = 0; i < 15; i++) { if (address.Address[i] != 0) fail("resolve ipv6 prefix mismatch"); } if (address.Address[15] != 1) fail("resolve ipv6 loopback mismatch"); } // Verifies IPv4 and IPv6 sockets accept only matching generic address records. static void check_socket_address_validation(void) { uint32_t ipv4 = 0; uint32_t ipv6 = 0; uint32_t status = SysCreateSocket(SYS_AF_INET, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &ipv4); if (status != NTLSTATUS_SUCCESS) fail_status("create ipv4 udp", status); status = SysCreateSocket(SYS_AF_INET6, SYS_SOCK_DGRAM, SYS_IPPROTO_UDP, &ipv6); if (status != NTLSTATUS_SUCCESS) fail_status("create ipv6 udp", status); SYS_SOCKET_ADDRESS ipv4Address; memset(&ipv4Address, 0, sizeof(ipv4Address)); ipv4Address.Size = sizeof(ipv4Address); ipv4Address.Family = SYS_AF_INET; ipv4Address.Address[0] = 127; ipv4Address.Address[3] = 1; SYS_SOCKET_ADDRESS ipv6Address; memset(&ipv6Address, 0, sizeof(ipv6Address)); ipv6Address.Size = sizeof(ipv6Address); ipv6Address.Family = SYS_AF_INET6; ipv6Address.Address[15] = 1; SYS_SOCKET_ADDRESS badSize = ipv6Address; badSize.Size = sizeof(badSize) - 1; status = SysBindSocket(ipv6, &badSize, sizeof(badSize)); if (status != NTLSTATUS_INVALID_PARAMETER) fail_status("bind wrong struct size", status); status = SysBindSocket(ipv6, &ipv6Address, sizeof(ipv6Address) - 1); if (status != NTLSTATUS_BUFFER_TOO_SMALL) fail_status("bind short buffer size", status); status = SysBindSocket(ipv6, &ipv6Address, sizeof(ipv6Address) + 1); if (status != NTLSTATUS_INVALID_PARAMETER) fail_status("bind oversized buffer size", status); status = SysConnectSocket(ipv4, &ipv6Address, sizeof(ipv6Address)); if (status == NTLSTATUS_SUCCESS) fail("connect accepted wrong address family"); SysCloseHandle(ipv4); SysCloseHandle(ipv6); } // Runs the socket address ABI smoke test. int main(void) { print("socket_addr_smoke: start\n"); check_address_shape(); check_ipv4_resolve(); check_ipv6_resolve(); check_socket_address_validation(); print("socket_addr_smoke: PASS\n"); exit_now(0); return 0; }