diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/socket/netdb.c b/libc-bottom-half/cloudlibc/src/libc/sys/socket/netdb.c index a25c6d891..5e9ada012 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/socket/netdb.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/socket/netdb.c @@ -1,19 +1,150 @@ #ifdef __wasilibc_use_preview2 #include +#include #include +#include "__utils.h" _Thread_local int h_errno = 0; +static int map_error(ip_name_lookup_error_code_t error) +{ + switch (error) { + case NETWORK_ERROR_CODE_OUT_OF_MEMORY: + return EAI_MEMORY; + case NETWORK_ERROR_CODE_NAME_UNRESOLVABLE: + return EAI_NONAME; + case NETWORK_ERROR_CODE_TEMPORARY_RESOLVER_FAILURE: + return EAI_AGAIN; + case NETWORK_ERROR_CODE_PERMANENT_RESOLVER_FAILURE: + return EAI_FAIL; + + default: + errno = __wasi_sockets_utils__map_error(error); + return EAI_SYSTEM; + } +} + int getaddrinfo(const char* restrict host, const char* restrict serv, const struct addrinfo* restrict hint, struct addrinfo** restrict res) { - // TODO wasi-sockets - abort(); + *res = NULL; + imports_string_t name = { .ptr = (uint8_t*) host, .len = strlen(host) }; + ip_name_lookup_own_resolve_address_stream_t stream; + ip_name_lookup_error_code_t error; + if (ip_name_lookup_resolve_addresses(__wasi_sockets_utils__borrow_network(), &name, &stream, &error)) { + ip_name_lookup_borrow_resolve_address_stream_t stream_borrow = ip_name_lookup_borrow_resolve_address_stream(stream); + while (true) { + ip_name_lookup_option_ip_address_t address; + if (ip_name_lookup_method_resolve_address_stream_resolve_next_address(stream_borrow, &address, &error)) { + if (address.is_some) { + int family; + struct sockaddr* addr; + socklen_t addrlen; + switch (address.val.tag) { + case NETWORK_IP_ADDRESS_IPV4: { + network_ipv4_address_t ip = address.val.val.ipv4; + + family = PF_INET; + addrlen = sizeof(struct sockaddr_in); + addr = malloc(addrlen); + if (addr == NULL) { + freeaddrinfo(*res); + return EAI_MEMORY; + } + + struct sockaddr_in sockaddr = { + .sin_family = AF_INET, + .sin_port = 0, + .sin_addr = { .s_addr = ip.f0 | (ip.f1 << 8) | (ip.f2 << 16) | (ip.f3 << 24) }, + }; + memcpy(addr, &sockaddr, addrlen); + break; + } + case NETWORK_IP_ADDRESS_IPV6: { + network_ipv6_address_t ip = address.val.val.ipv6; + + family = PF_INET6; + addrlen = sizeof(struct sockaddr_in6); + addr = malloc(addrlen); + if (addr == NULL) { + freeaddrinfo(*res); + return EAI_MEMORY; + } + + struct sockaddr_in6 sockaddr = { + .sin6_family = AF_INET6, + .sin6_port = 0, + .sin6_addr = { + .s6_addr = { + ip.f0 >> 8, + ip.f0 & 0xFF, + ip.f1 >> 8, + ip.f1 & 0xFF, + ip.f2 >> 8, + ip.f2 & 0xFF, + ip.f3 >> 8, + ip.f3 & 0xFF, + ip.f4 >> 8, + ip.f4 & 0xFF, + ip.f5 >> 8, + ip.f5 & 0xFF, + ip.f6 >> 8, + ip.f6 & 0xFF, + ip.f7 >> 8, + ip.f7 & 0xFF, + } }, + .sin6_flowinfo = 0, + .sin6_scope_id = 0, + }; + memcpy(addr, &sockaddr, addrlen); + break; + } + default: /* unreachable */ + abort(); + } + + struct addrinfo* result = malloc(sizeof(struct addrinfo)); + if (result == NULL) { + freeaddrinfo(*res); + return EAI_MEMORY; + } + + *result = (struct addrinfo) { + .ai_family = family, + .ai_flags = 0, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + .ai_addrlen = addrlen, + .ai_addr = addr, + .ai_canonname = NULL, + .ai_next = *res + }; + *res = result; + } else { + return 0; + } + } else if (error == NETWORK_ERROR_CODE_WOULD_BLOCK) { + ip_name_lookup_own_pollable_t pollable = ip_name_lookup_method_resolve_address_stream_subscribe(stream_borrow); + poll_borrow_pollable_t pollable_borrow = poll_borrow_pollable(pollable); + poll_method_pollable_block(pollable_borrow); + poll_pollable_drop_own(pollable); + } else { + freeaddrinfo(*res); + return map_error(error); + } + } + } else { + return map_error(error); + } } void freeaddrinfo(struct addrinfo* p) { - // TODO - abort(); + while (p) { + struct addrinfo* next = p->ai_next; + free(p->ai_addr); + free(p); + p = next; + } } int getnameinfo(const struct sockaddr* restrict sa, socklen_t salen, char* restrict host, socklen_t hostlen, char* restrict serv, socklen_t servlen, int flags)