tests: net: socket: tcp: Add test for big block data transfer

A reproducible case to see what happens when the TCP stack runs out
of buffers. It transfers a block, bigger then the number of buffers
available.
Also test by introducing packet loss in the loopback driver.

Signed-off-by: Sjors Hettinga <s.a.hettinga@gmail.com>
This commit is contained in:
Sjors Hettinga 2022-04-01 09:40:33 +02:00 committed by Maureen Helm
commit 3b03344a8d
3 changed files with 140 additions and 1 deletions

View file

@ -16,6 +16,7 @@ CONFIG_POSIX_MAX_FDS=20
# Network driver config
CONFIG_NET_DRIVERS=y
CONFIG_NET_LOOPBACK=y
CONFIG_NET_LOOPBACK_SIMULATE_PACKET_DROP=y
CONFIG_TEST_RANDOM_GENERATOR=y
# Network address config

View file

@ -10,6 +10,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL);
#include <ztest_assert.h>
#include <fcntl.h>
#include <net/socket.h>
#include <net/loopback.h>
#include "../../socket_helpers.h"
@ -234,6 +235,139 @@ void test_v6_send_recv(void)
k_sleep(TCP_TEARDOWN_TIMEOUT);
}
/* Test the stack behavior with a resonable sized block data, be sure to have multiple packets */
#define TEST_LARGE_TRANSFER_SIZE 60000
#define TEST_PRIME 811
#define TCP_SERVER_STACK_SIZE 2048
K_THREAD_STACK_DEFINE(tcp_server_stack_area, TCP_SERVER_STACK_SIZE);
struct k_thread tcp_server_thread_data;
/* A thread that receives, while the other part transmits */
void tcp_server_block_thread(void *vps_sock, void *unused2, void *unused3)
{
int new_sock;
struct sockaddr addr;
int *ps_sock = (int *)vps_sock;
socklen_t addrlen = sizeof(addr);
test_accept(*ps_sock, &new_sock, &addr, &addrlen);
zassert_equal(addrlen, sizeof(struct sockaddr_in), "wrong addrlen");
/* Check the received data */
ssize_t recved = 0;
ssize_t total_received = 0;
int iteration = 0;
uint8_t buffer[256];
while (total_received < TEST_LARGE_TRANSFER_SIZE) {
/* Compute the remaining contents */
size_t chunk_size = sizeof(buffer);
size_t remain = TEST_LARGE_TRANSFER_SIZE - total_received;
if (chunk_size > remain) {
chunk_size = remain;
}
recved = recv(new_sock, buffer, chunk_size, 0);
zassert(recved > 0, "received bigger then 0",
"Error receiving bytes %i bytes, got %i on top of %i in iteration %i, errno %i",
chunk_size, recved, total_received, iteration, errno);
/* Validate the contents */
for (int i = 0; i < recved; i++) {
int total_idx = i + total_received;
uint8_t expValue = (total_idx * TEST_PRIME) & 0xff;
zassert_equal(buffer[i], expValue, "Unexpected data at %i", total_idx);
}
total_received += recved;
iteration++;
}
test_close(new_sock);
}
void test_v4_send_recv_large(void)
{
int c_sock;
int s_sock;
struct sockaddr_in c_saddr;
struct sockaddr_in s_saddr;
prepare_sock_tcp_v4(CONFIG_NET_CONFIG_MY_IPV4_ADDR, ANY_PORT,
&c_sock, &c_saddr);
prepare_sock_tcp_v4(CONFIG_NET_CONFIG_MY_IPV4_ADDR, SERVER_PORT,
&s_sock, &s_saddr);
test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
test_listen(s_sock);
(void)k_thread_create(&tcp_server_thread_data, tcp_server_stack_area,
K_THREAD_STACK_SIZEOF(tcp_server_stack_area),
tcp_server_block_thread,
&s_sock, NULL, NULL,
k_thread_priority_get(k_current_get()), 0, K_NO_WAIT);
test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr));
/* send piece by piece */
ssize_t total_send = 0;
int iteration = 0;
uint8_t buffer[256];
while (total_send < TEST_LARGE_TRANSFER_SIZE) {
/* Fill the buffer with a known patern */
for (int i = 0; i < sizeof(buffer); i++) {
int total_idx = i + total_send;
buffer[i] = (total_idx * TEST_PRIME) & 0xff;
}
size_t chunk_size = sizeof(buffer);
size_t remain = TEST_LARGE_TRANSFER_SIZE - total_send;
if (chunk_size > remain) {
chunk_size = remain;
}
int send_bytes = send(c_sock, buffer, chunk_size, 0);
zassert(send_bytes > 0, "send_bytes bigger then 0",
"Error sending %i bytes on top of %i, got %i in iteration %i, errno %i",
chunk_size, total_send, send_bytes, iteration, errno);
total_send += send_bytes;
iteration++;
}
/* join the thread, to wait for the receiving part */
zassert_equal(k_thread_join(&tcp_server_thread_data, K_SECONDS(60)), 0,
"Not successfully wait for TCP thread to finish");
test_close(s_sock);
test_close(c_sock);
k_sleep(TCP_TEARDOWN_TIMEOUT);
}
/* Control the packet drop ratio at the loopback adapter 8 */
static void set_packet_loss_ratio(void)
{
/* drop one every 8 packets */
zassert_equal(loopback_set_packet_drop_ratio(0.125f), 0,
"Error setting packet drop rate");
}
static void restore_packet_loss_ratio(void)
{
/* no packet dropping any more */
zassert_equal(loopback_set_packet_drop_ratio(0.0f), 0,
"Error setting packet drop rate");
}
void test_v4_sendto_recvfrom(void)
{
int c_sock;
@ -1116,7 +1250,10 @@ void test_main(void)
ztest_unit_test(test_v6_so_rcvtimeo),
ztest_unit_test(test_v4_msg_waitall),
ztest_unit_test(test_v6_msg_waitall),
ztest_user_unit_test(test_socket_permission)
ztest_user_unit_test(test_socket_permission),
ztest_unit_test(test_v4_send_recv_large),
ztest_unit_test_setup_teardown(test_v4_send_recv_large,
set_packet_loss_ratio, restore_packet_loss_ratio)
);
ztest_run_test_suite(socket_tcp);

View file

@ -3,6 +3,7 @@ common:
min_ram: 32
tags: net socket userspace
filter: TOOLCHAIN_HAS_NEWLIB == 1
timeout: 120
tests:
net.socket.tcp:
extra_configs: