Просмотр исходного кода

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.
Callum Macmillan 3 лет назад
Родитель
Сommit
4de5b52ba0

+ 399 - 8
core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h

@@ -6,6 +6,7 @@
 #ifndef _WASI_SOCKET_EXT_H_
 #define _WASI_SOCKET_EXT_H_
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -63,6 +64,14 @@ typedef struct __wasi_addr_ip6_port_t {
     __wasi_ip_port_t port; /* host byte order */
 } __wasi_addr_ip6_port_t;
 
+typedef struct __wasi_addr_ip_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_t ip4;
+        __wasi_addr_ip6_t ip6;
+    } addr;
+} __wasi_addr_ip_t;
+
 typedef struct __wasi_addr_t {
     __wasi_addr_type_t kind;
     union {
@@ -93,10 +102,33 @@ typedef struct __wasi_addr_info_hints_t {
  * <sys/socket.h>
  * <sys/types.h>
  */
-
+#define SO_REUSEADDR 2
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_LINGER 13
+#define SO_REUSEPORT 15
 #define SO_RCVTIMEO 20
 #define SO_SNDTIMEO 21
 
+#define TCP_NODELAY 1
+#define TCP_KEEPIDLE 4
+#define TCP_KEEPINTVL 5
+#define TCP_QUICKACK 12
+#define TCP_FASTOPEN_CONNECT 30
+
+#define IP_TTL 2
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+
+#define IPV6_MULTICAST_LOOP 19
+#define IPV6_JOIN_GROUP 20
+#define IPV6_LEAVE_GROUP 21
+#define IPV6_V6ONLY 26
+
 struct addrinfo {
     int ai_flags;             /* Input flags.  */
     int ai_family;            /* Protocol family for socket.  */
@@ -368,7 +400,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0,
                    __import_name__("sock_get_reuse_addr")));
 
 static inline __wasi_errno_t
-__wasi_sock_get_reuse_addr(__wasi_fd_t fd, uint8_t *reuse)
+__wasi_sock_get_reuse_addr(__wasi_fd_t fd, bool *reuse)
 {
     return (__wasi_errno_t)
         __imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd,
@@ -386,7 +418,7 @@ __imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0,
                    __import_name__("sock_get_reuse_port")));
 
 static inline __wasi_errno_t
-__wasi_sock_get_reuse_port(__wasi_fd_t fd, int8_t *reuse)
+__wasi_sock_get_reuse_port(__wasi_fd_t fd, bool *reuse)
 {
     return (__wasi_errno_t)
         __imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd,
@@ -483,7 +515,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0,
                    __import_name__("sock_set_reuse_addr")));
 
 static inline __wasi_errno_t
-__wasi_sock_set_reuse_addr(__wasi_fd_t fd, uint8_t reuse)
+__wasi_sock_set_reuse_addr(__wasi_fd_t fd, bool reuse)
 {
     return (__wasi_errno_t)
         __imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd,
@@ -501,7 +533,7 @@ __imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0,
                    __import_name__("sock_set_reuse_port")));
 
 static inline __wasi_errno_t
-__wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse)
+__wasi_sock_set_reuse_port(__wasi_fd_t fd, bool reuse)
 {
     return (__wasi_errno_t)
         __imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd,
@@ -513,15 +545,17 @@ __wasi_sock_set_reuse_port(__wasi_fd_t fd, uint8_t reuse)
  * Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF
  */
 int32_t
-__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0)
+__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0,
+                                                         int32_t arg1)
     __attribute__((__import_module__("wasi_snapshot_preview1"),
                    __import_name__("sock_set_send_buf_size")));
 
 static inline __wasi_errno_t
-__wasi_sock_set_send_buf_size(__wasi_fd_t fd)
+__wasi_sock_set_send_buf_size(__wasi_fd_t fd, __wasi_size_t buf_len)
 {
     return (__wasi_errno_t)
-        __imported_wasi_snapshot_preview1_sock_set_send_buf_size((int32_t)fd);
+        __imported_wasi_snapshot_preview1_sock_set_send_buf_size(
+            (int32_t)fd, (int32_t)buf_len);
 }
 
 int32_t
@@ -580,6 +614,363 @@ __wasi_sock_set_send_timeout(__wasi_fd_t fd, uint64_t timeout_us)
             (int32_t)fd, (int64_t)timeout_us);
 }
 
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_keep_alive(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_keep_alive")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_keep_alive(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_keep_alive((int32_t)fd,
+                                                              (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_keep_alive(int32_t arg0,
+                                                      int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_keep_alive")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_keep_alive(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_keep_alive((int32_t)fd,
+                                                              (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_linger(int32_t arg0, int32_t arg1,
+                                                  int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_linger")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_linger(__wasi_fd_t fd, bool is_enabled, int linger_s)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_linger(
+        (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_linger(int32_t arg0, int32_t arg1,
+                                                  int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_linger")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_linger(__wasi_fd_t fd, bool *is_enabled, int *linger_s)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_linger(
+        (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_tcp_keep_idle")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_tcp_keep_idle(__wasi_fd_t fd, uint32_t time_s)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(
+            (int32_t)fd, (int32_t)time_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_tcp_keep_idle")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_tcp_keep_idle(__wasi_fd_t fd, uint32_t *time_s)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(
+            (int32_t)fd, (int32_t)time_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(int32_t arg0,
+                                                          int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_tcp_keep_intvl")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_tcp_keep_intvl(__wasi_fd_t fd, uint32_t time_s)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(
+            (int32_t)fd, (int32_t)time_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(int32_t arg0,
+                                                          int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_tcp_keep_intvl")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_tcp_keep_intvl(__wasi_fd_t fd, uint32_t *time_s)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(
+            (int32_t)fd, (int32_t)time_s);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(int32_t arg0,
+                                                                int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_tcp_fastopen_connect")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_tcp_fastopen_connect(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(int32_t arg0,
+                                                                int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_tcp_fastopen_connect")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_tcp_fastopen_connect(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(int32_t arg0,
+                                                             int32_t arg1,
+                                                             int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ip_multicast_loop")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(
+            (int32_t)fd, (int32_t)ipv6, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(int32_t arg0,
+                                                             int32_t arg1,
+                                                             int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_ip_multicast_loop")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(
+            (int32_t)fd, (int32_t)ipv6, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(int32_t arg0,
+                                                            int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ip_multicast_ttl")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ip_multicast_ttl(__wasi_fd_t fd, uint8_t option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(int32_t arg0,
+                                                            int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_ip_multicast_ttl")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_ip_multicast_ttl(__wasi_fd_t fd, uint8_t *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ip_add_membership(int32_t arg0,
+                                                             int32_t arg1,
+                                                             int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ip_add_membership")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ip_add_membership(__wasi_fd_t fd,
+                                  __wasi_addr_ip_t *imr_multiaddr,
+                                  uint32_t imr_interface)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_ip_add_membership(
+            (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(int32_t arg0,
+                                                              int32_t arg1,
+                                                              int32_t arg2)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ip_drop_membership")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ip_drop_membership(__wasi_fd_t fd,
+                                   __wasi_addr_ip_t *imr_multiaddr,
+                                   uint32_t imr_interface)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(
+            (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_broadcast(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_broadcast")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_broadcast(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_broadcast(
+        (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_broadcast(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_broadcast")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_broadcast(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_broadcast(
+        (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(int32_t arg0,
+                                                        int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_tcp_no_delay")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_tcp_no_delay(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(int32_t arg0,
+                                                        int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_tcp_no_delay")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_tcp_no_delay(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_tcp_quick_ack")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_tcp_quick_ack(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(int32_t arg0,
+                                                         int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_tcp_quick_ack")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_tcp_quick_ack(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)
+        __imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(
+            (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ip_ttl(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ip_ttl")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ip_ttl(__wasi_fd_t fd, uint8_t option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ip_ttl(
+        (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_ip_ttl(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_ip_ttl")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_ip_ttl(__wasi_fd_t fd, uint8_t *option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ip_ttl(
+        (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_set_ipv6_only(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_set_ipv6_only")));
+
+static inline __wasi_errno_t
+__wasi_sock_set_ipv6_only(__wasi_fd_t fd, bool option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ipv6_only(
+        (int32_t)fd, (int32_t)option);
+}
+
+int32_t
+__imported_wasi_snapshot_preview1_sock_get_ipv6_only(int32_t arg0, int32_t arg1)
+    __attribute__((__import_module__("wasi_snapshot_preview1"),
+                   __import_name__("sock_get_ipv6_only")));
+
+static inline __wasi_errno_t
+__wasi_sock_get_ipv6_only(__wasi_fd_t fd, bool *option)
+{
+    return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ipv6_only(
+        (int32_t)fd, (int32_t)option);
+}
 /**
  * TODO: modify recv() and send()
  * since don't want to re-compile the wasi-libc,

+ 368 - 19
core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c

@@ -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;
+    }
+}
+
+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;
 
-    HANDLE_ERROR(__WASI_ERRNO_NOTSUP);
+    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);
 }

+ 591 - 18
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -1119,11 +1119,81 @@ wasi_sock_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr)
     return wasi_ssp_sock_connect(curfds, addr_pool, fd, addr);
 }
 
+static wasi_errno_t
+wasi_sock_get_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                        bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_broadcast(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_keep_alive(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool *is_enabled,
+                     int *linger_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool))
+        || !validate_native_addr(linger_s, sizeof(int)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_linger(curfds, fd, is_enabled, linger_s);
+}
+
 static wasi_errno_t
 wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
-                            wasi_size_t *size)
+                            size_t *size)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(size, sizeof(wasi_size_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_recv_buf_size(curfds, fd, size);
 }
 
 static wasi_errno_t
@@ -1146,22 +1216,60 @@ wasi_sock_get_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd,
 }
 
 static wasi_errno_t
-wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse)
+wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool *is_enabled)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_reuse_addr(curfds, fd, is_enabled);
 }
 
 static wasi_errno_t
-wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 *reuse)
+wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool *is_enabled)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_reuse_port(curfds, fd, is_enabled);
 }
 
 static wasi_errno_t
 wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
-                            wasi_size_t *size)
+                            size_t *size)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(size, sizeof(__wasi_size_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_send_buf_size(curfds, fd, size);
 }
 
 static wasi_errno_t
@@ -1183,6 +1291,177 @@ wasi_sock_get_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd,
     return wasmtime_ssp_sock_get_send_timeout(curfds, fd, timeout_us);
 }
 
+static wasi_errno_t
+wasi_sock_get_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                   bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_tcp_fastopen_connect(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                           bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_tcp_no_delay(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_tcp_quick_ack(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            uint32_t *time_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(time_s, sizeof(uint32_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_tcp_keep_idle(curfds, fd, time_s);
+}
+
+static wasi_errno_t
+wasi_sock_get_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                             uint32_t *time_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(time_s, sizeof(uint32_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_tcp_keep_intvl(curfds, fd, time_s);
+}
+
+static wasi_errno_t
+wasi_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                bool ipv6, bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_ip_multicast_loop(curfds, fd, ipv6,
+                                                   is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_get_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t *ttl_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(ttl_s, sizeof(uint8_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_ip_ttl(curfds, fd, ttl_s);
+}
+
+static wasi_errno_t
+wasi_sock_get_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                               uint8_t *ttl_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(ttl_s, sizeof(uint8_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_ip_multicast_ttl(curfds, fd, ttl_s);
+}
+
+static wasi_errno_t
+wasi_sock_get_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                        bool *is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(is_enabled, sizeof(bool)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_get_ipv6_only(curfds, fd, is_enabled);
+}
+
 static wasi_errno_t
 wasi_sock_listen(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 backlog)
 {
@@ -1216,10 +1495,65 @@ wasi_sock_open(wasm_exec_env_t exec_env, wasi_fd_t poolfd,
 }
 
 static wasi_errno_t
-wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
-                            wasi_size_t size)
+wasi_sock_set_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_broadcast(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_keep_alive(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled,
+                     int linger_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_linger(curfds, fd, is_enabled, linger_s);
+}
+
+static wasi_errno_t
+wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_recv_buf_size(curfds, fd, size);
 }
 
 static wasi_errno_t
@@ -1239,22 +1573,50 @@ wasi_sock_set_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd,
 }
 
 static wasi_errno_t
-wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse)
+wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool is_enabled)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_reuse_addr(curfds, fd, is_enabled);
 }
 
 static wasi_errno_t
-wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8 reuse)
+wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                         bool is_enabled)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_reuse_port(curfds, fd, is_enabled);
 }
 
 static wasi_errno_t
-wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd,
-                            wasi_size_t size)
+wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size)
 {
-    return __WASI_ENOSYS;
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_send_buf_size(curfds, fd, size);
 }
 
 static wasi_errno_t
@@ -1273,6 +1635,191 @@ wasi_sock_set_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd,
     return wasmtime_ssp_sock_set_send_timeout(curfds, fd, timeout_us);
 }
 
+static wasi_errno_t
+wasi_sock_set_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                   bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_tcp_fastopen_connect(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                           bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_tcp_no_delay(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_tcp_quick_ack(curfds, fd, is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                            uint32_t time_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_tcp_keep_idle(curfds, fd, time_s);
+}
+
+static wasi_errno_t
+wasi_sock_set_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                             uint32_t time_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_tcp_keep_intvl(curfds, fd, time_s);
+}
+
+static wasi_errno_t
+wasi_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                bool ipv6, bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ip_multicast_loop(curfds, fd, ipv6,
+                                                   is_enabled);
+}
+
+static wasi_errno_t
+wasi_sock_set_ip_add_membership(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                __wasi_addr_ip_t *imr_multiaddr,
+                                uint32_t imr_interface)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ip_add_membership(curfds, fd, imr_multiaddr,
+                                                   imr_interface);
+}
+
+static wasi_errno_t
+wasi_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                                 __wasi_addr_ip_t *imr_multiaddr,
+                                 uint32_t imr_interface)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t)))
+        return __WASI_EINVAL;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ip_drop_membership(curfds, fd, imr_multiaddr,
+                                                    imr_interface);
+}
+
+static wasi_errno_t
+wasi_sock_set_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t ttl_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ip_ttl(curfds, fd, ttl_s);
+}
+
+static wasi_errno_t
+wasi_sock_set_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd,
+                               uint8_t ttl_s)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ip_multicast_ttl(curfds, fd, ttl_s);
+}
+
+static wasi_errno_t
+wasi_sock_set_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled)
+{
+    wasm_module_inst_t module_inst = get_module_inst(exec_env);
+    wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
+    struct fd_table *curfds = NULL;
+
+    if (!wasi_ctx)
+        return __WASI_EACCES;
+
+    curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
+
+    return wasmtime_ssp_sock_set_ipv6_only(curfds, fd, is_enabled);
+}
+
 static wasi_errno_t
 allocate_iovec_app_buffer(wasm_module_inst_t module_inst,
                           const iovec_app_t *data, uint32 data_len,
@@ -1589,24 +2136,50 @@ static NativeSymbol native_symbols_libc_wasi[] = {
     REG_NATIVE_FUNC(sock_bind, "(i*)i"),
     REG_NATIVE_FUNC(sock_close, "(i)i"),
     REG_NATIVE_FUNC(sock_connect, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_broadcast, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_keep_alive, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_linger, "(i**)i"),
     REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"),
     REG_NATIVE_FUNC(sock_get_recv_timeout, "(i*)i"),
     REG_NATIVE_FUNC(sock_get_reuse_addr, "(i*)i"),
     REG_NATIVE_FUNC(sock_get_reuse_port, "(i*)i"),
     REG_NATIVE_FUNC(sock_get_send_buf_size, "(i*)i"),
     REG_NATIVE_FUNC(sock_get_send_timeout, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_tcp_fastopen_connect, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_tcp_keep_idle, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_tcp_keep_intvl, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_tcp_no_delay, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_tcp_quick_ack, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_ip_multicast_loop, "(ii*)i"),
+    REG_NATIVE_FUNC(sock_get_ip_multicast_ttl, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_ip_ttl, "(i*)i"),
+    REG_NATIVE_FUNC(sock_get_ipv6_only, "(i*)i"),
     REG_NATIVE_FUNC(sock_listen, "(ii)i"),
     REG_NATIVE_FUNC(sock_open, "(iii*)i"),
     REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"),
     REG_NATIVE_FUNC(sock_recv_from, "(i*ii**)i"),
     REG_NATIVE_FUNC(sock_send, "(i*ii*)i"),
     REG_NATIVE_FUNC(sock_send_to, "(i*ii**)i"),
+    REG_NATIVE_FUNC(sock_set_broadcast, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_keep_alive, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_linger, "(iii)i"),
     REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"),
     REG_NATIVE_FUNC(sock_set_recv_timeout, "(iI)i"),
     REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"),
     REG_NATIVE_FUNC(sock_set_reuse_port, "(ii)i"),
     REG_NATIVE_FUNC(sock_set_send_buf_size, "(ii)i"),
     REG_NATIVE_FUNC(sock_set_send_timeout, "(iI)i"),
+    REG_NATIVE_FUNC(sock_set_tcp_fastopen_connect, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_tcp_keep_idle, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_tcp_keep_intvl, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_tcp_no_delay, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_tcp_quick_ack, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_ip_multicast_loop, "(iii)i"),
+    REG_NATIVE_FUNC(sock_set_ip_multicast_ttl, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_ip_add_membership, "(i*i)i"),
+    REG_NATIVE_FUNC(sock_set_ip_drop_membership, "(i*i)i"),
+    REG_NATIVE_FUNC(sock_set_ip_ttl, "(ii)i"),
+    REG_NATIVE_FUNC(sock_set_ipv6_only, "(ii)i"),
     REG_NATIVE_FUNC(sock_shutdown, "(ii)i"),
     REG_NATIVE_FUNC(sched_yield, "()i"),
 };

+ 286 - 0
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h

@@ -18,6 +18,7 @@
 #ifndef WASMTIME_SSP_H
 #define WASMTIME_SSP_H
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -588,6 +589,14 @@ typedef struct __wasi_addr_ip6_port_t {
     __wasi_ip_port_t port;
 } __wasi_addr_ip6_port_t;
 
+typedef struct __wasi_addr_ip_t {
+    __wasi_addr_type_t kind;
+    union {
+        __wasi_addr_ip4_t ip4;
+        __wasi_addr_ip6_t ip6;
+    } addr;
+} __wasi_addr_ip_t;
+
 typedef struct __wasi_addr_t {
     __wasi_addr_type_t kind;
     union {
@@ -1144,6 +1153,283 @@ __wasi_errno_t wasmtime_ssp_sock_get_send_timeout(
     uint64_t *timeout_us
 ) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__));
 
+__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    size_t bufsiz
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    size_t *bufsiz
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    size_t bufsiz
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    size_t *bufsiz
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__));
+
+
+__wasi_errno_t wasmtime_ssp_sock_set_keep_alive(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_keep_alive(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_reuse_port(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_reuse_port(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_linger(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, 
+    bool is_enabled, 
+    int linger_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_linger(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, bool *is_enabled, int *linger_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_broadcast(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_broadcast(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint32_t time_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint32_t *time_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint32_t time_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint32_t *time_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool ipv6,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool ipv6,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    __wasi_addr_ip_t *imr_multiaddr,
+    uint32_t imr_interface
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    __wasi_addr_ip_t *imr_multiaddr,
+    uint32_t imr_interface
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint8_t ttl_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint8_t *ttl_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint8_t ttl_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    uint8_t *ttl_s
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool is_enabled
+) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__));
+
+__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock,
+    bool *is_enabled 
+) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__));
+
 __wasi_errno_t wasmtime_ssp_sched_yield(void)
     WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__));
 

+ 187 - 0
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -250,6 +250,7 @@ wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr,
     }
 }
 
+// Converts an IPv6 binary address object to WASI address object.
 static void
 bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr,
                          __wasi_addr_t *wasi_addr)
@@ -279,6 +280,26 @@ bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr,
     }
 }
 
+static void
+wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr,
+                                  bh_ip_addr_buffer_t *out)
+{
+    if (addr->kind == IPv4) {
+        out->ipv4 = htonl((addr->addr.ip4.n0 << 24) | (addr->addr.ip4.n1 << 16)
+                          | (addr->addr.ip4.n2 << 8) | addr->addr.ip4.n3);
+    }
+    else {
+        out->ipv6[0] = htons(addr->addr.ip6.n0);
+        out->ipv6[1] = htons(addr->addr.ip6.n1);
+        out->ipv6[2] = htons(addr->addr.ip6.n2);
+        out->ipv6[3] = htons(addr->addr.ip6.n3);
+        out->ipv6[4] = htons(addr->addr.ip6.h0);
+        out->ipv6[5] = htons(addr->addr.ip6.h1);
+        out->ipv6[6] = htons(addr->addr.ip6.h2);
+        out->ipv6[7] = htons(addr->addr.ip6.h3);
+    }
+}
+
 __wasi_errno_t
 wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id,
                            __wasi_timestamp_t *resolution)
@@ -3645,6 +3666,172 @@ WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_timeout, uint64)
 WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_timeout, uint64 *)
 WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_timeout, uint64)
 WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_timeout, uint64 *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_buf_size, size_t)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_buf_size, size_t *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_buf_size, size_t)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_buf_size, size_t *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_broadcast, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_broadcast, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_keep_alive, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_keep_alive, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_addr, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_addr, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_port, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_port, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_no_delay, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_no_delay, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_quick_ack, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_quick_ack, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_idle, uint32)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_idle, uint32 *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_intvl, uint32)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_intvl, uint32 *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_fastopen_connect, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_fastopen_connect, bool *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_ttl, uint8_t)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_ttl, uint8_t *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_multicast_ttl, uint8_t)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_multicast_ttl, uint8_t *)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ipv6_only, bool)
+WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ipv6_only, bool *)
 
 #undef WASMTIME_SSP_PASSTHROUGH_FD_TABLE
 #undef WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION
+
+__wasi_errno_t
+wasmtime_ssp_sock_set_linger(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, bool is_enabled, int linger_s)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_get_linger(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, bool *is_enabled, int *linger_s)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_set_ip_add_membership(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    bh_ip_addr_buffer_t addr_info;
+    bool is_ipv6;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info);
+    is_ipv6 = imr_multiaddr->kind == IPv6;
+    ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info,
+                                          imr_interface, is_ipv6);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_set_ip_drop_membership(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    bh_ip_addr_buffer_t addr_info;
+    bool is_ipv6;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info);
+    is_ipv6 = imr_multiaddr->kind == IPv6;
+    ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info,
+                                           imr_interface, is_ipv6);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_set_ip_multicast_loop(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, bool ipv6, bool is_enabled)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+    return __WASI_ESUCCESS;
+}
+
+__wasi_errno_t
+wasmtime_ssp_sock_get_ip_multicast_loop(
+#if !defined(WASMTIME_SSP_STATIC_CURFDS)
+    struct fd_table *curfds,
+#endif
+    __wasi_fd_t sock, bool ipv6, bool *is_enabled)
+{
+    struct fd_object *fo;
+    __wasi_errno_t error;
+    int ret;
+    error = fd_object_get(curfds, &fo, sock, 0, 0);
+    if (error != 0)
+        return error;
+
+    ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled);
+    fd_object_release(fo);
+    if (BHT_OK != ret)
+        return convert_errno(errno);
+
+    return __WASI_ESUCCESS;
+}

+ 481 - 0
core/shared/platform/common/posix/posix_socket.c

@@ -8,6 +8,8 @@
 
 #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)
@@ -400,6 +402,485 @@ os_socket_addr_resolve(const char *host, const char *service,
     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;
+    int 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)
+{
+    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);
+}
+
+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(time_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) {
+        return os_socket_setbooloption(socket, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_LOOP, is_enabled);
+    }
+    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) {
+        return os_socket_getbooloption(socket, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_LOOP, is_enabled);
+    }
+    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) {
+        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 {
+        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) {
+        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 {
+        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)
+{
+    return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
+                                   is_enabled);
+}
+
+int
+os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled)
+{
+    return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
+                                   is_enabled);
+}
+
+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)
 {

+ 402 - 0
core/shared/platform/include/platform_api_extension.h

@@ -531,6 +531,73 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr);
 int
 os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr);
 
+/**
+ * Set the maximum send buffer size.
+ *
+ * @param socket the socket to set
+ * @param bufsiz requested kernel buffer size
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz);
+
+/**
+ * Get the maximum send buffer size.
+ *
+ * @param socket the socket to set
+ * @param bufsiz the returned kernel buffer size
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz);
+
+/**
+ * Set the maximum receive buffer size.
+ *
+ * @param socket the socket to set
+ * @param bufsiz requested kernel buffer size
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz);
+
+/**
+ * Get the maximum receive buffer size.
+ *
+ * @param socket the socket to set
+ * @param bufsiz the returned kernel buffer size
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz);
+
+/**
+ * Enable sending of keep-alive messages on connection-oriented sockets
+ *
+ * @param socket the socket to set the flag
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get if sending of keep-alive messages on connection-oriented sockets is
+ * enabled
+ *
+ * @param socket the socket to check
+ * @param is_enabled 1 if enabled or 0 if disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled);
+
 /**
  * Set the send timeout until reporting an error
  *
@@ -575,6 +642,341 @@ os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us);
 int
 os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us);
 
+/**
+ * Enable re-use of local addresses
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get whether re-use of local addresses is enabled
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 for enabled or 0 for disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Enable re-use of local ports
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get whether re-use of local ports is enabled
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 for enabled or 0 for disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Set the linger options for the given socket
+ *
+ * @param socket the socket to set
+ * @param is_enabled whether linger is enabled
+ * @param linger_s linger time (seconds)
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s);
+
+/**
+ * Get the linger options for the given socket
+ *
+ * @param socket the socket to get
+ * @param is_enabled whether linger is enabled
+ * @param linger_s linger time (seconds)
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s);
+
+/**
+ * Set no delay TCP
+ * If set, disable the Nagle algorithm.
+ * This means that segments are always sent as soon as possible,
+ * even if there is only a small amount of data
+ *
+ * @param socket the socket to set the flag
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get no delay TCP
+ * If set, disable the Nagle algorithm.
+ * This means that segments are always sent as soon as possible,
+ * even if there is only a small amount of data
+ *
+ * @param socket the socket to check
+ * @param is_enabled 1 if enabled or 0 if disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Enable/Disable tcp quickack mode
+ * In quickack mode, acks are sent immediately, rather than delayed if needed in
+ * accordance to normal TCP operation
+ *
+ * @param socket the socket to set the flag
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Enable/Disable tcp quickack mode
+ * In quickack mode, acks are sent immediately, rather than delayed if needed in
+ * accordance to normal TCP operation
+ *
+ * @param socket the socket to check
+ * @param is_enabled 1 if enabled or 0 if disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Set the time the connection needs to remain idle before sending keepalive
+ * probes
+ *
+ * @param socket the socket to set
+ * @param time_s seconds until keepalive probes are sent
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32_t time_s);
+
+/**
+ * Gets the time the connection needs to remain idle before sending keepalive
+ * probes
+ *
+ * @param socket the socket to check
+ * @param time_s seconds until keepalive probes are sent
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32_t *time_s);
+
+/**
+ * Set the time between individual keepalive probes
+ *
+ * @param socket the socket to set
+ * @param time_us seconds between individual keepalive probes
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32_t time_s);
+
+/**
+ * Get the time between individual keepalive probes
+ *
+ * @param socket the socket to get
+ * @param time_s seconds between individual keepalive probes
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32_t *time_s);
+
+/**
+ * Set use of TCP Fast Open
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get whether use of TCP Fast Open is enabled
+ *
+ * @param socket the socket to get
+ * @param is_enabled 1 to enabled or 0 to disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Set enable or disable IPv4 or IPv6 multicast loopback.
+ *
+ * @param socket the socket to set
+ * @param ipv6 true to set ipv6 loopback or false for ipv4
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled);
+
+/**
+ * Get enable or disable IPv4 or IPv6 multicast loopback.
+ *
+ * @param socket the socket to check
+ * @param ipv6 true to set ipv6 loopback or false for ipv4
+ * @param is_enabled 1 for enabled or 0 for disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6,
+                                bool *is_enabled);
+
+/**
+ * Add membership to a group
+ *
+ * @param socket the socket to add membership to
+ * @param imr_multiaddr the group multicast address (IPv4 or IPv6)
+ * @param imr_interface the interface to join on
+ * @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+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);
+
+/**
+ * Drop membership of a group
+ *
+ * @param socket the socket to drop membership to
+ * @param imr_multiaddr the group multicast address (IPv4 or IPv6)
+ * @param imr_interface the interface to join on
+ * @param is_ipv6 whether the imr_multiaddr is IPv4 or IPv6 (true for IPv6)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+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);
+
+/**
+ * Set the current time-to-live field that is
+ * used in every packet sent from this socket.
+ * @param socket the socket to set the flag
+ * @param ttl_s time to live (seconds)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s);
+
+/**
+ * Retrieve the current time-to-live field that is
+ * used in every packet sent from this socket.
+ * @param socket the socket to set the flag
+ * @param ttl_s time to live (seconds)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s);
+
+/**
+ * Set the time-to-live value of outgoing multicast
+ * packets for this socket
+ * @param socket the socket to set the flag
+ * @param ttl_s time to live (seconds)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s);
+
+/**
+ * Read the time-to-live value of outgoing multicast
+ * packets for this socket
+ * @param socket the socket to set the flag
+ * @param ttl_s time to live (seconds)
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s);
+
+/**
+ * Restrict to sending and receiving IPv6 packets only
+ *
+ * @param socket the socket to set
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get whether only sending and receiving IPv6 packets
+ *
+ * @param socket the socket to check
+ * @param is_enabled 1 for enabled or 0 for disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled);
+
+/**
+ * Set whether broadcast is enabled
+ * When enabled, datagram sockets are allowed
+ * to send packets to a broadcast address.
+ *
+ * @param socket the socket to set the flag
+ * @param is_enabled 1 to enable or 0 to disable
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_set_broadcast(bh_socket_t socket, bool is_enabled);
+
+/**
+ * Get whether broadcast is enabled
+ * When enabled, datagram sockets are allowed
+ * to send packets to a broadcast address.
+ *
+ * @param socket the socket to check
+ * @param is_enabled 1 if enabled or 0 if disabled
+ *
+ * @return 0 if success, -1 otherwise
+ */
+int
+os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled);
+
 #ifdef __cplusplus
 }
 #endif

+ 276 - 0
core/shared/platform/linux-sgx/sgx_socket.c

@@ -760,4 +760,280 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us)
     return BHT_ERROR;
 }
 
+int
+os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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;
+}
+
+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 time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ipv6_only(bh_socket_t socket, bool option)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ipv6_only(bh_socket_t socket, bool *option)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
 #endif

+ 1 - 1
core/shared/platform/linux-sgx/sgx_socket.h

@@ -46,7 +46,7 @@ extern "C" {
 #define SHUT_RDWR 2
 
 /* Address families.  */
-#define AF_INET 2 /* IP protocol family.  */
+#define AF_INET 2   /* IP protocol family.  */
 #define AF_INET6 10 /* IP version 6.  */
 
 /* Standard well-defined IP protocols.  */

+ 276 - 1
core/shared/platform/windows/win_socket.c

@@ -263,4 +263,279 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr)
     errno = ENOSYS;
 
     return BHT_ERROR;
-}
+}
+
+int
+os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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;
+}
+
+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 time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+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)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_ipv6_only(bh_socket_t socket, bool option)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_ipv6_only(bh_socket_t socket, bool *option)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_set_broadcast(bh_socket_t socket, bool is_enabled)
+{
+    errno = ENOSYS;
+
+    return BHT_ERROR;
+}
+
+int
+os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled)
+{
+    errno = ENOSYS;
+    return BHT_ERROR;
+}

+ 8 - 5
samples/socket-api/README.md

@@ -87,12 +87,15 @@ Data:
 $ ./iwasm ./socket_opts.wasm
 ```
 
-The output is:
+The output describes the different socket options that are set & retrieved, like so:
 ```bash
-[Client] Create socket
-recv_timeout is expected
-send_timeout is expected
-[Client] Close socket
+[Client] Create TCP socket
+[Client] Create UDP socket
+[Client] Create UDP IPv6 socket
+SO_RCVTIMEO tv_sec is expected
+SO_RCVTIMEO tv_usec is expected
+...
+[Client] Close sockets
 ```
 
 Refer to [socket api document](../../doc/socket_api.md) for more details.

+ 217 - 11
samples/socket-api/wasm-src/socket_opts.c

@@ -1,3 +1,7 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/tcp.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
@@ -12,6 +16,7 @@
     }                                         \
     else {                                    \
         printf("%s is unexpected\n", OPTION); \
+        perror("assertion failed");           \
         return EXIT_FAILURE;                  \
     }
 
@@ -22,35 +27,236 @@ to_timeval(time_t tv_sec, suseconds_t tv_usec)
     return tv;
 }
 
+int
+set_and_get_bool_opt(int socket_fd, int level, int optname, int val)
+{
+    int bool_opt = val;
+    socklen_t opt_len = sizeof(bool_opt);
+    setsockopt(socket_fd, level, optname, &bool_opt, sizeof(bool_opt));
+    bool_opt = !bool_opt;
+    getsockopt(socket_fd, level, optname, &bool_opt, &opt_len);
+    return bool_opt;
+}
+
 int
 main(int argc, char *argv[])
 {
-    int socket_fd = 0;
+    int tcp_socket_fd = 0;
+    int udp_socket_fd = 0;
+    int udp_ipv6_socket_fd = 0;
     struct timeval tv;
-    socklen_t tv_len = sizeof(tv);
+    socklen_t opt_len;
+    int buf_len;
+    int result;
+    struct linger linger_opt;
+    uint32_t time_s;
+    struct ip_mreq mcast;
+    struct ipv6_mreq mcast_ipv6;
+    unsigned char ttl;
 
-    printf("[Client] Create socket\n");
-    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
-    if (socket_fd == -1) {
+    printf("[Client] Create TCP socket\n");
+    tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (tcp_socket_fd == -1) {
         perror("Create socket failed");
         return EXIT_FAILURE;
     }
 
+    printf("[Client] Create UDP socket\n");
+    udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (udp_socket_fd == -1) {
+        perror("Create socket failed");
+        return EXIT_FAILURE;
+    }
+
+    printf("[Client] Create UDP IPv6 socket\n");
+    udp_ipv6_socket_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (udp_ipv6_socket_fd == -1) {
+        perror("Create socket failed");
+        return EXIT_FAILURE;
+    }
+
+    // SO_RCVTIMEO
     tv = to_timeval(123, 1000);
-    setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
     tv = to_timeval(0, 0);
-    getsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &tv_len);
+    opt_len = sizeof(tv);
+    getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &opt_len);
     OPTION_ASSERT(tv.tv_sec, 123, "SO_RCVTIMEO tv_sec");
     OPTION_ASSERT(tv.tv_usec, 1000, "SO_RCVTIMEO tv_usec");
 
+    // SO_SNDTIMEO
     tv = to_timeval(456, 2000);
-    setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+    setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
     tv = to_timeval(0, 0);
-    getsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &tv_len);
+    opt_len = sizeof(tv);
+    getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &opt_len);
     OPTION_ASSERT(tv.tv_sec, 456, "SO_SNDTIMEO tv_sec");
     OPTION_ASSERT(tv.tv_usec, 2000, "SO_SNDTIMEO tv_usec");
 
-    printf("[Client] Close socket\n");
-    close(socket_fd);
+    // SO_SNDBUF
+    buf_len = 8192;
+    setsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, sizeof(buf_len));
+    buf_len = 0;
+    opt_len = sizeof(buf_len);
+    getsockopt(tcp_socket_fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &opt_len);
+    OPTION_ASSERT(buf_len, 16384, "SO_SNDBUF buf_len");
+
+    // SO_RCVBUF
+    buf_len = 4096;
+    setsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, sizeof(buf_len));
+    buf_len = 0;
+    opt_len = sizeof(buf_len);
+    getsockopt(tcp_socket_fd, SOL_SOCKET, SO_RCVBUF, &buf_len, &opt_len);
+    OPTION_ASSERT(buf_len, 8192, "SO_RCVBUF buf_len");
+
+    // SO_KEEPALIVE
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 1), 1,
+        "SO_KEEPALIVE enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_KEEPALIVE, 0), 0,
+        "SO_KEEPALIVE disabled");
+
+    // SO_REUSEADDR
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 1), 1,
+        "SO_REUSEADDR enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEADDR, 0), 0,
+        "SO_REUSEADDR disabled");
+
+    // SO_REUSEPORT
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 1), 1,
+        "SO_REUSEPORT enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, SOL_SOCKET, SO_REUSEPORT, 0), 0,
+        "SO_REUSEPORT disabled");
+
+    // SO_LINGER
+    linger_opt.l_onoff = 1;
+    linger_opt.l_linger = 10;
+    setsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt,
+               sizeof(linger_opt));
+    linger_opt.l_onoff = 0;
+    linger_opt.l_linger = 0;
+    opt_len = sizeof(linger_opt);
+    getsockopt(tcp_socket_fd, SOL_SOCKET, SO_LINGER, &linger_opt, &opt_len);
+    OPTION_ASSERT(linger_opt.l_onoff, 1, "SO_LINGER l_onoff");
+    OPTION_ASSERT(linger_opt.l_linger, 10, "SO_LINGER l_linger");
+
+    // SO_BROADCAST
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 1), 1,
+        "SO_BROADCAST enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_socket_fd, SOL_SOCKET, SO_BROADCAST, 0), 0,
+        "SO_BROADCAST disabled");
+
+    // TCP_KEEPIDLE
+    time_s = 16;
+    setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s,
+               sizeof(time_s));
+    time_s = 0;
+    opt_len = sizeof(time_s);
+    getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &time_s, &opt_len);
+    OPTION_ASSERT(time_s, 16, "TCP_KEEPIDLE");
+
+    // TCP_KEEPINTVL
+    time_s = 8;
+    setsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s,
+               sizeof(time_s));
+    time_s = 0;
+    opt_len = sizeof(time_s);
+    getsockopt(tcp_socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &time_s, &opt_len);
+    OPTION_ASSERT(time_s, 8, "TCP_KEEPINTVL");
+
+    // TCP_FASTOPEN_CONNECT
+    OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
+                                       TCP_FASTOPEN_CONNECT, 1),
+                  1, "TCP_FASTOPEN_CONNECT enabled");
+    OPTION_ASSERT(set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP,
+                                       TCP_FASTOPEN_CONNECT, 0),
+                  0, "TCP_FASTOPEN_CONNECT disabled");
+
+    // TCP_NODELAY
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 1), 1,
+        "TCP_NODELAY enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_NODELAY, 0), 0,
+        "TCP_NODELAY disabled");
+
+    // TCP_QUICKACK
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 1), 1,
+        "TCP_QUICKACK enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(tcp_socket_fd, IPPROTO_TCP, TCP_QUICKACK, 0), 0,
+        "TCP_QUICKACK disabled");
+
+    // IP_TTL
+    ttl = 8;
+    setsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+    ttl = 0;
+    opt_len = sizeof(ttl);
+    getsockopt(tcp_socket_fd, IPPROTO_IP, IP_TTL, &ttl, &opt_len);
+    OPTION_ASSERT(ttl, 8, "IP_TTL");
+
+    // IPV6_V6ONLY
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1),
+        1, "IPV6_V6ONLY enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, 0),
+        0, "IPV6_V6ONLY disabled");
+
+    // IP_MULTICAST_LOOP
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1),
+        1, "IP_MULTICAST_LOOP enabled");
+    OPTION_ASSERT(
+        set_and_get_bool_opt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 0),
+        0, "IP_MULTICAST_LOOP disabled");
+
+    // IP_ADD_MEMBERSHIP
+    mcast.imr_multiaddr.s_addr = 16777440;
+    mcast.imr_interface.s_addr = htonl(INADDR_ANY);
+    result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast,
+                        sizeof(mcast));
+    OPTION_ASSERT(result, 0, "IP_ADD_MEMBERSHIP");
+
+    // IP_DROP_MEMBERSHIP
+    result = setsockopt(udp_socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcast,
+                        sizeof(mcast));
+    OPTION_ASSERT(result, 0, "IP_DROP_MEMBERSHIP");
+
+    // IP_MULTICAST_TTL
+    ttl = 8;
+    setsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+    ttl = 0;
+    opt_len = sizeof(ttl);
+    getsockopt(udp_socket_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &opt_len);
+    OPTION_ASSERT(ttl, 8, "IP_MULTICAST_TTL");
+
+    // IPV6_MULTICAST_LOOP
+    OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_LOOP, 1),
+                  1, "IPV6_MULTICAST_LOOP enabled");
+    OPTION_ASSERT(set_and_get_bool_opt(udp_ipv6_socket_fd, IPPROTO_IPV6,
+                                       IPV6_MULTICAST_LOOP, 0),
+                  0, "IPV6_MULTICAST_LOOP disabled");
+
+    // IPV6_JOIN_GROUP
+    setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mcast_ipv6,
+               sizeof(mcast_ipv6));
+
+    // IPV6_LEAVE_GROUP
+    setsockopt(udp_ipv6_socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mcast_ipv6,
+               sizeof(mcast_ipv6));
+
+    printf("[Client] Close sockets\n");
+    close(tcp_socket_fd);
+    close(udp_socket_fd);
     return EXIT_SUCCESS;
 }