mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 23:15:16 +00:00
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:
parent
9a04c21075
commit
3c4e980c9c
|
@ -94,6 +94,17 @@ typedef struct __wasi_addr_info_hints_t {
|
|||
* <sys/types.h>
|
||||
*/
|
||||
|
||||
struct addrinfo {
|
||||
int ai_flags; /* Input flags. */
|
||||
int ai_family; /* Protocol family for socket. */
|
||||
int ai_socktype; /* Socket type. */
|
||||
int ai_protocol; /* Protocol for socket. */
|
||||
socklen_t ai_addrlen; /* Length of socket address. */
|
||||
struct sockaddr *ai_addr; /* Socket address for socket. */
|
||||
char *ai_canonname; /* Canonical name for service location. */
|
||||
struct addrinfo *ai_next; /* Pointer to next in list. */
|
||||
};
|
||||
|
||||
int
|
||||
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
|
@ -120,6 +131,13 @@ getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
|||
|
||||
int
|
||||
getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
int
|
||||
getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *res);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -256,14 +256,15 @@ os_socket_addr_resolve(const char *host, const char *service,
|
|||
|
||||
if (hints_enabled) {
|
||||
if (hint_is_ipv4) {
|
||||
hints.ai_family = *hint_is_ipv4 ? PF_INET : PF_INET6;
|
||||
hints.ai_family = *hint_is_ipv4 ? AF_INET : AF_INET6;
|
||||
}
|
||||
if (hint_is_tcp) {
|
||||
hints.ai_socktype = *hint_is_tcp ? SOCK_STREAM : SOCK_DGRAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = getaddrinfo(host, service, hints_enabled ? &hints : NULL, &result);
|
||||
ret = getaddrinfo(host, strlen(service) == 0 ? NULL : service,
|
||||
hints_enabled ? &hints : NULL, &result);
|
||||
if (ret != BHT_OK) {
|
||||
errno = getaddrinfo_error_to_errno(ret);
|
||||
return BHT_ERROR;
|
||||
|
|
|
@ -100,6 +100,8 @@ add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c)
|
|||
add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c)
|
||||
target_link_libraries(send_recv pthread)
|
||||
|
||||
add_executable(addr_resolve ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/addr_resolve.c)
|
||||
|
||||
############################################
|
||||
## Build iwasm with wasi and pthread support
|
||||
############################################
|
||||
|
|
|
@ -79,3 +79,4 @@ endfunction()
|
|||
compile_with_clang(tcp_server.c)
|
||||
compile_with_clang(tcp_client.c)
|
||||
compile_with_clang(send_recv.c)
|
||||
compile_with_clang(addr_resolve.c)
|
||||
|
|
69
samples/socket-api/wasm-src/addr_resolve.c
Normal file
69
samples/socket-api/wasm-src/addr_resolve.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
lookup_host(const char *host)
|
||||
{
|
||||
struct addrinfo hints, *res, *result;
|
||||
int errcode;
|
||||
char addrstr[100];
|
||||
void *ptr;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
errcode = getaddrinfo(host, NULL, &hints, &result);
|
||||
if (errcode != 0) {
|
||||
perror("getaddrinfo");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = result;
|
||||
|
||||
printf("Host: %s\n", host);
|
||||
while (res) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
|
||||
break;
|
||||
case AF_INET6:
|
||||
ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
|
||||
break;
|
||||
default:
|
||||
printf("Unsupported address family: %d\n", res->ai_family);
|
||||
continue;
|
||||
}
|
||||
inet_ntop(res->ai_family, ptr, addrstr, 100);
|
||||
printf("IPv%d address: %s (%s)\n", res->ai_family == AF_INET6 ? 6 : 4,
|
||||
addrstr, res->ai_socktype == SOCK_STREAM ? "TCP" : "UDP");
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s DOMAIN\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return lookup_host(argv[1]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user