Skip to content

Commit 62a3cb0

Browse files
committed
Add a simple test for TCP sockets
Add two test programs, sockets-client.c and sockets-server.c, that are run by the test driver as separate executables (since without threads, this can't be written as a single test).
1 parent 7c616cb commit 62a3cb0

File tree

4 files changed

+174
-1
lines changed

4 files changed

+174
-1
lines changed

test/Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,15 @@ endif
153153
# Build up all the `*.wasm.o` object files; these are the same regardless of
154154
# whether we're building core modules or components.
155155
$(WASM_OBJS): $(INFRA_HEADERS)
156-
$(OBJDIR)/%.wasm.o: $(SRCDIR)/%.c $(DOWNLOADED) $(SYSROOT)
156+
157+
# Sockets tests only run under wasm32-wasip2
158+
ifneq ($(TARGET_TRIPLE), wasm32-wasip2)
159+
C_SOURCES := $(shell find $(SRCDIR) -name '*.c' | grep -v sockets)
160+
else
161+
C_SOURCES := $(shell find $(SRCDIR) -name '*.c')
162+
endif
163+
164+
$(OBJDIR)/%.wasm.o: $(C_SOURCES) $(DOWNLOADED) $(SYSROOT)
157165
@mkdir -p $(@D)
158166
$(CC) $(CFLAGS) $(shell scripts/add-flags.py CFLAGS $<) -c $< -o $@
159167

test/scripts/run-test.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,40 @@ ENGINE="${ENGINE:-wasmtime}"
1212
[ -n "$WASM" ] || (echo "missing WASM variable" && exit 1)
1313
[ -n "$DIR" ] || (echo "missing DIR variable" && exit 1)
1414

15+
# Run the client/server sockets test, which requires a client and server
16+
# running in separate processes
17+
run_sockets_test() {
18+
# Args are the same for client and server
19+
cd $DIR
20+
server_wasm=`echo $WASM | sed -e 's/client/server/g'`
21+
echo "$ENV $ENGINE $RUN $server_wasm $ARGS" > server_cmd.sh
22+
chmod +x server_cmd.sh
23+
# Start the server
24+
./server_cmd.sh &> server_output.log &
25+
PID=$!
26+
[ $? -ne -1 ] || (echo "Failed to start server $server_wasm" && exit 1)
27+
echo "$ENV $ENGINE $RUN $WASM $ARGS" > cmd.sh
28+
chmod +x cmd.sh
29+
# Allow time for the server to start
30+
sleep 1
31+
# Start the client
32+
./cmd.sh &> output.log
33+
test_result=$?
34+
# Server normally exits on its own, but kill it in case the test failed
35+
if [ ps -p $PID > /dev/null 2>&1 ]; then
36+
kill -9 $PID
37+
fi
38+
[ $test_result -eq 0 ] || echo "Test failed" >> output.log
39+
}
40+
41+
testname=$(basename $WASM)
42+
if [ $testname == "sockets-server.component.wasm" ]; then
43+
exit 0
44+
fi
45+
if [ $testname == "sockets-client.component.wasm" ]; then
46+
run_sockets_test
47+
exit $?
48+
fi
1549
cd $DIR
1650
mkdir -p fs
1751
echo "$ENV $ENGINE $RUN $WASM $ARGS" > cmd.sh

test/src/misc/sockets-client.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! add-flags.py(RUN): --wasi=inherit-network=y
2+
#include <errno.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
#include <netdb.h>
9+
#include <sys/socket.h>
10+
#include <netinet/in.h>
11+
#include <arpa/inet.h>
12+
#include "test.h"
13+
14+
#define TEST(c) do { \
15+
errno = 0; \
16+
if (!(c)) \
17+
t_error("%s failed (errno = %d)\n", #c, errno); \
18+
} while(0)
19+
20+
int BUFSIZE = 256;
21+
22+
// See sockets-server.c -- must be running already as a separate executable
23+
void test_tcp_client() {
24+
// Prepare server socket
25+
int server_port = 4001;
26+
27+
// Prepare client socket
28+
// Use blocking sockets
29+
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
30+
TEST(socket_fd != -1);
31+
32+
// Prepare sockaddr_in for client
33+
struct sockaddr_in sockaddr_in;
34+
sockaddr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
35+
sockaddr_in.sin_family = AF_INET;
36+
sockaddr_in.sin_port = htons(server_port);
37+
38+
// Connect from client
39+
char message[] = "There's gonna be a party when the wolf comes home";
40+
int len = strlen(message);
41+
char client_buffer[BUFSIZE];
42+
43+
TEST(connect(socket_fd, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) != -1);
44+
45+
// Client writes a message to server
46+
TEST(send(socket_fd, message, len, 0) == len);
47+
48+
// Client reads from server
49+
int32_t bytes_received = recv(socket_fd, client_buffer, len, 0);
50+
TEST(bytes_received == len);
51+
52+
// Message received should be the same as message sent
53+
TEST(strcmp(message, client_buffer) == 0);
54+
55+
// Shut down client
56+
close(socket_fd);
57+
}
58+
59+
int main(void)
60+
{
61+
test_tcp_client();
62+
63+
return t_status;
64+
}

test/src/misc/sockets-server.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! add-flags.py(RUN): --wasi=inherit-network=y
2+
#include <errno.h>
3+
#include <fcntl.h>
4+
#include <stdbool.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <unistd.h>
9+
#include <netdb.h>
10+
#include <sys/socket.h>
11+
#include <netinet/in.h>
12+
#include <arpa/inet.h>
13+
#include "test.h"
14+
15+
#define TEST(c) do { \
16+
errno = 0; \
17+
if (!(c)) \
18+
t_error("%s failed (errno = %d)\n", #c, errno); \
19+
} while(0)
20+
21+
int BUFSIZE = 256;
22+
23+
void run_tcp_server() {
24+
// Prepare server socket
25+
int server_port = 4001;
26+
// Use blocking sockets
27+
int server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
28+
29+
// Bind server to socket
30+
struct sockaddr_in server_address;
31+
server_address.sin_family = AF_INET;
32+
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
33+
server_address.sin_port = htons(server_port);
34+
TEST(bind(server_socket_fd, (struct sockaddr*)&server_address, sizeof(server_address)) != -1);
35+
36+
// Listen on socket
37+
char buffer[BUFSIZE];
38+
socklen_t client_len = sizeof(struct sockaddr_in);
39+
int client_socket_fd;
40+
struct sockaddr_in client_address;
41+
int32_t bytes_read = 0, total_bytes_read = 0;
42+
TEST(listen(server_socket_fd, 1) != -1);
43+
44+
// Server accepts connection
45+
client_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_address, &client_len);
46+
TEST(client_socket_fd != -1);
47+
48+
// Server waits for input and echoes message back to client
49+
// The server shuts down after the client closes the connection
50+
while ((bytes_read = recv(client_socket_fd, buffer, BUFSIZE, 0)) > 0) {
51+
total_bytes_read += bytes_read;
52+
// Echo back the data received from the client
53+
send(client_socket_fd, buffer, bytes_read, 0);
54+
}
55+
56+
TEST(total_bytes_read > 0);
57+
58+
close(client_socket_fd);
59+
close(server_socket_fd);
60+
}
61+
62+
int main()
63+
{
64+
run_tcp_server();
65+
66+
return t_status;
67+
}

0 commit comments

Comments
 (0)