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:
parent
951983191b
commit
3b03344a8d
3 changed files with 140 additions and 1 deletions
|
@ -16,6 +16,7 @@ CONFIG_POSIX_MAX_FDS=20
|
||||||
# Network driver config
|
# Network driver config
|
||||||
CONFIG_NET_DRIVERS=y
|
CONFIG_NET_DRIVERS=y
|
||||||
CONFIG_NET_LOOPBACK=y
|
CONFIG_NET_LOOPBACK=y
|
||||||
|
CONFIG_NET_LOOPBACK_SIMULATE_PACKET_DROP=y
|
||||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||||
|
|
||||||
# Network address config
|
# Network address config
|
||||||
|
|
|
@ -10,6 +10,7 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL);
|
||||||
#include <ztest_assert.h>
|
#include <ztest_assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <net/socket.h>
|
#include <net/socket.h>
|
||||||
|
#include <net/loopback.h>
|
||||||
|
|
||||||
#include "../../socket_helpers.h"
|
#include "../../socket_helpers.h"
|
||||||
|
|
||||||
|
@ -234,6 +235,139 @@ void test_v6_send_recv(void)
|
||||||
k_sleep(TCP_TEARDOWN_TIMEOUT);
|
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)
|
void test_v4_sendto_recvfrom(void)
|
||||||
{
|
{
|
||||||
int c_sock;
|
int c_sock;
|
||||||
|
@ -1116,7 +1250,10 @@ void test_main(void)
|
||||||
ztest_unit_test(test_v6_so_rcvtimeo),
|
ztest_unit_test(test_v6_so_rcvtimeo),
|
||||||
ztest_unit_test(test_v4_msg_waitall),
|
ztest_unit_test(test_v4_msg_waitall),
|
||||||
ztest_unit_test(test_v6_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);
|
ztest_run_test_suite(socket_tcp);
|
||||||
|
|
|
@ -3,6 +3,7 @@ common:
|
||||||
min_ram: 32
|
min_ram: 32
|
||||||
tags: net socket userspace
|
tags: net socket userspace
|
||||||
filter: TOOLCHAIN_HAS_NEWLIB == 1
|
filter: TOOLCHAIN_HAS_NEWLIB == 1
|
||||||
|
timeout: 120
|
||||||
tests:
|
tests:
|
||||||
net.socket.tcp:
|
net.socket.tcp:
|
||||||
extra_configs:
|
extra_configs:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue