Import Base Code

This commit is contained in:
lucas 2024-03-29 10:55:59 +01:00
parent b9740beb31
commit cdaab9f05c
No known key found for this signature in database
GPG Key ID: 73B3EDBA15466FFA
2 changed files with 1294 additions and 0 deletions

View File

@ -0,0 +1,302 @@
#ifndef ZEPHYR_ERRNO_H
#define ZEPHYR_ERRNO_H
#include "platform_wasi_types.h"
#include <errno.h>
// Add your custom code here
static inline __wasi_errno_t
zephyr_to_wasi_errno(int zephyr_errno) {
switch (zephyr_errno) {
case EPERM:
return __WASI_EPERM; // Operation not permitted
case ENOENT:
return __WASI_ENOENT; // No such file or directory
case ESRCH:
return __WASI_ESRCH; // No such process
case EINTR:
return __WASI_EINTR; // Interrupted system call
case EIO:
return __WASI_EIO; // I/O error
case ENXIO:
return __WASI_ENXIO; // No such device or address
case E2BIG:
return __WASI_E2BIG; // Argument list too long
case ENOEXEC:
return __WASI_ENOEXEC; // Exec format error
case EBADF:
return __WASI_EBADF; // Bad file descriptor
case ECHILD:
return __WASI_ECHILD; // No child processes
case EAGAIN:
return __WASI_EAGAIN; // Try again
case ENOMEM:
return __WASI_ENOMEM; // Out of memory
case EACCES:
return __WASI_EACCES; // Permission denied
case EFAULT:
return __WASI_EFAULT; // Bad address
case EBUSY:
return __WASI_EBUSY; // Device or resource busy
case EEXIST:
return __WASI_EEXIST; // File exists
case EXDEV:
return __WASI_EXDEV; // Cross-device link
case ENODEV:
return __WASI_ENODEV; // No such device
case ENOTDIR:
return __WASI_ENOTDIR; // Not a directory
case EISDIR:
return __WASI_EISDIR; // Is a directory
case EINVAL:
return __WASI_EINVAL; // Invalid argument
case ENFILE:
return __WASI_ENFILE; // File table overflow
case EMFILE:
return __WASI_EMFILE; // Too many open files
case ENOTTY:
return __WASI_ENOTTY; // Not a typewriter
case EFBIG:
return __WASI_EFBIG; // File too large
case ENOSPC:
return __WASI_ENOSPC; // No space left on device
case EROFS:
return __WASI_EROFS; // Read-only file system
case EMLINK:
return __WASI_EMLINK; // Too many links
case EPIPE:
return __WASI_EPIPE; // Broken pipe
case EDOM:
return __WASI_EDOM; // Math argument out of domain of func
case ERANGE:
return __WASI_ERANGE; // Math result not representable
case ENOMSG:
return __WASI_ENOMSG; // No message of desired type
case EDEADLK:
return __WASI_EDEADLK; // Resource deadlock would occur
case ENOLCK:
return __WASI_ENOLCK; // No record locks available
case ENOSYS:
return __WASI_ENOSYS; // Function not implemented
case ENOTEMPTY:
return __WASI_ENOTEMPTY; // Directory not empty
case ENAMETOOLONG:
return __WASI_ENAMETOOLONG; // File name too long
case ELOOP:
return __WASI_ELOOP; // Too many symbolic links encountered
case EOPNOTSUPP:
return __WASI_ENOTSUP; // Operation not supported on transport endpoint
case EPFNOSUPPORT:
return __WASI_EAFNOSUPPORT; // Protocol family not supported
case ECONNRESET:
return __WASI_ECONNRESET; // Connection reset by peer
case ENOBUFS:
return __WASI_ENOBUFS; // No buffer space available
case EAFNOSUPPORT:
return __WASI_EAFNOSUPPORT; // Address family not supported by protocol
case EPROTOTYPE:
return __WASI_EPROTOTYPE; // Protocol wrong type for socket
case ENOTSOCK:
return __WASI_ENOTSOCK; // Socket operation on non-socket
case ENOPROTOOPT:
return __WASI_ENOPROTOOPT; // Protocol not available
case ESHUTDOWN:
return __WASI_ECANCELED; // Cannot send after transport endpoint shutdown
case ECONNREFUSED:
return __WASI_ECONNREFUSED; // Connection refused
case EADDRINUSE:
return __WASI_EADDRINUSE; // Address already in use
case ECONNABORTED:
return __WASI_ECONNABORTED; // Connection aborted
case ENETUNREACH:
return __WASI_ENETUNREACH; // Network is unreachable
case ENETDOWN:
return __WASI_ENETDOWN; // Network is down
case ETIMEDOUT:
return __WASI_ETIMEDOUT; // Connection timed out
case EHOSTDOWN:
return __WASI_ENETDOWN; // Host is down
case EHOSTUNREACH:
return __WASI_EHOSTUNREACH; // No route to host
case EINPROGRESS:
return __WASI_EINPROGRESS; // Operation now in progress
case EALREADY:
return __WASI_EALREADY; // Operation already in progress
case EDESTADDRREQ:
return __WASI_EDESTADDRREQ; // Destination address required
case EMSGSIZE:
return __WASI_EMSGSIZE; // Message too long
case EPROTONOSUPPORT:
return __WASI_EPROTONOSUPPORT; // Protocol not supported
case ESOCKTNOSUPPORT:
// return __WASI_ESOCKTNOSUPPORT; // Socket type not supported
case EADDRNOTAVAIL:
return __WASI_EADDRNOTAVAIL; // Cannot assign requested address
case ENETRESET:
return __WASI_ENETRESET; // Network dropped connection because of reset
case EISCONN:
return __WASI_EISCONN; // Transport endpoint is already connected
case ENOTCONN:
return __WASI_ENOTCONN; // Transport endpoint is not connected
case ETOOMANYREFS:
return __WASI_ENOTRECOVERABLE; // Too many references: cannot splice
case ENOTSUP:
return __WASI_ENOTSUP; // Operation not supported
case EILSEQ:
return __WASI_EILSEQ; // Illegal byte sequence
case EOVERFLOW:
return __WASI_EOVERFLOW; // Value too large for defined data type
case ECANCELED:
return __WASI_ECANCELED; // Operation canceled
default:
return __WASI_ENOSYS; // Function not implemented
}
}
static inline int
wasi_to_zephyr_errno(__wasi_errno_t wasi_errno) {
switch (wasi_errno) {
case __WASI_EPERM:
return EPERM;
case __WASI_ENOENT:
return ENOENT;
case __WASI_ESRCH:
return ESRCH;
case __WASI_EINTR:
return EINTR;
case __WASI_EIO:
return EIO;
case __WASI_ENXIO:
return ENXIO;
case __WASI_E2BIG:
return E2BIG;
case __WASI_ENOEXEC:
return ENOEXEC;
case __WASI_EBADF:
return EBADF;
case __WASI_ECHILD:
return ECHILD;
case __WASI_EAGAIN:
return EAGAIN;
case __WASI_ENOMEM:
return ENOMEM;
case __WASI_EACCES:
return EACCES;
case __WASI_EFAULT:
return EFAULT;
case __WASI_EBUSY:
return EBUSY;
case __WASI_EEXIST:
return EEXIST;
case __WASI_EXDEV:
return EXDEV;
case __WASI_ENODEV:
return ENODEV;
case __WASI_ENOTDIR:
return ENOTDIR;
case __WASI_EISDIR:
return EISDIR;
case __WASI_EINVAL:
return EINVAL;
case __WASI_ENFILE:
return ENFILE;
case __WASI_EMFILE:
return EMFILE;
case __WASI_ENOTTY:
return ENOTTY;
case __WASI_EFBIG:
return EFBIG;
case __WASI_ENOSPC:
return ENOSPC;
case __WASI_EROFS:
return EROFS;
case __WASI_EMLINK:
return EMLINK;
case __WASI_EPIPE:
return EPIPE;
case __WASI_EDOM:
return EDOM;
case __WASI_ERANGE:
return ERANGE;
case __WASI_ENOMSG:
return ENOMSG;
case __WASI_EDEADLK:
return EDEADLK;
case __WASI_ENOLCK:
return ENOLCK;
case __WASI_ENOSYS:
return ENOSYS;
case __WASI_ENOTEMPTY:
return ENOTEMPTY;
case __WASI_ENAMETOOLONG:
return ENAMETOOLONG;
case __WASI_ELOOP:
return ELOOP;
//case __WASI_ENOTSUPP :
// return EOPNOTSUPP;
case __WASI_EAFNOSUPPORT:
return EPFNOSUPPORT;
case __WASI_ECONNRESET:
return ECONNRESET;
case __WASI_ENOBUFS:
return ENOBUFS;
case __WASI_EPROTOTYPE:
return EPROTOTYPE;
case __WASI_ENOTSOCK:
return ENOTSOCK;
case __WASI_ENOPROTOOPT:
return ENOPROTOOPT;
//case __WASI_ECANCELED:
// return ESHUTDOWN;
case __WASI_ECONNREFUSED:
return ECONNREFUSED;
case __WASI_EADDRINUSE:
return EADDRINUSE;
case __WASI_ECONNABORTED:
return ECONNABORTED;
case __WASI_ENETUNREACH:
return ENETUNREACH;
case __WASI_ENETDOWN:
return ENETDOWN;
case __WASI_ETIMEDOUT:
return ETIMEDOUT;
// case __WASI_EHOSTDOWN:
// return EHOSTDOWN;
case __WASI_EHOSTUNREACH:
return EHOSTUNREACH;
case __WASI_EINPROGRESS:
return EINPROGRESS;
case __WASI_EALREADY:
return EALREADY;
case __WASI_EDESTADDRREQ:
return EDESTADDRREQ;
case __WASI_EMSGSIZE:
return EMSGSIZE;
case __WASI_EPROTONOSUPPORT:
return EPROTONOSUPPORT;
// case __WASI_ESOCKTNOSUPPORT:
// return ESOCKTNOSUPPORT;
case __WASI_EADDRNOTAVAIL:
return EADDRNOTAVAIL;
case __WASI_ENETRESET:
return ENETRESET;
case __WASI_EISCONN:
return EISCONN;
case __WASI_ENOTCONN:
return ENOTCONN;
case __WASI_ENOTRECOVERABLE:
return ETOOMANYREFS;
case __WASI_ENOTSUP:
return ENOTSUP;
case __WASI_EILSEQ:
return EILSEQ;
case __WASI_EOVERFLOW:
return EOVERFLOW;
case __WASI_ECANCELED:
return ECANCELED;
default:
return ENOSYS;
}
}
#endif /* ZEPHYR_ERRNO_H */

View File

@ -0,0 +1,992 @@
#include "platform_api_extension.h"
//#include "platform_wasi_types.h"
#include <zephyr/net/net_ip.h>
#include <zephyr/net/socket.h>
#include <zephyr/net/socket_types.h>
#include "zephyr_errno.h"
// Static functions
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_in *v6;
#endif
assert(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_in *)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_in);
return true;
}
#endif
return false;
}
static int
sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr,
bh_sockaddr_t *bh_sockaddr)
{
switch (sockaddr->sa_family) {
case AF_INET:
{
struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr;
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_in *addr = (struct sockaddr_in *)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
}
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;
case EAI_SYSTEM:
return errno;
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);
}
static int
os_socket_setbooloption(bh_socket_t socket, int level, int optname,
bool is_enabled)
{
int option = (int)is_enabled;
if (zsock_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 (zsock_setsockopt(socket, level, optname, &optval, &optval_size) != 0) {
return BHT_ERROR;
}
*is_enabled = (bool)optval;
return BHT_OK;
}
// Platform API implementation
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 = zsock_socket(af, SOCK_STREAM, IPPROTO_TCP);
}
else {
*sock = zsock_socket(af, SOCK_DGRAM, IPPROTO_UDP); // IPPROTO_UDP or 0 ?
}
return (*sock == -1) ? BHT_ERROR : BHT_OK;
}
int
os_socket_bind(bh_socket_t socket, const char *host, int *port)
{
struct sockaddr_storage addr = { 0 };
socklen_t socklen;
int ret;
assert(host);
assert(port);
if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr,
&socklen)) {
goto fail;
}
// F_SETF_SETFD and FD_CLOEXEC are not defined in zephyr.
// SO_LINGER: Socket lingers on close (ignored, for compatibility)
ret = zsock_bind(socket, (struct sockaddr *)&addr, socklen);
if (ret < 0) {
goto fail;
}
socklen = sizeof(addr);
if (zsock_getsockname(socket, (void *)&addr, &socklen) == -1) {
goto fail;
}
if (addr.sin_family == AF_INET) {
*port = ntohs((&addr)->sin_port);
}
else {
#ifdef IPPROTO_IPV6
*port = ntohs((&addr)->sin6_port);
#else
goto fail;
#endif
}
return BHT_OK;
fail:
// Close the fd because FD_CLOEXEC isn't implemented.
os_socket_close(socket);
return BHT_ERROR;
}
int
os_socket_settimeout(bh_socket_t socket, uint64 timeout_us)
{
struct timeval timeout = { 0 };
timeout.tv_sec = timeout_us / 1000000;
timeout.tv_usec = timeout_us % 1000000;
return zsock_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
}
int
os_socket_listen(bh_socket_t socket, int max_client)
{
return zsock_listen(socket, max_client) != 0 ? BHT_ERROR : BHT_OK;
}
int
os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
unsigned int *addrlen)
{
*sock = zsock_accept(server_sock, addr, addrlen);
if (*sock < 0) {
return BHT_ERROR;
}
return BHT_OK;
}
int
os_socket_connect(bh_socket_t socket, const char *addr, int port)
{
struct sockaddr_storage addr = { 0 };
socklen_t socklen;
int ret;
assert(addr);
if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr,
&socklen)) {
return BHT_ERROR;
}
ret = zsock_connect(socket, (struct sockaddr *)&addr, socklen);
if (ret < 0) {
return BHT_ERROR;
}
return BHT_OK;
}
int
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
{
return zsock_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 addr = { 0 };
socklen_t socklen = sizeof(addr);
int ret;
ret = zsock_recvfrom(socket, buf, len, flags, (struct sockaddr *)&addr,
&socklen);
if (ret < 0) {
return BHT_ERROR;
}
if (src_addr && socklen > 0) {
if (sockaddr_to_bh_sockaddr((struct sockaddr *)&addr, src_addr) != BHT_OK) {
return BHT_ERROR;
}
}
return ret;
}
int
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
{
return zsock_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 addr = { 0 };
socklen_t socklen;
int ret;
if (bh_sockaddr_to_sockaddr(dest_addr, (struct sockaddr *)&addr, &socklen)
== BHT_ERROR) {
return -1;
}
return zsock_sendto(socket, buf, len, flags, (struct sockaddr *)&addr,
socklen);
}
int
os_socket_close(bh_socket_t socket)
{
return zsock_close(socket) == -1 ? BHT_ERROR : BHT_OK;
}
__wasi_errno_t
os_socket_shutdown(bh_socket_t socket)
{
if (zsock_shutdown(socket, ZSOCK_SHUT_RDWR) == -1) {
return zephyr_to_wasi_errno(errno);
}
return __WASI_ESUCCESS;;
}
int
os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out)
{
if (!cp)
return BHT_ERROR;
if (is_ipv4) {
if (zsock_inet_pton(AF_INET, cp, &out->ipv4) != 1) {
return BHT_ERROR;
}
/* Note: ntohl(INADDR_NONE) == INADDR_NONE */
out->ipv4 = ntohl(out->ipv4);
}
else {
#ifdef IPPROTO_IPV6
if (zsock_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;
}
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 zsock_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 = zsock_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) {
zsock_freeaddrinfo(result);
return BHT_ERROR;
}
addr_info[pos].is_tcp = res->ai_socktype == SOCK_STREAM;
}
pos++;
res = res->ai_next;
}
*max_info_size = pos;
zsock_freeaddrinfo(result);
return BHT_OK;
}
int
os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr)
{
struct sockaddr_storage addr_storage = { 0 };
socklen_t addr_len = sizeof(addr_storage);
int ret;
ret = zsock_getsockname(socket, (struct sockaddr *)&addr_storage, &addr_len);
if (ret != BHT_OK) {
return BHT_ERROR;
}
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 = zsock_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);
}
int
os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
{
int buf_size_int = (int)bufsiz;
if (zsock_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 (zsock_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 (zsock_getsockopt(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 (zsock_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_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 (zsock_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 (zsock_setsockopt(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 (zsock_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 (zsock_setsockopt(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_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)
{
return os_socket_setbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
is_enabled);
}
int
os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
{
return os_socket_getbooloption(socket, SOL_SOCKET, SO_REUSEPORT,
is_enabled);
}
// SO_LINGER Socket lingers on close (ignored, for compatibility)
int
os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s)
{
errno = ENOSYS;
return BHT_ERROR;
}
// TCP_NODELAY Disable TCP buffering (ignored, for compatibility)
int
os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32_t time_s)
{
int time_s_int = (int)time_s;
#ifdef TCP_KEEPIDLE
if (zsock_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 (zsock_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_t *time_s)
{
assert(time_s);
int time_s_int;
socklen_t time_s_len = sizeof(time_s_int);
#ifdef TCP_KEEPIDLE
if (getsozsock_setsockoptkopt(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 (zsock_setsockopt(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_t time_s)
{
int time_s_int = (int)time_s;
#ifdef TCP_KEEPINTVL
if (zsock_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_t *time_s)
{
#ifdef TCP_KEEPINTVL
assert(time_s);
int time_s_int;
socklen_t time_s_len = sizeof(time_s_int);
if (zsock_setsockopt(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)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
int
os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6,
bool *is_enabled)
{
errno = ENOSYS;
return BHT_ERROR;
}
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_ADD_MEMBERSHIP, &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_set_ip_drop_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_DROP_MEMBERSHIP, &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;
}
}
}
int
os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
{
if (zsock_setsockopt(socket, IPPROTO_IP, IP_TTL, &ttl_s, sizeof(ttl_s)) != 0) {
return BHT_ERROR;
}
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 (zsock_setsockopt(socket, IPPROTO_IP, IP_MULTICAST_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 (zsock_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 (zsock_setsockopt(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);
}