Skip to content

Commit 5ddc335

Browse files
authored
Add timeout send/recv and multicast client/server socket examples (#1519)
Add a couple of socket examples that can be used with WAMR: - The `timeout_client` and `timeout_server` examples demonstrate socket send and receive timeouts using the socket options - The `multicast_client` and `multicast_server` examples demonstrate receiving multicast packets in WASM And add several macro controls for `socket_opts` example.
1 parent e2a3f0f commit 5ddc335

File tree

9 files changed

+534
-39
lines changed

9 files changed

+534
-39
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -692,12 +692,12 @@ get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval,
692692
HANDLE_ERROR(error);
693693
return error;
694694
case IP_TTL:
695-
assert(*optlen == sizeof(uint8_t));
695+
assert(*optlen == sizeof(int));
696696
error = __wasi_sock_get_ip_ttl(sockfd, (uint8_t *)optval);
697697
HANDLE_ERROR(error);
698698
return error;
699699
case IP_MULTICAST_TTL:
700-
assert(*optlen == sizeof(uint8_t));
700+
assert(*optlen == sizeof(int));
701701
error = __wasi_sock_get_ip_multicast_ttl(sockfd, (uint8_t *)optval);
702702
HANDLE_ERROR(error);
703703
return error;
@@ -915,12 +915,12 @@ set_ipproto_ip_option(int sockfd, int optname, const void *optval,
915915
HANDLE_ERROR(error);
916916
return error;
917917
case IP_TTL:
918-
assert(optlen == sizeof(uint8_t));
918+
assert(optlen == sizeof(int));
919919
error = __wasi_sock_set_ip_ttl(sockfd, *(uint8_t *)optval);
920920
HANDLE_ERROR(error);
921921
return error;
922922
case IP_MULTICAST_TTL:
923-
assert(optlen == sizeof(uint8_t));
923+
assert(optlen == sizeof(int));
924924
error =
925925
__wasi_sock_set_ip_multicast_ttl(sockfd, *(uint8_t *)optval);
926926
HANDLE_ERROR(error);

samples/socket-api/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ ExternalProject_Add(wasm-app
9494
socket_opts.wasm ${CMAKE_BINARY_DIR}
9595
udp_client.wasm ${CMAKE_BINARY_DIR}
9696
udp_server.wasm ${CMAKE_BINARY_DIR}
97+
multicast_client.wasm ${CMAKE_BINARY_DIR}
98+
multicast_server.wasm ${CMAKE_BINARY_DIR}
99+
timeout_client.wasm ${CMAKE_BINARY_DIR}
100+
timeout_server.wasm ${CMAKE_BINARY_DIR}
97101
)
98102

99103
add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c)
@@ -112,6 +116,14 @@ add_executable(udp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_client.c)
112116

113117
add_executable(udp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/udp_server.c)
114118

119+
add_executable(multicast_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/multicast_client.c)
120+
121+
add_executable(multicast_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/multicast_server.c)
122+
123+
add_executable(timeout_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/timeout_client.c)
124+
125+
add_executable(timeout_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/timeout_server.c)
126+
115127
############################################
116128
## Build iwasm with wasi and pthread support
117129
############################################

samples/socket-api/README.md

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,73 @@ Data:
9393

9494
`socket_opts.wasm` shows an example of getting and setting various supported socket options
9595
```bash
96-
$ ./iwasm ./socket_opts.wasm
96+
$ ./iwasm socket_opts.wasm
9797
```
98-
99-
The output describes the different socket options that are set & retrieved, like so:
98+
The output is:
10099
```bash
101100
[Client] Create TCP socket
102101
[Client] Create UDP socket
103102
[Client] Create UDP IPv6 socket
104-
SO_RCVTIMEO tv_sec is expected
105-
SO_RCVTIMEO tv_usec is expected
103+
setsockopt SO_RCVTIMEO result is expected
104+
getsockopt SO_RCVTIMEO result is expected
106105
...
107106
[Client] Close sockets
108107
```
109108

109+
The `timeout_client.wasm` and `timeout_server.wasm` examples demonstrate socket send and receive timeouts using the socket options. Start the server, then start the client.
110+
111+
```bash
112+
$ ./iwasm --addr-pool=0.0.0.0/15 timeout_server.wasm
113+
```
114+
115+
The output is:
116+
117+
```bash
118+
Wait for client to connect
119+
Client connected, sleeping for 10s
120+
Shuting down
121+
```
122+
123+
```bash
124+
$ ./iwasm --addr-pool=127.0.0.1/15 --heap-size=10000000 timeout_client.wasm
125+
```
126+
127+
The output is:
128+
129+
```bash
130+
Waiting on recv, which should timeout
131+
Waiting on send, which should timeout
132+
Success. Closing socket
133+
```
134+
135+
The `multicast_client` and `multicast_server` examples demonstrate receiving multicast packets in WASM. Start the client and then the server with a multicast IP address and port.
136+
137+
```bash
138+
$ ./iwasm --addr-pool=0.0.0.0/0,::/0 multicast_client.wasm <Multicast IP> <Port>
139+
$ ./iwasm --addr-pool=0.0.0.0/0,::/0 multicast_client.wasm 224.0.0.1
140+
$ ./iwasm --addr-pool=0.0.0.0/0,::/0 multicast_client.wasm FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2
141+
```
142+
143+
The output should be
144+
145+
```bash
146+
Joined multicast group. Waiting for datagram...
147+
Reading datagram message...OK.
148+
The message from multicast server is: "Test message"
149+
```
150+
151+
```bash
152+
$ ./multicast_server <Multicast IP> <Port>
153+
$ ./multicast_server 224.0.0.1
154+
$ ./multicast_server FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2
155+
```
156+
157+
The output should be
158+
159+
```bash
160+
Datagram sent
161+
```
162+
110163
### Domain name server resolution
111164

112165
`addr_resolve.wasm` demonstrates the usage of resolving a domain name

samples/socket-api/wasm-src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,7 @@ compile_with_clang(addr_resolve.c)
8383
compile_with_clang(socket_opts.c)
8484
compile_with_clang(udp_client.c)
8585
compile_with_clang(udp_server.c)
86+
compile_with_clang(multicast_client.c)
87+
compile_with_clang(multicast_server.c)
88+
compile_with_clang(timeout_client.c)
89+
compile_with_clang(timeout_server.c)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include <arpa/inet.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
#include <sys/socket.h>
11+
#include <unistd.h>
12+
#ifdef __wasi__
13+
#include <wasi_socket_ext.h>
14+
#endif
15+
16+
static void
17+
init_sockaddr_inet(struct sockaddr_in *addr)
18+
{
19+
addr->sin_family = AF_INET;
20+
addr->sin_port = htons(1234);
21+
}
22+
23+
static void
24+
init_sockaddr_inet6(struct sockaddr_in6 *addr)
25+
{
26+
addr->sin6_family = AF_INET6;
27+
addr->sin6_port = htons(1234);
28+
}
29+
30+
static int
31+
get_ip_addr_type(char *addr, char *buf)
32+
{
33+
if (inet_pton(AF_INET6, addr, buf)) {
34+
return AF_INET6;
35+
}
36+
if (inet_pton(AF_INET, addr, buf)) {
37+
return AF_INET;
38+
}
39+
return -1;
40+
}
41+
42+
static int
43+
is_valid_addr_type(int addr_type)
44+
{
45+
return !(addr_type == -1
46+
|| (addr_type != AF_INET && addr_type != AF_INET6));
47+
}
48+
49+
int
50+
main(int argc, char *argv[])
51+
{
52+
struct ipv6_mreq ipv6_group;
53+
struct ip_mreq ipv4_group;
54+
int sd;
55+
int datalen;
56+
char databuf[1024];
57+
char multicast_addr_buffer[16];
58+
struct sockaddr_storage local_address = { 0 };
59+
int addr_type = -1;
60+
int read_result;
61+
int bool_opt = 1;
62+
63+
if (argc < 2) {
64+
printf("Usage is <Multicast IP>\n");
65+
return EXIT_FAILURE;
66+
}
67+
68+
addr_type = get_ip_addr_type(argv[1], multicast_addr_buffer);
69+
70+
if (!is_valid_addr_type(addr_type)) {
71+
printf("Not a valid ipv4 or ipv6 address\n");
72+
return EXIT_FAILURE;
73+
}
74+
75+
if ((sd = socket(addr_type, SOCK_DGRAM, 0)) == -1) {
76+
perror("Failed opening socket");
77+
return EXIT_FAILURE;
78+
}
79+
80+
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &bool_opt, sizeof(bool_opt))
81+
== -1) {
82+
perror("Failed setting SO_REUSEADDR");
83+
goto fail;
84+
}
85+
86+
if (addr_type == AF_INET) {
87+
init_sockaddr_inet((struct sockaddr_in *)&local_address);
88+
memcpy(&(ipv4_group.imr_multiaddr), multicast_addr_buffer, 4);
89+
ipv4_group.imr_interface.s_addr = htonl(INADDR_ANY);
90+
91+
if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipv4_group,
92+
sizeof(ipv4_group))
93+
== -1) {
94+
perror("Failed joining IPv4 multicast group");
95+
goto fail;
96+
}
97+
}
98+
else {
99+
init_sockaddr_inet6((struct sockaddr_in6 *)&local_address);
100+
memcpy(&(ipv6_group.ipv6mr_multiaddr), multicast_addr_buffer, 16);
101+
ipv6_group.ipv6mr_interface = 0;
102+
103+
if (setsockopt(sd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6_group,
104+
sizeof(ipv6_group))
105+
== -1) {
106+
perror("Failed joining IPv6 multicast group");
107+
goto fail;
108+
}
109+
}
110+
111+
if (bind(sd, (struct sockaddr *)&local_address, sizeof(local_address))
112+
== -1) {
113+
perror("Failed binding socket");
114+
goto fail;
115+
}
116+
117+
printf("Joined multicast group. Waiting for datagram...\n");
118+
119+
datalen = sizeof(databuf);
120+
read_result = read(sd, databuf, datalen);
121+
122+
if (read_result < 0) {
123+
perror("Failed binding socket");
124+
goto fail;
125+
}
126+
127+
printf("Reading datagram message...OK.\n");
128+
printf("The message from multicast server is: \"%s\"\n", databuf);
129+
close(sd);
130+
return EXIT_SUCCESS;
131+
132+
fail:
133+
close(sd);
134+
return EXIT_FAILURE;
135+
}

0 commit comments

Comments
 (0)