@@ -16,6 +16,8 @@ namespace {
1616void on_message (udpard_rx_t * rx, udpard_rx_port_t * port, udpard_rx_transfer_t transfer);
1717void on_collision (udpard_rx_t * rx, udpard_rx_port_t * port, udpard_remote_t remote);
1818constexpr udpard_rx_port_vtable_t callbacks{ .on_message = &on_message, .on_collision = &on_collision };
19+ void on_message_p2p (udpard_rx_t * rx, udpard_rx_port_p2p_t * port, udpard_rx_transfer_p2p_t transfer);
20+ constexpr udpard_rx_port_p2p_vtable_t p2p_callbacks{ &on_message_p2p };
1921
2022struct CapturedFrame
2123{
@@ -47,8 +49,9 @@ constexpr udpard_tx_vtable_t tx_vtable{ .eject = &capture_tx_frame };
4749struct Context
4850{
4951 std::vector<uint64_t > ids;
50- size_t collisions = 0 ;
51- uint64_t expected_uid = 0 ;
52+ size_t collisions = 0 ;
53+ uint64_t expected_uid = 0 ;
54+ uint64_t expected_topic = 0 ;
5255 udpard_udpip_ep_t source{};
5356};
5457
@@ -164,6 +167,19 @@ void on_collision(udpard_rx_t* const rx, udpard_rx_port_t* const /*port*/, const
164167 ctx->collisions ++;
165168}
166169
170+ void on_message_p2p (udpard_rx_t * const rx, udpard_rx_port_p2p_t * const port, const udpard_rx_transfer_p2p_t transfer)
171+ {
172+ auto * const ctx = static_cast <Context*>(rx->user );
173+ ctx->ids .push_back (transfer.base .transfer_id );
174+ if (ctx->expected_topic != 0 ) {
175+ TEST_ASSERT_EQUAL_UINT64 (ctx->expected_topic , transfer.topic_hash );
176+ }
177+ TEST_ASSERT_EQUAL_UINT64 (ctx->expected_uid , transfer.base .remote .uid );
178+ TEST_ASSERT_EQUAL_UINT32 (ctx->source .ip , transfer.base .remote .endpoints [0 ].ip );
179+ TEST_ASSERT_EQUAL_UINT16 (ctx->source .port , transfer.base .remote .endpoints [0 ].port );
180+ udpard_fragment_free_all (transfer.base .payload , port->base .memory .fragment );
181+ }
182+
167183// / UNORDERED mode should drop duplicates while keeping arrival order.
168184void test_udpard_rx_unordered_duplicates ()
169185{
@@ -262,6 +278,86 @@ void test_udpard_rx_ordered_head_advanced_late()
262278 TEST_ASSERT_EQUAL_size_t (0 , fix.ctx .collisions );
263279}
264280
281+ // / P2P helper should emit frames with auto transfer-ID and proper addressing.
282+ void test_udpard_tx_push_p2p ()
283+ {
284+ instrumented_allocator_t tx_alloc_transfer{};
285+ instrumented_allocator_t tx_alloc_payload{};
286+ instrumented_allocator_t rx_alloc_frag{};
287+ instrumented_allocator_t rx_alloc_session{};
288+ instrumented_allocator_new (&tx_alloc_transfer);
289+ instrumented_allocator_new (&tx_alloc_payload);
290+ instrumented_allocator_new (&rx_alloc_frag);
291+ instrumented_allocator_new (&rx_alloc_session);
292+ udpard_tx_mem_resources_t tx_mem{};
293+ tx_mem.transfer = instrumented_allocator_make_resource (&tx_alloc_transfer);
294+ for (auto & res : tx_mem.payload ) {
295+ res = instrumented_allocator_make_resource (&tx_alloc_payload);
296+ }
297+ udpard_tx_t tx{};
298+ TEST_ASSERT_TRUE (udpard_tx_new (&tx, 0x1122334455667788ULL , 5U , 8 , tx_mem, &tx_vtable));
299+ std::vector<CapturedFrame> frames;
300+ tx.user = &frames;
301+
302+ const udpard_rx_mem_resources_t rx_mem{ .session = instrumented_allocator_make_resource (&rx_alloc_session),
303+ .fragment = instrumented_allocator_make_resource (&rx_alloc_frag) };
304+ udpard_rx_t rx{};
305+ udpard_rx_port_p2p_t port{};
306+ Context ctx{};
307+ const udpard_udpip_ep_t source{ .ip = 0x0A0000AAU , .port = 7600U };
308+ const udpard_udpip_ep_t dest{ .ip = 0x0A000010U , .port = 7400U };
309+ const uint64_t local_uid = 0xCAFEBABECAFED00DULL ;
310+ const uint64_t topic_hash = 0xAABBCCDDEEFF1122ULL ;
311+ ctx.expected_uid = tx.local_uid ;
312+ ctx.expected_topic = topic_hash;
313+ ctx.source = source;
314+ rx.user = &ctx;
315+ TEST_ASSERT_TRUE (udpard_rx_port_new_p2p (&port, local_uid, 1024 , rx_mem, &p2p_callbacks));
316+
317+ udpard_remote_t remote{};
318+ remote.uid = local_uid;
319+ remote.endpoints [0U ] = dest;
320+
321+ std::array<uint8_t , UDPARD_P2P_HEADER_BYTES> payload_buf{};
322+ constexpr uint8_t p2p_kind_response = 0U ;
323+ payload_buf[0 ] = p2p_kind_response;
324+ for (size_t i = 0 ; i < sizeof (topic_hash); i++) {
325+ payload_buf[8U + i] = static_cast <uint8_t >((topic_hash >> (i * 8U )) & 0xFFU );
326+ }
327+ const uint64_t response_transfer_id = 55 ;
328+ for (size_t i = 0 ; i < sizeof (response_transfer_id); i++) {
329+ payload_buf[16U + i] = static_cast <uint8_t >((response_transfer_id >> (i * 8U )) & 0xFFU );
330+ }
331+ const udpard_bytes_t payload{ .size = payload_buf.size (), .data = payload_buf.data () };
332+ const udpard_us_t now = 0 ;
333+ const uint64_t first_id = tx.p2p_transfer_id ;
334+ TEST_ASSERT_GREATER_THAN_UINT32 (
335+ 0U , udpard_tx_push_p2p (&tx, now, now + 1000000 , udpard_prio_nominal, remote, payload, nullptr , nullptr ));
336+ udpard_tx_poll (&tx, now, UDPARD_IFACE_MASK_ALL);
337+ TEST_ASSERT_FALSE (frames.empty ());
338+
339+ const udpard_mem_deleter_t tx_payload_deleter{ .user = nullptr , .free = &tx_refcount_free };
340+ for (const auto & f : frames) {
341+ TEST_ASSERT_TRUE (udpard_rx_port_push (
342+ &rx, reinterpret_cast <udpard_rx_port_t *>(&port), now, source, f.datagram , tx_payload_deleter, f.iface_index ));
343+ }
344+ udpard_rx_poll (&rx, now);
345+ TEST_ASSERT_EQUAL_size_t (1 , ctx.ids .size ());
346+ TEST_ASSERT_EQUAL_UINT64 (first_id, ctx.ids [0 ]);
347+ TEST_ASSERT_EQUAL_size_t (0 , ctx.collisions );
348+
349+ udpard_rx_port_free (&rx, reinterpret_cast <udpard_rx_port_t *>(&port));
350+ udpard_tx_free (&tx);
351+ TEST_ASSERT_EQUAL (0 , tx_alloc_transfer.allocated_fragments );
352+ TEST_ASSERT_EQUAL (0 , tx_alloc_payload.allocated_fragments );
353+ TEST_ASSERT_EQUAL (0 , rx_alloc_frag.allocated_fragments );
354+ TEST_ASSERT_EQUAL (0 , rx_alloc_session.allocated_fragments );
355+ instrumented_allocator_reset (&tx_alloc_transfer);
356+ instrumented_allocator_reset (&tx_alloc_payload);
357+ instrumented_allocator_reset (&rx_alloc_frag);
358+ instrumented_allocator_reset (&rx_alloc_session);
359+ }
360+
265361} // namespace
266362
267363extern " C" void setUp () {}
@@ -274,5 +370,6 @@ int main()
274370 RUN_TEST (test_udpard_rx_unordered_duplicates);
275371 RUN_TEST (test_udpard_rx_ordered_out_of_order);
276372 RUN_TEST (test_udpard_rx_ordered_head_advanced_late);
373+ RUN_TEST (test_udpard_tx_push_p2p);
277374 return UNITY_END ();
278375}
0 commit comments