Implement getaddrinfo in wasi_socket_ext.c (#1413)

So getaddrinfo() can be used when compiling wasm app of C programs.
This commit is contained in:
Marcin Kolny
2022-09-02 15:11:58 +02:00
committed by GitHub
parent 9a04c21075
commit 3c4e980c9c
6 changed files with 246 additions and 2 deletions

View File

@ -317,3 +317,156 @@ getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
return __WASI_ERRNO_SUCCESS;
}
struct aibuf {
struct addrinfo ai;
union sa {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} sa;
};
static __wasi_errno_t
addrinfo_hints_to_wasi_hints(const struct addrinfo *hints,
__wasi_addr_info_hints_t *wasi_hints)
{
if (hints) {
wasi_hints->hints_enabled = 1;
switch (hints->ai_family) {
case AF_INET:
wasi_hints->family = INET4;
break;
case AF_INET6:
wasi_hints->family = INET6;
break;
default:
return __WASI_ERRNO_AFNOSUPPORT;
}
switch (hints->ai_socktype) {
case SOCK_STREAM:
wasi_hints->type = SOCKET_STREAM;
break;
case SOCK_DGRAM:
wasi_hints->type = SOCKET_DGRAM;
break;
default:
return __WASI_ERRNO_NOTSUP;
}
if (hints->ai_protocol != 0) {
return __WASI_ERRNO_NOTSUP;
}
if (hints->ai_flags != 0) {
return __WASI_ERRNO_NOTSUP;
}
}
else {
wasi_hints->hints_enabled = 0;
}
return __WASI_ERRNO_SUCCESS;
}
static __wasi_errno_t
wasi_addr_info_to_addr_info(const __wasi_addr_info_t *addr_info,
struct addrinfo *ai)
{
ai->ai_socktype =
addr_info->type == SOCKET_DGRAM ? SOCK_DGRAM : SOCK_STREAM;
ai->ai_protocol = 0;
ai->ai_canonname = NULL;
if (addr_info->addr.kind == IPv4) {
ai->ai_family = AF_INET;
ai->ai_addrlen = sizeof(struct sockaddr_in);
}
else {
ai->ai_family = AF_INET6;
ai->ai_addrlen = sizeof(struct sockaddr_in6);
}
return wasi_addr_to_sockaddr(&addr_info->addr, ai->ai_addr,
&ai->ai_addrlen); // TODO err handling
}
int
getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
struct addrinfo **res)
{
__wasi_addr_info_hints_t wasi_hints;
__wasi_addr_info_t *addr_info = NULL;
__wasi_size_t addr_info_size, i;
__wasi_size_t max_info_size = 16;
__wasi_errno_t error;
struct aibuf *aibuf_res;
error = addrinfo_hints_to_wasi_hints(hints, &wasi_hints);
HANDLE_ERROR(error)
do {
if (addr_info)
free(addr_info);
addr_info_size = max_info_size;
addr_info = (__wasi_addr_info_t *)malloc(addr_info_size
* sizeof(__wasi_addr_info_t));
if (!addr_info) {
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
}
error = __wasi_sock_addr_resolve(node, service == NULL ? "" : service,
&wasi_hints, addr_info, addr_info_size,
&max_info_size);
if (error != __WASI_ERRNO_SUCCESS) {
free(addr_info);
HANDLE_ERROR(error);
}
} while (max_info_size > addr_info_size);
if (addr_info_size == 0) {
free(addr_info);
*res = NULL;
return __WASI_ERRNO_SUCCESS;
}
aibuf_res = calloc(1, addr_info_size * sizeof(struct aibuf));
if (!aibuf_res) {
free(addr_info);
HANDLE_ERROR(__WASI_ERRNO_NOMEM)
}
*res = &aibuf_res[0].ai;
if (addr_info_size) {
addr_info_size = max_info_size;
}
for (i = 0; i < addr_info_size; i++) {
struct addrinfo *ai = &aibuf_res[i].ai;
ai->ai_addr = (struct sockaddr *)&aibuf_res[i].sa;
error = wasi_addr_info_to_addr_info(&addr_info[i], ai);
if (error != __WASI_ERRNO_SUCCESS) {
free(addr_info);
free(aibuf_res);
HANDLE_ERROR(error)
}
ai->ai_next = i == addr_info_size - 1 ? NULL : &aibuf_res[i + 1].ai;
}
free(addr_info);
return __WASI_ERRNO_SUCCESS;
}
void
freeaddrinfo(struct addrinfo *res)
{
/* res is a pointer to a first field in the first element
* of aibuf array allocated in getaddrinfo, therefore this call
* frees the memory of the entire array. */
free(res);
}