@@ -2095,6 +2095,86 @@ static void test_rx_session_unordered_duplicates(void)
20952095 instrumented_allocator_reset (& alloc_payload );
20962096}
20972097
2098+ static void test_rx_session_malformed (void )
2099+ {
2100+ // Malformed transfer increments error counter and drops slot.
2101+ instrumented_allocator_t alloc_frag = { 0 };
2102+ instrumented_allocator_new (& alloc_frag );
2103+ instrumented_allocator_t alloc_session = { 0 };
2104+ instrumented_allocator_new (& alloc_session );
2105+ instrumented_allocator_t alloc_slot = { 0 };
2106+ instrumented_allocator_new (& alloc_slot );
2107+ instrumented_allocator_t alloc_payload = { 0 };
2108+ instrumented_allocator_new (& alloc_payload );
2109+ const udpard_mem_t mem_frag = instrumented_allocator_make_resource (& alloc_frag );
2110+ const udpard_mem_t mem_session = instrumented_allocator_make_resource (& alloc_session );
2111+ const udpard_mem_t mem_slot = instrumented_allocator_make_resource (& alloc_slot );
2112+ const udpard_mem_t mem_payload = instrumented_allocator_make_resource (& alloc_payload );
2113+ const udpard_deleter_t del_payload = instrumented_allocator_make_deleter (& alloc_payload );
2114+ const udpard_rx_mem_resources_t rx_mem = { .fragment = mem_frag , .session = mem_session , .slot = mem_slot };
2115+
2116+ udpard_rx_t rx ;
2117+ udpard_rx_new (& rx , NULL );
2118+ callback_result_t cb_result = { 0 };
2119+ rx .user = & cb_result ;
2120+
2121+ udpard_rx_port_t port = { 0 };
2122+ TEST_ASSERT (udpard_rx_port_new (& port , 64 , rx_mem , & callbacks ));
2123+
2124+ const uint64_t remote_uid = 0xABCDEF1234567890ULL ;
2125+ rx_session_factory_args_t fac_args = {
2126+ .owner = & port ,
2127+ .sessions_by_animation = & rx .list_session_by_animation ,
2128+ .remote_uid = remote_uid ,
2129+ .now = 0 ,
2130+ };
2131+ rx_session_t * const ses = (rx_session_t * )cavl2_find_or_insert (& port .index_session_by_remote_uid ,
2132+ & remote_uid ,
2133+ & cavl_compare_rx_session_by_remote_uid ,
2134+ & fac_args ,
2135+ & cavl_factory_rx_session_by_remote_uid );
2136+ TEST_ASSERT_NOT_NULL (ses );
2137+
2138+ meta_t meta = { .priority = udpard_prio_nominal ,
2139+ .kind = frame_msg_best ,
2140+ .transfer_payload_size = 8 ,
2141+ .transfer_id = 1 ,
2142+ .sender_uid = remote_uid };
2143+ udpard_us_t now = 0 ;
2144+ rx_session_update (ses ,
2145+ & rx ,
2146+ now ,
2147+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1111 },
2148+ make_frame_ptr (meta , mem_payload , "ABCDEFGH" , 0 , 4 ),
2149+ del_payload ,
2150+ 0 );
2151+ TEST_ASSERT_EQUAL_UINT64 (0 , rx .errors_transfer_malformed );
2152+ TEST_ASSERT_EQUAL (0 , cb_result .message .count );
2153+ TEST_ASSERT_EQUAL_size_t (1 , alloc_frag .allocated_fragments );
2154+ TEST_ASSERT_EQUAL_size_t (1 , alloc_slot .allocated_fragments );
2155+
2156+ meta .priority = udpard_prio_high ;
2157+ now += 10 ;
2158+ rx_session_update (ses ,
2159+ & rx ,
2160+ now ,
2161+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1111 },
2162+ make_frame_ptr (meta , mem_payload , "ABCDEFGH" , 4 , 4 ),
2163+ del_payload ,
2164+ 0 );
2165+ TEST_ASSERT_EQUAL_UINT64 (1 , rx .errors_transfer_malformed );
2166+ TEST_ASSERT_EQUAL (0 , cb_result .message .count );
2167+ TEST_ASSERT_EQUAL_size_t (0 , alloc_frag .allocated_fragments );
2168+ TEST_ASSERT_EQUAL_size_t (0 , alloc_slot .allocated_fragments );
2169+ TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
2170+
2171+ udpard_rx_port_free (& rx , & port );
2172+ instrumented_allocator_reset (& alloc_frag );
2173+ instrumented_allocator_reset (& alloc_session );
2174+ instrumented_allocator_reset (& alloc_slot );
2175+ instrumented_allocator_reset (& alloc_payload );
2176+ }
2177+
20982178static void test_rx_port (void )
20992179{
21002180 // P2P ports behave like ordinary ports for payload delivery.
@@ -2277,6 +2357,67 @@ static void test_rx_port_oom(void)
22772357 instrumented_allocator_reset (& alloc_frag );
22782358 instrumented_allocator_reset (& alloc_session );
22792359 instrumented_allocator_reset (& alloc_payload );
2360+
2361+ // Slot allocation failure should be reported gracefully.
2362+ instrumented_allocator_t alloc_frag_slot = { 0 };
2363+ instrumented_allocator_new (& alloc_frag_slot );
2364+ instrumented_allocator_t alloc_session_slot = { 0 };
2365+ instrumented_allocator_new (& alloc_session_slot );
2366+ instrumented_allocator_t alloc_slot = { 0 };
2367+ instrumented_allocator_new (& alloc_slot );
2368+ alloc_slot .limit_fragments = 0 ; // force slot allocation failure
2369+ instrumented_allocator_t alloc_payload_slot = { 0 };
2370+ instrumented_allocator_new (& alloc_payload_slot );
2371+ const udpard_mem_t mem_frag_slot = instrumented_allocator_make_resource (& alloc_frag_slot );
2372+ const udpard_mem_t mem_session_slot = instrumented_allocator_make_resource (& alloc_session_slot );
2373+ const udpard_mem_t mem_slot = instrumented_allocator_make_resource (& alloc_slot );
2374+ const udpard_mem_t mem_payload_slot = instrumented_allocator_make_resource (& alloc_payload_slot );
2375+ const udpard_deleter_t del_payload_slot = instrumented_allocator_make_deleter (& alloc_payload_slot );
2376+ const udpard_rx_mem_resources_t rx_mem_slot = { .fragment = mem_frag_slot ,
2377+ .session = mem_session_slot ,
2378+ .slot = mem_slot };
2379+
2380+ udpard_rx_t rx_slot ;
2381+ udpard_rx_new (& rx_slot , NULL );
2382+ callback_result_t cb_result_slot = { 0 };
2383+ rx_slot .user = & cb_result_slot ;
2384+
2385+ udpard_rx_port_t port_slot = { 0 };
2386+ TEST_ASSERT (udpard_rx_port_new (& port_slot , 64 , rx_mem_slot , & callbacks ));
2387+
2388+ meta_t meta_slot = { .priority = udpard_prio_nominal ,
2389+ .kind = frame_msg_best ,
2390+ .transfer_payload_size = 4 ,
2391+ .transfer_id = 1 ,
2392+ .sender_uid = 0x0202020202020202ULL };
2393+ rx_frame_t * frame_slot = make_frame_ptr (meta_slot , mem_payload_slot , "oom!" , 0 , 4 );
2394+ const byte_t payload_slot [] = { 'o' , 'o' , 'm' , '!' };
2395+ byte_t dgram_slot [HEADER_SIZE_BYTES + sizeof (payload_slot )];
2396+ header_serialize (dgram_slot , meta_slot , 0 , 0 , frame_slot -> base .crc );
2397+ memcpy (dgram_slot + HEADER_SIZE_BYTES , payload_slot , sizeof (payload_slot ));
2398+ mem_free (mem_payload_slot , frame_slot -> base .origin .size , frame_slot -> base .origin .data );
2399+ void * payload_buf_slot = mem_res_alloc (mem_payload_slot , sizeof (dgram_slot ));
2400+ memcpy (payload_buf_slot , dgram_slot , sizeof (dgram_slot ));
2401+
2402+ now = 0 ;
2403+ TEST_ASSERT (udpard_rx_port_push (& rx_slot ,
2404+ & port_slot ,
2405+ now ,
2406+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1234 },
2407+ (udpard_bytes_mut_t ){ .data = payload_buf_slot , .size = sizeof (dgram_slot ) },
2408+ del_payload_slot ,
2409+ 0 ));
2410+ TEST_ASSERT_GREATER_THAN_UINT64 (0 , rx_slot .errors_oom );
2411+ TEST_ASSERT_EQUAL (1 , alloc_session_slot .allocated_fragments );
2412+ TEST_ASSERT_EQUAL (0 , alloc_slot .allocated_fragments );
2413+ TEST_ASSERT_EQUAL (0 , alloc_frag_slot .allocated_fragments );
2414+ TEST_ASSERT_EQUAL (0 , alloc_payload_slot .allocated_fragments );
2415+ udpard_rx_port_free (& rx_slot , & port_slot );
2416+ TEST_ASSERT_EQUAL (0 , alloc_session_slot .allocated_fragments );
2417+ instrumented_allocator_reset (& alloc_frag_slot );
2418+ instrumented_allocator_reset (& alloc_session_slot );
2419+ instrumented_allocator_reset (& alloc_slot );
2420+ instrumented_allocator_reset (& alloc_payload_slot );
22802421}
22812422
22822423static void test_rx_port_free_loop (void )
@@ -2548,6 +2689,7 @@ int main(void)
25482689 RUN_TEST (test_rx_session_unordered );
25492690 RUN_TEST (test_rx_session_unordered_reject_old );
25502691 RUN_TEST (test_rx_session_unordered_duplicates );
2692+ RUN_TEST (test_rx_session_malformed );
25512693
25522694 RUN_TEST (test_rx_port );
25532695 RUN_TEST (test_rx_port_timeouts );
0 commit comments