Added http downloader and multicast socket options (#1467)

Add a group of socket options used by cURL and rust stdlib, as well as some UDP multicast options.
This commit is contained in:
Callum Macmillan
2022-09-15 10:09:39 +01:00
committed by GitHub
parent b731ca4668
commit 4de5b52ba0
12 changed files with 3493 additions and 64 deletions

View File

@ -18,17 +18,36 @@
return -1; \
}
static void
ipv4_addr_to_wasi_ip4_addr(uint32_t addr_num, __wasi_addr_ip4_t *out)
{
addr_num = ntohl(addr_num);
out->n0 = (addr_num & 0xFF000000) >> 24;
out->n1 = (addr_num & 0x00FF0000) >> 16;
out->n2 = (addr_num & 0x0000FF00) >> 8;
out->n3 = (addr_num & 0x000000FF);
}
/* addr_num and port are in network order */
static void
ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
{
addr_num = ntohl(addr_num);
out->kind = IPv4;
out->addr.ip4.port = ntohs(port);
out->addr.ip4.addr.n0 = (addr_num & 0xFF000000) >> 24;
out->addr.ip4.addr.n1 = (addr_num & 0x00FF0000) >> 16;
out->addr.ip4.addr.n2 = (addr_num & 0x0000FF00) >> 8;
out->addr.ip4.addr.n3 = (addr_num & 0x000000FF);
ipv4_addr_to_wasi_ip4_addr(addr_num, &(out->addr.ip4.addr));
}
static void
ipv6_addr_to_wasi_ipv6_addr(uint16_t *addr, __wasi_addr_ip6_t *out)
{
out->n0 = ntohs(addr[0]);
out->n1 = ntohs(addr[1]);
out->n2 = ntohs(addr[2]);
out->n3 = ntohs(addr[3]);
out->h0 = ntohs(addr[4]);
out->h1 = ntohs(addr[5]);
out->h2 = ntohs(addr[6]);
out->h3 = ntohs(addr[7]);
}
static void
@ -36,14 +55,7 @@ ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out)
{
out->kind = IPv6;
out->addr.ip6.port = ntohs(port);
out->addr.ip6.addr.n0 = ntohs(addr[0]);
out->addr.ip6.addr.n1 = ntohs(addr[1]);
out->addr.ip6.addr.n2 = ntohs(addr[2]);
out->addr.ip6.addr.n3 = ntohs(addr[3]);
out->addr.ip6.addr.h0 = ntohs(addr[4]);
out->addr.ip6.addr.h1 = ntohs(addr[5]);
out->addr.ip6.addr.h2 = ntohs(addr[6]);
out->addr.ip6.addr.h3 = ntohs(addr[7]);
ipv6_addr_to_wasi_ipv6_addr(addr, &(out->addr.ip6.addr));
}
static __wasi_errno_t
@ -552,6 +564,8 @@ get_sol_socket_option(int sockfd, int optname, void *__restrict optval,
{
__wasi_errno_t error;
uint64_t timeout_us;
bool is_linger_enabled;
int linger_s;
switch (optname) {
case SO_RCVTIMEO:
@ -566,21 +580,165 @@ get_sol_socket_option(int sockfd, int optname, void *__restrict optval,
HANDLE_ERROR(error);
*(struct timeval *)optval = time_us_to_timeval(timeout_us);
return error;
case SO_SNDBUF:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_send_buf_size(sockfd, (size_t *)optval);
HANDLE_ERROR(error);
return error;
case SO_RCVBUF:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_recv_buf_size(sockfd, (size_t *)optval);
HANDLE_ERROR(error);
return error;
case SO_KEEPALIVE:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_keep_alive(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_REUSEADDR:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_reuse_addr(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_REUSEPORT:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_reuse_port(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_LINGER:
assert(*optlen == sizeof(struct linger));
error =
__wasi_sock_get_linger(sockfd, &is_linger_enabled, &linger_s);
HANDLE_ERROR(error);
((struct linger *)optval)->l_onoff = (int)is_linger_enabled;
((struct linger *)optval)->l_linger = linger_s;
return error;
case SO_BROADCAST:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_broadcast(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
HANDLE_ERROR(__WASI_ERRNO_NOTSUP);
int
get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
__wasi_errno_t error;
switch (optname) {
case TCP_KEEPIDLE:
assert(*optlen == sizeof(uint32_t));
error = __wasi_sock_get_tcp_keep_idle(sockfd, (uint32_t *)optval);
HANDLE_ERROR(error);
return error;
case TCP_KEEPINTVL:
assert(*optlen == sizeof(uint32_t));
error = __wasi_sock_get_tcp_keep_intvl(sockfd, (uint32_t *)optval);
HANDLE_ERROR(error);
return error;
case TCP_FASTOPEN_CONNECT:
assert(*optlen == sizeof(int));
error =
__wasi_sock_get_tcp_fastopen_connect(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case TCP_NODELAY:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_tcp_no_delay(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case TCP_QUICKACK:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_tcp_quick_ack(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
__wasi_errno_t error;
switch (optname) {
case IP_MULTICAST_LOOP:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_ip_multicast_loop(sockfd, false,
(bool *)optval);
HANDLE_ERROR(error);
return error;
case IP_TTL:
assert(*optlen == sizeof(uint8_t));
error = __wasi_sock_get_ip_ttl(sockfd, (uint8_t *)optval);
HANDLE_ERROR(error);
return error;
case IP_MULTICAST_TTL:
assert(*optlen == sizeof(uint8_t));
error = __wasi_sock_get_ip_multicast_ttl(sockfd, (uint8_t *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
get_ipproto_ipv6_option(int sockfd, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
__wasi_errno_t error;
switch (optname) {
case IPV6_V6ONLY:
assert(*optlen == sizeof(int));
error = __wasi_sock_get_ipv6_only(sockfd, (bool *)optval);
HANDLE_ERROR(error);
return error;
case IPV6_MULTICAST_LOOP:
assert(*optlen == sizeof(int));
error =
__wasi_sock_get_ip_multicast_loop(sockfd, true, (bool *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
getsockopt(int sockfd, int level, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
__wasi_errno_t error;
switch (level) {
case SOL_SOCKET:
return get_sol_socket_option(sockfd, optname, optval, optlen);
case IPPROTO_TCP:
return get_ipproto_tcp_option(sockfd, optname, optval, optlen);
case IPPROTO_IP:
return get_ipproto_ip_option(sockfd, optname, optval, optlen);
case IPPROTO_IPV6:
return get_ipproto_ipv6_option(sockfd, optname, optval, optlen);
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
HANDLE_ERROR(__WASI_ERRNO_NOTSUP);
}
int
@ -603,19 +761,210 @@ set_sol_socket_option(int sockfd, int optname, const void *optval,
error = __wasi_sock_set_send_timeout(sockfd, timeout_us);
HANDLE_ERROR(error);
return error;
case SO_SNDBUF:
assert(optlen == sizeof(int));
error = __wasi_sock_set_send_buf_size(sockfd, *(size_t *)optval);
HANDLE_ERROR(error);
return error;
case SO_RCVBUF:
assert(optlen == sizeof(int));
error = __wasi_sock_set_recv_buf_size(sockfd, *(size_t *)optval);
HANDLE_ERROR(error);
return error;
case SO_KEEPALIVE:
assert(optlen == sizeof(int));
error = __wasi_sock_set_keep_alive(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_REUSEADDR:
assert(optlen == sizeof(int));
error = __wasi_sock_set_reuse_addr(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_REUSEPORT:
assert(optlen == sizeof(int));
error = __wasi_sock_set_reuse_port(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case SO_LINGER:
assert(optlen == sizeof(struct linger));
struct linger *linger_opt = ((struct linger *)optval);
error = __wasi_sock_set_linger(sockfd, (bool)linger_opt->l_onoff,
linger_opt->l_linger);
HANDLE_ERROR(error);
return error;
case SO_BROADCAST:
assert(optlen == sizeof(int));
error = __wasi_sock_set_broadcast(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
HANDLE_ERROR(__WASI_ERRNO_NOTSUP);
int
set_ipproto_tcp_option(int sockfd, int optname, const void *optval,
socklen_t optlen)
{
__wasi_errno_t error;
switch (optname) {
case TCP_NODELAY:
assert(optlen == sizeof(int));
error = __wasi_sock_set_tcp_no_delay(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case TCP_KEEPIDLE:
assert(optlen == sizeof(uint32_t));
error = __wasi_sock_set_tcp_keep_idle(sockfd, *(uint32_t *)optval);
HANDLE_ERROR(error);
return error;
case TCP_KEEPINTVL:
assert(optlen == sizeof(uint32_t));
error = __wasi_sock_set_tcp_keep_intvl(sockfd, *(uint32_t *)optval);
HANDLE_ERROR(error);
return error;
case TCP_FASTOPEN_CONNECT:
assert(optlen == sizeof(int));
error =
__wasi_sock_set_tcp_fastopen_connect(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case TCP_QUICKACK:
assert(optlen == sizeof(int));
error = __wasi_sock_set_tcp_quick_ack(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
set_ipproto_ip_option(int sockfd, int optname, const void *optval,
socklen_t optlen)
{
__wasi_errno_t error;
__wasi_addr_ip_t imr_multiaddr;
struct ip_mreq *ip_mreq_opt;
switch (optname) {
case IP_MULTICAST_LOOP:
assert(optlen == sizeof(int));
error = __wasi_sock_set_ip_multicast_loop(sockfd, false,
*(bool *)optval);
HANDLE_ERROR(error);
return error;
case IP_ADD_MEMBERSHIP:
assert(optlen == sizeof(struct ip_mreq));
ip_mreq_opt = (struct ip_mreq *)optval;
imr_multiaddr.kind = IPv4;
ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr,
&imr_multiaddr.addr.ip4);
error = __wasi_sock_set_ip_add_membership(
sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr);
HANDLE_ERROR(error);
return error;
case IP_DROP_MEMBERSHIP:
assert(optlen == sizeof(struct ip_mreq));
ip_mreq_opt = (struct ip_mreq *)optval;
imr_multiaddr.kind = IPv4;
ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr,
&imr_multiaddr.addr.ip4);
error = __wasi_sock_set_ip_drop_membership(
sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr);
HANDLE_ERROR(error);
return error;
case IP_TTL:
assert(optlen == sizeof(uint8_t));
error = __wasi_sock_set_ip_ttl(sockfd, *(uint8_t *)optval);
HANDLE_ERROR(error);
return error;
case IP_MULTICAST_TTL:
assert(optlen == sizeof(uint8_t));
error =
__wasi_sock_set_ip_multicast_ttl(sockfd, *(uint8_t *)optval);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
set_ipproto_ipv6_option(int sockfd, int optname, const void *optval,
socklen_t optlen)
{
__wasi_errno_t error;
struct ipv6_mreq *ipv6_mreq_opt;
__wasi_addr_ip_t imr_multiaddr;
switch (optname) {
case IPV6_V6ONLY:
assert(optlen == sizeof(int));
error = __wasi_sock_set_ipv6_only(sockfd, *(bool *)optval);
HANDLE_ERROR(error);
return error;
case IPV6_MULTICAST_LOOP:
assert(optlen == sizeof(int));
error = __wasi_sock_set_ip_multicast_loop(sockfd, true,
*(bool *)optval);
HANDLE_ERROR(error);
return error;
case IPV6_JOIN_GROUP:
assert(optlen == sizeof(struct ipv6_mreq));
ipv6_mreq_opt = (struct ipv6_mreq *)optval;
imr_multiaddr.kind = IPv6;
ipv6_addr_to_wasi_ipv6_addr(
(uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr,
&imr_multiaddr.addr.ip6);
error = __wasi_sock_set_ip_add_membership(
sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface);
HANDLE_ERROR(error);
return error;
case IPV6_LEAVE_GROUP:
assert(optlen == sizeof(struct ipv6_mreq));
ipv6_mreq_opt = (struct ipv6_mreq *)optval;
imr_multiaddr.kind = IPv6;
ipv6_addr_to_wasi_ipv6_addr(
(uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr,
&imr_multiaddr.addr.ip6);
error = __wasi_sock_set_ip_drop_membership(
sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface);
HANDLE_ERROR(error);
return error;
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
}
int
setsockopt(int sockfd, int level, int optname, const void *optval,
socklen_t optlen)
{
__wasi_errno_t error;
switch (level) {
case SOL_SOCKET:
return set_sol_socket_option(sockfd, optname, optval, optlen);
case IPPROTO_TCP:
return set_ipproto_tcp_option(sockfd, optname, optval, optlen);
case IPPROTO_IP:
return set_ipproto_ip_option(sockfd, optname, optval, optlen);
case IPPROTO_IPV6:
return set_ipproto_ipv6_option(sockfd, optname, optval, optlen);
default:
error = __WASI_ERRNO_NOTSUP;
HANDLE_ERROR(error);
return error;
}
HANDLE_ERROR(__WASI_ERRNO_NOTSUP);
}