Przeglądaj źródła

Fix `bind()` calls to receive the correct size of `sockaddr` structure (#1490)

For some implementations (e.g. Mac OS) `bind()` requires the length to be exactly
equal to either `sockaddr_in` or `sockaddr_in6` structure. Because we always used
 `sizeof(struct sockaddr_storage)`, `bind()` was returning errors. In this change we
 fix the behavior. See StackOverflow [1] for details.

[1] https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos
Marcin Kolny 3 lat temu
rodzic
commit
f96773410a

+ 13 - 8
core/shared/platform/common/posix/posix_socket.c

@@ -12,7 +12,8 @@
 #include <netinet/in.h>
 
 static bool
-textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out)
+textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out,
+                         socklen_t *out_len)
 {
     struct sockaddr_in *v4;
     struct sockaddr_in6 *v6;
@@ -23,6 +24,7 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out)
     if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
         v4->sin_family = AF_INET;
         v4->sin_port = htons(port);
+        *out_len = sizeof(struct sockaddr_in);
         return true;
     }
 
@@ -30,6 +32,7 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out)
     if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) {
         v6->sin6_family = AF_INET6;
         v6->sin6_port = htons(port);
+        *out_len = sizeof(struct sockaddr_in6);
         return true;
     }
 
@@ -129,7 +132,7 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
 int
 os_socket_bind(bh_socket_t socket, const char *host, int *port)
 {
-    struct sockaddr_storage addr;
+    struct sockaddr_storage addr = { 0 };
     struct linger ling;
     socklen_t socklen;
     int ret;
@@ -150,11 +153,12 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
         goto fail;
     }
 
-    if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr)) {
+    if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr,
+                                  &socklen)) {
         goto fail;
     }
 
-    ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr));
+    ret = bind(socket, (struct sockaddr *)&addr, socklen);
     if (ret < 0) {
         goto fail;
     }
@@ -220,10 +224,11 @@ int
 os_socket_connect(bh_socket_t socket, const char *addr, int port)
 {
     struct sockaddr_storage addr_in = { 0 };
-    socklen_t addr_len = sizeof(struct sockaddr_storage);
+    socklen_t addr_len;
     int ret = 0;
 
-    if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in)) {
+    if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in,
+                                  &addr_len)) {
         return BHT_ERROR;
     }
 
@@ -245,7 +250,7 @@ int
 os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags,
                     bh_sockaddr_t *src_addr)
 {
-    struct sockaddr_storage sock_addr = {};
+    struct sockaddr_storage sock_addr = { 0 };
     socklen_t socklen = sizeof(sock_addr);
     int ret;
 
@@ -274,7 +279,7 @@ int
 os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len,
                   int flags, const bh_sockaddr_t *dest_addr)
 {
-    struct sockaddr_storage sock_addr = {};
+    struct sockaddr_storage sock_addr = { 0 };
     socklen_t socklen = 0;
 
     bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen);

+ 3 - 3
samples/socket-api/wasm-src/tcp_client.c

@@ -45,10 +45,12 @@ main(int argc, char *argv[])
 
     if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
         af = AF_INET6;
+        len = sizeof(struct sockaddr_in6);
         init_sockaddr_inet6((struct sockaddr_in6 *)&server_address);
     }
     else {
         af = AF_INET;
+        len = sizeof(struct sockaddr_in);
         init_sockaddr_inet((struct sockaddr_in *)&server_address);
     }
 
@@ -60,9 +62,7 @@ main(int argc, char *argv[])
     }
 
     printf("[Client] Connect socket\n");
-    if (connect(socket_fd, (struct sockaddr *)&server_address,
-                sizeof(server_address))
-        == -1) {
+    if (connect(socket_fd, (struct sockaddr *)&server_address, len) == -1) {
         perror("Connect failed");
         close(socket_fd);
         return EXIT_FAILURE;

+ 3 - 1
samples/socket-api/wasm-src/tcp_server.c

@@ -73,10 +73,12 @@ main(int argc, char *argv[])
 
     if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
         af = AF_INET6;
+        addrlen = sizeof(struct sockaddr_in6);
         init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
     }
     else {
         af = AF_INET;
+        addrlen = sizeof(struct sockaddr_in6);
         init_sockaddr_inet((struct sockaddr_in *)&addr);
     }
 
@@ -88,7 +90,6 @@ main(int argc, char *argv[])
     }
 
     printf("[Server] Bind socket\n");
-    addrlen = sizeof(addr);
     if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
         perror("Bind failed");
         goto fail;
@@ -102,6 +103,7 @@ main(int argc, char *argv[])
 
     printf("[Server] Wait for clients to connect ..\n");
     while (connections < WORKER_NUM) {
+        addrlen = sizeof(struct sockaddr);
         client_sock_fds[connections] =
             accept(socket_fd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
         if (client_sock_fds[connections] < 0) {

+ 3 - 1
samples/socket-api/wasm-src/udp_server.c

@@ -48,10 +48,12 @@ main(int argc, char *argv[])
 
     if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
         af = AF_INET6;
+        addrlen = sizeof(struct sockaddr_in6);
         init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
     }
     else {
         af = AF_INET;
+        addrlen = sizeof(struct sockaddr_in);
         init_sockaddr_inet((struct sockaddr_in *)&addr);
     }
 
@@ -63,7 +65,6 @@ main(int argc, char *argv[])
     }
 
     printf("[Server] Bind socket\n");
-    addrlen = sizeof(addr);
     if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
         perror("Bind failed");
         goto fail;
@@ -71,6 +72,7 @@ main(int argc, char *argv[])
 
     printf("[Server] Wait for clients to connect ..\n");
     while (connections < MAX_CONNECTIONS_COUNT) {
+        addrlen = sizeof(addr);
         int ret = recvfrom(socket_fd, buffer, sizeof(buffer), 0,
                            (struct sockaddr *)&addr, &addrlen);
         if (ret < 0) {