@@ -82,7 +82,7 @@ static bool transfer_payload_verify(udpard_rx_transfer_t* const transfer,
8282 return (transfer -> payload_size_wire == payload_size_wire ) && (offset == payload_size_stored );
8383}
8484
85- // --------------------------------------------- FRAGMENT TREE ---------------------------------------------
85+ // --------------------------------------------- RX FRAGMENT TREE ---------------------------------------------
8686
8787static udpard_fragment_t * fragment_at (udpard_tree_t * const root , uint32_t index )
8888{
@@ -1163,7 +1163,7 @@ static void test_rx_fragment_tree_oom(void)
11631163 instrumented_allocator_reset (& alloc_payload );
11641164}
11651165
1166- // --------------------------------------------- TRANSFER-ID WINDOW ---------------------------------------------
1166+ // --------------------------------------------- RX TRANSFER-ID WINDOW ---------------------------------------------
11671167
11681168static void test_rx_transfer_id_forward_distance (void )
11691169{
@@ -1610,7 +1610,7 @@ static void test_rx_transfer_id_window_manip(void)
16101610 TEST_ASSERT_FALSE (rx_transfer_id_window_contains (& obj , 1001 )); // ahead (outside)
16111611}
16121612
1613- // --------------------------------------------- SLOT ---------------------------------------------
1613+ // --------------------------------------------- RX SLOT ---------------------------------------------
16141614
16151615static void test_rx_slot_update (void )
16161616{
@@ -1971,7 +1971,7 @@ static void test_rx_slot_update(void)
19711971 TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
19721972}
19731973
1974- // --------------------------------------------- SESSION ---------------------------------------------
1974+ // --------------------------------------------- RX SESSION ---------------------------------------------
19751975
19761976typedef struct
19771977{
@@ -2908,7 +2908,7 @@ static void test_rx_session_unordered(void)
29082908 instrumented_allocator_reset (& alloc_payload );
29092909}
29102910
2911- // --------------------------------------------- PORT ---------------------------------------------
2911+ // --------------------------------------------- RX PORT ---------------------------------------------
29122912
29132913/// Tests ports in ORDERED, UNORDERED, and STATELESS modes.
29142914/// The UNORDERED port is the p2p_port in the rx instance; the other modes are tested on separate port instances.
@@ -3453,6 +3453,93 @@ static void test_rx_port_timeouts(void)
34533453 TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
34543454}
34553455
3456+ static void test_rx_port_oom (void )
3457+ {
3458+ instrumented_allocator_t alloc_frag = { 0 };
3459+ instrumented_allocator_new (& alloc_frag );
3460+ instrumented_allocator_t alloc_session = { 0 };
3461+ instrumented_allocator_new (& alloc_session );
3462+ instrumented_allocator_t alloc_payload = { 0 };
3463+ instrumented_allocator_new (& alloc_payload );
3464+ alloc_session .limit_fragments = 0 ;
3465+ alloc_frag .limit_fragments = 0 ;
3466+ const udpard_mem_resource_t mem_frag = instrumented_allocator_make_resource (& alloc_frag );
3467+ const udpard_mem_resource_t mem_session = instrumented_allocator_make_resource (& alloc_session );
3468+ const udpard_mem_resource_t mem_payload = instrumented_allocator_make_resource (& alloc_payload );
3469+ const udpard_mem_deleter_t del_payload = instrumented_allocator_make_deleter (& alloc_payload );
3470+ const udpard_rx_memory_resources_t rx_mem = { .fragment = mem_frag , .session = mem_session };
3471+ udpard_rx_t rx ;
3472+ callback_result_t cb_result = { 0 };
3473+ TEST_ASSERT (udpard_rx_new (& rx , 0x5555ULL , rx_mem , & on_message , & on_collision , & on_ack_mandate ));
3474+ rx .user = & cb_result ;
3475+ udpard_rx_port_t port_ordered ;
3476+ udpard_rx_port_t port_stateless ;
3477+ TEST_ASSERT (udpard_rx_port_new (& port_ordered , 0xAAAALL , 100 , 20000 , rx_mem ));
3478+ TEST_ASSERT (udpard_rx_port_new (& port_stateless , 0xBBBBLL , 100 , UDPARD_REORDERING_WINDOW_STATELESS , rx_mem ));
3479+ udpard_us_t now = 0 ;
3480+ const byte_t payload_state [] = { 's' , 't' , 'a' , 't' , 'e' , 'f' , 'u' , 'l' };
3481+ const size_t payload_len = sizeof (payload_state );
3482+ meta_t meta_state = { .priority = udpard_prio_nominal ,
3483+ .flag_ack = false,
3484+ .transfer_payload_size = (uint32_t )payload_len ,
3485+ .transfer_id = 1 ,
3486+ .sender_uid = 0x1111ULL ,
3487+ .topic_hash = 0xAAAALL };
3488+ const rx_frame_t frame_state = make_frame (meta_state , mem_payload , payload_state , 0 , payload_len );
3489+ byte_t dgram_state [HEADER_SIZE_BYTES + payload_len ];
3490+ header_serialize (dgram_state , meta_state , 0 , 0 , frame_state .base .crc );
3491+ memcpy (dgram_state + HEADER_SIZE_BYTES , payload_state , payload_len );
3492+ mem_free (mem_payload , frame_state .base .origin .size , frame_state .base .origin .data );
3493+ void * push_state = mem_payload .alloc (mem_payload .user , sizeof (dgram_state ));
3494+ memcpy (push_state , dgram_state , sizeof (dgram_state ));
3495+ const uint64_t errors_before = rx .errors_oom ;
3496+ TEST_ASSERT (udpard_rx_port_push (& rx ,
3497+ & port_ordered ,
3498+ now ,
3499+ (udpard_udpip_ep_t ){ .ip = 0x0A000001 , .port = 0x1234 },
3500+ (udpard_bytes_mut_t ){ .data = push_state , .size = sizeof (dgram_state ) },
3501+ del_payload ,
3502+ 0 ));
3503+ TEST_ASSERT_EQUAL (errors_before + 1 , rx .errors_oom );
3504+ TEST_ASSERT_EQUAL (0 , cb_result .message .count );
3505+ const byte_t payload_stateless [] = { 's' , 't' , 'a' , 't' , 'e' , 'l' , 'e' , 's' , 's' };
3506+ const size_t payload_stat_len = sizeof (payload_stateless );
3507+ meta_t meta_stateless = { .priority = udpard_prio_slow ,
3508+ .flag_ack = false,
3509+ .transfer_payload_size = (uint32_t )payload_stat_len ,
3510+ .transfer_id = 2 ,
3511+ .sender_uid = 0x2222ULL ,
3512+ .topic_hash = 0xBBBBLL };
3513+ const rx_frame_t frame_stateless = make_frame (meta_stateless , mem_payload , payload_stateless , 0 , payload_stat_len );
3514+ byte_t dgram_stateless [HEADER_SIZE_BYTES + payload_stat_len ];
3515+ header_serialize (dgram_stateless , meta_stateless , 0 , 0 , frame_stateless .base .crc );
3516+ memcpy (dgram_stateless + HEADER_SIZE_BYTES , payload_stateless , payload_stat_len );
3517+ mem_free (mem_payload , frame_stateless .base .origin .size , frame_stateless .base .origin .data );
3518+ void * push_stateless = mem_payload .alloc (mem_payload .user , sizeof (dgram_stateless ));
3519+ memcpy (push_stateless , dgram_stateless , sizeof (dgram_stateless ));
3520+ now += 1000 ;
3521+ TEST_ASSERT (udpard_rx_port_push (& rx ,
3522+ & port_stateless ,
3523+ now ,
3524+ (udpard_udpip_ep_t ){ .ip = 0x0A000002 , .port = 0x5678 },
3525+ (udpard_bytes_mut_t ){ .data = push_stateless , .size = sizeof (dgram_stateless ) },
3526+ del_payload ,
3527+ 1 ));
3528+ TEST_ASSERT_EQUAL (errors_before + 2 , rx .errors_oom );
3529+ TEST_ASSERT_EQUAL (0 , cb_result .message .count );
3530+ udpard_rx_port_free (& rx , & port_ordered );
3531+ udpard_rx_port_free (& rx , & port_stateless );
3532+ udpard_rx_free (& rx );
3533+ TEST_ASSERT_EQUAL_size_t (0 , alloc_frag .allocated_fragments );
3534+ TEST_ASSERT_EQUAL_size_t (0 , alloc_session .allocated_fragments );
3535+ TEST_ASSERT_EQUAL_size_t (0 , alloc_payload .allocated_fragments );
3536+ instrumented_allocator_reset (& alloc_frag );
3537+ instrumented_allocator_reset (& alloc_session );
3538+ instrumented_allocator_reset (& alloc_payload );
3539+ }
3540+
3541+ // --------------------------------------------- RX ---------------------------------------------
3542+
34563543/// Ensures udpard_rx_free walks and clears all sessions across ports.
34573544static void test_rx_free_loop (void )
34583545{
@@ -3569,6 +3656,7 @@ int main(void)
35693656
35703657 RUN_TEST (test_rx_port );
35713658 RUN_TEST (test_rx_port_timeouts );
3659+ RUN_TEST (test_rx_port_oom );
35723660
35733661 RUN_TEST (test_rx_free_loop );
35743662
0 commit comments