@@ -2904,6 +2904,101 @@ static void test_rx_session_unordered(void)
29042904 instrumented_allocator_reset (& alloc_payload );
29052905}
29062906
2907+ /// Ensure the reassembler can detect repeated transfers even after the window has moved past them.
2908+ static void test_rx_session_history (void )
2909+ {
2910+ instrumented_allocator_t alloc_frag = { 0 };
2911+ instrumented_allocator_new (& alloc_frag );
2912+ const udpard_mem_resource_t mem_frag = instrumented_allocator_make_resource (& alloc_frag );
2913+ instrumented_allocator_t alloc_session = { 0 };
2914+ instrumented_allocator_new (& alloc_session );
2915+ const udpard_mem_resource_t mem_session = instrumented_allocator_make_resource (& alloc_session );
2916+ instrumented_allocator_t alloc_payload = { 0 };
2917+ instrumented_allocator_new (& alloc_payload );
2918+ const udpard_mem_resource_t mem_payload = instrumented_allocator_make_resource (& alloc_payload );
2919+ const udpard_mem_deleter_t del_payload = instrumented_allocator_make_deleter (& alloc_payload );
2920+ const udpard_rx_mem_resources_t rx_mem = { .fragment = mem_frag , .session = mem_session };
2921+ udpard_rx_t rx ;
2922+ callback_result_t cb_result = { 0 };
2923+ TEST_ASSERT (udpard_rx_new (& rx , & on_message , & on_collision , & on_ack_mandate ));
2924+ rx .user = & cb_result ;
2925+ const uint64_t local_uid = 0xF00DCAFEF00DCAFEULL ;
2926+ udpard_rx_port_t port ;
2927+ TEST_ASSERT (udpard_rx_port_new (& port , local_uid , SIZE_MAX , UDPARD_RX_REORDERING_WINDOW_UNORDERED , rx_mem ));
2928+ udpard_us_t now = 0 ;
2929+ const uint64_t remote_uid = 0xFACEB00CFACEB00CULL ;
2930+ rx_session_factory_args_t fac_args = {
2931+ .owner = & port ,
2932+ .sessions_by_animation = & rx .list_session_by_animation ,
2933+ .remote_uid = remote_uid ,
2934+ .now = now ,
2935+ };
2936+ rx_session_t * const ses = (rx_session_t * )cavl2_find_or_insert (& port .index_session_by_remote_uid ,
2937+ & remote_uid ,
2938+ & cavl_compare_rx_session_by_remote_uid ,
2939+ & fac_args ,
2940+ & cavl_factory_rx_session_by_remote_uid );
2941+ TEST_ASSERT_NOT_NULL (ses );
2942+ meta_t meta = { .priority = udpard_prio_fast ,
2943+ .flag_ack = false,
2944+ .transfer_payload_size = 3 ,
2945+ .transfer_id = 10 ,
2946+ .sender_uid = remote_uid ,
2947+ .topic_hash = local_uid };
2948+ now += 1000 ;
2949+ rx_session_update (ses ,
2950+ & rx ,
2951+ now ,
2952+ (udpard_udpip_ep_t ){ .ip = 0x0A00000A , .port = 0x0A00 },
2953+ make_frame (meta , mem_payload , "old" , 0 , 3 ),
2954+ del_payload ,
2955+ 0 );
2956+ TEST_ASSERT_EQUAL (1 , cb_result .message .count );
2957+ TEST_ASSERT_EQUAL (10 , cb_result .message .history [0 ].transfer_id );
2958+ TEST_ASSERT_EQUAL (10 , ses -> history [0 ]);
2959+ TEST_ASSERT_EQUAL (1 , ses -> history_index );
2960+ const uint64_t jump_tid = 10 + RX_TRANSFER_ID_WINDOW_BITS + 5U ;
2961+ meta .transfer_id = jump_tid ;
2962+ meta .transfer_payload_size = 4 ;
2963+ now += 1000 ;
2964+ rx_session_update (ses ,
2965+ & rx ,
2966+ now ,
2967+ (udpard_udpip_ep_t ){ .ip = 0x0A00000B , .port = 0x0B00 },
2968+ make_frame (meta , mem_payload , "jump" , 0 , 4 ),
2969+ del_payload ,
2970+ 1 );
2971+ TEST_ASSERT_EQUAL (2 , cb_result .message .count );
2972+ TEST_ASSERT_EQUAL (jump_tid , cb_result .message .history [0 ].transfer_id );
2973+ TEST_ASSERT_EQUAL (jump_tid , ses -> history [1 ]);
2974+ TEST_ASSERT_FALSE (rx_transfer_id_window_contains (& ses -> window , 10 ));
2975+ meta .transfer_id = 10 ;
2976+ meta .transfer_payload_size = 3 ;
2977+ meta .flag_ack = true;
2978+ now += 1000 ;
2979+ rx_session_update (ses ,
2980+ & rx ,
2981+ now ,
2982+ (udpard_udpip_ep_t ){ .ip = 0x0A00000A , .port = 0x0A00 },
2983+ make_frame (meta , mem_payload , "dup" , 0 , 3 ),
2984+ del_payload ,
2985+ 0 );
2986+ TEST_ASSERT_EQUAL (2 , cb_result .message .count );
2987+ TEST_ASSERT_EQUAL (1 , cb_result .ack_mandate .count );
2988+ TEST_ASSERT_EQUAL (10 , cb_result .ack_mandate .am .transfer_id );
2989+ TEST_ASSERT_EQUAL_size_t (3 , cb_result .ack_mandate .am .payload_head .size );
2990+ TEST_ASSERT_EQUAL_MEMORY ("dup" , cb_result .ack_mandate .am .payload_head .data , 3 );
2991+ udpard_fragment_free_all (cb_result .message .history [0 ].payload , mem_frag );
2992+ udpard_fragment_free_all (cb_result .message .history [1 ].payload , mem_frag );
2993+ TEST_ASSERT_EQUAL_size_t (0 , alloc_frag .allocated_fragments );
2994+ TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
2995+ udpard_rx_port_free (& rx , & port );
2996+ TEST_ASSERT_EQUAL_size_t (0 , alloc_session .allocated_fragments );
2997+ instrumented_allocator_reset (& alloc_frag );
2998+ instrumented_allocator_reset (& alloc_session );
2999+ instrumented_allocator_reset (& alloc_payload );
3000+ }
3001+
29073002// --------------------------------------------- RX PORT ---------------------------------------------
29083003
29093004/// Exercises udpard_rx_port_push() across ORDERED and STATELESS ports, covering single- and multi-frame transfers.
@@ -3646,6 +3741,7 @@ int main(void)
36463741
36473742 RUN_TEST (test_rx_session_ordered );
36483743 RUN_TEST (test_rx_session_unordered );
3744+ RUN_TEST (test_rx_session_history );
36493745
36503746 RUN_TEST (test_rx_port );
36513747 RUN_TEST (test_rx_port_timeouts );
0 commit comments