diff --git a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h index 0cc418648..b2260d356 100644 --- a/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h +++ b/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -94,6 +94,9 @@ typedef struct __wasi_addr_info_hints_t { * */ +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + struct addrinfo { int ai_flags; /* Input flags. */ int ai_family; /* Protocol family for socket. */ @@ -132,6 +135,14 @@ getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen); + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen); + int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); @@ -463,6 +474,62 @@ __wasi_sock_set_send_buf_size(__wasi_fd_t fd) __imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd); } +int32_t +__imported_wasi_snapshot_preview1_sock_get_recv_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_recv_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_recv_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_recv_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_recv_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_recv_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_send_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_send_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_send_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_send_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_send_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_send_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + /** * TODO: modify recv() and send() * since don't want to re-compile the wasi-libc, diff --git a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c index bcc2a3ea6..0c85368e1 100644 --- a/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c +++ b/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -469,4 +469,93 @@ freeaddrinfo(struct addrinfo *res) * of aibuf array allocated in getaddrinfo, therefore this call * frees the memory of the entire array. */ free(res); -} \ No newline at end of file +} + +struct timeval +time_us_to_timeval(uint64_t time_us) +{ + struct timeval tv; + tv.tv_sec = time_us / 1000000UL; + tv.tv_usec = time_us % 1000000UL; + return tv; +} + +uint64_t +timeval_to_time_us(struct timeval tv) +{ + return (tv.tv_sec * 1000000UL) + tv.tv_usec; +} + +int +get_sol_socket_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + + switch (optname) { + case SO_RCVTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_recv_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + case SO_SNDTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_send_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + } + + HANDLE_ERROR(__WASI_ERRNO_NOTSUP); +} + +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + switch (level) { + case SOL_SOCKET: + return get_sol_socket_option(sockfd, optname, optval, optlen); + } + + HANDLE_ERROR(__WASI_ERRNO_NOTSUP); +} + +int +set_sol_socket_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + + switch (optname) { + case SO_RCVTIMEO: + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_recv_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + case SO_SNDTIMEO: + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_send_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + } + + HANDLE_ERROR(__WASI_ERRNO_NOTSUP); +} + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen) +{ + switch (level) { + case SOL_SOCKET: + return set_sol_socket_option(sockfd, optname, optval, optlen); + } + + HANDLE_ERROR(__WASI_ERRNO_NOTSUP); +} diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 5dae3ffeb..78dee4725 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -1126,6 +1126,25 @@ wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, return __WASI_ENOSYS; } +static wasi_errno_t +wasi_sock_get_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_recv_timeout(curfds, fd, timeout_us); +} + static wasi_errno_t wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse) { @@ -1145,6 +1164,25 @@ wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, return __WASI_ENOSYS; } +static wasi_errno_t +wasi_sock_get_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_send_timeout(curfds, fd, timeout_us); +} + static wasi_errno_t wasi_sock_listen(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 backlog) { @@ -1184,6 +1222,22 @@ wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, return __WASI_ENOSYS; } +static wasi_errno_t +wasi_sock_set_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_recv_timeout(curfds, fd, timeout_us); +} + static wasi_errno_t wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse) { @@ -1203,6 +1257,22 @@ wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, return __WASI_ENOSYS; } +static wasi_errno_t +wasi_sock_set_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_send_timeout(curfds, fd, timeout_us); +} + static wasi_errno_t wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len, @@ -1427,17 +1497,21 @@ static NativeSymbol native_symbols_libc_wasi[] = { REG_NATIVE_FUNC(sock_close, "(i)i"), REG_NATIVE_FUNC(sock_connect, "(i*)i"), REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_recv_timeout, "(i*)i"), REG_NATIVE_FUNC(sock_get_reuse_addr, "(i*)i"), REG_NATIVE_FUNC(sock_get_reuse_port, "(i*)i"), REG_NATIVE_FUNC(sock_get_send_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_send_timeout, "(i*)i"), REG_NATIVE_FUNC(sock_listen, "(ii)i"), REG_NATIVE_FUNC(sock_open, "(iii*)i"), REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_recv_timeout, "(iI)i"), REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"), REG_NATIVE_FUNC(sock_set_reuse_port, "(ii)i"), REG_NATIVE_FUNC(sock_set_send_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_send_timeout, "(iI)i"), REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), REG_NATIVE_FUNC(sched_yield, "()i"), }; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 6a8b0716e..e0b3356bb 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -1088,6 +1088,38 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown( __wasi_fd_t sock ) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_sched_yield(void) WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 6910ac2f5..5a884e73c 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -3556,3 +3556,37 @@ addr_pool_destroy(struct addr_pool *addr_pool) cur = next; } } + +#ifndef WASMTIME_SSP_STATIC_CURFDS +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE struct fd_table *curfds, +#else +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#endif + +// Defines a function that passes through the socket option to the OS +// implementation +#define WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(FUNC_NAME, OPTION_TYPE) \ + __wasi_errno_t wasmtime_ssp_sock_##FUNC_NAME( \ + WASMTIME_SSP_PASSTHROUGH_FD_TABLE __wasi_fd_t sock, \ + OPTION_TYPE option) \ + { \ + struct fd_object *fo; \ + __wasi_errno_t error; \ + int ret; \ + error = fd_object_get(curfds, &fo, sock, 0, 0); \ + if (error != 0) \ + return error; \ + ret = os_socket_##FUNC_NAME(fd_number(fo), option); \ + fd_object_release(fo); \ + if (BHT_OK != ret) \ + return convert_errno(errno); \ + return __WASI_ESUCCESS; \ + } + +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_timeout, uint64 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_timeout, uint64 *) + +#undef WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#undef WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index 6ed0b9884..f1effb004 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -351,6 +351,54 @@ os_socket_convert_sockaddr(struct sockaddr *addr, uint8_t *buf, size_t buflen, return BHT_OK; } +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + if (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) { + return BHT_ERROR; + } + return BHT_OK; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + struct timeval tv; + socklen_t tv_len = sizeof(tv); + if (getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len) != 0) { + return BHT_ERROR; + } + *timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec; + return BHT_OK; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) { + return BHT_ERROR; + } + return BHT_OK; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + struct timeval tv; + socklen_t tv_len = sizeof(tv); + if (getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len) != 0) { + return BHT_ERROR; + } + *timeout_us = (tv.tv_sec * 1000000UL) + tv.tv_usec; + return BHT_OK; +} + int os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, uint16_t *port, uint8_t *is_ipv4) diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index b4e75266f..77de1b3ff 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -511,6 +511,50 @@ int os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, uint16_t *port, uint8_t *is_ipv4); +/** + * Set the send timeout until reporting an error + * + * @param socket the socket to set + * @param time_us microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us); + +/** + * Get the send timeout until reporting an error + * + * @param socket the socket to set + * @param time_us the returned microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us); + +/** + * Set the recv timeout until reporting an error + * + * @param socket the socket to set + * @param time_us microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us); + +/** + * Get the recv timeout until reporting an error + * + * @param socket the socket to set + * @param time_us the returned microseconds until timeout + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index 4f422c965..089d7c78a 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/core/shared/platform/linux-sgx/sgx_socket.c @@ -713,4 +713,36 @@ os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, return BHT_ERROR; } +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + #endif diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 67660ee93..bf031d1b8 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -209,6 +209,38 @@ os_socket_addr_local(bh_socket_t socket, uint8_t *buf, size_t buflen, return BHT_ERROR; } +int +os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + +int +os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) +{ + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_addr_remote(bh_socket_t socket, uint8_t *buf, size_t buflen, uint16_t *port, uint8_t *is_ipv4) diff --git a/samples/socket-api/CMakeLists.txt b/samples/socket-api/CMakeLists.txt index c7298b14d..7793497b1 100644 --- a/samples/socket-api/CMakeLists.txt +++ b/samples/socket-api/CMakeLists.txt @@ -90,6 +90,7 @@ ExternalProject_Add(wasm-app tcp_client.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build send_recv.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build + socket_opts.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build ) add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c) @@ -102,6 +103,8 @@ target_link_libraries(send_recv pthread) add_executable(addr_resolve ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/addr_resolve.c) +add_executable(socket_opts ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/socket_opts.c) + ############################################ ## Build iwasm with wasi and pthread support ############################################ diff --git a/samples/socket-api/README.md b/samples/socket-api/README.md index 71f62ca82..3cd5d0800 100644 --- a/samples/socket-api/README.md +++ b/samples/socket-api/README.md @@ -82,4 +82,17 @@ Data: And mourns for us ``` +`socket_opts.wasm` shows an example of getting and setting various supported socket options +```bash +$ ./iwasm ./socket_opts.wasm +``` + +The output is: +```bash +[Client] Create socket +recv_timeout is expected +send_timeout is expected +[Client] Close socket +``` + Refer to [socket api document](../../doc/socket_api.md) for more details. diff --git a/samples/socket-api/wasm-src/CMakeLists.txt b/samples/socket-api/wasm-src/CMakeLists.txt index 19aba5f0b..9dbcaa63a 100644 --- a/samples/socket-api/wasm-src/CMakeLists.txt +++ b/samples/socket-api/wasm-src/CMakeLists.txt @@ -80,3 +80,4 @@ compile_with_clang(tcp_server.c) compile_with_clang(tcp_client.c) compile_with_clang(send_recv.c) compile_with_clang(addr_resolve.c) +compile_with_clang(socket_opts.c) diff --git a/samples/socket-api/wasm-src/socket_opts.c b/samples/socket-api/wasm-src/socket_opts.c new file mode 100644 index 000000000..f33078034 --- /dev/null +++ b/samples/socket-api/wasm-src/socket_opts.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#ifdef __wasi__ +#include +#endif + +#define OPTION_ASSERT(A, B, OPTION) \ + if (A == B) { \ + printf("%s is expected\n", OPTION); \ + } \ + else { \ + printf("%s is unexpected\n", OPTION); \ + return EXIT_FAILURE; \ + } + +struct timeval +to_timeval(time_t tv_sec, suseconds_t tv_usec) +{ + struct timeval tv = { tv_sec, tv_usec }; + return tv; +} + +int +main(int argc, char *argv[]) +{ + int socket_fd = 0; + struct timeval tv; + socklen_t tv_len = sizeof(tv); + + printf("[Client] Create socket\n"); + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) { + perror("Create socket failed"); + return EXIT_FAILURE; + } + + tv = to_timeval(123, 1000); + setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + tv = to_timeval(0, 0); + getsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len); + OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec"); + OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec"); + + tv = to_timeval(456, 2000); + setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + tv = to_timeval(0, 0); + getsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len); + OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec"); + OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec"); + + printf("[Client] Close socket\n"); + close(socket_fd); + return EXIT_SUCCESS; +}