From ff3887757e0a1c23334539afcef7628c37a665d7 Mon Sep 17 00:00:00 2001 From: Hritik Gupta Date: Thu, 9 Mar 2023 04:31:06 +0000 Subject: [PATCH] Add internal tests for socket apis (#1900) --- .../compilation_on_android_ubuntu.yml | 5 + .gitignore | 1 + core/iwasm/libraries/lib-socket/test/build.sh | 27 +++ .../libraries/lib-socket/test/nslookup.c | 49 +++++ .../iwasm/libraries/lib-socket/test/tcp_udp.c | 193 ++++++++++++++++++ .../wasi-test-script/run_wasi_tests.sh | 3 +- 6 files changed, 277 insertions(+), 1 deletion(-) create mode 100755 core/iwasm/libraries/lib-socket/test/build.sh create mode 100644 core/iwasm/libraries/lib-socket/test/nslookup.c create mode 100644 core/iwasm/libraries/lib-socket/test/tcp_udp.c diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 9d52cac4..0fa9acb0 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -560,6 +560,11 @@ jobs: run: WASI_SYSROOT=../../../../../core/deps/wasi-libc/sysroot bash build.sh working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/ + - name: build socket api tests + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: WASI_SYSROOT=../../../../../core/deps/wasi-libc/sysroot bash build.sh + working-directory: ./core/iwasm/libraries/lib-socket/test/ + - name: run tests timeout-minutes: 10 run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} diff --git a/.gitignore b/.gitignore index 719972ef..a4889fb7 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ core/deps/** core/shared/mem-alloc/tlsf core/app-framework/wgl core/iwasm/libraries/lib-wasi-threads/test/*.wasm +core/iwasm/libraries/lib-socket/test/*.wasm wamr-sdk/out/ wamr-sdk/runtime/build_runtime_sdk/ diff --git a/core/iwasm/libraries/lib-socket/test/build.sh b/core/iwasm/libraries/lib-socket/test/build.sh new file mode 100755 index 00000000..ec8d6608 --- /dev/null +++ b/core/iwasm/libraries/lib-socket/test/build.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set -ueo pipefail +CC="${CC:=/opt/wasi-sdk/bin/clang}" +files=("tcp_udp.c" "nslookup.c") +WASI_SYSROOT=${WASI_SYSROOT:=~/dev/wasi-libc/sysroot} + +for file in "${files[@]}" +do + echo $file + $CC \ + --target=wasm32-wasi-threads \ + -I../inc \ + --sysroot $WASI_SYSROOT \ + ../src/wasi/wasi_socket_ext.c -pthread -ftls-model=local-exec \ + -Wl,--allow-undefined \ + -Wl,--strip-all,--no-entry \ + -Wl,--export=__heap_base \ + -Wl,--export=__data_end \ + -Wl,--shared-memory,--max-memory=10485760 \ + -Wl,--export=malloc \ + -Wl,--export=free \ + -o "${file%.*}.wasm" "$file" +done \ No newline at end of file diff --git a/core/iwasm/libraries/lib-socket/test/nslookup.c b/core/iwasm/libraries/lib-socket/test/nslookup.c new file mode 100644 index 00000000..37150f1e --- /dev/null +++ b/core/iwasm/libraries/lib-socket/test/nslookup.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#ifdef __wasi__ +#include +#include +#include +#include +#else +#include +#endif + +void +test_nslookup(int af) +{ + struct addrinfo *res; + int count = 0; + struct addrinfo hints; + char *url = "google-public-dns-a.google.com"; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + int ret = getaddrinfo(url, 0, &hints, &res); + assert(ret == 0); + struct addrinfo *address = res; + while (address) { + assert(address->ai_family == af); + assert(address->ai_socktype == SOCK_STREAM); + count++; + address = address->ai_next; + } + + assert(count > 0); + freeaddrinfo(res); +} + +int +main() +{ + test_nslookup(AF_INET); /* for ipv4 */ + test_nslookup(AF_INET6); /* for ipv6 */ + + return 0; +} diff --git a/core/iwasm/libraries/lib-socket/test/tcp_udp.c b/core/iwasm/libraries/lib-socket/test/tcp_udp.c new file mode 100644 index 00000000..49231de8 --- /dev/null +++ b/core/iwasm/libraries/lib-socket/test/tcp_udp.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include +#ifdef __wasi__ +#include +#include +#include +#endif +#include +#include +#define SERVER_MSG "Message from server." +#define PORT 8989 +pthread_mutex_t mut; +pthread_cond_t cond; +int server_init_complete = 0; +char buffer[sizeof(SERVER_MSG) + 1]; + +struct socket_info { + union { + struct sockaddr_in addr_ipv4; + struct sockaddr_in6 addr_ipv6; + } addr; + int sock; +}; + +struct thread_args { + int family; + int protocol; +}; + +struct socket_info +init_socket_addr(int family, int protocol) +{ + int sock = socket(family, protocol, 0); + assert(sock != -1); + + struct socket_info info; + if (family == AF_INET) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + info.addr.addr_ipv4 = addr; + } + else if (family == AF_INET6) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(PORT); + addr.sin6_addr = in6addr_loopback; + info.addr.addr_ipv6 = addr; + } + info.sock = sock; + return info; +} + +void +assert_thread_args(struct thread_args *args) +{ + assert(args->family == AF_INET || args->family == AF_INET6); + assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM); +} + +void * +server(void *arg) +{ + server_init_complete = 0; + struct thread_args *args = (struct thread_args *)arg; + assert_thread_args(args); + + struct socket_info init_server_sock = + init_socket_addr(args->family, args->protocol); + + int server_sock = init_server_sock.sock; + socklen_t addr_size; + struct sockaddr_storage client_addr; + strcpy(buffer, SERVER_MSG); + + struct sockaddr *server_addr = (struct sockaddr *)&init_server_sock.addr; + int ret = bind(server_sock, server_addr, + args->family == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6)); + assert(ret == 0); + + (args->protocol == SOCK_STREAM) && listen(server_sock, 1); + pthread_mutex_lock(&mut); + server_init_complete = 1; + pthread_mutex_unlock(&mut); + pthread_cond_signal(&cond); + + addr_size = sizeof(client_addr); + if (args->protocol == SOCK_STREAM) { + int client_sock = + accept(server_sock, (struct sockaddr *)&client_addr, &addr_size); + assert(client_sock >= 0); + sendto(client_sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&client_addr, addr_size); + + assert(close(client_sock) == 0); + } + else { + recvfrom(server_sock, buffer, sizeof(buffer), 0, + (struct sockaddr *)&client_addr, &addr_size); + sendto(server_sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&client_addr, addr_size); + + assert(close(server_sock) == 0); + } + + return NULL; +} + +void * +client(void *arg) +{ + struct thread_args *args = (struct thread_args *)arg; + assert_thread_args(args); + + pthread_mutex_lock(&mut); + + while (server_init_complete == 0) { + pthread_cond_wait(&cond, &mut); + } + + struct socket_info init_client_sock = + init_socket_addr(args->family, args->protocol); + int sock = init_client_sock.sock; + pthread_mutex_unlock(&mut); + + if (args->family == AF_INET) { + struct sockaddr_in addr = init_client_sock.addr.addr_ipv4; + if (args->protocol == SOCK_STREAM) { + assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); + } + else { + assert(sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)) + != -1); + } + } + else { + struct sockaddr_in6 addr = init_client_sock.addr.addr_ipv6; + if (args->protocol == SOCK_STREAM) { + assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); + } + else { + assert(sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)) + != -1); + } + } + + recv(sock, buffer, sizeof(buffer), 0); + assert(strcmp(buffer, SERVER_MSG) == 0); + assert(close(sock) == 0); + return NULL; +} + +void +test_protocol(int family, int protocol) +{ + pthread_t server_thread, client_thread; + assert(pthread_cond_init(&cond, NULL) == 0); + assert(pthread_mutex_init(&mut, NULL) == 0); + + struct thread_args args = { family, protocol }; + assert(pthread_create(&server_thread, NULL, server, (void *)&args) == 0); + assert(pthread_create(&client_thread, NULL, client, (void *)&args) == 0); + assert(pthread_join(server_thread, NULL) == 0); + assert(pthread_join(client_thread, NULL) == 0); + + assert(pthread_mutex_destroy(&mut) == 0); + assert(pthread_cond_destroy(&cond) == 0); +} + +int +main(int argc, char **argv) +{ + /* test tcp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_STREAM); + test_protocol(AF_INET6, SOCK_STREAM); + + /* test udp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_DGRAM); + test_protocol(AF_INET6, SOCK_DGRAM); + + return 0; +} \ No newline at end of file diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index 17c28243..30d32d5f 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -23,7 +23,8 @@ if [[ $MODE != "aot" ]];then tests/c/testsuite/ \ tests/assemblyscript/testsuite/ \ tests/proposals/wasi-threads/ \ - ${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/test/ + ${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/test/ \ + ${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/ \ exit_code=${PIPESTATUS[0]} deactivate else