tests: sockets: Add TCP test cases
- Test ipv4/ipv6 send() and recv().
- Test ipv4/ipv6 sendto() and recvfrom().
- Test ipv4/ipv6 sendto() and recvfrom() with NULL dest address.
Signed-off-by: Aska Wu <aska.wu@linaro.org>
diff --git a/tests/net/socket/tcp/Makefile b/tests/net/socket/tcp/Makefile
new file mode 100644
index 0000000..295b8c2
--- /dev/null
+++ b/tests/net/socket/tcp/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2017 Linaro Limited
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+BOARD ?= qemu_x86
+CONF_FILE ?= prj.conf
+
+include $(ZEPHYR_BASE)/Makefile.inc
+include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
diff --git a/tests/net/socket/tcp/prj.conf b/tests/net/socket/tcp/prj.conf
new file mode 100644
index 0000000..7ff6fb3
--- /dev/null
+++ b/tests/net/socket/tcp/prj.conf
@@ -0,0 +1,30 @@
+# General config
+CONFIG_NEWLIB_LIBC=y
+
+# Networking config
+CONFIG_NETWORKING=y
+CONFIG_NET_IPV4=y
+CONFIG_NET_IPV6=y
+CONFIG_NET_TCP=y
+CONFIG_NET_SOCKETS=y
+CONFIG_NET_SOCKETS_POSIX_NAMES=y
+
+# Network driver config
+CONFIG_TEST_RANDOM_GENERATOR=y
+
+# Network address config
+CONFIG_NET_APP_SETTINGS=y
+CONFIG_NET_APP_NEED_IPV4=y
+CONFIG_NET_APP_NEED_IPV6=y
+CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
+CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
+
+CONFIG_MAIN_STACK_SIZE=2048
+
+# Required:
+# Net pkt will be reused since src and dst address are the same.
+# It takes at least 3 tx pkt to establish TCP connection (syn/syn-ack/ack)
+CONFIG_NET_PKT_TX_COUNT=6
+
+CONFIG_ZTEST=y
+CONFIG_ZTEST_STACKSIZE=2048
diff --git a/tests/net/socket/tcp/src/Makefile b/tests/net/socket/tcp/src/Makefile
new file mode 100644
index 0000000..513cbee
--- /dev/null
+++ b/tests/net/socket/tcp/src/Makefile
@@ -0,0 +1,3 @@
+obj-y += main.o
+ccflags-y += -I${ZEPHYR_BASE}/tests/include
+ccflags-y += -I${ZEPHYR_BASE}/tests/ztest/include
diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c
new file mode 100644
index 0000000..13732bb
--- /dev/null
+++ b/tests/net/socket/tcp/src/main.c
@@ -0,0 +1,369 @@
+#include <ztest_assert.h>
+#include <net/socket.h>
+
+#define TEST_STR_SMALL "test"
+
+#define ANY_PORT 0
+#define SERVER_PORT 4242
+
+#define MAX_CONNS 5
+
+#define TCP_TEARDOWN_TIMEOUT K_SECONDS(1)
+
+static void prepare_sock_v4(const char *addr,
+ u16_t port,
+ int *sock,
+ struct sockaddr_in *sockaddr)
+{
+ int rv;
+
+ zassert_not_null(addr, "null addr");
+ zassert_not_null(sock, "null sock");
+ zassert_not_null(sockaddr, "null sockaddr");
+
+ *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ zassert_true(*sock >= 0, "socket open failed");
+
+ sockaddr->sin_family = AF_INET;
+ sockaddr->sin_port = htons(port);
+ rv = inet_pton(AF_INET, addr, &sockaddr->sin_addr);
+ zassert_equal(rv, 1, "inet_pton failed");
+}
+
+static void prepare_sock_v6(const char *addr,
+ u16_t port,
+ int *sock,
+ struct sockaddr_in6 *sockaddr)
+{
+ int rv;
+
+ zassert_not_null(addr, "null addr");
+ zassert_not_null(sock, "null sock");
+ zassert_not_null(sockaddr, "null sockaddr");
+
+ *sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ zassert_true(*sock >= 0, "socket open failed");
+
+ sockaddr->sin6_family = AF_INET6;
+ sockaddr->sin6_port = htons(port);
+ rv = inet_pton(AF_INET6, addr, &sockaddr->sin6_addr);
+ zassert_equal(rv, 1, "inet_pton failed");
+}
+
+static void test_bind(int sock, struct sockaddr *addr, socklen_t addrlen)
+{
+ zassert_equal(bind(sock, addr, addrlen),
+ 0,
+ "bind failed");
+}
+
+static void test_listen(int sock)
+{
+ zassert_equal(listen(sock, MAX_CONNS),
+ 0,
+ "listen failed");
+}
+
+static void test_connect(int sock, struct sockaddr *addr, socklen_t addrlen)
+{
+ zassert_equal(connect(sock, addr, addrlen),
+ 0,
+ "connect failed");
+}
+
+static void test_send(int sock, const void *buf, size_t len, int flags)
+{
+ zassert_equal(send(sock, buf, len, flags),
+ len,
+ "send failed");
+}
+
+static void test_sendto(int sock, const void *buf, size_t len, int flags,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ zassert_equal(sendto(sock, buf, len, flags, addr, addrlen),
+ len,
+ "send failed");
+}
+
+static int test_accept(int sock)
+{
+ int new_sock;
+ struct sockaddr addr;
+ socklen_t addrlen = sizeof(addr);
+
+ new_sock = accept(sock, &addr, &addrlen);
+ zassert_true(new_sock >= 0, "accept failed");
+ return new_sock;
+}
+
+static void test_recv(int sock)
+{
+ ssize_t recved = 0;
+ char rx_buf[30] = {0};
+
+ recved = recv(sock, rx_buf, sizeof(rx_buf), 0);
+ zassert_equal(recved,
+ strlen(TEST_STR_SMALL),
+ "unexpected received bytes");
+ zassert_equal(strncmp(rx_buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL)),
+ 0,
+ "unexpected data");
+}
+
+static void test_recvfrom(int sock,
+ struct sockaddr *addr,
+ socklen_t *addrlen)
+{
+ ssize_t recved = 0;
+ char rx_buf[30] = {0};
+
+ recved = recvfrom(sock,
+ rx_buf,
+ sizeof(rx_buf),
+ 0,
+ addr,
+ addrlen);
+ zassert_equal(recved,
+ strlen(TEST_STR_SMALL),
+ "unexpected received bytes");
+ zassert_equal(strncmp(rx_buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL)),
+ 0,
+ "unexpected data");
+}
+
+static void test_close(int sock)
+{
+ zassert_equal(close(sock),
+ 0,
+ "close failed");
+}
+
+void test_v4_send_recv(void)
+{
+ /* Test if send() and recv() work on a ipv4 stream socket. */
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in c_saddr;
+ struct sockaddr_in s_saddr;
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0);
+
+ new_sock = test_accept(s_sock);
+ test_recv(new_sock);
+
+ test_close(new_sock);
+ test_close(c_sock);
+ test_close(s_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_v6_send_recv(void)
+{
+ /* Test if send() and recv() work on a ipv6 stream socket. */
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in6 c_saddr;
+ struct sockaddr_in6 s_saddr;
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_send(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0);
+
+ new_sock = test_accept(s_sock);
+ test_recv(new_sock);
+
+ test_close(new_sock);
+ test_close(s_sock);
+ test_close(c_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_v4_sendto_recvfrom(void)
+{
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in c_saddr;
+ struct sockaddr_in s_saddr;
+ struct sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_sendto(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0,
+ (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+
+ new_sock = test_accept(s_sock);
+ test_recvfrom(new_sock, (struct sockaddr *)&addr, &addrlen);
+
+ test_close(new_sock);
+ test_close(s_sock);
+ test_close(c_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_v6_sendto_recvfrom(void)
+{
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in6 c_saddr;
+ struct sockaddr_in6 s_saddr;
+ struct sockaddr_in6 addr;
+ socklen_t addrlen = sizeof(addr);
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_sendto(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0,
+ (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+
+ new_sock = test_accept(s_sock);
+ test_recvfrom(new_sock, (struct sockaddr *)&addr, &addrlen);
+
+ test_close(new_sock);
+ test_close(s_sock);
+ test_close(c_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_v4_sendto_recvfrom_null_dest(void)
+{
+ /* For a stream socket, sendto() should ignore NULL dest address */
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in c_saddr;
+ struct sockaddr_in s_saddr;
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v4(CONFIG_NET_APP_MY_IPV4_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_sendto(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0,
+ (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+
+ new_sock = test_accept(s_sock);
+ test_recvfrom(new_sock, NULL, NULL);
+
+ test_close(new_sock);
+ test_close(s_sock);
+ test_close(c_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_v6_sendto_recvfrom_null_dest(void)
+{
+ /* For a stream socket, sendto() should ignore NULL dest address */
+ int c_sock;
+ int s_sock;
+ int new_sock;
+ struct sockaddr_in6 c_saddr;
+ struct sockaddr_in6 s_saddr;
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ ANY_PORT,
+ &c_sock,
+ &c_saddr);
+
+ prepare_sock_v6(CONFIG_NET_APP_MY_IPV6_ADDR,
+ SERVER_PORT,
+ &s_sock,
+ &s_saddr);
+
+ test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_listen(s_sock);
+
+ test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+ test_sendto(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL), 0,
+ (struct sockaddr *)&s_saddr, sizeof(s_saddr));
+
+ new_sock = test_accept(s_sock);
+ test_recvfrom(new_sock, NULL, NULL);
+
+ test_close(new_sock);
+ test_close(s_sock);
+ test_close(c_sock);
+
+ k_sleep(TCP_TEARDOWN_TIMEOUT);
+}
+
+void test_main(void)
+{
+ ztest_test_suite(socket_tcp,
+ ztest_unit_test(test_v4_send_recv),
+ ztest_unit_test(test_v6_send_recv),
+ ztest_unit_test(test_v4_sendto_recvfrom),
+ ztest_unit_test(test_v6_sendto_recvfrom),
+ ztest_unit_test(test_v4_sendto_recvfrom_null_dest),
+ ztest_unit_test(test_v6_sendto_recvfrom_null_dest));
+
+ ztest_run_test_suite(socket_tcp);
+}
diff --git a/tests/net/socket/tcp/testcase.yaml b/tests/net/socket/tcp/testcase.yaml
new file mode 100644
index 0000000..e8b360d
--- /dev/null
+++ b/tests/net/socket/tcp/testcase.yaml
@@ -0,0 +1,5 @@
+tests:
+ - test:
+ build_only: true
+ min_ram: 32
+ tags: net