@@ -249,9 +249,10 @@ static uint32_t crc_partial_finalize(const size_t n_bytes, const uint32_t crc_ac
249249
250250// --------------------------------------------- HEADER ---------------------------------------------
251251
252- #define HEADER_SIZE_BYTES 48U
253- #define HEADER_VERSION 2U
254- #define HEADER_FLAG_ACK 0x01U
252+ #define HEADER_SIZE_BYTES 48U
253+ #define HEADER_VERSION 2U
254+ #define HEADER_FLAG_ACK 0x01U
255+ #define HEADER_FRAME_INDEX_MAX 0xFFFFFFU /// 4 GiB with 256-byte MTU
255256
256257typedef struct
257258{
@@ -316,7 +317,7 @@ static byte_t* header_serialize(byte_t* const buffer,
316317 * ptr ++ = flags ;
317318 * ptr ++ = 0 ;
318319 * ptr ++ = 0 ;
319- ptr = serialize_u32 (ptr , frame_index );
320+ ptr = serialize_u32 (ptr , frame_index & HEADER_FRAME_INDEX_MAX );
320321 ptr = serialize_u32 (ptr , frame_payload_offset );
321322 ptr = serialize_u32 (ptr , meta .transfer_payload_size );
322323 ptr = serialize_u64 (ptr , meta .transfer_id );
@@ -355,10 +356,15 @@ static bool header_deserialize(const udpard_bytes_mut_t dgram_payload,
355356 ptr = deserialize_u64 (ptr , & out_meta -> topic_hash );
356357 ptr = deserialize_u32 (ptr , prefix_crc );
357358 (void )ptr ;
358- // TODO: validate the fields (e.g., ensure offset+size does not exceed the transfer payload size)
359359 // Set up the output payload view.
360360 out_payload -> size = dgram_payload .size - HEADER_SIZE_BYTES ;
361361 out_payload -> data = (byte_t * )dgram_payload .data + HEADER_SIZE_BYTES ;
362+ // Finalize the fields.
363+ * frame_index = HEADER_FRAME_INDEX_MAX & * frame_index ;
364+ // Validate the fields.
365+ ok = ((uint64_t )* frame_payload_offset + (uint64_t )out_payload -> size ) <=
366+ (uint64_t )out_meta -> transfer_payload_size ;
367+ ok = ok && ((0 == * frame_index ) == (0 == * frame_payload_offset ));
362368 } else {
363369 ok = false;
364370 }
@@ -715,9 +721,8 @@ void udpard_tx_free(const udpard_tx_mem_resources_t memory, udpard_tx_item_t* co
715721/// All but the transfer metadata: fields that change from frame to frame within the same transfer.
716722typedef struct
717723{
718- uint32_t index ;
719724 uint32_t offset ; ///< Offset of this fragment's payload within the full transfer payload.
720- udpard_bytes_t payload ; ///< Also contains the transfer CRC (but not the header CRC) .
725+ udpard_bytes_t payload ; ///< Does not include the header, just pure payload .
721726 udpard_bytes_mut_t origin ; ///< The entirety of the free-able buffer passed from the application.
722727} rx_frame_base_t ;
723728
@@ -732,7 +737,11 @@ typedef struct
732737/// One implication is that no two fragments can have the same offset.
733738static int32_t rx_cavl_compare_fragment_offset (const void * const user , const udpard_tree_t * const node )
734739{
735- return ((* (const size_t * )user ) - ((udpard_fragment_t * )node )-> offset ) ? +1 : -1 ;
740+ const size_t u = * (const size_t * )user ;
741+ const size_t v = ((const udpard_fragment_t * )node )-> offset ; // clang-format off
742+ if (u < v ) { return -1 ; }
743+ if (u > v ) { return +1 ; }
744+ return 0 ; // clang-format on
736745}
737746
738747/// Find the first fragment where offset >= left in log time. Returns NULL if no such fragment exists.
@@ -756,6 +765,7 @@ static bool rx_fragment_tree_has_gap_in_range(udpard_tree_t* const root, const s
756765 if (frag == NULL ) {
757766 return true;
758767 }
768+ // offset+size can overflow on platforms with 16-bit size and requires special treatment there.
759769 if ((frag -> offset + frag -> view .size ) <= left ) { // The predecessor ends before the left edge.
760770 return true;
761771 }
@@ -808,6 +818,27 @@ static size_t rx_fragment_tree_update_covered_prefix(udpard_tree_t* const root,
808818 return out ;
809819}
810820
821+ typedef enum
822+ {
823+ rx_fragment_tree_not_done ,
824+ rx_fragment_tree_done ,
825+ rx_fragment_tree_oom ,
826+ } rx_fragment_tree_update_result_t ;
827+
828+ /// Takes ownership of the frame payload. Returns true if the transfer is fully reassembled in the tree.
829+ static rx_fragment_tree_update_result_t rx_fragment_tree_update (udpard_tree_t * * const root ,
830+ const udpard_mem_resource_t fragment_memory ,
831+ const rx_frame_base_t frame ,
832+ const udpard_mem_deleter_t payload_deleter ,
833+ const size_t transfer_payload_size ,
834+ const size_t extent ,
835+ size_t * const covered_prefix_io )
836+ {
837+ // First we need to check if the new fragment is needed at all. It is needed in two cases:
838+ // 1) It covers new ground in the [0, extent) range.
839+ // 2) It overlaps smaller fragments that are already in the tree, which can be replaced.
840+ }
841+
811842typedef enum
812843{
813844 rx_slot_idle = 0 ,
0 commit comments