| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- /*
- * Copyright (C) 2021 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "platform_api_vmcore.h"
- #include "platform_api_extension.h"
- #include "libc_errno.h"
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <netinet/tcp.h>
- #include <netinet/in.h>
- 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);
- 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,
- 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_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, SOCK_STREAM, IPPROTO_TCP);
- }
- else {
- *sock = socket(af, SOCK_DGRAM, 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 };
- struct linger ling;
- socklen_t socklen;
- int ret;
- assert(host);
- assert(port);
- ling.l_onoff = 1;
- ling.l_linger = 0;
- 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, (void *)&addr, &socklen) == -1) {
- goto fail;
- }
- 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;
- fail:
- return BHT_ERROR;
- }
- int
- os_socket_settimeout(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, (const char *)&tv,
- sizeof(tv))
- != 0) {
- return BHT_ERROR;
- }
- return BHT_OK;
- }
- int
- os_socket_listen(bh_socket_t socket, int max_client)
- {
- if (listen(socket, max_client) != 0) {
- return BHT_ERROR;
- }
- return BHT_OK;
- }
- int
- os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
- unsigned int *addrlen)
- {
- *sock = accept(server_sock, addr, (socklen_t *)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_in = { 0 };
- socklen_t addr_len;
- int ret = 0;
- 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) {
- return BHT_ERROR;
- }
- return BHT_OK;
- }
- int
- 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)
- {
- close(socket);
- return BHT_OK;
- }
- __wasi_errno_t
- os_socket_shutdown(bh_socket_t socket)
- {
- if (shutdown(socket, O_RDWR) != 0) {
- return convert_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 (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 (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_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_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;
- }
- }
- 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 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_storage addr_storage = { 0 };
- socklen_t addr_len = sizeof(addr_storage);
- int ret;
- ret = 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 = 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);
- }
|