33/// Copyright Amazon.com Inc. or its affiliates.
44/// SPDX-License-Identifier: MIT
55
6+ // ReSharper disable CppDFATimeOver
7+
68#include <udpard.c> // NOLINT(bugprone-suspicious-include)
79#include "helpers.h"
810#include <unity.h>
@@ -62,8 +64,8 @@ static bool transfer_payload_verify(udpard_rx_transfer_t* const transfer,
6264 const void * const payload ,
6365 const size_t payload_size_wire )
6466{
65- udpard_fragment_t * frag = transfer -> payload_head ;
66- size_t offset = 0 ;
67+ const udpard_fragment_t * frag = transfer -> payload_head ;
68+ size_t offset = 0 ;
6769 while (frag != NULL ) {
6870 if (frag -> offset != offset ) {
6971 return false;
@@ -2040,7 +2042,7 @@ static void on_ack_mandate(udpard_rx_t* const rx, udpard_rx_port_t* const port,
20402042}
20412043
20422044/// Tests the ORDERED reassembly mode (strictly increasing transfer-ID sequence).
2043- static void test_session_ordered (void )
2045+ static void test_rx_session_ordered (void )
20442046{
20452047 // Initialize the memory resources.
20462048 instrumented_allocator_t alloc_frag = { 0 };
@@ -2659,7 +2661,7 @@ static void test_session_ordered(void)
26592661 instrumented_allocator_reset (& alloc_payload );
26602662}
26612663
2662- static void test_session_unordered (void )
2664+ static void test_rx_session_unordered (void )
26632665{
26642666 // Initialize the memory resources.
26652667 instrumented_allocator_t alloc_frag = { 0 };
@@ -2863,6 +2865,36 @@ static void test_session_unordered(void)
28632865 TEST_ASSERT_EQUAL (4 , cb_result .message .count ); // duplicate rejected, count unchanged
28642866 TEST_ASSERT_EQUAL (0 , alloc_payload .allocated_fragments ); // payload was freed
28652867
2868+ // Populate all slots with stale in-progress transfers, then verify they are reclaimed on timeout.
2869+ meta .transfer_payload_size = 4 ;
2870+ meta .priority = udpard_prio_nominal ;
2871+ meta .flag_ack = false;
2872+ for (size_t i = 0 ; i < RX_SLOT_COUNT ; i ++ ) {
2873+ meta .transfer_id = 300 + i ;
2874+ now += 1 ;
2875+ rx_session_update (ses ,
2876+ & rx ,
2877+ now ,
2878+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1234 },
2879+ make_frame (meta , mem_payload , "OLD!" , 0 , 2 ),
2880+ del_payload ,
2881+ 0 );
2882+ }
2883+ TEST_ASSERT_EQUAL (RX_SLOT_COUNT , alloc_frag .allocated_fragments );
2884+ TEST_ASSERT_EQUAL (RX_SLOT_COUNT , alloc_payload .allocated_fragments );
2885+ now += SESSION_LIFETIME + 10 ;
2886+ meta .transfer_id = 400 ;
2887+ rx_session_update (ses ,
2888+ & rx ,
2889+ now ,
2890+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1234 },
2891+ make_frame (meta , mem_payload , "NEW!" , 0 , 2 ),
2892+ del_payload ,
2893+ 0 );
2894+ TEST_ASSERT_EQUAL (4 , cb_result .message .count );
2895+ TEST_ASSERT_EQUAL (1 , alloc_frag .allocated_fragments );
2896+ TEST_ASSERT_EQUAL (1 , alloc_payload .allocated_fragments );
2897+
28662898 // Verify session cleanup on timeout.
28672899 now += SESSION_LIFETIME ;
28682900 rx .p2p_port .invoked = false;
@@ -2881,7 +2913,7 @@ static void test_session_unordered(void)
28812913/// Tests ports in ORDERED, UNORDERED, and STATELESS modes.
28822914/// The UNORDERED port is the p2p_port in the rx instance; the other modes are tested on separate port instances.
28832915/// All transfers are single-frame transfers for simplicity, since we already have dedicated lower-level tests.
2884- static void test_port (void )
2916+ static void test_rx_port (void )
28852917{
28862918 // Initialize the memory resources.
28872919 instrumented_allocator_t alloc_frag = { 0 };
@@ -3257,7 +3289,7 @@ static void test_port(void)
32573289}
32583290
32593291/// Starts a few transfers on multiple ports, lets them expire, and ensures cleanup in udpard_rx_poll().
3260- static void test_port_timeouts (void )
3292+ static void test_rx_port_timeouts (void )
32613293{
32623294 instrumented_allocator_t alloc_frag = { 0 };
32633295 instrumented_allocator_new (& alloc_frag );
@@ -3421,6 +3453,99 @@ static void test_port_timeouts(void)
34213453 TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
34223454}
34233455
3456+ /// Ensures udpard_rx_free walks and clears all sessions across ports.
3457+ static void test_rx_free_loop (void )
3458+ {
3459+ instrumented_allocator_t alloc_frag = { 0 };
3460+ instrumented_allocator_new (& alloc_frag );
3461+ const udpard_mem_resource_t mem_frag = instrumented_allocator_make_resource (& alloc_frag );
3462+
3463+ instrumented_allocator_t alloc_session = { 0 };
3464+ instrumented_allocator_new (& alloc_session );
3465+ const udpard_mem_resource_t mem_session = instrumented_allocator_make_resource (& alloc_session );
3466+
3467+ instrumented_allocator_t alloc_payload = { 0 };
3468+ instrumented_allocator_new (& alloc_payload );
3469+ const udpard_mem_resource_t mem_payload = instrumented_allocator_make_resource (& alloc_payload );
3470+ const udpard_mem_deleter_t del_payload = instrumented_allocator_make_deleter (& alloc_payload );
3471+
3472+ const udpard_rx_memory_resources_t rx_mem = { .fragment = mem_frag , .session = mem_session };
3473+
3474+ udpard_rx_t rx ;
3475+ callback_result_t cb_result = { 0 };
3476+ TEST_ASSERT (udpard_rx_new (& rx , 0xCAFED00DCAFED00DULL , rx_mem , & on_message , & on_collision , & on_ack_mandate ));
3477+ rx .user = & cb_result ;
3478+
3479+ udpard_rx_port_t port_extra ;
3480+ const uint64_t topic_hash_extra = 0xDEADBEEFF00D1234ULL ;
3481+ TEST_ASSERT (udpard_rx_port_new (& port_extra , topic_hash_extra , 1000 , 5000 , rx_mem ));
3482+
3483+ udpard_us_t now = 0 ;
3484+
3485+ // Incomplete transfer on the p2p port.
3486+ {
3487+ const char * payload = "INCOMPLETE" ;
3488+ meta_t meta = { .priority = udpard_prio_slow ,
3489+ .flag_ack = false,
3490+ .transfer_payload_size = (uint32_t )strlen (payload ),
3491+ .transfer_id = 10 ,
3492+ .sender_uid = 0xAAAAULL ,
3493+ .topic_hash = rx .p2p_port .topic_hash };
3494+ const rx_frame_t frame = make_frame (meta , mem_payload , payload , 0 , 4 );
3495+ byte_t dgram [HEADER_SIZE_BYTES + 4 ];
3496+ header_serialize (dgram , meta , 0 , 0 , frame .base .crc );
3497+ memcpy (dgram + HEADER_SIZE_BYTES , payload , 4 );
3498+ mem_free (mem_payload , frame .base .origin .size , frame .base .origin .data );
3499+ void * push_payload = mem_payload .alloc (mem_payload .user , sizeof (dgram ));
3500+ memcpy (push_payload , dgram , sizeof (dgram ));
3501+ now += 1000 ;
3502+ TEST_ASSERT (udpard_rx_port_push (& rx ,
3503+ & rx .p2p_port ,
3504+ now ,
3505+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1234 },
3506+ (udpard_bytes_mut_t ){ .data = push_payload , .size = sizeof (dgram ) },
3507+ del_payload ,
3508+ 0 ));
3509+ }
3510+
3511+ // Incomplete transfer on the extra port.
3512+ {
3513+ const char * payload = "FRAGMENTS" ;
3514+ meta_t meta = { .priority = udpard_prio_fast ,
3515+ .flag_ack = false,
3516+ .transfer_payload_size = (uint32_t )strlen (payload ),
3517+ .transfer_id = 20 ,
3518+ .sender_uid = 0xBBBBULL ,
3519+ .topic_hash = topic_hash_extra };
3520+ const rx_frame_t frame = make_frame (meta , mem_payload , payload , 0 , 3 );
3521+ byte_t dgram [HEADER_SIZE_BYTES + 3 ];
3522+ header_serialize (dgram , meta , 0 , 0 , frame .base .crc );
3523+ memcpy (dgram + HEADER_SIZE_BYTES , payload , 3 );
3524+ mem_free (mem_payload , frame .base .origin .size , frame .base .origin .data );
3525+ void * push_payload = mem_payload .alloc (mem_payload .user , sizeof (dgram ));
3526+ memcpy (push_payload , dgram , sizeof (dgram ));
3527+ now += 1000 ;
3528+ TEST_ASSERT (udpard_rx_port_push (& rx ,
3529+ & port_extra ,
3530+ now ,
3531+ (udpard_udpip_ep_t ){ .ip = 0x0A000002 , .port = 0x5678 },
3532+ (udpard_bytes_mut_t ){ .data = push_payload , .size = sizeof (dgram ) },
3533+ del_payload ,
3534+ 1 ));
3535+ }
3536+
3537+ TEST_ASSERT (alloc_session .allocated_fragments >= 2 );
3538+ TEST_ASSERT (alloc_frag .allocated_fragments >= 2 );
3539+ udpard_rx_free (& rx );
3540+ TEST_ASSERT_EQUAL_size_t (0 , alloc_session .allocated_fragments );
3541+ TEST_ASSERT_EQUAL_size_t (0 , alloc_frag .allocated_fragments );
3542+ TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
3543+
3544+ instrumented_allocator_reset (& alloc_frag );
3545+ instrumented_allocator_reset (& alloc_session );
3546+ instrumented_allocator_reset (& alloc_payload );
3547+ }
3548+
34243549void setUp (void ) {}
34253550
34263551void tearDown (void ) {}
@@ -3439,11 +3564,13 @@ int main(void)
34393564
34403565 RUN_TEST (test_rx_slot_update );
34413566
3442- RUN_TEST (test_session_ordered );
3443- RUN_TEST (test_session_unordered );
3567+ RUN_TEST (test_rx_session_ordered );
3568+ RUN_TEST (test_rx_session_unordered );
3569+
3570+ RUN_TEST (test_rx_port );
3571+ RUN_TEST (test_rx_port_timeouts );
34443572
3445- RUN_TEST (test_port );
3446- RUN_TEST (test_port_timeouts );
3573+ RUN_TEST (test_rx_free_loop );
34473574
34483575 return UNITY_END ();
34493576}
0 commit comments