tests: net: socket: tcp: Add test to validate obstructed close

When there is no response from the server, a client side close
is obstructed, it should terminate and clean the context. This
tests breaks the connection after the accept and validates
this behavior.

Signed-off-by: Sjors Hettinga <s.a.hettinga@gmail.com>
This commit is contained in:
Sjors Hettinga 2022-04-04 11:50:25 +02:00 committed by Carles Cufí
parent ae31773ddd
commit c3158804d4

View file

@ -771,6 +771,106 @@ void test_connect_timeout(void)
"net_context still in use");
}
#define TCP_CLOSE_FAILURE_TIMEOUT 60000
void test_close_obstructed(void)
{
/* Test if socket closing even when there is not communication
* possible any more
*/
uint32_t start_time, time_diff;
int count_before = 0, count_after = 0;
struct sockaddr_in c_saddr;
struct sockaddr_in s_saddr;
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
int c_sock;
int s_sock;
int new_sock;
int dropped_packets_before = 0;
int dropped_packets_after = 0;
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);
zassert_equal(connect(c_sock, (struct sockaddr *)&s_saddr,
sizeof(s_saddr)),
0, "connect not succeed");
test_accept(s_sock, &new_sock, &addr, &addrlen);
/* We should have two contexts open now */
net_context_foreach(calc_net_context, &count_before);
/* Break the communication */
loopback_set_packet_drop_ratio(1.0f);
dropped_packets_before = loopback_get_num_dropped_packets();
test_close(c_sock);
start_time = k_uptime_get_32();
/* After the client socket closing, the context count should be 1 less */
net_context_foreach(calc_net_context, &count_after);
time_diff = k_uptime_get_32() - start_time;
/* Eventually the client socket should be cleaned up */
while ((count_before == count_after) && (time_diff < TCP_CLOSE_FAILURE_TIMEOUT)) {
count_after = 0;
net_context_foreach(calc_net_context, &count_after);
k_sleep(K_MSEC(50));
time_diff = k_uptime_get_32() - start_time;
}
zassert_equal(count_before - 1, count_after,
"net_context still in use (before %d vs after %d)",
count_before - 1, count_after);
dropped_packets_after = loopback_get_num_dropped_packets();
int dropped_packets = dropped_packets_after - dropped_packets_before;
/* At least some packet should have been dropped */
zassert_equal(dropped_packets,
CONFIG_NET_TCP_RETRY_COUNT + 1,
"Incorrect number of FIN retries, got %i, expected %i",
dropped_packets, CONFIG_NET_TCP_RETRY_COUNT+1);
test_close(new_sock);
test_close(s_sock);
start_time = k_uptime_get_32();
k_sleep(TCP_TEARDOWN_TIMEOUT);
/* After the client socket closing, the context count should be 0 */
count_after = 0;
net_context_foreach(calc_net_context, &count_after);
/* Eventually the client socket should be cleaned up */
while ((count_after > 0) && (time_diff < TCP_CLOSE_FAILURE_TIMEOUT)) {
count_after = 0;
net_context_foreach(calc_net_context, &count_after);
k_sleep(K_MSEC(50));
time_diff = k_uptime_get_32() - start_time;
}
zassert_equal(count_after, 0, "net_context still in use");
/* After everything is closed, we expect no more dropped packets */
dropped_packets_before = loopback_get_num_dropped_packets();
k_sleep(K_SECONDS(2));
dropped_packets_after = loopback_get_num_dropped_packets();
zassert_equal(dropped_packets_before, dropped_packets_after,
"packets after close");
}
void test_v4_accept_timeout(void)
{
/* Test if accept() will timeout properly */
@ -1336,6 +1436,8 @@ void test_main(void)
ztest_unit_test(test_open_close_immediately),
ztest_unit_test_setup_teardown(test_connect_timeout,
restore_packet_loss_ratio, restore_packet_loss_ratio),
ztest_unit_test_setup_teardown(test_close_obstructed,
restore_packet_loss_ratio, restore_packet_loss_ratio),
ztest_user_unit_test(test_v4_accept_timeout),
ztest_unit_test(test_so_type),
ztest_unit_test(test_so_protocol),