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:
@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user