mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 07:21:54 +00:00
Add WASI support for esp-idf platform (#3348)
Add WASI support for esp-idf platform: 1. add Kconfig and cmake scripts 2. add API "openat" when using littlefs 3. add clock/rwlock/file/socket OS adapter
This commit is contained in:
parent
0aeef69d23
commit
6aa7cb85f6
|
@ -2,56 +2,102 @@
|
|||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
# Set WAMR's build options
|
||||
if("${IDF_TARGET}" STREQUAL "esp32c3" OR "${IDF_TARGET}" STREQUAL "esp32c6")
|
||||
set(WAMR_BUILD_TARGET "RISCV32")
|
||||
else()
|
||||
set(WAMR_BUILD_TARGET "XTENSA")
|
||||
endif()
|
||||
|
||||
set(WAMR_BUILD_PLATFORM "esp-idf")
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_INTERP)
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
|
||||
set (WAMR_BUILD_FAST_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_AOT)
|
||||
set (WAMR_BUILD_AOT 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN)
|
||||
set (WAMR_BUILD_LIBC_BUILTIN 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_APP_FRAMEWORK)
|
||||
set (WAMR_BUILD_APP_FRAMEWORK 0)
|
||||
endif ()
|
||||
|
||||
if (NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
if (WAMR_BUILD_TARGET STREQUAL "XTENSA")
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "-DBUILD_TARGET_XTENSA=1" APPEND)
|
||||
endif ()
|
||||
if (WAMR_BUILD_INTERP)
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "-DWASM_ENABLE_INTERP=1" APPEND)
|
||||
endif ()
|
||||
if (WAMR_BUILD_AOT)
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "-DWASM_ENABLE_AOT=1" APPEND)
|
||||
endif ()
|
||||
|
||||
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
endif()
|
||||
if (CONFIG_IDF_TARGET_ARCH_RISCV)
|
||||
set (WAMR_BUILD_TARGET "RISCV32")
|
||||
elseif (CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
set (WAMR_BUILD_TARGET "XTENSA")
|
||||
else ()
|
||||
message (FATAL_ERROR "Arch ${CONFIG_IDF_TARGET_ARCH} is not supported")
|
||||
endif ()
|
||||
|
||||
idf_component_register(SRCS ${WAMR_RUNTIME_LIB_SOURCE} ${PLATFORM_SHARED_SOURCE}
|
||||
INCLUDE_DIRS ${IWASM_DIR}/include ${UTILS_SHARED_DIR} ${PLATFORM_SHARED_DIR} ${PLATFORM_SHARED_DIR}/../include
|
||||
REQUIRES pthread lwip esp_timer
|
||||
)
|
||||
set (WAMR_BUILD_PLATFORM "esp-idf")
|
||||
|
||||
if (CONFIG_WAMR_BUILD_DEBUG)
|
||||
set (CMAKE_BUILD_TYPE Debug)
|
||||
else ()
|
||||
set (CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_INTERP)
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_INTERP_FAST)
|
||||
set (WAMR_BUILD_FAST_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_AOT)
|
||||
set (WAMR_BUILD_AOT 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_LIBC_BUILTIN)
|
||||
set (WAMR_BUILD_LIBC_BUILTIN 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_INTERP_LOADER_MINI)
|
||||
set (WAMR_BUILD_MINI_LOADER 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_MULTI_MODULE)
|
||||
set (WAMR_BUILD_MULTI_MODULE 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_SHARED_MEMORY)
|
||||
set (WAMR_BUILD_SHARED_MEMORY 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_MEMORY_PROFILING)
|
||||
set (WAMR_BUILD_MEMORY_PROFILING 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_PERF_PROFILING)
|
||||
set (WAMR_BUILD_PERF_PROFILING 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_REF_TYPES)
|
||||
set (WAMR_BUILD_REF_TYPES 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_LIBC_WASI)
|
||||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_LIB_PTHREAD)
|
||||
set (WAMR_BUILD_LIB_PTHREAD 1)
|
||||
endif ()
|
||||
|
||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
list (APPEND srcs "${WAMR_RUNTIME_LIB_SOURCE}"
|
||||
"${PLATFORM_SHARED_SOURCE}")
|
||||
|
||||
set (include_dirs "${IWASM_DIR}/include"
|
||||
"${UTILS_SHARED_DIR}"
|
||||
"${PLATFORM_SHARED_DIR}"
|
||||
"${PLATFORM_SHARED_DIR}/../include"
|
||||
"${IWASM_COMMON_DIR}")
|
||||
endif ()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include_dirs}
|
||||
REQUIRES pthread lwip esp_timer
|
||||
KCONFIG ${CMAKE_CURRENT_LIST_DIR}/Kconfig)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
||||
if (CONFIG_IDF_TARGET_ARCH_RISCV)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DBUILD_TARGET_RISCV32_ILP32=1)
|
||||
elseif (CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DBUILD_TARGET_XTENSA=1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_AOT)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DWASM_ENABLE_AOT=1)
|
||||
endif ()
|
||||
|
||||
if (CONFIG_WAMR_ENABLE_INTERP)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DWASM_ENABLE_INTERP=1)
|
||||
endif ()
|
||||
|
|
77
build-scripts/esp-idf/wamr/Kconfig
Normal file
77
build-scripts/esp-idf/wamr/Kconfig
Normal file
|
@ -0,0 +1,77 @@
|
|||
menu "WASM Micro Runtime"
|
||||
choice WAMR_BUILD_TYPE
|
||||
prompt "Build type"
|
||||
default WAMR_BUILD_RELEASE
|
||||
|
||||
config WAMR_BUILD_RELEASE
|
||||
bool "Release"
|
||||
|
||||
config WAMR_BUILD_DEBUG
|
||||
bool "Debug"
|
||||
endchoice
|
||||
|
||||
config WAMR_ENABLE_AOT
|
||||
bool "AOT"
|
||||
default y
|
||||
|
||||
menuconfig WAMR_ENABLE_INTERP
|
||||
bool "Interpreter"
|
||||
default y
|
||||
|
||||
if WAMR_ENABLE_INTERP
|
||||
|
||||
choice WAMR_INTERP_MODE
|
||||
prompt "Interpreter mode"
|
||||
default WAMR_INTERP_FAST
|
||||
|
||||
config WAMR_INTERP_CLASSIC
|
||||
bool "Classic"
|
||||
|
||||
config WAMR_INTERP_FAST
|
||||
bool "Fast"
|
||||
endchoice
|
||||
|
||||
choice WAMR_INTERP_LOADER_MODE
|
||||
prompt "Loader mode"
|
||||
default WAMR_INTERP_LOADER_NORMAL
|
||||
|
||||
config WAMR_INTERP_LOADER_NORMAL
|
||||
bool "Normal"
|
||||
|
||||
config WAMR_INTERP_LOADER_MINI
|
||||
bool "Mini"
|
||||
endchoice
|
||||
endif
|
||||
|
||||
config WAMR_ENABLE_LIB_PTHREAD
|
||||
bool "Lib pthread"
|
||||
default y
|
||||
|
||||
config WAMR_ENABLE_LIBC_BUILTIN
|
||||
bool "Libc builtin"
|
||||
default y
|
||||
|
||||
config WAMR_ENABLE_LIBC_WASI
|
||||
bool "Libc WASI"
|
||||
default y
|
||||
|
||||
config WAMR_ENABLE_MEMORY_PROFILING
|
||||
bool "Memory profiling"
|
||||
default n
|
||||
|
||||
config WAMR_ENABLE_MULTI_MODULE
|
||||
bool "Multi module"
|
||||
default n
|
||||
|
||||
config WAMR_ENABLE_PERF_PROFILING
|
||||
bool "Performance profiling"
|
||||
default n
|
||||
|
||||
config WAMR_ENABLE_REF_TYPES
|
||||
bool "Reference types"
|
||||
default n
|
||||
|
||||
config WAMR_ENABLE_SHARED_MEMORY
|
||||
bool "Shared memory"
|
||||
default n
|
||||
endmenu
|
88
core/shared/platform/esp-idf/espidf_clock.c
Normal file
88
core/shared/platform/esp-idf/espidf_clock.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Amazon Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "libc_errno.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
#define NANOSECONDS_PER_SECOND 1000000000ULL
|
||||
|
||||
static __wasi_errno_t
|
||||
wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out)
|
||||
{
|
||||
switch (in) {
|
||||
case __WASI_CLOCK_MONOTONIC:
|
||||
*out = CLOCK_MONOTONIC;
|
||||
return __WASI_ESUCCESS;
|
||||
case __WASI_CLOCK_REALTIME:
|
||||
*out = CLOCK_REALTIME;
|
||||
return __WASI_ESUCCESS;
|
||||
case __WASI_CLOCK_PROCESS_CPUTIME_ID:
|
||||
#if defined(CLOCK_PROCESS_CPUTIME_ID)
|
||||
*out = CLOCK_PROCESS_CPUTIME_ID;
|
||||
return __WASI_ESUCCESS;
|
||||
#else
|
||||
return __WASI_ENOTSUP;
|
||||
#endif
|
||||
case __WASI_CLOCK_THREAD_CPUTIME_ID:
|
||||
#if defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
*out = CLOCK_THREAD_CPUTIME_ID;
|
||||
return __WASI_ESUCCESS;
|
||||
#else
|
||||
return __WASI_ENOTSUP;
|
||||
#endif
|
||||
default:
|
||||
return __WASI_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static __wasi_timestamp_t
|
||||
timespec_to_nanoseconds(const struct timespec *ts)
|
||||
{
|
||||
if (ts->tv_sec < 0)
|
||||
return 0;
|
||||
if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / NANOSECONDS_PER_SECOND)
|
||||
return UINT64_MAX;
|
||||
return (__wasi_timestamp_t)ts->tv_sec * NANOSECONDS_PER_SECOND
|
||||
+ (__wasi_timestamp_t)ts->tv_nsec;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution)
|
||||
{
|
||||
clockid_t nclock_id;
|
||||
__wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id);
|
||||
|
||||
if (error != __WASI_ESUCCESS)
|
||||
return error;
|
||||
|
||||
struct timespec ts;
|
||||
if (clock_getres(nclock_id, &ts) < 0)
|
||||
return convert_errno(errno);
|
||||
|
||||
*resolution = timespec_to_nanoseconds(&ts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
__wasi_errno_t
|
||||
os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision,
|
||||
__wasi_timestamp_t *time)
|
||||
{
|
||||
clockid_t nclock_id;
|
||||
__wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id);
|
||||
|
||||
(void)precision;
|
||||
|
||||
if (error != __WASI_ESUCCESS)
|
||||
return error;
|
||||
|
||||
struct timespec ts;
|
||||
if (clock_gettime(nclock_id, &ts) < 0)
|
||||
return convert_errno(errno);
|
||||
|
||||
*time = timespec_to_nanoseconds(&ts);
|
||||
|
||||
return error;
|
||||
}
|
1014
core/shared/platform/esp-idf/espidf_file.c
Normal file
1014
core/shared/platform/esp-idf/espidf_file.c
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "platform_api_vmcore.h"
|
||||
#include "platform_api_extension.h"
|
||||
|
||||
|
@ -12,6 +13,15 @@
|
|||
#define FUTIMENS_TIMESPEC_POINTER 1
|
||||
#endif
|
||||
|
||||
#if CONFIG_LITTLEFS_OPEN_DIR && CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
#define OPENAT_SUPPORT 1
|
||||
|
||||
#undef F_GETPATH
|
||||
#define F_GETPATH CONFIG_LITTLEFS_FCNTL_F_GETPATH_VALUE
|
||||
|
||||
#define DIR_PATH_LEN (CONFIG_LITTLEFS_OBJ_NAME_LEN + 1)
|
||||
#endif
|
||||
|
||||
int
|
||||
bh_platform_init()
|
||||
{
|
||||
|
@ -183,12 +193,40 @@ writev(int fildes, const struct iovec *iov, int iovcnt)
|
|||
return ntotal;
|
||||
}
|
||||
|
||||
#if OPENAT_SUPPORT
|
||||
int
|
||||
openat(int fd, const char *pathname, int flags, ...)
|
||||
{
|
||||
int new_fd;
|
||||
int ret;
|
||||
char dir_path[DIR_PATH_LEN];
|
||||
char *full_path;
|
||||
|
||||
ret = fcntl(fd, F_GETPATH, dir_path);
|
||||
if (ret != 0) {
|
||||
errno = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = asprintf(&full_path, "%s/%s", dir_path, pathname);
|
||||
if (ret < 0) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_fd = open(full_path, flags);
|
||||
free(full_path);
|
||||
|
||||
return new_fd;
|
||||
}
|
||||
#else
|
||||
int
|
||||
openat(int fd, const char *path, int oflags, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
fstatat(int fd, const char *path, struct stat *buf, int flag)
|
||||
|
|
|
@ -8,19 +8,44 @@
|
|||
#include "libc_errno.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static void
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
|
||||
static bool
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out,
|
||||
socklen_t *out_len)
|
||||
{
|
||||
struct sockaddr_in *v4;
|
||||
#ifdef IPPROTO_IPV6
|
||||
struct sockaddr_in6 *v6;
|
||||
#endif
|
||||
|
||||
assert(textual);
|
||||
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(port);
|
||||
out->sin_addr.s_addr = inet_addr(textual);
|
||||
v4 = (struct sockaddr_in *)out;
|
||||
if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
|
||||
v4->sin_family = AF_INET;
|
||||
v4->sin_port = htons(port);
|
||||
*out_len = sizeof(struct sockaddr_in);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IPPROTO_IPV6
|
||||
v6 = (struct sockaddr_in6 *)out;
|
||||
if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) {
|
||||
v6->sin6_family = AF_INET6;
|
||||
v6->sin6_port = htons(port);
|
||||
*out_len = sizeof(struct sockaddr_in6);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen,
|
||||
sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr,
|
||||
bh_sockaddr_t *bh_sockaddr)
|
||||
{
|
||||
switch (sockaddr->sa_family) {
|
||||
|
@ -28,31 +53,82 @@ sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen,
|
|||
{
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr;
|
||||
|
||||
assert(socklen >= sizeof(struct sockaddr_in));
|
||||
|
||||
bh_sockaddr->port = ntohs(addr->sin_port);
|
||||
bh_sockaddr->addr_buffer.ipv4 = ntohl(addr->sin_addr.s_addr);
|
||||
bh_sockaddr->is_ipv4 = true;
|
||||
return BHT_OK;
|
||||
}
|
||||
#ifdef IPPROTO_IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr;
|
||||
size_t i;
|
||||
|
||||
bh_sockaddr->port = ntohs(addr->sin6_port);
|
||||
|
||||
for (i = 0; i < sizeof(bh_sockaddr->addr_buffer.ipv6)
|
||||
/ sizeof(bh_sockaddr->addr_buffer.ipv6[0]);
|
||||
i++) {
|
||||
uint16 part_addr = addr->sin6_addr.s6_addr[i * 2]
|
||||
| (addr->sin6_addr.s6_addr[i * 2 + 1] << 8);
|
||||
bh_sockaddr->addr_buffer.ipv6[i] = ntohs(part_addr);
|
||||
}
|
||||
|
||||
bh_sockaddr->is_ipv4 = false;
|
||||
return BHT_OK;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr,
|
||||
struct sockaddr_storage *sockaddr, socklen_t *socklen)
|
||||
{
|
||||
if (bh_sockaddr->is_ipv4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr;
|
||||
addr->sin_port = htons(bh_sockaddr->port);
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = htonl(bh_sockaddr->addr_buffer.ipv4);
|
||||
*socklen = sizeof(*addr);
|
||||
}
|
||||
#ifdef IPPROTO_IPV6
|
||||
else {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr;
|
||||
size_t i;
|
||||
addr->sin6_port = htons(bh_sockaddr->port);
|
||||
addr->sin6_family = AF_INET6;
|
||||
|
||||
for (i = 0; i < sizeof(bh_sockaddr->addr_buffer.ipv6)
|
||||
/ sizeof(bh_sockaddr->addr_buffer.ipv6[0]);
|
||||
i++) {
|
||||
uint16 part_addr = htons(bh_sockaddr->addr_buffer.ipv6[i]);
|
||||
addr->sin6_addr.s6_addr[i * 2] = 0xff & part_addr;
|
||||
addr->sin6_addr.s6_addr[i * 2 + 1] = (0xff00 & part_addr) >> 8;
|
||||
}
|
||||
|
||||
*socklen = sizeof(*addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
|
||||
{
|
||||
int af = is_ipv4 ? AF_INET : AF_INET6;
|
||||
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (is_tcp) {
|
||||
*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
*sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
else {
|
||||
*sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
*sock = socket(af, SOCK_DGRAM, 0);
|
||||
}
|
||||
|
||||
return (*sock == -1) ? BHT_ERROR : BHT_OK;
|
||||
|
@ -61,28 +137,47 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
|
|||
int
|
||||
os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr = { 0 };
|
||||
struct linger ling;
|
||||
socklen_t socklen;
|
||||
int ret;
|
||||
|
||||
assert(host);
|
||||
assert(port);
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(*port);
|
||||
addr.sin_family = AF_INET;
|
||||
ling.l_onoff = 1;
|
||||
ling.l_linger = 0;
|
||||
|
||||
ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr,
|
||||
&socklen)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = setsockopt(socket, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = bind(socket, (struct sockaddr *)&addr, socklen);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
socklen = sizeof(addr);
|
||||
if (getsockname(socket, (struct sockaddr *)&addr, &socklen) == -1) {
|
||||
if (getsockname(socket, (void *)&addr, &socklen) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
if (addr.ss_family == AF_INET) {
|
||||
*port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
|
||||
}
|
||||
else {
|
||||
#ifdef IPPROTO_IPV6
|
||||
*port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
|
||||
|
@ -120,10 +215,7 @@ int
|
|||
os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
||||
unsigned int *addrlen)
|
||||
{
|
||||
struct sockaddr addr_tmp;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
|
||||
*sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len);
|
||||
*sock = accept(server_sock, addr, (socklen_t *)addrlen);
|
||||
|
||||
if (*sock < 0) {
|
||||
return BHT_ERROR;
|
||||
|
@ -135,11 +227,14 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
|||
int
|
||||
os_socket_connect(bh_socket_t socket, const char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in addr_in = { 0 };
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_storage addr_in = { 0 };
|
||||
socklen_t addr_len;
|
||||
int ret = 0;
|
||||
|
||||
textual_addr_to_sockaddr(addr, port, &addr_in);
|
||||
if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in,
|
||||
&addr_len)) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
|
||||
if (ret == -1) {
|
||||
|
@ -155,12 +250,53 @@ os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
|||
return recv(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
|
||||
bh_sockaddr_t *src_addr)
|
||||
{
|
||||
struct sockaddr_storage sock_addr = { 0 };
|
||||
socklen_t socklen = sizeof(sock_addr);
|
||||
int ret;
|
||||
|
||||
ret = recvfrom(socket, buf, len, flags, (struct sockaddr *)&sock_addr,
|
||||
&socklen);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (src_addr && socklen > 0) {
|
||||
if (sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, src_addr)
|
||||
== BHT_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (src_addr) {
|
||||
memset(src_addr, 0, sizeof(*src_addr));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
return send(socket, buf, len, 0);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
|
||||
int flags, const bh_sockaddr_t *dest_addr)
|
||||
{
|
||||
struct sockaddr_storage sock_addr = { 0 };
|
||||
socklen_t socklen = 0;
|
||||
|
||||
bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen);
|
||||
|
||||
return sendto(socket, buf, len, flags, (const struct sockaddr *)&sock_addr,
|
||||
socklen);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_close(bh_socket_t socket)
|
||||
{
|
||||
|
@ -191,41 +327,701 @@ os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out)
|
|||
out->ipv4 = ntohl(out->ipv4);
|
||||
}
|
||||
else {
|
||||
#ifdef IPPROTO_IPV6
|
||||
if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
out->ipv6[i] = ntohs(out->ipv6[i]);
|
||||
}
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
getaddrinfo_error_to_errno(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case EAI_AGAIN:
|
||||
return EAGAIN;
|
||||
case EAI_FAIL:
|
||||
return EFAULT;
|
||||
case EAI_MEMORY:
|
||||
return ENOMEM;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
is_addrinfo_supported(struct addrinfo *info)
|
||||
{
|
||||
return
|
||||
// Allow only IPv4 and IPv6
|
||||
(info->ai_family == AF_INET || info->ai_family == AF_INET6)
|
||||
// Allow only UDP and TCP
|
||||
&& (info->ai_socktype == SOCK_DGRAM || info->ai_socktype == SOCK_STREAM)
|
||||
&& (info->ai_protocol == IPPROTO_TCP
|
||||
|| info->ai_protocol == IPPROTO_UDP);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_resolve(const char *host, const char *service,
|
||||
uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4,
|
||||
bh_addr_info_t *addr_info, size_t addr_info_size,
|
||||
size_t *max_info_size)
|
||||
{
|
||||
struct addrinfo hints = { 0 }, *res, *result;
|
||||
int hints_enabled = hint_is_tcp || hint_is_ipv4;
|
||||
int ret;
|
||||
size_t pos = 0;
|
||||
|
||||
if (hints_enabled) {
|
||||
if (hint_is_ipv4) {
|
||||
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, strlen(service) == 0 ? NULL : service,
|
||||
hints_enabled ? &hints : NULL, &result);
|
||||
if (ret != BHT_OK) {
|
||||
errno = getaddrinfo_error_to_errno(ret);
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
res = result;
|
||||
while (res) {
|
||||
if (addr_info_size > pos) {
|
||||
if (!is_addrinfo_supported(res)) {
|
||||
res = res->ai_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret =
|
||||
sockaddr_to_bh_sockaddr(res->ai_addr, &addr_info[pos].sockaddr);
|
||||
|
||||
if (ret == BHT_ERROR) {
|
||||
freeaddrinfo(result);
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
addr_info[pos].is_tcp = res->ai_socktype == SOCK_STREAM;
|
||||
}
|
||||
|
||||
pos++;
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
*max_info_size = pos;
|
||||
freeaddrinfo(result);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
os_socket_setbooloption(bh_socket_t socket, int level, int optname,
|
||||
bool is_enabled)
|
||||
{
|
||||
int option = (int)is_enabled;
|
||||
if (setsockopt(socket, level, optname, &option, sizeof(option)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
os_socket_getbooloption(bh_socket_t socket, int level, int optname,
|
||||
bool *is_enabled)
|
||||
{
|
||||
assert(is_enabled);
|
||||
|
||||
int optval;
|
||||
socklen_t optval_size = sizeof(optval);
|
||||
if (getsockopt(socket, level, optname, &optval, &optval_size) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*is_enabled = (bool)optval;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
int buf_size_int = (int)bufsiz;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int,
|
||||
sizeof(buf_size_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
assert(bufsiz);
|
||||
|
||||
int buf_size_int;
|
||||
socklen_t bufsiz_len = sizeof(buf_size_int);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, &buf_size_int, &bufsiz_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*bufsiz = (size_t)buf_size_int;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
|
||||
{
|
||||
int buf_size_int = (int)bufsiz;
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int,
|
||||
sizeof(buf_size_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
|
||||
{
|
||||
assert(bufsiz);
|
||||
|
||||
int buf_size_int;
|
||||
socklen_t bufsiz_len = sizeof(buf_size_int);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, &buf_size_int, &bufsiz_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*bufsiz = (size_t)buf_size_int;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_KEEPALIVE,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_KEEPALIVE,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOTSUP;
|
||||
return BHT_ERROR;
|
||||
#endif /* defined(SO_REUSEPORT) */
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOTSUP;
|
||||
return BHT_ERROR;
|
||||
#endif /* defined(SO_REUSEPORT) */
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s)
|
||||
{
|
||||
struct linger linger_opts = { .l_onoff = (int)is_enabled,
|
||||
.l_linger = linger_s };
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts,
|
||||
sizeof(linger_opts))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s)
|
||||
{
|
||||
assert(is_enabled);
|
||||
assert(linger_s);
|
||||
|
||||
struct linger linger_opts;
|
||||
socklen_t linger_opts_len = sizeof(linger_opts);
|
||||
if (getsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_opts,
|
||||
&linger_opts_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*linger_s = linger_opts.l_linger;
|
||||
*is_enabled = (bool)linger_opts.l_onoff;
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_NODELAY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_NODELAY,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#ifdef TCP_QUICKACK
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_QUICKACK,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#ifdef TCP_QUICKACK
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_QUICKACK,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
int time_s_int = (int)time_s;
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
assert(time_s);
|
||||
int time_s_int;
|
||||
socklen_t time_s_len = sizeof(time_s_int);
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
|
||||
{
|
||||
int time_s_int = (int)time_s;
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int,
|
||||
sizeof(time_s_int))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
|
||||
{
|
||||
#ifdef TCP_KEEPINTVL
|
||||
assert(time_s);
|
||||
int time_s_int;
|
||||
socklen_t time_s_len = sizeof(time_s_int);
|
||||
if (getsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &time_s_int, &time_s_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
*time_s = (uint32)time_s_int;
|
||||
return BHT_OK;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN_CONNECT
|
||||
return os_socket_setbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN_CONNECT
|
||||
return os_socket_getbooloption(socket, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled)
|
||||
{
|
||||
if (ipv6) {
|
||||
#ifdef IPPROTO_IPV6
|
||||
return os_socket_setbooloption(socket, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, is_enabled);
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return os_socket_setbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
is_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled)
|
||||
{
|
||||
if (ipv6) {
|
||||
#ifdef IPPROTO_IPV6
|
||||
return os_socket_getbooloption(socket, IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_LOOP, is_enabled);
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return os_socket_getbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
is_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_add_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
assert(imr_multiaddr);
|
||||
if (is_ipv6) {
|
||||
#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN)
|
||||
struct ipv6_mreq mreq;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =
|
||||
imr_multiaddr->ipv6[i];
|
||||
}
|
||||
mreq.ipv6mr_interface = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4;
|
||||
mreq.imr_interface.s_addr = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
os_socket_set_ip_drop_membership(bh_socket_t socket,
|
||||
bh_ip_addr_buffer_t *imr_multiaddr,
|
||||
uint32_t imr_interface, bool is_ipv6)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
assert(imr_multiaddr);
|
||||
if (is_ipv6) {
|
||||
#if defined(IPPROTO_IPV6) && !defined(BH_PLATFORM_COSMOPOLITAN)
|
||||
struct ipv6_mreq mreq;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] =
|
||||
imr_multiaddr->ipv6[i];
|
||||
}
|
||||
mreq.ipv6mr_interface = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = imr_multiaddr->ipv4;
|
||||
mreq.imr_interface.s_addr = imr_interface;
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
|
||||
sizeof(mreq))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (getpeername(socket, (struct sockaddr *)&addr, &addr_len) == -1) {
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_TTL, &ttl_s, sizeof(ttl_s)) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr, addr_len,
|
||||
sockaddr);
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
socklen_t opt_len = sizeof(*ttl_s);
|
||||
if (getsockopt(socket, IPPROTO_IP, IP_TTL, ttl_s, &opt_len) != 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
|
||||
{
|
||||
if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl_s, sizeof(ttl_s))
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
|
||||
{
|
||||
socklen_t opt_len = sizeof(*ttl_s);
|
||||
if (getsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, ttl_s, &opt_len)
|
||||
!= 0) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
#ifdef IPPROTO_IPV6
|
||||
return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
#ifdef IPPROTO_IPV6
|
||||
return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
is_enabled);
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return BHT_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
|
||||
{
|
||||
return os_socket_setbooloption(socket, SOL_SOCKET, SO_BROADCAST,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
|
||||
{
|
||||
return os_socket_getbooloption(socket, SOL_SOCKET, SO_BROADCAST,
|
||||
is_enabled);
|
||||
}
|
||||
|
||||
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, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
struct sockaddr_storage addr_storage = { 0 };
|
||||
socklen_t addr_len = sizeof(addr_storage);
|
||||
int ret;
|
||||
|
||||
if (getsockname(socket, (struct sockaddr *)&addr, &addr_len) == -1) {
|
||||
ret = getsockname(socket, (struct sockaddr *)&addr_storage, &addr_len);
|
||||
|
||||
if (ret != BHT_OK) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr, addr_len,
|
||||
sockaddr);
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, sockaddr);
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
|
||||
{
|
||||
struct sockaddr_storage addr_storage = { 0 };
|
||||
socklen_t addr_len = sizeof(addr_storage);
|
||||
int ret;
|
||||
|
||||
ret = getpeername(socket, (struct sockaddr *)&addr_storage, &addr_len);
|
||||
|
||||
if (ret != BHT_OK) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, sockaddr);
|
||||
}
|
||||
|
|
|
@ -230,4 +230,59 @@ int
|
|||
os_cond_broadcast(korp_cond *cond)
|
||||
{
|
||||
return pthread_cond_broadcast(cond);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_init(korp_rwlock *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
if (pthread_rwlock_init(lock, NULL) != BHT_OK)
|
||||
return BHT_ERROR;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_rdlock(korp_rwlock *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
if (pthread_rwlock_rdlock(lock) != BHT_OK)
|
||||
return BHT_ERROR;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_wrlock(korp_rwlock *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
if (pthread_rwlock_wrlock(lock) != BHT_OK)
|
||||
return BHT_ERROR;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_unlock(korp_rwlock *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
if (pthread_rwlock_unlock(lock) != BHT_OK)
|
||||
return BHT_ERROR;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_rwlock_destroy(korp_rwlock *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
if (pthread_rwlock_destroy(lock) != BHT_OK)
|
||||
return BHT_ERROR;
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user